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