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 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 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 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 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 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 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 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 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 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 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 124 bool LogEvent::write(float value) { 125 if (mContext) { 126 return android_log_write_float32(mContext, value) >= 0; 127 } 128 return false; 129 } 130 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 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 */ 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 275 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 298 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 318 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 338 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 360 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 380 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 392 void LogEvent::ToProto(ProtoOutputStream& protoOutput) const { 393 writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput); 394 } 395 396 } // namespace statsd 397 } // namespace os 398 } // namespace android 399