Home | History | Annotate | Download | only in external
      1 /*
      2  * Copyright (C) 2018 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 "Log.h"
     19 
     20 #include "StatsPullerManager.h"
     21 #include "puller_util.h"
     22 #include "statslog.h"
     23 
     24 namespace android {
     25 namespace os {
     26 namespace statsd {
     27 
     28 using std::list;
     29 using std::map;
     30 using std::set;
     31 using std::shared_ptr;
     32 using std::sort;
     33 using std::vector;
     34 
     35 /**
     36  * Process all data and merge isolated with host if necessary.
     37  * For example:
     38  *   NetworkBytesAtom {
     39  *       int uid = 1;
     40  *       State process_state = 2;
     41  *       int byte_send = 3;
     42  *       int byte_recv = 4;
     43  *   }
     44  *   additive fields are {3, 4}
     45  * If we pulled the following events (uid1_child is an isolated uid which maps to uid1):
     46  * [uid1, fg, 100, 200]
     47  * [uid1_child, fg, 100, 200]
     48  * [uid1, bg, 100, 200]
     49  *
     50  * We want to merge them and results should be:
     51  * [uid1, fg, 200, 400]
     52  * [uid1, bg, 100, 200]
     53  *
     54  * All atoms should be of the same tagId. All fields should be present.
     55  */
     56 void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
     57                                       int tagId) {
     58     if (StatsPullerManager::kAllPullAtomInfo.find(tagId) ==
     59         StatsPullerManager::kAllPullAtomInfo.end()) {
     60         VLOG("Unknown pull atom id %d", tagId);
     61         return;
     62     }
     63     if ((android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) ==
     64          android::util::AtomsInfo::kAtomsWithAttributionChain.end()) &&
     65         (android::util::AtomsInfo::kAtomsWithUidField.find(tagId) ==
     66          android::util::AtomsInfo::kAtomsWithUidField.end())) {
     67         VLOG("No uid or attribution chain to merge, atom %d", tagId);
     68         return;
     69     }
     70 
     71     // 1. Map all isolated uid in-place to host uid
     72     for (shared_ptr<LogEvent>& event : data) {
     73         if (event->GetTagId() != tagId) {
     74             ALOGE("Wrong atom. Expecting %d, got %d", tagId, event->GetTagId());
     75             return;
     76         }
     77         if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) !=
     78             android::util::AtomsInfo::kAtomsWithAttributionChain.end()) {
     79             for (auto& value : *(event->getMutableValues())) {
     80                 if (value.mField.getPosAtDepth(0) > kAttributionField) {
     81                     break;
     82                 }
     83                 if (isAttributionUidField(value)) {
     84                     const int hostUid = uidMap->getHostUidOrSelf(value.mValue.int_value);
     85                     value.mValue.setInt(hostUid);
     86                 }
     87             }
     88         } else {
     89             auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId);
     90             if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
     91                 int uidField = it->second;  // uidField is the field number in proto,
     92                 // starting from 1
     93                 if (uidField > 0 && (int)event->getValues().size() >= uidField &&
     94                     (event->getValues())[uidField - 1].mValue.getType() == INT) {
     95                     Value& value = (*event->getMutableValues())[uidField - 1].mValue;
     96                     const int hostUid = uidMap->getHostUidOrSelf(value.int_value);
     97                     value.setInt(hostUid);
     98                 } else {
     99                     ALOGE("Malformed log, uid not found. %s", event->ToString().c_str());
    100                     return;
    101                 }
    102             }
    103         }
    104     }
    105 
    106     // 2. sort the data, bit-wise
    107     sort(data.begin(), data.end(),
    108          [](const shared_ptr<LogEvent>& lhs, const shared_ptr<LogEvent>& rhs) {
    109              if (lhs->size() != rhs->size()) {
    110                  return lhs->size() < rhs->size();
    111              }
    112              const std::vector<FieldValue>& lhsValues = lhs->getValues();
    113              const std::vector<FieldValue>& rhsValues = rhs->getValues();
    114              for (int i = 0; i < (int)lhs->size(); i++) {
    115                  if (lhsValues[i] != rhsValues[i]) {
    116                      return lhsValues[i] < rhsValues[i];
    117                  }
    118              }
    119              return false;
    120          });
    121 
    122     vector<shared_ptr<LogEvent>> mergedData;
    123     const vector<int>& additiveFieldsVec =
    124             StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.additiveFields;
    125     const set<int> additiveFields(additiveFieldsVec.begin(), additiveFieldsVec.end());
    126     bool needMerge = true;
    127 
    128     // 3. do the merge.
    129     // The loop invariant is this: for every event, check if it differs on
    130     // non-additive fields, or have different attribution chain length.
    131     // If so, no need to merge, add itself to the result.
    132     // Otherwise, merge the value onto the one immediately next to it.
    133     for (int i = 0; i < (int)data.size() - 1; i++) {
    134         // Size different, must be different chains.
    135         if (data[i]->size() != data[i + 1]->size()) {
    136             mergedData.push_back(data[i]);
    137             continue;
    138         }
    139         vector<FieldValue>* lhsValues = data[i]->getMutableValues();
    140         vector<FieldValue>* rhsValues = data[i + 1]->getMutableValues();
    141         needMerge = true;
    142         for (int p = 0; p < (int)lhsValues->size(); p++) {
    143             if ((*lhsValues)[p] != (*rhsValues)[p]) {
    144                 int pos = (*lhsValues)[p].mField.getPosAtDepth(0);
    145                 // Differ on non-additive field, abort.
    146                 if (additiveFields.find(pos) == additiveFields.end()) {
    147                     needMerge = false;
    148                     break;
    149                 }
    150             }
    151         }
    152         if (!needMerge) {
    153             mergedData.push_back(data[i]);
    154             continue;
    155         }
    156         // This should be infrequent operation.
    157         for (int p = 0; p < (int)lhsValues->size(); p++) {
    158             int pos = (*lhsValues)[p].mField.getPosAtDepth(0);
    159             if (additiveFields.find(pos) != additiveFields.end()) {
    160                 (*rhsValues)[p].mValue += (*lhsValues)[p].mValue;
    161             }
    162         }
    163     }
    164     mergedData.push_back(data.back());
    165 
    166     data.clear();
    167     data = mergedData;
    168 }
    169 
    170 }  // namespace statsd
    171 }  // namespace os
    172 }  // namespace android
    173