blob: 51aa2ad2bfd9a10cff2e2a70a533377a24c9884c [file] [log] [blame]
Mark Salyzyn0175b072014-02-26 09:50:16 -08001/*
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
Mark Salyzynfa3716b2014-02-14 16:05:05 -080017#include <ctype.h>
Mark Salyzyn0175b072014-02-26 09:50:16 -080018#include <poll.h>
19#include <sys/socket.h>
Mark Salyzyndfc47e82014-03-24 10:26:47 -070020
Mark Salyzyn0175b072014-02-26 09:50:16 -080021#include <cutils/sockets.h>
22
23#include "LogReader.h"
24#include "FlushCommand.h"
25
26LogReader::LogReader(LogBuffer *logbuf)
Mark Salyzyndfc47e82014-03-24 10:26:47 -070027 : SocketListener(getLogSocket(), true)
Mark Salyzyn0175b072014-02-26 09:50:16 -080028 , mLogbuf(*logbuf)
29{ }
30
31// When we are notified a new log entry is available, inform
32// all of our listening sockets.
33void LogReader::notifyNewLog() {
34 FlushCommand command(*this);
35 runOnEachSocket(&command);
36}
37
38bool LogReader::onDataAvailable(SocketClient *cli) {
39 char buffer[255];
40
41 int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
42 if (len <= 0) {
43 doSocketDelete(cli);
44 return false;
45 }
46 buffer[len] = '\0';
47
48 unsigned long tail = 0;
49 static const char _tail[] = " tail=";
50 char *cp = strstr(buffer, _tail);
51 if (cp) {
52 tail = atol(cp + sizeof(_tail) - 1);
53 }
54
Mark Salyzynfa3716b2014-02-14 16:05:05 -080055 log_time start(log_time::EPOCH);
56 static const char _start[] = " start=";
57 cp = strstr(buffer, _start);
58 if (cp) {
59 // Parse errors will result in current time
60 start.strptime(cp + sizeof(_start) - 1, "%s.%q");
61 }
62
Mark Salyzyn0175b072014-02-26 09:50:16 -080063 unsigned int logMask = -1;
64 static const char _logIds[] = " lids=";
65 cp = strstr(buffer, _logIds);
66 if (cp) {
67 logMask = 0;
68 cp += sizeof(_logIds) - 1;
69 while (*cp && *cp != '\0') {
70 int val = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -080071 while (isdigit(*cp)) {
72 val = val * 10 + *cp - '0';
Mark Salyzyn0175b072014-02-26 09:50:16 -080073 ++cp;
74 }
75 logMask |= 1 << val;
76 if (*cp != ',') {
77 break;
78 }
79 ++cp;
80 }
81 }
82
83 pid_t pid = 0;
84 static const char _pid[] = " pid=";
85 cp = strstr(buffer, _pid);
86 if (cp) {
87 pid = atol(cp + sizeof(_pid) - 1);
88 }
89
90 bool nonBlock = false;
91 if (strncmp(buffer, "dumpAndClose", 12) == 0) {
92 nonBlock = true;
93 }
94
Mark Salyzynfa3716b2014-02-14 16:05:05 -080095 // Convert realtime to monotonic time
Mark Salyzynfa3716b2014-02-14 16:05:05 -080096 if (start == log_time::EPOCH) {
97 start = LogTimeEntry::EPOCH;
Mark Salyzyna1c60cf2014-02-19 07:33:12 -080098 } else {
99 class LogFindStart {
100 const pid_t mPid;
101 const unsigned mLogMask;
102 bool startTimeSet;
103 log_time &start;
104 log_time last;
105
106 public:
107 LogFindStart(unsigned logMask, pid_t pid, log_time &start)
108 : mPid(pid)
109 , mLogMask(logMask)
110 , startTimeSet(false)
111 , start(start)
112 , last(LogTimeEntry::EPOCH)
113 { }
114
115 static bool callback(const LogBufferElement *element, void *obj) {
116 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
117 if (!me->startTimeSet
118 && (!me->mPid || (me->mPid == element->getPid()))
119 && (me->mLogMask & (1 << element->getLogId()))) {
120 if (me->start == element->getRealTime()) {
121 me->start = element->getMonotonicTime();
122 me->startTimeSet = true;
123 } else {
124 if (me->start < element->getRealTime()) {
125 me->start = me->last;
126 me->startTimeSet = true;
127 }
128 me->last = element->getMonotonicTime();
129 }
130 }
131 return false;
132 }
133
134 bool found() { return startTimeSet; }
135 } logFindStart(logMask, pid, start);
136
137 logbuf().flushTo(cli, LogTimeEntry::EPOCH,
138 FlushCommand::hasReadLogs(cli),
139 logFindStart.callback, &logFindStart);
140
141 if (!logFindStart.found()) {
142 if (nonBlock) {
143 doSocketDelete(cli);
144 return false;
145 }
146 log_time now(CLOCK_MONOTONIC);
147 start = now;
148 }
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800149 }
150
151 FlushCommand command(*this, nonBlock, tail, logMask, pid, start);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800152 command.runSocketCommand(cli);
153 return true;
154}
155
156void LogReader::doSocketDelete(SocketClient *cli) {
157 LastLogTimes &times = mLogbuf.mTimes;
158 LogTimeEntry::lock();
159 LastLogTimes::iterator it = times.begin();
160 while(it != times.end()) {
161 LogTimeEntry *entry = (*it);
162 if (entry->mClient == cli) {
163 times.erase(it);
164 entry->release_Locked();
165 break;
166 }
167 it++;
168 }
169 LogTimeEntry::unlock();
170}
Mark Salyzyndfc47e82014-03-24 10:26:47 -0700171
172int LogReader::getLogSocket() {
173 static const char socketName[] = "logdr";
174 int sock = android_get_control_socket(socketName);
175
176 if (sock < 0) {
177 sock = socket_local_server(socketName,
178 ANDROID_SOCKET_NAMESPACE_RESERVED,
179 SOCK_SEQPACKET);
180 }
181
182 return sock;
183}