LogReader.cpp revision 8daa9af02dc0e63ce220e3fa95bf5fe4d6b7a99a
1/* 2 * Copyright (C) 2012-2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <ctype.h> 18#include <poll.h> 19#include <sys/prctl.h> 20#include <sys/socket.h> 21 22#include <cutils/sockets.h> 23 24#include "LogReader.h" 25#include "FlushCommand.h" 26 27LogReader::LogReader(LogBuffer *logbuf) 28 : SocketListener(getLogSocket(), true) 29 , mLogbuf(*logbuf) 30{ } 31 32// When we are notified a new log entry is available, inform 33// all of our listening sockets. 34void LogReader::notifyNewLog() { 35 FlushCommand command(*this); 36 runOnEachSocket(&command); 37} 38 39bool LogReader::onDataAvailable(SocketClient *cli) { 40 prctl(PR_SET_NAME, "logd.reader"); 41 42 char buffer[255]; 43 44 int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); 45 if (len <= 0) { 46 doSocketDelete(cli); 47 return false; 48 } 49 buffer[len] = '\0'; 50 51 unsigned long tail = 0; 52 static const char _tail[] = " tail="; 53 char *cp = strstr(buffer, _tail); 54 if (cp) { 55 tail = atol(cp + sizeof(_tail) - 1); 56 } 57 58 log_time start(log_time::EPOCH); 59 static const char _start[] = " start="; 60 cp = strstr(buffer, _start); 61 if (cp) { 62 // Parse errors will result in current time 63 start.strptime(cp + sizeof(_start) - 1, "%s.%q"); 64 } 65 66 unsigned int logMask = -1; 67 static const char _logIds[] = " lids="; 68 cp = strstr(buffer, _logIds); 69 if (cp) { 70 logMask = 0; 71 cp += sizeof(_logIds) - 1; 72 while (*cp && *cp != '\0') { 73 int val = 0; 74 while (isdigit(*cp)) { 75 val = val * 10 + *cp - '0'; 76 ++cp; 77 } 78 logMask |= 1 << val; 79 if (*cp != ',') { 80 break; 81 } 82 ++cp; 83 } 84 } 85 86 pid_t pid = 0; 87 static const char _pid[] = " pid="; 88 cp = strstr(buffer, _pid); 89 if (cp) { 90 pid = atol(cp + sizeof(_pid) - 1); 91 } 92 93 bool nonBlock = false; 94 if (strncmp(buffer, "dumpAndClose", 12) == 0) { 95 nonBlock = true; 96 } 97 98 // Convert realtime to monotonic time 99 if (start == log_time::EPOCH) { 100 start = LogTimeEntry::EPOCH; 101 } else { 102 class LogFindStart { 103 const pid_t mPid; 104 const unsigned mLogMask; 105 bool startTimeSet; 106 log_time &start; 107 log_time last; 108 109 public: 110 LogFindStart(unsigned logMask, pid_t pid, log_time &start) 111 : mPid(pid) 112 , mLogMask(logMask) 113 , startTimeSet(false) 114 , start(start) 115 , last(LogTimeEntry::EPOCH) 116 { } 117 118 static bool callback(const LogBufferElement *element, void *obj) { 119 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj); 120 if (!me->startTimeSet 121 && (!me->mPid || (me->mPid == element->getPid())) 122 && (me->mLogMask & (1 << element->getLogId()))) { 123 if (me->start == element->getRealTime()) { 124 me->start = element->getMonotonicTime(); 125 me->startTimeSet = true; 126 } else { 127 if (me->start < element->getRealTime()) { 128 me->start = me->last; 129 me->startTimeSet = true; 130 } 131 me->last = element->getMonotonicTime(); 132 } 133 } 134 return false; 135 } 136 137 bool found() { return startTimeSet; } 138 } logFindStart(logMask, pid, start); 139 140 logbuf().flushTo(cli, LogTimeEntry::EPOCH, 141 FlushCommand::hasReadLogs(cli), 142 logFindStart.callback, &logFindStart); 143 144 if (!logFindStart.found()) { 145 if (nonBlock) { 146 doSocketDelete(cli); 147 return false; 148 } 149 log_time now(CLOCK_MONOTONIC); 150 start = now; 151 } 152 } 153 154 FlushCommand command(*this, nonBlock, tail, logMask, pid, start); 155 command.runSocketCommand(cli); 156 return true; 157} 158 159void LogReader::doSocketDelete(SocketClient *cli) { 160 LastLogTimes × = mLogbuf.mTimes; 161 LogTimeEntry::lock(); 162 LastLogTimes::iterator it = times.begin(); 163 while(it != times.end()) { 164 LogTimeEntry *entry = (*it); 165 if (entry->mClient == cli) { 166 times.erase(it); 167 entry->release_Locked(); 168 break; 169 } 170 it++; 171 } 172 LogTimeEntry::unlock(); 173} 174 175int LogReader::getLogSocket() { 176 static const char socketName[] = "logdr"; 177 int sock = android_get_control_socket(socketName); 178 179 if (sock < 0) { 180 sock = socket_local_server(socketName, 181 ANDROID_SOCKET_NAMESPACE_RESERVED, 182 SOCK_SEQPACKET); 183 } 184 185 return sock; 186} 187