1 /*
2  * Copyright (C) 2017 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 #define DEBUG false  // STOPSHIP if true
18 #include "logd/LogEvent.h"
19 
20 #include "stats_log_util.h"
21 
22 namespace android {
23 namespace os {
24 namespace statsd {
25 
26 using namespace android::util;
27 using android::util::ProtoOutputStream;
28 using std::string;
29 using std::vector;
30 
LogEvent(log_msg & msg)31 LogEvent::LogEvent(log_msg& msg) {
32     mContext =
33             create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
34     mLogdTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
35     mLogUid = msg.entry_v4.uid;
36     init(mContext);
37     if (mContext) {
38         // android_log_destroy will set mContext to NULL
39         android_log_destroy(&mContext);
40     }
41 }
42 
LogEvent(int32_t tagId,int64_t wallClockTimestampNs,int64_t elapsedTimestampNs)43 LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
44     mLogdTimestampNs = wallClockTimestampNs;
45     mTagId = tagId;
46     mLogUid = 0;
47     mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
48     if (mContext) {
49         android_log_write_int64(mContext, elapsedTimestampNs);
50         android_log_write_int32(mContext, tagId);
51     }
52 }
53 
LogEvent(int32_t tagId,int64_t timestampNs)54 LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) {
55     mLogdTimestampNs = timestampNs;
56     mTagId = tagId;
57     mLogUid = 0;
58     mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
59     if (mContext) {
60         android_log_write_int64(mContext, timestampNs);
61         android_log_write_int32(mContext, tagId);
62     }
63 }
64 
init()65 void LogEvent::init() {
66     if (mContext) {
67         const char* buffer;
68         size_t len = android_log_write_list_buffer(mContext, &buffer);
69         // turns to reader mode
70         android_log_context contextForRead = create_android_log_parser(buffer, len);
71         if (contextForRead) {
72             init(contextForRead);
73             // destroy the context to save memory.
74             // android_log_destroy will set mContext to NULL
75             android_log_destroy(&contextForRead);
76         }
77         android_log_destroy(&mContext);
78     }
79 }
80 
~LogEvent()81 LogEvent::~LogEvent() {
82     if (mContext) {
83         // This is for the case when LogEvent is created using the test interface
84         // but init() isn't called.
85         android_log_destroy(&mContext);
86     }
87 }
88 
write(int32_t value)89 bool LogEvent::write(int32_t value) {
90     if (mContext) {
91         return android_log_write_int32(mContext, value) >= 0;
92     }
93     return false;
94 }
95 
write(uint32_t value)96 bool LogEvent::write(uint32_t value) {
97     if (mContext) {
98         return android_log_write_int32(mContext, value) >= 0;
99     }
100     return false;
101 }
102 
write(int64_t value)103 bool LogEvent::write(int64_t value) {
104     if (mContext) {
105         return android_log_write_int64(mContext, value) >= 0;
106     }
107     return false;
108 }
109 
write(uint64_t value)110 bool LogEvent::write(uint64_t value) {
111     if (mContext) {
112         return android_log_write_int64(mContext, value) >= 0;
113     }
114     return false;
115 }
116 
write(const string & value)117 bool LogEvent::write(const string& value) {
118     if (mContext) {
119         return android_log_write_string8_len(mContext, value.c_str(), value.length()) >= 0;
120     }
121     return false;
122 }
123 
write(float value)124 bool LogEvent::write(float value) {
125     if (mContext) {
126         return android_log_write_float32(mContext, value) >= 0;
127     }
128     return false;
129 }
130 
write(const std::vector<AttributionNodeInternal> & nodes)131 bool LogEvent::write(const std::vector<AttributionNodeInternal>& nodes) {
132     if (mContext) {
133          if (android_log_write_list_begin(mContext) < 0) {
134             return false;
135          }
136          for (size_t i = 0; i < nodes.size(); ++i) {
137              if (!write(nodes[i])) {
138                 return false;
139              }
140          }
141          if (android_log_write_list_end(mContext) < 0) {
142             return false;
143          }
144          return true;
145     }
146     return false;
147 }
148 
write(const AttributionNodeInternal & node)149 bool LogEvent::write(const AttributionNodeInternal& node) {
150     if (mContext) {
151          if (android_log_write_list_begin(mContext) < 0) {
152             return false;
153          }
154          if (android_log_write_int32(mContext, node.uid()) < 0) {
155             return false;
156          }
157          if (android_log_write_string8(mContext, node.tag().c_str()) < 0) {
158             return false;
159          }
160          if (android_log_write_list_end(mContext) < 0) {
161             return false;
162          }
163          return true;
164     }
165     return false;
166 }
167 
168 /**
169  * The elements of each log event are stored as a vector of android_log_list_elements.
170  * The goal is to do as little preprocessing as possible, because we read a tiny fraction
171  * of the elements that are written to the log.
172  *
173  * The idea here is to read through the log items once, we get as much information we need for
174  * matching as possible. Because this log will be matched against lots of matchers.
175  */
init(android_log_context context)176 void LogEvent::init(android_log_context context) {
177     android_log_list_element elem;
178     int i = 0;
179     int depth = -1;
180     int pos[] = {1, 1, 1};
181     do {
182         elem = android_log_read_next(context);
183         switch ((int)elem.type) {
184             case EVENT_TYPE_INT:
185                 // elem at [0] is EVENT_TYPE_LIST, [1] is the timestamp, [2] is tag id.
186                 if (i == 2) {
187                     mTagId = elem.data.int32;
188                 } else {
189                     if (depth < 0 || depth > 2) {
190                         return;
191                     }
192 
193                     mValues.push_back(
194                             FieldValue(Field(mTagId, pos, depth), Value((int32_t)elem.data.int32)));
195 
196                     pos[depth]++;
197                 }
198                 break;
199             case EVENT_TYPE_FLOAT: {
200                 if (depth < 0 || depth > 2) {
201                     ALOGE("Depth > 2. Not supported!");
202                     return;
203                 }
204 
205                 mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(elem.data.float32)));
206 
207                 pos[depth]++;
208 
209             } break;
210             case EVENT_TYPE_STRING: {
211                 if (depth < 0 || depth > 2) {
212                     ALOGE("Depth > 2. Not supported!");
213                     return;
214                 }
215 
216                 mValues.push_back(FieldValue(Field(mTagId, pos, depth),
217                                              Value(string(elem.data.string, elem.len))));
218 
219                 pos[depth]++;
220 
221             } break;
222             case EVENT_TYPE_LONG: {
223                 if (i == 1) {
224                     mElapsedTimestampNs = elem.data.int64;
225                 } else {
226                     if (depth < 0 || depth > 2) {
227                         ALOGE("Depth > 2. Not supported!");
228                         return;
229                     }
230                     mValues.push_back(
231                             FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));
232 
233                     pos[depth]++;
234                 }
235             } break;
236             case EVENT_TYPE_LIST:
237                 depth++;
238                 if (depth > 2) {
239                     ALOGE("Depth > 2. Not supported!");
240                     return;
241                 }
242                 pos[depth] = 1;
243 
244                 break;
245             case EVENT_TYPE_LIST_STOP: {
246                 int prevDepth = depth;
247                 depth--;
248                 if (depth >= 0 && depth < 2) {
249                     // Now go back to decorate the previous items that are last at prevDepth.
250                     // So that we can later easily match them with Position=Last matchers.
251                     pos[prevDepth]--;
252                     int path = getEncodedField(pos, prevDepth, false);
253                     for (auto it = mValues.rbegin(); it != mValues.rend(); ++it) {
254                         if (it->mField.getDepth() >= prevDepth &&
255                             it->mField.getPath(prevDepth) == path) {
256                             it->mField.decorateLastPos(prevDepth);
257                         } else {
258                             // Safe to break, because the items are in DFS order.
259                             break;
260                         }
261                     }
262                     pos[depth]++;
263                 }
264                 break;
265             }
266             case EVENT_TYPE_UNKNOWN:
267                 break;
268             default:
269                 break;
270         }
271         i++;
272     } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
273 }
274 
GetLong(size_t key,status_t * err) const275 int64_t LogEvent::GetLong(size_t key, status_t* err) const {
276     // TODO: encapsulate the magical operations all in Field struct as a static function.
277     int field = getSimpleField(key);
278     for (const auto& value : mValues) {
279         if (value.mField.getField() == field) {
280             if (value.mValue.getType() == LONG) {
281                 return value.mValue.long_value;
282             } else if (value.mValue.getType() == INT) {
283                 return value.mValue.int_value;
284             } else {
285                 *err = BAD_TYPE;
286                 return 0;
287             }
288         }
289         if ((size_t)value.mField.getPosAtDepth(0) > key) {
290             break;
291         }
292     }
293 
294     *err = BAD_INDEX;
295     return 0;
296 }
297 
GetInt(size_t key,status_t * err) const298 int LogEvent::GetInt(size_t key, status_t* err) const {
299     int field = getSimpleField(key);
300     for (const auto& value : mValues) {
301         if (value.mField.getField() == field) {
302             if (value.mValue.getType() == INT) {
303                 return value.mValue.int_value;
304             } else {
305                 *err = BAD_TYPE;
306                 return 0;
307             }
308         }
309         if ((size_t)value.mField.getPosAtDepth(0) > key) {
310             break;
311         }
312     }
313 
314     *err = BAD_INDEX;
315     return 0;
316 }
317 
GetString(size_t key,status_t * err) const318 const char* LogEvent::GetString(size_t key, status_t* err) const {
319     int field = getSimpleField(key);
320     for (const auto& value : mValues) {
321         if (value.mField.getField() == field) {
322             if (value.mValue.getType() == STRING) {
323                 return value.mValue.str_value.c_str();
324             } else {
325                 *err = BAD_TYPE;
326                 return 0;
327             }
328         }
329         if ((size_t)value.mField.getPosAtDepth(0) > key) {
330             break;
331         }
332     }
333 
334     *err = BAD_INDEX;
335     return NULL;
336 }
337 
GetBool(size_t key,status_t * err) const338 bool LogEvent::GetBool(size_t key, status_t* err) const {
339     int field = getSimpleField(key);
340     for (const auto& value : mValues) {
341         if (value.mField.getField() == field) {
342             if (value.mValue.getType() == INT) {
343                 return value.mValue.int_value != 0;
344             } else if (value.mValue.getType() == LONG) {
345                 return value.mValue.long_value != 0;
346             } else {
347                 *err = BAD_TYPE;
348                 return false;
349             }
350         }
351         if ((size_t)value.mField.getPosAtDepth(0) > key) {
352             break;
353         }
354     }
355 
356     *err = BAD_INDEX;
357     return false;
358 }
359 
GetFloat(size_t key,status_t * err) const360 float LogEvent::GetFloat(size_t key, status_t* err) const {
361     int field = getSimpleField(key);
362     for (const auto& value : mValues) {
363         if (value.mField.getField() == field) {
364             if (value.mValue.getType() == FLOAT) {
365                 return value.mValue.float_value;
366             } else {
367                 *err = BAD_TYPE;
368                 return 0.0;
369             }
370         }
371         if ((size_t)value.mField.getPosAtDepth(0) > key) {
372             break;
373         }
374     }
375 
376     *err = BAD_INDEX;
377     return 0.0;
378 }
379 
ToString() const380 string LogEvent::ToString() const {
381     string result;
382     result += StringPrintf("{ %lld %lld (%d)", (long long)mLogdTimestampNs,
383                            (long long)mElapsedTimestampNs, mTagId);
384     for (const auto& value : mValues) {
385         result +=
386                 StringPrintf("%#x", value.mField.getField()) + "->" + value.mValue.toString() + " ";
387     }
388     result += " }";
389     return result;
390 }
391 
ToProto(ProtoOutputStream & protoOutput) const392 void LogEvent::ToProto(ProtoOutputStream& protoOutput) const {
393     writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
394 }
395 
396 }  // namespace statsd
397 }  // namespace os
398 }  // namespace android
399