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 */ 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