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,
     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 
     56 void 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 
     78 void 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 
    117 void* 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                                        &timesLock, &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, &timesLock);
    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
    191 int 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
    219 int 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 
    269 ok:
    270     if (!me->skipAhead[element->getLogId()]) {
    271         LogTimeEntry::unlock();
    272         return true;
    273     }
    274 // FALLTHRU
    275 
    276 skip:
    277     LogTimeEntry::unlock();
    278     return false;
    279 
    280 stop:
    281     LogTimeEntry::unlock();
    282     return -1;
    283 }
    284 
    285 void LogTimeEntry::cleanSkip_Locked(void) {
    286     memset(skipAhead, 0, sizeof(skipAhead));
    287 }
    288