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