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 <sys/prctl.h> 18 19#include "FlushCommand.h" 20#include "LogBuffer.h" 21#include "LogTimes.h" 22#include "LogReader.h" 23 24pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER; 25 26const struct timespec LogTimeEntry::EPOCH = { 0, 1 }; 27 28LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client, 29 bool nonBlock, unsigned long tail, 30 unsigned int logMask, pid_t pid, 31 log_time start) 32 : mRefCount(1) 33 , mRelease(false) 34 , mError(false) 35 , threadRunning(false) 36 , mReader(reader) 37 , mLogMask(logMask) 38 , mPid(pid) 39 , skipAhead(0) 40 , mCount(0) 41 , mTail(tail) 42 , mIndex(0) 43 , mClient(client) 44 , mStart(start) 45 , mNonBlock(nonBlock) 46 , mEnd(CLOCK_MONOTONIC) 47{ 48 pthread_cond_init(&threadTriggeredCondition, NULL); 49} 50 51void LogTimeEntry::startReader_Locked(void) { 52 pthread_attr_t attr; 53 54 threadRunning = true; 55 56 if (!pthread_attr_init(&attr)) { 57 if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) { 58 if (!pthread_create(&mThread, &attr, 59 LogTimeEntry::threadStart, this)) { 60 pthread_attr_destroy(&attr); 61 return; 62 } 63 } 64 pthread_attr_destroy(&attr); 65 } 66 threadRunning = false; 67 if (mClient) { 68 mClient->decRef(); 69 } 70 decRef_Locked(); 71} 72 73void LogTimeEntry::threadStop(void *obj) { 74 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 75 76 lock(); 77 78 if (me->mNonBlock) { 79 me->error_Locked(); 80 } 81 82 SocketClient *client = me->mClient; 83 84 if (me->isError_Locked()) { 85 LogReader &reader = me->mReader; 86 LastLogTimes × = reader.logbuf().mTimes; 87 88 LastLogTimes::iterator it = times.begin(); 89 while(it != times.end()) { 90 if (*it == me) { 91 times.erase(it); 92 me->release_Locked(); 93 break; 94 } 95 it++; 96 } 97 98 me->mClient = NULL; 99 reader.release(client); 100 } 101 102 if (client) { 103 client->decRef(); 104 } 105 106 me->threadRunning = false; 107 me->decRef_Locked(); 108 109 unlock(); 110} 111 112void *LogTimeEntry::threadStart(void *obj) { 113 prctl(PR_SET_NAME, "logd.reader.per"); 114 115 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 116 117 pthread_cleanup_push(threadStop, obj); 118 119 SocketClient *client = me->mClient; 120 if (!client) { 121 me->error(); 122 return NULL; 123 } 124 125 LogBuffer &logbuf = me->mReader.logbuf(); 126 127 bool privileged = FlushCommand::hasReadLogs(client); 128 129 lock(); 130 131 while (me->threadRunning && !me->isError_Locked()) { 132 log_time start = me->mStart; 133 134 unlock(); 135 136 if (me->mTail) { 137 logbuf.flushTo(client, start, privileged, FilterFirstPass, me); 138 } 139 start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me); 140 141 lock(); 142 143 if (start == LogBufferElement::FLUSH_ERROR) { 144 me->error_Locked(); 145 } 146 147 if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) { 148 break; 149 } 150 151 pthread_cond_wait(&me->threadTriggeredCondition, ×Lock); 152 } 153 154 unlock(); 155 156 pthread_cleanup_pop(true); 157 158 return NULL; 159} 160 161// A first pass to count the number of elements 162bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { 163 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 164 165 LogTimeEntry::lock(); 166 167 if (me->mCount == 0) { 168 me->mStart = element->getMonotonicTime(); 169 } 170 171 if ((!me->mPid || (me->mPid == element->getPid())) 172 && (me->mLogMask & (1 << element->getLogId()))) { 173 ++me->mCount; 174 } 175 176 LogTimeEntry::unlock(); 177 178 return false; 179} 180 181// A second pass to send the selected elements 182bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { 183 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 184 185 LogTimeEntry::lock(); 186 187 if (me->skipAhead) { 188 me->skipAhead--; 189 goto skip; 190 } 191 192 me->mStart = element->getMonotonicTime(); 193 194 // Truncate to close race between first and second pass 195 if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { 196 goto skip; 197 } 198 199 if ((me->mLogMask & (1 << element->getLogId())) == 0) { 200 goto skip; 201 } 202 203 if (me->mPid && (me->mPid != element->getPid())) { 204 goto skip; 205 } 206 207 if (me->isError_Locked()) { 208 goto skip; 209 } 210 211 if (!me->mTail) { 212 goto ok; 213 } 214 215 ++me->mIndex; 216 217 if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) { 218 goto skip; 219 } 220 221 if (!me->mNonBlock) { 222 me->mTail = 0; 223 } 224 225ok: 226 if (!me->skipAhead) { 227 LogTimeEntry::unlock(); 228 return true; 229 } 230 // FALLTHRU 231 232skip: 233 LogTimeEntry::unlock(); 234 return false; 235} 236