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