Home | History | Annotate | Download | only in logd
      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