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 #include <private/android_logger.h>
25
26 #include "FlushCommand.h"
27 #include "LogBuffer.h"
28 #include "LogBufferElement.h"
29 #include "LogReader.h"
30 #include "LogUtils.h"
31
LogReader(LogBuffer * logbuf)32 LogReader::LogReader(LogBuffer* logbuf)
33 : SocketListener(getLogSocket(), true), 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 (!fastcmp<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 log_time sequence = start;
120 //
121 // This somewhat expensive data validation operation is required
122 // for non-blocking, with timeout. The incoming timestamp must be
123 // in range of the list, if not, return immediately. This is
124 // used to prevent us from from getting stuck in timeout processing
125 // with an invalid time.
126 //
127 // Find if time is really present in the logs, monotonic or real, implicit
128 // conversion from monotonic or real as necessary to perform the check.
129 // Exit in the check loop ASAP as you find a transition from older to
130 // newer, but use the last entry found to ensure overlap.
131 //
132 if (nonBlock && (sequence != log_time::EPOCH) && timeout) {
133 class LogFindStart { // A lambda by another name
134 private:
135 const pid_t mPid;
136 const unsigned mLogMask;
137 bool mStartTimeSet;
138 log_time mStart;
139 log_time& mSequence;
140 log_time mLast;
141 bool mIsMonotonic;
142
143 public:
144 LogFindStart(pid_t pid, unsigned logMask, log_time& sequence,
145 bool isMonotonic)
146 : mPid(pid),
147 mLogMask(logMask),
148 mStartTimeSet(false),
149 mStart(sequence),
150 mSequence(sequence),
151 mLast(sequence),
152 mIsMonotonic(isMonotonic) {
153 }
154
155 static int callback(const LogBufferElement* element, void* obj) {
156 LogFindStart* me = reinterpret_cast<LogFindStart*>(obj);
157 if ((!me->mPid || (me->mPid == element->getPid())) &&
158 (me->mLogMask & (1 << element->getLogId()))) {
159 log_time real = element->getRealTime();
160 if (me->mStart == real) {
161 me->mSequence = real;
162 me->mStartTimeSet = true;
163 return -1;
164 } else if (!me->mIsMonotonic || android::isMonotonic(real)) {
165 if (me->mStart < real) {
166 me->mSequence = me->mLast;
167 me->mStartTimeSet = true;
168 return -1;
169 }
170 me->mLast = real;
171 } else {
172 me->mLast = real;
173 }
174 }
175 return false;
176 }
177
178 bool found() {
179 return mStartTimeSet;
180 }
181
182 } logFindStart(pid, logMask, sequence,
183 logbuf().isMonotonic() && android::isMonotonic(start));
184
185 logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
186 FlushCommand::hasSecurityLogs(cli),
187 logFindStart.callback, &logFindStart);
188
189 if (!logFindStart.found()) {
190 doSocketDelete(cli);
191 return false;
192 }
193 }
194
195 FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
196
197 // Set acceptable upper limit to wait for slow reader processing b/27242723
198 struct timeval t = { LOGD_SNDTIMEO, 0 };
199 setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
200 sizeof(t));
201
202 command.runSocketCommand(cli);
203 return true;
204 }
205
doSocketDelete(SocketClient * cli)206 void LogReader::doSocketDelete(SocketClient* cli) {
207 LastLogTimes& times = mLogbuf.mTimes;
208 LogTimeEntry::lock();
209 LastLogTimes::iterator it = times.begin();
210 while (it != times.end()) {
211 LogTimeEntry* entry = (*it);
212 if (entry->mClient == cli) {
213 times.erase(it);
214 entry->release_Locked();
215 break;
216 }
217 it++;
218 }
219 LogTimeEntry::unlock();
220 }
221
getLogSocket()222 int LogReader::getLogSocket() {
223 static const char socketName[] = "logdr";
224 int sock = android_get_control_socket(socketName);
225
226 if (sock < 0) {
227 sock = socket_local_server(
228 socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
229 }
230
231 return sock;
232 }
233