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 27 LogReader::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. 34 void LogReader::notifyNewLog() { 35 FlushCommand command(*this); 36 runOnEachSocket(&command); 37 } 38 39 bool 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 // Allow writer to get some cycles, and wait for pending notifications 96 sched_yield(); 97 LogTimeEntry::lock(); 98 LogTimeEntry::unlock(); 99 sched_yield(); 100 nonBlock = true; 101 } 102 103 // Convert realtime to monotonic time 104 if (start == log_time::EPOCH) { 105 start = LogTimeEntry::EPOCH; 106 } else { 107 class LogFindStart { 108 const pid_t mPid; 109 const unsigned mLogMask; 110 bool startTimeSet; 111 log_time &start; 112 log_time last; 113 114 public: 115 LogFindStart(unsigned logMask, pid_t pid, log_time &start) 116 : mPid(pid) 117 , mLogMask(logMask) 118 , startTimeSet(false) 119 , start(start) 120 , last(LogTimeEntry::EPOCH) 121 { } 122 123 static bool callback(const LogBufferElement *element, void *obj) { 124 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj); 125 if (!me->startTimeSet 126 && (!me->mPid || (me->mPid == element->getPid())) 127 && (me->mLogMask & (1 << element->getLogId()))) { 128 if (me->start == element->getRealTime()) { 129 me->start = element->getMonotonicTime(); 130 me->startTimeSet = true; 131 } else { 132 if (me->start < element->getRealTime()) { 133 me->start = me->last; 134 me->startTimeSet = true; 135 } 136 me->last = element->getMonotonicTime(); 137 } 138 } 139 return false; 140 } 141 142 bool found() { return startTimeSet; } 143 } logFindStart(logMask, pid, start); 144 145 logbuf().flushTo(cli, LogTimeEntry::EPOCH, 146 FlushCommand::hasReadLogs(cli), 147 logFindStart.callback, &logFindStart); 148 149 if (!logFindStart.found()) { 150 if (nonBlock) { 151 doSocketDelete(cli); 152 return false; 153 } 154 log_time now(CLOCK_MONOTONIC); 155 start = now; 156 } 157 } 158 159 FlushCommand command(*this, nonBlock, tail, logMask, pid, start); 160 command.runSocketCommand(cli); 161 return true; 162 } 163 164 void LogReader::doSocketDelete(SocketClient *cli) { 165 LastLogTimes × = mLogbuf.mTimes; 166 LogTimeEntry::lock(); 167 LastLogTimes::iterator it = times.begin(); 168 while(it != times.end()) { 169 LogTimeEntry *entry = (*it); 170 if (entry->mClient == cli) { 171 times.erase(it); 172 entry->release_Locked(); 173 break; 174 } 175 it++; 176 } 177 LogTimeEntry::unlock(); 178 } 179 180 int LogReader::getLogSocket() { 181 static const char socketName[] = "logdr"; 182 int sock = android_get_control_socket(socketName); 183 184 if (sock < 0) { 185 sock = socket_local_server(socketName, 186 ANDROID_SOCKET_NAMESPACE_RESERVED, 187 SOCK_SEQPACKET); 188 } 189 190 return sock; 191 } 192