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