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 static bool name_set; 41 if (!name_set) { 42 prctl(PR_SET_NAME, "logd.reader"); 43 name_set = true; 44 } 45 46 char buffer[255]; 47 48 int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); 49 if (len <= 0) { 50 doSocketDelete(cli); 51 return false; 52 } 53 buffer[len] = '\0'; 54 55 unsigned long tail = 0; 56 static const char _tail[] = " tail="; 57 char *cp = strstr(buffer, _tail); 58 if (cp) { 59 tail = atol(cp + sizeof(_tail) - 1); 60 } 61 62 log_time start(log_time::EPOCH); 63 static const char _start[] = " start="; 64 cp = strstr(buffer, _start); 65 if (cp) { 66 // Parse errors will result in current time 67 start.strptime(cp + sizeof(_start) - 1, "%s.%q"); 68 } 69 70 unsigned int logMask = -1; 71 static const char _logIds[] = " lids="; 72 cp = strstr(buffer, _logIds); 73 if (cp) { 74 logMask = 0; 75 cp += sizeof(_logIds) - 1; 76 while (*cp && *cp != '\0') { 77 int val = 0; 78 while (isdigit(*cp)) { 79 val = val * 10 + *cp - '0'; 80 ++cp; 81 } 82 logMask |= 1 << val; 83 if (*cp != ',') { 84 break; 85 } 86 ++cp; 87 } 88 } 89 90 pid_t pid = 0; 91 static const char _pid[] = " pid="; 92 cp = strstr(buffer, _pid); 93 if (cp) { 94 pid = atol(cp + sizeof(_pid) - 1); 95 } 96 97 bool nonBlock = false; 98 if (strncmp(buffer, "dumpAndClose", 12) == 0) { 99 // Allow writer to get some cycles, and wait for pending notifications 100 sched_yield(); 101 LogTimeEntry::lock(); 102 LogTimeEntry::unlock(); 103 sched_yield(); 104 nonBlock = true; 105 } 106 107 uint64_t sequence = 1; 108 // Convert realtime to sequence number 109 if (start != log_time::EPOCH) { 110 class LogFindStart { 111 const pid_t mPid; 112 const unsigned mLogMask; 113 bool startTimeSet; 114 log_time &start; 115 uint64_t &sequence; 116 uint64_t last; 117 118 public: 119 LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) : 120 mPid(pid), 121 mLogMask(logMask), 122 startTimeSet(false), 123 start(start), 124 sequence(sequence), 125 last(sequence) { 126 } 127 128 static int callback(const LogBufferElement *element, void *obj) { 129 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj); 130 if ((!me->mPid || (me->mPid == element->getPid())) 131 && (me->mLogMask & (1 << element->getLogId()))) { 132 if (me->start == element->getRealTime()) { 133 me->sequence = element->getSequence(); 134 me->startTimeSet = true; 135 return -1; 136 } else { 137 if (me->start < element->getRealTime()) { 138 me->sequence = me->last; 139 me->startTimeSet = true; 140 return -1; 141 } 142 me->last = element->getSequence(); 143 } 144 } 145 return false; 146 } 147 148 bool found() { return startTimeSet; } 149 } logFindStart(logMask, pid, start, sequence); 150 151 logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli), 152 logFindStart.callback, &logFindStart); 153 154 if (!logFindStart.found()) { 155 if (nonBlock) { 156 doSocketDelete(cli); 157 return false; 158 } 159 sequence = LogBufferElement::getCurrentSequence(); 160 } 161 } 162 163 FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence); 164 command.runSocketCommand(cli); 165 return true; 166 } 167 168 void LogReader::doSocketDelete(SocketClient *cli) { 169 LastLogTimes × = mLogbuf.mTimes; 170 LogTimeEntry::lock(); 171 LastLogTimes::iterator it = times.begin(); 172 while(it != times.end()) { 173 LogTimeEntry *entry = (*it); 174 if (entry->mClient == cli) { 175 times.erase(it); 176 entry->release_Locked(); 177 break; 178 } 179 it++; 180 } 181 LogTimeEntry::unlock(); 182 } 183 184 int LogReader::getLogSocket() { 185 static const char socketName[] = "logdr"; 186 int sock = android_get_control_socket(socketName); 187 188 if (sock < 0) { 189 sock = socket_local_server(socketName, 190 ANDROID_SOCKET_NAMESPACE_RESERVED, 191 SOCK_SEQPACKET); 192 } 193 194 return sock; 195 } 196