1/* 2 * Copyright (C) 2014 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 <errno.h> 18#include <string.h> 19#include <sys/prctl.h> 20 21#include <private/android_logger.h> 22 23#include "FlushCommand.h" 24#include "LogBuffer.h" 25#include "LogReader.h" 26#include "LogTimes.h" 27 28pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER; 29 30LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client, 31 bool nonBlock, unsigned long tail, 32 unsigned int logMask, pid_t pid, log_time start, 33 uint64_t timeout) 34 : mRefCount(1), 35 mRelease(false), 36 mError(false), 37 threadRunning(false), 38 leadingDropped(false), 39 mReader(reader), 40 mLogMask(logMask), 41 mPid(pid), 42 mCount(0), 43 mTail(tail), 44 mIndex(0), 45 mClient(client), 46 mStart(start), 47 mNonBlock(nonBlock), 48 mEnd(log_time(android_log_clockid())) { 49 mTimeout.tv_sec = timeout / NS_PER_SEC; 50 mTimeout.tv_nsec = timeout % NS_PER_SEC; 51 memset(mLastTid, 0, sizeof(mLastTid)); 52 pthread_cond_init(&threadTriggeredCondition, nullptr); 53 cleanSkip_Locked(); 54} 55 56void LogTimeEntry::startReader_Locked(void) { 57 pthread_attr_t attr; 58 59 threadRunning = true; 60 61 if (!pthread_attr_init(&attr)) { 62 if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) { 63 if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart, 64 this)) { 65 pthread_attr_destroy(&attr); 66 return; 67 } 68 } 69 pthread_attr_destroy(&attr); 70 } 71 threadRunning = false; 72 if (mClient) { 73 mClient->decRef(); 74 } 75 decRef_Locked(); 76} 77 78void LogTimeEntry::threadStop(void* obj) { 79 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj); 80 81 wrlock(); 82 83 if (me->mNonBlock) { 84 me->error_Locked(); 85 } 86 87 SocketClient* client = me->mClient; 88 89 if (me->isError_Locked()) { 90 LogReader& reader = me->mReader; 91 LastLogTimes& times = reader.logbuf().mTimes; 92 93 LastLogTimes::iterator it = times.begin(); 94 while (it != times.end()) { 95 if (*it == me) { 96 times.erase(it); 97 me->release_nodelete_Locked(); 98 break; 99 } 100 it++; 101 } 102 103 me->mClient = nullptr; 104 reader.release(client); 105 } 106 107 if (client) { 108 client->decRef(); 109 } 110 111 me->threadRunning = false; 112 me->decRef_Locked(); 113 114 unlock(); 115} 116 117void* LogTimeEntry::threadStart(void* obj) { 118 prctl(PR_SET_NAME, "logd.reader.per"); 119 120 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj); 121 122 pthread_cleanup_push(threadStop, obj); 123 124 SocketClient* client = me->mClient; 125 if (!client) { 126 me->error(); 127 return nullptr; 128 } 129 130 LogBuffer& logbuf = me->mReader.logbuf(); 131 132 bool privileged = FlushCommand::hasReadLogs(client); 133 bool security = FlushCommand::hasSecurityLogs(client); 134 135 me->leadingDropped = true; 136 137 wrlock(); 138 139 log_time start = me->mStart; 140 141 while (me->threadRunning && !me->isError_Locked()) { 142 if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) { 143 if (pthread_cond_timedwait(&me->threadTriggeredCondition, 144 ×Lock, &me->mTimeout) == ETIMEDOUT) { 145 me->mTimeout.tv_sec = 0; 146 me->mTimeout.tv_nsec = 0; 147 } 148 if (!me->threadRunning || me->isError_Locked()) { 149 break; 150 } 151 } 152 153 unlock(); 154 155 if (me->mTail) { 156 logbuf.flushTo(client, start, nullptr, privileged, security, 157 FilterFirstPass, me); 158 me->leadingDropped = true; 159 } 160 start = logbuf.flushTo(client, start, me->mLastTid, privileged, 161 security, FilterSecondPass, me); 162 163 wrlock(); 164 165 if (start == LogBufferElement::FLUSH_ERROR) { 166 me->error_Locked(); 167 break; 168 } 169 170 me->mStart = start + log_time(0, 1); 171 172 if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) { 173 break; 174 } 175 176 me->cleanSkip_Locked(); 177 178 if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) { 179 pthread_cond_wait(&me->threadTriggeredCondition, ×Lock); 180 } 181 } 182 183 unlock(); 184 185 pthread_cleanup_pop(true); 186 187 return nullptr; 188} 189 190// A first pass to count the number of elements 191int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) { 192 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj); 193 194 LogTimeEntry::wrlock(); 195 196 if (me->leadingDropped) { 197 if (element->getDropped()) { 198 LogTimeEntry::unlock(); 199 return false; 200 } 201 me->leadingDropped = false; 202 } 203 204 if (me->mCount == 0) { 205 me->mStart = element->getRealTime(); 206 } 207 208 if ((!me->mPid || (me->mPid == element->getPid())) && 209 (me->isWatching(element->getLogId()))) { 210 ++me->mCount; 211 } 212 213 LogTimeEntry::unlock(); 214 215 return false; 216} 217 218// A second pass to send the selected elements 219int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) { 220 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj); 221 222 LogTimeEntry::wrlock(); 223 224 me->mStart = element->getRealTime(); 225 226 if (me->skipAhead[element->getLogId()]) { 227 me->skipAhead[element->getLogId()]--; 228 goto skip; 229 } 230 231 if (me->leadingDropped) { 232 if (element->getDropped()) { 233 goto skip; 234 } 235 me->leadingDropped = false; 236 } 237 238 // Truncate to close race between first and second pass 239 if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { 240 goto stop; 241 } 242 243 if (!me->isWatching(element->getLogId())) { 244 goto skip; 245 } 246 247 if (me->mPid && (me->mPid != element->getPid())) { 248 goto skip; 249 } 250 251 if (me->isError_Locked()) { 252 goto stop; 253 } 254 255 if (!me->mTail) { 256 goto ok; 257 } 258 259 ++me->mIndex; 260 261 if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) { 262 goto skip; 263 } 264 265 if (!me->mNonBlock) { 266 me->mTail = 0; 267 } 268 269ok: 270 if (!me->skipAhead[element->getLogId()]) { 271 LogTimeEntry::unlock(); 272 return true; 273 } 274// FALLTHRU 275 276skip: 277 LogTimeEntry::unlock(); 278 return false; 279 280stop: 281 LogTimeEntry::unlock(); 282 return -1; 283} 284 285void LogTimeEntry::cleanSkip_Locked(void) { 286 memset(skipAhead, 0, sizeof(skipAhead)); 287} 288