• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                                        &timesLock, &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, &timesLock);
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