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 
LogReader(LogBuffer * logbuf)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.
notifyNewLog()34 void LogReader::notifyNewLog() {
35     FlushCommand command(*this);
36     runOnEachSocket(&command);
37 }
38 
onDataAvailable(SocketClient * cli)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 
doSocketDelete(SocketClient * cli)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 
getLogSocket()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