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 "StatsPullerManagerImpl.h"
21 #include "puller_util.h"
22 #include "statslog.h"
23 
24 namespace android {
25 namespace os {
26 namespace statsd {
27 
28 using std::map;
29 using std::shared_ptr;
30 using std::vector;
31 
32 namespace {
shouldMerge(shared_ptr<LogEvent> & lhs,shared_ptr<LogEvent> & rhs,const vector<int> & nonAdditiveFields)33 bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
34                  const vector<int>& nonAdditiveFields) {
35     const auto& l_values = lhs->getValues();
36     const auto& r_values = rhs->getValues();
37 
38     for (size_t i : nonAdditiveFields) {
39         // We store everything starting from index 0, so we need to use i-1
40         if (!(l_values.size() > i - 1 && r_values.size() > i - 1 &&
41               l_values[i - 1].mValue == r_values[i - 1].mValue)) {
42             return false;
43         }
44     }
45     return true;
46 }
47 
48 // merge rhs to lhs
49 // when calling this function, all sanity check should be done already.
50 // e.g., index boundary, nonAdditiveFields matching etc.
mergeEvent(shared_ptr<LogEvent> & lhs,shared_ptr<LogEvent> & rhs,const vector<int> & additiveFields)51 bool mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
52                 const vector<int>& additiveFields) {
53     vector<FieldValue>* host_values = lhs->getMutableValues();
54     const auto& child_values = rhs->getValues();
55     for (int i : additiveFields) {
56         Value& host = (*host_values)[i - 1].mValue;
57         const Value& child = (child_values[i - 1]).mValue;
58         if (child.getType() != host.getType()) {
59             return false;
60         }
61         switch (child.getType()) {
62             case INT:
63                 host.setInt(host.int_value + child.int_value);
64                 break;
65             case LONG:
66                 host.setLong(host.long_value + child.long_value);
67                 break;
68             default:
69                 ALOGE("Tried to merge 2 fields with unsupported type");
70                 return false;
71         }
72     }
73     return true;
74 }
75 
tryMerge(vector<shared_ptr<LogEvent>> & data,int child_pos,const vector<int> & host_pos,const vector<int> & nonAdditiveFields,const vector<int> & additiveFields)76 bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<int>& host_pos,
77               const vector<int>& nonAdditiveFields, const vector<int>& additiveFields) {
78     for (const auto& pos : host_pos) {
79         if (shouldMerge(data[pos], data[child_pos], nonAdditiveFields) &&
80             mergeEvent(data[pos], data[child_pos], additiveFields)) {
81             return true;
82         }
83     }
84     return false;
85 }
86 
87 }  // namespace
88 
89 /**
90  * Process all data and merge isolated with host if necessary.
91  * For example:
92  *   NetworkBytesAtom {
93  *       int uid = 1;
94  *       State process_state = 2;
95  *       int byte_send = 3;
96  *       int byte_recv = 4;
97  *   }
98  *   additive fields are {3, 4}, non-additive field is {2}
99  * If we pulled the following events (uid1_child is an isolated uid which maps to uid1):
100  * [uid1, fg, 100, 200]
101  * [uid1_child, fg, 100, 200]
102  * [uid1, bg, 100, 200]
103  *
104  * We want to merge them and results should be:
105  * [uid1, fg, 200, 400]
106  * [uid1, bg, 100, 200]
107  */
mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>> & data,const sp<UidMap> & uidMap,int tagId)108 void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
109                                 int tagId) {
110     if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
111         StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
112         VLOG("Unknown pull atom id %d", tagId);
113         return;
114     }
115     int uidField;
116     auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId);
117     if (it == android::util::AtomsInfo::kAtomsWithUidField.end()) {
118         VLOG("No uid to merge for atom %d", tagId);
119         return;
120     } else {
121         uidField = it->second;  // uidField is the field number in proto,
122     }
123     const vector<int>& additiveFields =
124             StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.additiveFields;
125     const vector<int>& nonAdditiveFields =
126             StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.nonAdditiveFields;
127 
128     // map of host uid to their position in the original vector
129     map<int, vector<int>> hostPosition;
130     vector<bool> toRemove = vector<bool>(data.size(), false);
131 
132     for (size_t i = 0; i < data.size(); i++) {
133         vector<FieldValue>* valueList = data[i]->getMutableValues();
134 
135         int uid;
136         if (uidField > 0 && (int)data[i]->getValues().size() >= uidField &&
137             (data[i]->getValues())[uidField - 1].mValue.getType() == INT) {
138             uid = (*data[i]->getMutableValues())[uidField - 1].mValue.int_value;
139         } else {
140             ALOGE("Malformed log, uid not found. %s", data[i]->ToString().c_str());
141             continue;
142         }
143 
144         const int hostUid = uidMap->getHostUidOrSelf(uid);
145 
146         if (hostUid != uid) {
147             (*valueList)[0].mValue.setInt(hostUid);
148         }
149         if (hostPosition.find(hostUid) == hostPosition.end()) {
150             hostPosition[hostUid].push_back(i);
151         } else {
152             if (tryMerge(data, i, hostPosition[hostUid], nonAdditiveFields, additiveFields)) {
153                 toRemove[i] = true;
154             } else {
155                 hostPosition[hostUid].push_back(i);
156             }
157         }
158     }
159 
160     vector<shared_ptr<LogEvent>> mergedData;
161     for (size_t i = 0; i < toRemove.size(); i++) {
162         if (!toRemove[i]) {
163             mergedData.push_back(data[i]);
164         }
165     }
166     data.clear();
167     data = mergedData;
168 }
169 
170 }  // namespace statsd
171 }  // namespace os
172 }  // namespace android
173