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