• 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,log_mask_t logMask,pid_t pid,log_time start,uint64_t timeout)30 LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
31                            bool nonBlock, unsigned long tail, log_mask_t logMask,
32                            pid_t pid, log_time start, uint64_t timeout)
33     : leadingDropped(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(log_time(android_log_clockid())) {
44     mTimeout.tv_sec = timeout / NS_PER_SEC;
45     mTimeout.tv_nsec = timeout % NS_PER_SEC;
46     memset(mLastTid, 0, sizeof(mLastTid));
47     pthread_cond_init(&threadTriggeredCondition, nullptr);
48     cleanSkip_Locked();
49 }
50 
startReader_Locked()51 bool LogTimeEntry::startReader_Locked() {
52     pthread_attr_t attr;
53 
54     if (!pthread_attr_init(&attr)) {
55         if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
56             if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
57                                 this)) {
58                 pthread_attr_destroy(&attr);
59                 return true;
60             }
61         }
62         pthread_attr_destroy(&attr);
63     }
64 
65     return false;
66 }
67 
threadStart(void * obj)68 void* LogTimeEntry::threadStart(void* obj) {
69     prctl(PR_SET_NAME, "logd.reader.per");
70 
71     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
72 
73     SocketClient* client = me->mClient;
74 
75     LogBuffer& logbuf = me->mReader.logbuf();
76 
77     bool privileged = FlushCommand::hasReadLogs(client);
78     bool security = FlushCommand::hasSecurityLogs(client);
79 
80     me->leadingDropped = true;
81 
82     wrlock();
83 
84     log_time start = me->mStart;
85 
86     while (!me->mRelease) {
87         if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
88             if (pthread_cond_timedwait(&me->threadTriggeredCondition,
89                                        &timesLock, &me->mTimeout) == ETIMEDOUT) {
90                 me->mTimeout.tv_sec = 0;
91                 me->mTimeout.tv_nsec = 0;
92             }
93             if (me->mRelease) {
94                 break;
95             }
96         }
97 
98         unlock();
99 
100         if (me->mTail) {
101             logbuf.flushTo(client, start, nullptr, privileged, security,
102                            FilterFirstPass, me);
103             me->leadingDropped = true;
104         }
105         start = logbuf.flushTo(client, start, me->mLastTid, privileged,
106                                security, FilterSecondPass, me);
107 
108         wrlock();
109 
110         if (start == LogBufferElement::FLUSH_ERROR) {
111             break;
112         }
113 
114         me->mStart = start + log_time(0, 1);
115 
116         if (me->mNonBlock || me->mRelease) {
117             break;
118         }
119 
120         me->cleanSkip_Locked();
121 
122         if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) {
123             pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
124         }
125     }
126 
127     LogReader& reader = me->mReader;
128     reader.release(client);
129 
130     client->decRef();
131 
132     LastLogTimes& times = reader.logbuf().mTimes;
133     auto it =
134         std::find_if(times.begin(), times.end(),
135                      [&me](const auto& other) { return other.get() == me; });
136 
137     if (it != times.end()) {
138         times.erase(it);
139     }
140 
141     unlock();
142 
143     return nullptr;
144 }
145 
146 // A first pass to count the number of elements
FilterFirstPass(const LogBufferElement * element,void * obj)147 int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
148     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
149 
150     LogTimeEntry::wrlock();
151 
152     if (me->leadingDropped) {
153         if (element->getDropped()) {
154             LogTimeEntry::unlock();
155             return false;
156         }
157         me->leadingDropped = false;
158     }
159 
160     if (me->mCount == 0) {
161         me->mStart = element->getRealTime();
162     }
163 
164     if ((!me->mPid || (me->mPid == element->getPid())) &&
165         (me->isWatching(element->getLogId()))) {
166         ++me->mCount;
167     }
168 
169     LogTimeEntry::unlock();
170 
171     return false;
172 }
173 
174 // A second pass to send the selected elements
FilterSecondPass(const LogBufferElement * element,void * obj)175 int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
176     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
177 
178     LogTimeEntry::wrlock();
179 
180     me->mStart = element->getRealTime();
181 
182     if (me->skipAhead[element->getLogId()]) {
183         me->skipAhead[element->getLogId()]--;
184         goto skip;
185     }
186 
187     if (me->leadingDropped) {
188         if (element->getDropped()) {
189             goto skip;
190         }
191         me->leadingDropped = false;
192     }
193 
194     // Truncate to close race between first and second pass
195     if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
196         goto stop;
197     }
198 
199     if (!me->isWatching(element->getLogId())) {
200         goto skip;
201     }
202 
203     if (me->mPid && (me->mPid != element->getPid())) {
204         goto skip;
205     }
206 
207     if (me->mRelease) {
208         goto stop;
209     }
210 
211     if (!me->mTail) {
212         goto ok;
213     }
214 
215     ++me->mIndex;
216 
217     if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
218         goto skip;
219     }
220 
221     if (!me->mNonBlock) {
222         me->mTail = 0;
223     }
224 
225 ok:
226     if (!me->skipAhead[element->getLogId()]) {
227         LogTimeEntry::unlock();
228         return true;
229     }
230 // FALLTHRU
231 
232 skip:
233     LogTimeEntry::unlock();
234     return false;
235 
236 stop:
237     LogTimeEntry::unlock();
238     return -1;
239 }
240 
cleanSkip_Locked(void)241 void LogTimeEntry::cleanSkip_Locked(void) {
242     memset(skipAhead, 0, sizeof(skipAhead));
243 }
244