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 #include <sys/types.h> 22 23 #include <cutils/sockets.h> 24 25 #include "FlushCommand.h" 26 #include "LogBuffer.h" 27 #include "LogBufferElement.h" 28 #include "LogReader.h" 29 #include "LogUtils.h" 30 31 LogReader::LogReader(LogBuffer *logbuf) : 32 SocketListener(getLogSocket(), true), 33 mLogbuf(*logbuf) { 34 } 35 36 // When we are notified a new log entry is available, inform 37 // all of our listening sockets. 38 void LogReader::notifyNewLog() { 39 FlushCommand command(*this); 40 runOnEachSocket(&command); 41 } 42 43 bool LogReader::onDataAvailable(SocketClient *cli) { 44 static bool name_set; 45 if (!name_set) { 46 prctl(PR_SET_NAME, "logd.reader"); 47 name_set = true; 48 } 49 50 char buffer[255]; 51 52 int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); 53 if (len <= 0) { 54 doSocketDelete(cli); 55 return false; 56 } 57 buffer[len] = '\0'; 58 59 unsigned long tail = 0; 60 static const char _tail[] = " tail="; 61 char *cp = strstr(buffer, _tail); 62 if (cp) { 63 tail = atol(cp + sizeof(_tail) - 1); 64 } 65 66 log_time start(log_time::EPOCH); 67 static const char _start[] = " start="; 68 cp = strstr(buffer, _start); 69 if (cp) { 70 // Parse errors will result in current time 71 start.strptime(cp + sizeof(_start) - 1, "%s.%q"); 72 } 73 74 uint64_t timeout = 0; 75 static const char _timeout[] = " timeout="; 76 cp = strstr(buffer, _timeout); 77 if (cp) { 78 timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC + 79 log_time(CLOCK_REALTIME).nsec(); 80 } 81 82 unsigned int logMask = -1; 83 static const char _logIds[] = " lids="; 84 cp = strstr(buffer, _logIds); 85 if (cp) { 86 logMask = 0; 87 cp += sizeof(_logIds) - 1; 88 while (*cp && *cp != '\0') { 89 int val = 0; 90 while (isdigit(*cp)) { 91 val = val * 10 + *cp - '0'; 92 ++cp; 93 } 94 logMask |= 1 << val; 95 if (*cp != ',') { 96 break; 97 } 98 ++cp; 99 } 100 } 101 102 pid_t pid = 0; 103 static const char _pid[] = " pid="; 104 cp = strstr(buffer, _pid); 105 if (cp) { 106 pid = atol(cp + sizeof(_pid) - 1); 107 } 108 109 bool nonBlock = false; 110 if (!fast<strncmp>(buffer, "dumpAndClose", 12)) { 111 // Allow writer to get some cycles, and wait for pending notifications 112 sched_yield(); 113 LogTimeEntry::lock(); 114 LogTimeEntry::unlock(); 115 sched_yield(); 116 nonBlock = true; 117 } 118 119 uint64_t sequence = 1; 120 // Convert realtime to sequence number 121 if (start != log_time::EPOCH) { 122 class LogFindStart { 123 const pid_t mPid; 124 const unsigned mLogMask; 125 bool startTimeSet; 126 log_time &start; 127 uint64_t &sequence; 128 uint64_t last; 129 bool isMonotonic; 130 131 public: 132 LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence, bool isMonotonic) : 133 mPid(pid), 134 mLogMask(logMask), 135 startTimeSet(false), 136 start(start), 137 sequence(sequence), 138 last(sequence), 139 isMonotonic(isMonotonic) { 140 } 141 142 static int callback(const LogBufferElement *element, void *obj) { 143 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj); 144 if ((!me->mPid || (me->mPid == element->getPid())) 145 && (me->mLogMask & (1 << element->getLogId()))) { 146 if (me->start == element->getRealTime()) { 147 me->sequence = element->getSequence(); 148 me->startTimeSet = true; 149 return -1; 150 } else if (!me->isMonotonic || 151 android::isMonotonic(element->getRealTime())) { 152 if (me->start < element->getRealTime()) { 153 me->sequence = me->last; 154 me->startTimeSet = true; 155 return -1; 156 } 157 me->last = element->getSequence(); 158 } else { 159 me->last = element->getSequence(); 160 } 161 } 162 return false; 163 } 164 165 bool found() { return startTimeSet; } 166 } logFindStart(logMask, pid, start, sequence, 167 logbuf().isMonotonic() && android::isMonotonic(start)); 168 169 logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli), 170 FlushCommand::hasSecurityLogs(cli), 171 logFindStart.callback, &logFindStart); 172 173 if (!logFindStart.found()) { 174 if (nonBlock) { 175 doSocketDelete(cli); 176 return false; 177 } 178 sequence = LogBufferElement::getCurrentSequence(); 179 } 180 } 181 182 FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout); 183 184 // Set acceptable upper limit to wait for slow reader processing b/27242723 185 struct timeval t = { LOGD_SNDTIMEO, 0 }; 186 setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char *)&t, sizeof(t)); 187 188 command.runSocketCommand(cli); 189 return true; 190 } 191 192 void LogReader::doSocketDelete(SocketClient *cli) { 193 LastLogTimes × = mLogbuf.mTimes; 194 LogTimeEntry::lock(); 195 LastLogTimes::iterator it = times.begin(); 196 while(it != times.end()) { 197 LogTimeEntry *entry = (*it); 198 if (entry->mClient == cli) { 199 times.erase(it); 200 entry->release_Locked(); 201 break; 202 } 203 it++; 204 } 205 LogTimeEntry::unlock(); 206 } 207 208 int LogReader::getLogSocket() { 209 static const char socketName[] = "logdr"; 210 int sock = android_get_control_socket(socketName); 211 212 if (sock < 0) { 213 sock = socket_local_server(socketName, 214 ANDROID_SOCKET_NAMESPACE_RESERVED, 215 SOCK_SEQPACKET); 216 } 217 218 return sock; 219 } 220