• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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