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 <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 const struct timespec LogTimeEntry::EPOCH = { 0, 1 };
     27 
     28 LogTimeEntry::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 
     51 void 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 
     73 void 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 &times = 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 
    112 void *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, &timesLock);
    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
    162 bool 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
    182 bool 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 
    225 ok:
    226     if (!me->skipAhead) {
    227         LogTimeEntry::unlock();
    228         return true;
    229     }
    230     // FALLTHRU
    231 
    232 skip:
    233     LogTimeEntry::unlock();
    234     return false;
    235 }
    236