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