blob: ec67c07e893fa40b1954ff7bbf80d9a1e88f8524 [file] [log] [blame]
Mark Salyzyn0175b072014-02-26 09:50:16 -08001/*
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
Mark Salyzyn8daa9af2014-04-28 14:07:23 -070017#include <sys/prctl.h>
18
Mark Salyzyn0175b072014-02-26 09:50:16 -080019#include "FlushCommand.h"
20#include "LogBuffer.h"
21#include "LogTimes.h"
22#include "LogReader.h"
23
24pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
25
Mark Salyzyn0175b072014-02-26 09:50:16 -080026LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
27 bool nonBlock, unsigned long tail,
Mark Salyzynfa3716b2014-02-14 16:05:05 -080028 unsigned int logMask, pid_t pid,
Mark Salyzyn77187782015-05-12 15:21:31 -070029 uint64_t start) :
30 mRefCount(1),
31 mRelease(false),
32 mError(false),
33 threadRunning(false),
34 mReader(reader),
35 mLogMask(logMask),
36 mPid(pid),
37 mCount(0),
38 mTail(tail),
39 mIndex(0),
40 mClient(client),
41 mStart(start),
42 mNonBlock(nonBlock),
43 mEnd(LogBufferElement::getCurrentSequence()) {
44 pthread_cond_init(&threadTriggeredCondition, NULL);
45 cleanSkip_Locked();
Mark Salyzyna16f7612014-08-07 08:16:52 -070046}
Mark Salyzyn0175b072014-02-26 09:50:16 -080047
48void LogTimeEntry::startReader_Locked(void) {
Mark Salyzyn765f7822014-04-04 12:47:44 -070049 pthread_attr_t attr;
50
Mark Salyzyn0175b072014-02-26 09:50:16 -080051 threadRunning = true;
Mark Salyzyn765f7822014-04-04 12:47:44 -070052
53 if (!pthread_attr_init(&attr)) {
54 if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
55 if (!pthread_create(&mThread, &attr,
56 LogTimeEntry::threadStart, this)) {
57 pthread_attr_destroy(&attr);
58 return;
59 }
Mark Salyzyn0175b072014-02-26 09:50:16 -080060 }
Mark Salyzyn765f7822014-04-04 12:47:44 -070061 pthread_attr_destroy(&attr);
Mark Salyzyn0175b072014-02-26 09:50:16 -080062 }
Mark Salyzyn765f7822014-04-04 12:47:44 -070063 threadRunning = false;
64 if (mClient) {
65 mClient->decRef();
66 }
67 decRef_Locked();
Mark Salyzyn0175b072014-02-26 09:50:16 -080068}
69
70void LogTimeEntry::threadStop(void *obj) {
71 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
72
73 lock();
74
Mark Salyzyn0175b072014-02-26 09:50:16 -080075 if (me->mNonBlock) {
76 me->error_Locked();
77 }
78
79 SocketClient *client = me->mClient;
80
81 if (me->isError_Locked()) {
82 LogReader &reader = me->mReader;
83 LastLogTimes &times = reader.logbuf().mTimes;
84
85 LastLogTimes::iterator it = times.begin();
86 while(it != times.end()) {
87 if (*it == me) {
88 times.erase(it);
89 me->release_Locked();
90 break;
91 }
92 it++;
93 }
94
95 me->mClient = NULL;
96 reader.release(client);
97 }
98
99 if (client) {
100 client->decRef();
101 }
102
Mark Salyzyna16f7612014-08-07 08:16:52 -0700103 me->threadRunning = false;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800104 me->decRef_Locked();
105
106 unlock();
107}
108
109void *LogTimeEntry::threadStart(void *obj) {
Mark Salyzyn8daa9af2014-04-28 14:07:23 -0700110 prctl(PR_SET_NAME, "logd.reader.per");
111
Mark Salyzyn0175b072014-02-26 09:50:16 -0800112 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
113
114 pthread_cleanup_push(threadStop, obj);
115
116 SocketClient *client = me->mClient;
117 if (!client) {
118 me->error();
Mark Salyzyna16f7612014-08-07 08:16:52 -0700119 return NULL;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800120 }
121
122 LogBuffer &logbuf = me->mReader.logbuf();
123
124 bool privileged = FlushCommand::hasReadLogs(client);
125
126 lock();
127
Mark Salyzyna16f7612014-08-07 08:16:52 -0700128 while (me->threadRunning && !me->isError_Locked()) {
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800129 uint64_t start = me->mStart;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800130
131 unlock();
132
133 if (me->mTail) {
134 logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
135 }
136 start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
137
Mark Salyzyna16f7612014-08-07 08:16:52 -0700138 lock();
139
Mark Salyzyn0175b072014-02-26 09:50:16 -0800140 if (start == LogBufferElement::FLUSH_ERROR) {
Mark Salyzyna16f7612014-08-07 08:16:52 -0700141 me->error_Locked();
Mark Salyzyn0175b072014-02-26 09:50:16 -0800142 }
143
Mark Salyzyna16f7612014-08-07 08:16:52 -0700144 if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800145 break;
146 }
147
TraianX Schiauda6495d2014-12-17 10:53:41 +0200148 me->cleanSkip_Locked();
149
Mark Salyzyna16f7612014-08-07 08:16:52 -0700150 pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800151 }
152
153 unlock();
154
Mark Salyzyn0175b072014-02-26 09:50:16 -0800155 pthread_cleanup_pop(true);
156
157 return NULL;
158}
159
160// A first pass to count the number of elements
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800161int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800162 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
163
164 LogTimeEntry::lock();
165
166 if (me->mCount == 0) {
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800167 me->mStart = element->getSequence();
Mark Salyzyn0175b072014-02-26 09:50:16 -0800168 }
169
170 if ((!me->mPid || (me->mPid == element->getPid()))
TraianX Schiauda6495d2014-12-17 10:53:41 +0200171 && (me->isWatching(element->getLogId()))) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800172 ++me->mCount;
173 }
174
175 LogTimeEntry::unlock();
176
177 return false;
178}
179
180// A second pass to send the selected elements
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800181int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800182 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
183
184 LogTimeEntry::lock();
185
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800186 me->mStart = element->getSequence();
TraianX Schiauda6495d2014-12-17 10:53:41 +0200187
188 if (me->skipAhead[element->getLogId()]) {
189 me->skipAhead[element->getLogId()]--;
Mark Salyzyn8d7656b2014-06-05 15:58:43 -0700190 goto skip;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800191 }
192
Mark Salyzyn0175b072014-02-26 09:50:16 -0800193 // Truncate to close race between first and second pass
194 if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800195 goto stop;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800196 }
197
TraianX Schiauda6495d2014-12-17 10:53:41 +0200198 if (!me->isWatching(element->getLogId())) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800199 goto skip;
200 }
201
202 if (me->mPid && (me->mPid != element->getPid())) {
203 goto skip;
204 }
205
206 if (me->isError_Locked()) {
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800207 goto stop;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800208 }
209
210 if (!me->mTail) {
211 goto ok;
212 }
213
214 ++me->mIndex;
215
216 if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
217 goto skip;
218 }
219
220 if (!me->mNonBlock) {
221 me->mTail = 0;
222 }
223
224ok:
TraianX Schiauda6495d2014-12-17 10:53:41 +0200225 if (!me->skipAhead[element->getLogId()]) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800226 LogTimeEntry::unlock();
227 return true;
228 }
229 // FALLTHRU
230
231skip:
232 LogTimeEntry::unlock();
233 return false;
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800234
235stop:
236 LogTimeEntry::unlock();
237 return -1;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800238}
TraianX Schiauda6495d2014-12-17 10:53:41 +0200239
240void LogTimeEntry::cleanSkip_Locked(void) {
241 for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) {
242 skipAhead[i] = 0;
243 }
244}