1 /*
2 * Copyright (C) 2014 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 <errno.h>
18 #include <string.h>
19 #include <sys/prctl.h>
20
21 #include <private/android_logger.h>
22
23 #include "FlushCommand.h"
24 #include "LogBuffer.h"
25 #include "LogReader.h"
26 #include "LogTimes.h"
27
28 pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
29
LogTimeEntry(LogReader & reader,SocketClient * client,bool nonBlock,unsigned long tail,unsigned int logMask,pid_t pid,log_time start,uint64_t timeout)30 LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
31 bool nonBlock, unsigned long tail,
32 unsigned int logMask, pid_t pid, log_time start,
33 uint64_t timeout)
34 : mRefCount(1),
35 mRelease(false),
36 mError(false),
37 threadRunning(false),
38 leadingDropped(false),
39 mReader(reader),
40 mLogMask(logMask),
41 mPid(pid),
42 mCount(0),
43 mTail(tail),
44 mIndex(0),
45 mClient(client),
46 mStart(start),
47 mNonBlock(nonBlock),
48 mEnd(log_time(android_log_clockid())) {
49 mTimeout.tv_sec = timeout / NS_PER_SEC;
50 mTimeout.tv_nsec = timeout % NS_PER_SEC;
51 memset(mLastTid, 0, sizeof(mLastTid));
52 pthread_cond_init(&threadTriggeredCondition, nullptr);
53 cleanSkip_Locked();
54 }
55
startReader_Locked(void)56 void LogTimeEntry::startReader_Locked(void) {
57 pthread_attr_t attr;
58
59 threadRunning = true;
60
61 if (!pthread_attr_init(&attr)) {
62 if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
63 if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
64 this)) {
65 pthread_attr_destroy(&attr);
66 return;
67 }
68 }
69 pthread_attr_destroy(&attr);
70 }
71 threadRunning = false;
72 if (mClient) {
73 mClient->decRef();
74 }
75 decRef_Locked();
76 }
77
threadStop(void * obj)78 void LogTimeEntry::threadStop(void* obj) {
79 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
80
81 lock();
82
83 if (me->mNonBlock) {
84 me->error_Locked();
85 }
86
87 SocketClient* client = me->mClient;
88
89 if (me->isError_Locked()) {
90 LogReader& reader = me->mReader;
91 LastLogTimes& times = reader.logbuf().mTimes;
92
93 LastLogTimes::iterator it = times.begin();
94 while (it != times.end()) {
95 if (*it == me) {
96 times.erase(it);
97 me->release_nodelete_Locked();
98 break;
99 }
100 it++;
101 }
102
103 me->mClient = nullptr;
104 reader.release(client);
105 }
106
107 if (client) {
108 client->decRef();
109 }
110
111 me->threadRunning = false;
112 me->decRef_Locked();
113
114 unlock();
115 }
116
threadStart(void * obj)117 void* LogTimeEntry::threadStart(void* obj) {
118 prctl(PR_SET_NAME, "logd.reader.per");
119
120 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
121
122 pthread_cleanup_push(threadStop, obj);
123
124 SocketClient* client = me->mClient;
125 if (!client) {
126 me->error();
127 return nullptr;
128 }
129
130 LogBuffer& logbuf = me->mReader.logbuf();
131
132 bool privileged = FlushCommand::hasReadLogs(client);
133 bool security = FlushCommand::hasSecurityLogs(client);
134
135 me->leadingDropped = true;
136
137 lock();
138
139 log_time start = me->mStart;
140
141 while (me->threadRunning && !me->isError_Locked()) {
142 if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
143 if (pthread_cond_timedwait(&me->threadTriggeredCondition,
144 ×Lock, &me->mTimeout) == ETIMEDOUT) {
145 me->mTimeout.tv_sec = 0;
146 me->mTimeout.tv_nsec = 0;
147 }
148 if (!me->threadRunning || me->isError_Locked()) {
149 break;
150 }
151 }
152
153 unlock();
154
155 if (me->mTail) {
156 logbuf.flushTo(client, start, nullptr, privileged, security,
157 FilterFirstPass, me);
158 me->leadingDropped = true;
159 }
160 start = logbuf.flushTo(client, start, me->mLastTid, privileged,
161 security, FilterSecondPass, me);
162
163 lock();
164
165 if (start == LogBufferElement::FLUSH_ERROR) {
166 me->error_Locked();
167 break;
168 }
169
170 me->mStart = start + log_time(0, 1);
171
172 if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
173 break;
174 }
175
176 me->cleanSkip_Locked();
177
178 if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) {
179 pthread_cond_wait(&me->threadTriggeredCondition, ×Lock);
180 }
181 }
182
183 unlock();
184
185 pthread_cleanup_pop(true);
186
187 return nullptr;
188 }
189
190 // A first pass to count the number of elements
FilterFirstPass(const LogBufferElement * element,void * obj)191 int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
192 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
193
194 LogTimeEntry::lock();
195
196 if (me->leadingDropped) {
197 if (element->getDropped()) {
198 LogTimeEntry::unlock();
199 return false;
200 }
201 me->leadingDropped = false;
202 }
203
204 if (me->mCount == 0) {
205 me->mStart = element->getRealTime();
206 }
207
208 if ((!me->mPid || (me->mPid == element->getPid())) &&
209 (me->isWatching(element->getLogId()))) {
210 ++me->mCount;
211 }
212
213 LogTimeEntry::unlock();
214
215 return false;
216 }
217
218 // A second pass to send the selected elements
FilterSecondPass(const LogBufferElement * element,void * obj)219 int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
220 LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
221
222 LogTimeEntry::lock();
223
224 me->mStart = element->getRealTime();
225
226 if (me->skipAhead[element->getLogId()]) {
227 me->skipAhead[element->getLogId()]--;
228 goto skip;
229 }
230
231 if (me->leadingDropped) {
232 if (element->getDropped()) {
233 goto skip;
234 }
235 me->leadingDropped = false;
236 }
237
238 // Truncate to close race between first and second pass
239 if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
240 goto stop;
241 }
242
243 if (!me->isWatching(element->getLogId())) {
244 goto skip;
245 }
246
247 if (me->mPid && (me->mPid != element->getPid())) {
248 goto skip;
249 }
250
251 if (me->isError_Locked()) {
252 goto stop;
253 }
254
255 if (!me->mTail) {
256 goto ok;
257 }
258
259 ++me->mIndex;
260
261 if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
262 goto skip;
263 }
264
265 if (!me->mNonBlock) {
266 me->mTail = 0;
267 }
268
269 ok:
270 if (!me->skipAhead[element->getLogId()]) {
271 LogTimeEntry::unlock();
272 return true;
273 }
274 // FALLTHRU
275
276 skip:
277 LogTimeEntry::unlock();
278 return false;
279
280 stop:
281 LogTimeEntry::unlock();
282 return -1;
283 }
284
cleanSkip_Locked(void)285 void LogTimeEntry::cleanSkip_Locked(void) {
286 memset(skipAhead, 0, sizeof(skipAhead));
287 }
288