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 <inttypes.h>
     19 #include <poll.h>
     20 #include <sys/prctl.h>
     21 #include <sys/socket.h>
     22 #include <sys/types.h>
     23 
     24 #include <cutils/sockets.h>
     25 #include <private/android_logger.h>
     26 
     27 #include "FlushCommand.h"
     28 #include "LogBuffer.h"
     29 #include "LogBufferElement.h"
     30 #include "LogReader.h"
     31 #include "LogUtils.h"
     32 
     33 LogReader::LogReader(LogBuffer* logbuf)
     34     : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
     35 }
     36 
     37 // When we are notified a new log entry is available, inform
     38 // all of our listening sockets.
     39 void LogReader::notifyNewLog() {
     40     FlushCommand command(*this);
     41     runOnEachSocket(&command);
     42 }
     43 
     44 bool LogReader::onDataAvailable(SocketClient* cli) {
     45     static bool name_set;
     46     if (!name_set) {
     47         prctl(PR_SET_NAME, "logd.reader");
     48         name_set = true;
     49     }
     50 
     51     char buffer[255];
     52 
     53     int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
     54     if (len <= 0) {
     55         doSocketDelete(cli);
     56         return false;
     57     }
     58     buffer[len] = '\0';
     59 
     60     unsigned long tail = 0;
     61     static const char _tail[] = " tail=";
     62     char* cp = strstr(buffer, _tail);
     63     if (cp) {
     64         tail = atol(cp + sizeof(_tail) - 1);
     65     }
     66 
     67     log_time start(log_time::EPOCH);
     68     static const char _start[] = " start=";
     69     cp = strstr(buffer, _start);
     70     if (cp) {
     71         // Parse errors will result in current time
     72         start.strptime(cp + sizeof(_start) - 1, "%s.%q");
     73     }
     74 
     75     uint64_t timeout = 0;
     76     static const char _timeout[] = " timeout=";
     77     cp = strstr(buffer, _timeout);
     78     if (cp) {
     79         timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC +
     80                   log_time(CLOCK_REALTIME).nsec();
     81     }
     82 
     83     unsigned int logMask = -1;
     84     static const char _logIds[] = " lids=";
     85     cp = strstr(buffer, _logIds);
     86     if (cp) {
     87         logMask = 0;
     88         cp += sizeof(_logIds) - 1;
     89         while (*cp && *cp != '\0') {
     90             int val = 0;
     91             while (isdigit(*cp)) {
     92                 val = val * 10 + *cp - '0';
     93                 ++cp;
     94             }
     95             logMask |= 1 << val;
     96             if (*cp != ',') {
     97                 break;
     98             }
     99             ++cp;
    100         }
    101     }
    102 
    103     pid_t pid = 0;
    104     static const char _pid[] = " pid=";
    105     cp = strstr(buffer, _pid);
    106     if (cp) {
    107         pid = atol(cp + sizeof(_pid) - 1);
    108     }
    109 
    110     bool nonBlock = false;
    111     if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
    112         // Allow writer to get some cycles, and wait for pending notifications
    113         sched_yield();
    114         LogTimeEntry::wrlock();
    115         LogTimeEntry::unlock();
    116         sched_yield();
    117         nonBlock = true;
    118     }
    119 
    120     log_time sequence = start;
    121     //
    122     // This somewhat expensive data validation operation is required
    123     // for non-blocking, with timeout.  The incoming timestamp must be
    124     // in range of the list, if not, return immediately.  This is
    125     // used to prevent us from from getting stuck in timeout processing
    126     // with an invalid time.
    127     //
    128     // Find if time is really present in the logs, monotonic or real, implicit
    129     // conversion from monotonic or real as necessary to perform the check.
    130     // Exit in the check loop ASAP as you find a transition from older to
    131     // newer, but use the last entry found to ensure overlap.
    132     //
    133     if (nonBlock && (sequence != log_time::EPOCH) && timeout) {
    134         class LogFindStart {  // A lambda by another name
    135            private:
    136             const pid_t mPid;
    137             const unsigned mLogMask;
    138             bool mStartTimeSet;
    139             log_time mStart;
    140             log_time& mSequence;
    141             log_time mLast;
    142             bool mIsMonotonic;
    143 
    144            public:
    145             LogFindStart(pid_t pid, unsigned logMask, log_time& sequence,
    146                          bool isMonotonic)
    147                 : mPid(pid),
    148                   mLogMask(logMask),
    149                   mStartTimeSet(false),
    150                   mStart(sequence),
    151                   mSequence(sequence),
    152                   mLast(sequence),
    153                   mIsMonotonic(isMonotonic) {
    154             }
    155 
    156             static int callback(const LogBufferElement* element, void* obj) {
    157                 LogFindStart* me = reinterpret_cast<LogFindStart*>(obj);
    158                 if ((!me->mPid || (me->mPid == element->getPid())) &&
    159                     (me->mLogMask & (1 << element->getLogId()))) {
    160                     log_time real = element->getRealTime();
    161                     if (me->mStart == real) {
    162                         me->mSequence = real;
    163                         me->mStartTimeSet = true;
    164                         return -1;
    165                     } else if (!me->mIsMonotonic || android::isMonotonic(real)) {
    166                         if (me->mStart < real) {
    167                             me->mSequence = me->mLast;
    168                             me->mStartTimeSet = true;
    169                             return -1;
    170                         }
    171                         me->mLast = real;
    172                     } else {
    173                         me->mLast = real;
    174                     }
    175                 }
    176                 return false;
    177             }
    178 
    179             bool found() {
    180                 return mStartTimeSet;
    181             }
    182 
    183         } logFindStart(pid, logMask, sequence,
    184                        logbuf().isMonotonic() && android::isMonotonic(start));
    185 
    186         logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
    187                          FlushCommand::hasSecurityLogs(cli),
    188                          logFindStart.callback, &logFindStart);
    189 
    190         if (!logFindStart.found()) {
    191             doSocketDelete(cli);
    192             return false;
    193         }
    194     }
    195 
    196     android::prdebug(
    197         "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
    198         "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n",
    199         cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
    200         logMask, (int)pid, sequence.nsec(), timeout);
    201 
    202     FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
    203 
    204     // Set acceptable upper limit to wait for slow reader processing b/27242723
    205     struct timeval t = { LOGD_SNDTIMEO, 0 };
    206     setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
    207                sizeof(t));
    208 
    209     command.runSocketCommand(cli);
    210     return true;
    211 }
    212 
    213 void LogReader::doSocketDelete(SocketClient* cli) {
    214     LastLogTimes& times = mLogbuf.mTimes;
    215     LogTimeEntry::wrlock();
    216     LastLogTimes::iterator it = times.begin();
    217     while (it != times.end()) {
    218         LogTimeEntry* entry = (*it);
    219         if (entry->mClient == cli) {
    220             times.erase(it);
    221             entry->release_Locked();
    222             break;
    223         }
    224         it++;
    225     }
    226     LogTimeEntry::unlock();
    227 }
    228 
    229 int LogReader::getLogSocket() {
    230     static const char socketName[] = "logdr";
    231     int sock = android_get_control_socket(socketName);
    232 
    233     if (sock < 0) {
    234         sock = socket_local_server(
    235             socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
    236     }
    237 
    238     return sock;
    239 }
    240