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
28pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
29
30LogTimeEntry::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
56void 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
78void LogTimeEntry::threadStop(void* obj) {
79    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
80
81    wrlock();
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
117void* 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    wrlock();
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        wrlock();
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
191int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
192    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
193
194    LogTimeEntry::wrlock();
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
219int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
220    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
221
222    LogTimeEntry::wrlock();
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
269ok:
270    if (!me->skipAhead[element->getLogId()]) {
271        LogTimeEntry::unlock();
272        return true;
273    }
274// FALLTHRU
275
276skip:
277    LogTimeEntry::unlock();
278    return false;
279
280stop:
281    LogTimeEntry::unlock();
282    return -1;
283}
284
285void LogTimeEntry::cleanSkip_Locked(void) {
286    memset(skipAhead, 0, sizeof(skipAhead));
287}
288