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