blob: 7cfc1d487dfbd8bd2c3ce43d8430caa9aa9e78a3 [file] [log] [blame]
Chenjie Yu80f91122018-01-31 20:24:50 -08001/*
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 "field_util.h"
22#include "puller_util.h"
23#include "statslog.h"
24
25namespace android {
26namespace os {
27namespace statsd {
28
29using std::map;
30using std::shared_ptr;
31using std::vector;
32
33DimensionsValue* getFieldValue(shared_ptr<LogEvent> event, int tagId, int fieldNum) {
34 Field field;
35 buildSimpleAtomField(tagId, fieldNum, &field);
36 return event->findFieldValueOrNull(field);
37}
38
39bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
40 const vector<int>& nonAdditiveFields, int tagId) {
41 for (int f : nonAdditiveFields) {
42 DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
43 DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
44 if (!compareDimensionsValue(*lValue, *rValue)) {
45 return false;
46 }
47 }
48 return true;
49}
50
51// merge rhs to lhs
52void mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
53 const vector<int>& additiveFields, int tagId) {
54 for (int f : additiveFields) {
55 DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
56 DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
57 if (lValue->has_value_int()) {
58 lValue->set_value_int(lValue->value_int() + rValue->value_int());
59 } else if (lValue->has_value_long()) {
60 lValue->set_value_long(lValue->value_long() + rValue->value_long());
61 }
62 }
63}
64
65// process all data and merge isolated with host if necessary
66void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data,
67 const sp<UidMap>& uidMap, int tagId) {
68 if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
69 StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
70 VLOG("Unknown pull atom id %d", tagId);
71 return;
72 }
73 if (android::util::kAtomsWithUidField.find(tagId) ==
74 android::util::kAtomsWithUidField.end()) {
75 VLOG("No uid to merge for atom %d", tagId);
76 return;
77 }
78 const vector<int>& additiveFields =
79 StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
80 ->second.additiveFields;
81 const vector<int>& nonAdditiveFields =
82 StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
83 ->second.nonAdditiveFields;
84
85 // map of host uid to isolated uid data index in the original vector.
86 // because of non additive fields, there could be multiple of them that can't
87 // be merged into one
88 map<int, vector<int>> hostToIsolated;
89 // map of host uid to their position in the original vector
90 map<int, vector<int>> hostPosition;
91 vector<int> isolatedUidPos;
92 // all uids in the original vector
93 vector<int> allUids;
94 for (size_t i = 0; i < data.size(); i++) {
95 // uid field is always first primitive filed, if present
96 DimensionsValue* uidField = getFieldValue(data[i], tagId, 1);
97 if (!uidField) {
98 VLOG("Bad data for %d, %s", tagId, data[i]->ToString().c_str());
99 return;
100 }
101 int uid = uidField->value_int();
102 allUids.push_back(uid);
103 const int hostUid = uidMap->getHostUidOrSelf(uid);
104 if (hostUid != uid) {
105 uidField->set_value_int(hostUid);
106 hostToIsolated[hostUid].push_back(i);
107 isolatedUidPos.push_back(i);
108 }
109 }
110 vector<shared_ptr<LogEvent>> mergedData;
111 for (size_t i = 0; i < allUids.size(); i++) {
112 if (hostToIsolated.find(allUids[i]) != hostToIsolated.end()) {
113 hostPosition[allUids[i]].push_back(i);
114 } else if (std::find(isolatedUidPos.begin(), isolatedUidPos.end(), i) != isolatedUidPos.end()) {
115 continue;
116 } else {
117 mergedData.push_back(data[i]);
118 }
119 }
120 for (auto iter = hostToIsolated.begin(); iter != hostToIsolated.end();
121 iter++) {
122 int uid = iter->first;
123 vector<int>& isolated = hostToIsolated[uid];
124 vector<int> toBeMerged;
125 toBeMerged.insert(toBeMerged.begin(), isolated.begin(), isolated.end());
126 if (hostPosition.find(uid) != hostPosition.end()) {
127 vector<int>& host = hostPosition[uid];
128 toBeMerged.insert(toBeMerged.end(), host.begin(), host.end());
129 }
130 vector<bool> used(toBeMerged.size());
131 for (size_t i = 0; i < toBeMerged.size(); i++) {
132 if (used[i] == true) {
133 continue;
134 }
135 for (size_t j = i + 1; j < toBeMerged.size(); j++) {
136 shared_ptr<LogEvent>& lhs = data[toBeMerged[i]];
137 shared_ptr<LogEvent>& rhs = data[toBeMerged[j]];
138 if (shouldMerge(lhs, rhs, nonAdditiveFields, tagId)) {
139 mergeEvent(lhs, rhs, additiveFields, tagId);
140 used[j] = true;
141 }
142 }
143 }
144 for (size_t i = 0; i < toBeMerged.size(); i++) {
145 if (used[i] == false) {
146 mergedData.push_back(data[i]);
147 }
148 }
149 }
150 data.clear();
151 data = mergedData;
152}
153
154} // namespace statsd
155} // namespace os
156} // namespace android