Home | History | Annotate | Download | only in logd
      1 /*
      2  * Copyright (C) 2012-2013 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 <ctype.h>
     18 #include <poll.h>
     19 #include <sys/prctl.h>
     20 #include <sys/socket.h>
     21 
     22 #include <cutils/sockets.h>
     23 
     24 #include "LogReader.h"
     25 #include "FlushCommand.h"
     26 
     27 LogReader::LogReader(LogBuffer *logbuf)
     28         : SocketListener(getLogSocket(), true)
     29         , mLogbuf(*logbuf)
     30 { }
     31 
     32 // When we are notified a new log entry is available, inform
     33 // all of our listening sockets.
     34 void LogReader::notifyNewLog() {
     35     FlushCommand command(*this);
     36     runOnEachSocket(&command);
     37 }
     38 
     39 bool LogReader::onDataAvailable(SocketClient *cli) {
     40     prctl(PR_SET_NAME, "logd.reader");
     41 
     42     char buffer[255];
     43 
     44     int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
     45     if (len <= 0) {
     46         doSocketDelete(cli);
     47         return false;
     48     }
     49     buffer[len] = '\0';
     50 
     51     unsigned long tail = 0;
     52     static const char _tail[] = " tail=";
     53     char *cp = strstr(buffer, _tail);
     54     if (cp) {
     55         tail = atol(cp + sizeof(_tail) - 1);
     56     }
     57 
     58     log_time start(log_time::EPOCH);
     59     static const char _start[] = " start=";
     60     cp = strstr(buffer, _start);
     61     if (cp) {
     62         // Parse errors will result in current time
     63         start.strptime(cp + sizeof(_start) - 1, "%s.%q");
     64     }
     65 
     66     unsigned int logMask = -1;
     67     static const char _logIds[] = " lids=";
     68     cp = strstr(buffer, _logIds);
     69     if (cp) {
     70         logMask = 0;
     71         cp += sizeof(_logIds) - 1;
     72         while (*cp && *cp != '\0') {
     73             int val = 0;
     74             while (isdigit(*cp)) {
     75                 val = val * 10 + *cp - '0';
     76                 ++cp;
     77             }
     78             logMask |= 1 << val;
     79             if (*cp != ',') {
     80                 break;
     81             }
     82             ++cp;
     83         }
     84     }
     85 
     86     pid_t pid = 0;
     87     static const char _pid[] = " pid=";
     88     cp = strstr(buffer, _pid);
     89     if (cp) {
     90         pid = atol(cp + sizeof(_pid) - 1);
     91     }
     92 
     93     bool nonBlock = false;
     94     if (strncmp(buffer, "dumpAndClose", 12) == 0) {
     95         // Allow writer to get some cycles, and wait for pending notifications
     96         sched_yield();
     97         LogTimeEntry::lock();
     98         LogTimeEntry::unlock();
     99         sched_yield();
    100         nonBlock = true;
    101     }
    102 
    103     // Convert realtime to monotonic time
    104     if (start == log_time::EPOCH) {
    105         start = LogTimeEntry::EPOCH;
    106     } else {
    107         class LogFindStart {
    108             const pid_t mPid;
    109             const unsigned mLogMask;
    110             bool startTimeSet;
    111             log_time &start;
    112             log_time last;
    113 
    114         public:
    115             LogFindStart(unsigned logMask, pid_t pid, log_time &start)
    116                     : mPid(pid)
    117                     , mLogMask(logMask)
    118                     , startTimeSet(false)
    119                     , start(start)
    120                     , last(LogTimeEntry::EPOCH)
    121             { }
    122 
    123             static bool callback(const LogBufferElement *element, void *obj) {
    124                 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
    125                 if (!me->startTimeSet
    126                         && (!me->mPid || (me->mPid == element->getPid()))
    127                         && (me->mLogMask & (1 << element->getLogId()))) {
    128                     if (me->start == element->getRealTime()) {
    129                         me->start = element->getMonotonicTime();
    130                         me->startTimeSet = true;
    131                     } else {
    132                         if (me->start < element->getRealTime()) {
    133                             me->start = me->last;
    134                             me->startTimeSet = true;
    135                         }
    136                         me->last = element->getMonotonicTime();
    137                     }
    138                 }
    139                 return false;
    140             }
    141 
    142             bool found() { return startTimeSet; }
    143         } logFindStart(logMask, pid, start);
    144 
    145         logbuf().flushTo(cli, LogTimeEntry::EPOCH,
    146                          FlushCommand::hasReadLogs(cli),
    147                          logFindStart.callback, &logFindStart);
    148 
    149         if (!logFindStart.found()) {
    150             if (nonBlock) {
    151                 doSocketDelete(cli);
    152                 return false;
    153             }
    154             log_time now(CLOCK_MONOTONIC);
    155             start = now;
    156         }
    157     }
    158 
    159     FlushCommand command(*this, nonBlock, tail, logMask, pid, start);
    160     command.runSocketCommand(cli);
    161     return true;
    162 }
    163 
    164 void LogReader::doSocketDelete(SocketClient *cli) {
    165     LastLogTimes &times = mLogbuf.mTimes;
    166     LogTimeEntry::lock();
    167     LastLogTimes::iterator it = times.begin();
    168     while(it != times.end()) {
    169         LogTimeEntry *entry = (*it);
    170         if (entry->mClient == cli) {
    171             times.erase(it);
    172             entry->release_Locked();
    173             break;
    174         }
    175         it++;
    176     }
    177     LogTimeEntry::unlock();
    178 }
    179 
    180 int LogReader::getLogSocket() {
    181     static const char socketName[] = "logdr";
    182     int sock = android_get_control_socket(socketName);
    183 
    184     if (sock < 0) {
    185         sock = socket_local_server(socketName,
    186                                    ANDROID_SOCKET_NAMESPACE_RESERVED,
    187                                    SOCK_SEQPACKET);
    188     }
    189 
    190     return sock;
    191 }
    192