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 <inttypes.h> 19 #include <poll.h> 20 #include <sys/prctl.h> 21 #include <sys/socket.h> 22 #include <sys/types.h> 23 24 #include <cutils/sockets.h> 25 #include <private/android_logger.h> 26 27 #include "FlushCommand.h" 28 #include "LogBuffer.h" 29 #include "LogBufferElement.h" 30 #include "LogReader.h" 31 #include "LogUtils.h" 32 33 LogReader::LogReader(LogBuffer* logbuf) 34 : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) { 35 } 36 37 // When we are notified a new log entry is available, inform 38 // all of our listening sockets. 39 void LogReader::notifyNewLog() { 40 FlushCommand command(*this); 41 runOnEachSocket(&command); 42 } 43 44 bool LogReader::onDataAvailable(SocketClient* cli) { 45 static bool name_set; 46 if (!name_set) { 47 prctl(PR_SET_NAME, "logd.reader"); 48 name_set = true; 49 } 50 51 char buffer[255]; 52 53 int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); 54 if (len <= 0) { 55 doSocketDelete(cli); 56 return false; 57 } 58 buffer[len] = '\0'; 59 60 unsigned long tail = 0; 61 static const char _tail[] = " tail="; 62 char* cp = strstr(buffer, _tail); 63 if (cp) { 64 tail = atol(cp + sizeof(_tail) - 1); 65 } 66 67 log_time start(log_time::EPOCH); 68 static const char _start[] = " start="; 69 cp = strstr(buffer, _start); 70 if (cp) { 71 // Parse errors will result in current time 72 start.strptime(cp + sizeof(_start) - 1, "%s.%q"); 73 } 74 75 uint64_t timeout = 0; 76 static const char _timeout[] = " timeout="; 77 cp = strstr(buffer, _timeout); 78 if (cp) { 79 timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC + 80 log_time(CLOCK_REALTIME).nsec(); 81 } 82 83 unsigned int logMask = -1; 84 static const char _logIds[] = " lids="; 85 cp = strstr(buffer, _logIds); 86 if (cp) { 87 logMask = 0; 88 cp += sizeof(_logIds) - 1; 89 while (*cp && *cp != '\0') { 90 int val = 0; 91 while (isdigit(*cp)) { 92 val = val * 10 + *cp - '0'; 93 ++cp; 94 } 95 logMask |= 1 << val; 96 if (*cp != ',') { 97 break; 98 } 99 ++cp; 100 } 101 } 102 103 pid_t pid = 0; 104 static const char _pid[] = " pid="; 105 cp = strstr(buffer, _pid); 106 if (cp) { 107 pid = atol(cp + sizeof(_pid) - 1); 108 } 109 110 bool nonBlock = false; 111 if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) { 112 // Allow writer to get some cycles, and wait for pending notifications 113 sched_yield(); 114 LogTimeEntry::wrlock(); 115 LogTimeEntry::unlock(); 116 sched_yield(); 117 nonBlock = true; 118 } 119 120 log_time sequence = start; 121 // 122 // This somewhat expensive data validation operation is required 123 // for non-blocking, with timeout. The incoming timestamp must be 124 // in range of the list, if not, return immediately. This is 125 // used to prevent us from from getting stuck in timeout processing 126 // with an invalid time. 127 // 128 // Find if time is really present in the logs, monotonic or real, implicit 129 // conversion from monotonic or real as necessary to perform the check. 130 // Exit in the check loop ASAP as you find a transition from older to 131 // newer, but use the last entry found to ensure overlap. 132 // 133 if (nonBlock && (sequence != log_time::EPOCH) && timeout) { 134 class LogFindStart { // A lambda by another name 135 private: 136 const pid_t mPid; 137 const unsigned mLogMask; 138 bool mStartTimeSet; 139 log_time mStart; 140 log_time& mSequence; 141 log_time mLast; 142 bool mIsMonotonic; 143 144 public: 145 LogFindStart(pid_t pid, unsigned logMask, log_time& sequence, 146 bool isMonotonic) 147 : mPid(pid), 148 mLogMask(logMask), 149 mStartTimeSet(false), 150 mStart(sequence), 151 mSequence(sequence), 152 mLast(sequence), 153 mIsMonotonic(isMonotonic) { 154 } 155 156 static int callback(const LogBufferElement* element, void* obj) { 157 LogFindStart* me = reinterpret_cast<LogFindStart*>(obj); 158 if ((!me->mPid || (me->mPid == element->getPid())) && 159 (me->mLogMask & (1 << element->getLogId()))) { 160 log_time real = element->getRealTime(); 161 if (me->mStart == real) { 162 me->mSequence = real; 163 me->mStartTimeSet = true; 164 return -1; 165 } else if (!me->mIsMonotonic || android::isMonotonic(real)) { 166 if (me->mStart < real) { 167 me->mSequence = me->mLast; 168 me->mStartTimeSet = true; 169 return -1; 170 } 171 me->mLast = real; 172 } else { 173 me->mLast = real; 174 } 175 } 176 return false; 177 } 178 179 bool found() { 180 return mStartTimeSet; 181 } 182 183 } logFindStart(pid, logMask, sequence, 184 logbuf().isMonotonic() && android::isMonotonic(start)); 185 186 logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli), 187 FlushCommand::hasSecurityLogs(cli), 188 logFindStart.callback, &logFindStart); 189 190 if (!logFindStart.found()) { 191 doSocketDelete(cli); 192 return false; 193 } 194 } 195 196 android::prdebug( 197 "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d " 198 "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n", 199 cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, 200 logMask, (int)pid, sequence.nsec(), timeout); 201 202 FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout); 203 204 // Set acceptable upper limit to wait for slow reader processing b/27242723 205 struct timeval t = { LOGD_SNDTIMEO, 0 }; 206 setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t, 207 sizeof(t)); 208 209 command.runSocketCommand(cli); 210 return true; 211 } 212 213 void LogReader::doSocketDelete(SocketClient* cli) { 214 LastLogTimes& times = mLogbuf.mTimes; 215 LogTimeEntry::wrlock(); 216 LastLogTimes::iterator it = times.begin(); 217 while (it != times.end()) { 218 LogTimeEntry* entry = (*it); 219 if (entry->mClient == cli) { 220 times.erase(it); 221 entry->release_Locked(); 222 break; 223 } 224 it++; 225 } 226 LogTimeEntry::unlock(); 227 } 228 229 int LogReader::getLogSocket() { 230 static const char socketName[] = "logdr"; 231 int sock = android_get_control_socket(socketName); 232 233 if (sock < 0) { 234 sock = socket_local_server( 235 socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET); 236 } 237 238 return sock; 239 } 240