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