diff options
-rw-r--r-- | cmds/statsd/src/external/StatsCompanionServicePuller.cpp | 2 | ||||
-rw-r--r-- | cmds/statsd/src/external/StatsPuller.cpp | 7 | ||||
-rw-r--r-- | cmds/statsd/src/external/StatsPullerManager.cpp | 99 | ||||
-rw-r--r-- | cmds/statsd/src/external/StatsPullerManager.h | 3 | ||||
-rw-r--r-- | cmds/statsd/src/external/puller_util.cpp | 196 | ||||
-rw-r--r-- | cmds/statsd/src/external/puller_util.h | 4 | ||||
-rw-r--r-- | cmds/statsd/src/logd/LogEvent.cpp | 30 | ||||
-rw-r--r-- | cmds/statsd/src/logd/LogEvent.h | 11 | ||||
-rw-r--r-- | cmds/statsd/src/metrics/ValueMetricProducer.h | 2 | ||||
-rw-r--r-- | cmds/statsd/src/metrics/metrics_manager_util.cpp | 10 | ||||
-rw-r--r-- | cmds/statsd/tests/LogEvent_test.cpp | 161 | ||||
-rw-r--r-- | cmds/statsd/tests/external/puller_util_test.cpp | 12 | ||||
-rw-r--r-- | core/java/android/os/StatsLogEventWrapper.java | 45 | ||||
-rw-r--r-- | libs/services/include/android/os/StatsLogEventWrapper.h | 11 | ||||
-rw-r--r-- | libs/services/src/os/StatsLogEventWrapper.cpp | 25 |
15 files changed, 426 insertions, 192 deletions
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp index 3eb05a90e3b4..4e4b8f35726d 100644 --- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp +++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp @@ -59,7 +59,7 @@ bool StatsCompanionServicePuller::PullInternal(vector<shared_ptr<LogEvent> >* da } data->clear(); for (const StatsLogEventWrapper& it : returned_value) { - data->push_back(make_shared<LogEvent>(it)); + LogEvent::createLogEvents(it, *data); } VLOG("StatsCompanionServicePuller::pull succeeded for %d", mTagId); return true; diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index e3f251a5263d..f501574d6afc 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -32,9 +32,10 @@ using std::lock_guard; sp<UidMap> StatsPuller::mUidMap = nullptr; void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; } -// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently StatsPuller::StatsPuller(const int tagId) : mTagId(tagId) { + // Pullers can cause significant impact to system health and battery. + // So that we don't pull too frequently. mCoolDownNs = StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.coolDownNs; VLOG("Puller for tag %d created. Cooldown set to %lld", mTagId, (long long)mCoolDownNs); } @@ -64,8 +65,8 @@ bool StatsPuller::Pull(const int64_t elapsedTimeNs, std::vector<std::shared_ptr< data->setLogdWallClockTimestampNs(wallClockTimeNs); } if (ret && mCachedData.size() > 0) { - mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId); - (*data) = mCachedData; + mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId); + (*data) = mCachedData; } StatsdStats::getInstance().notePullDelay(mTagId, getElapsedRealtimeNs() - elapsedTimeNs); return ret; diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 87a065b81813..f9b79823741b 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -54,52 +54,42 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // wifi_bytes_transfer {android::util::WIFI_BYTES_TRANSFER, {{2, 3, 4, 5}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}}, // wifi_bytes_transfer_by_fg_bg {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, {{3, 4, 5, 6}, - {2}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}}, // mobile_bytes_transfer {android::util::MOBILE_BYTES_TRANSFER, {{2, 3, 4, 5}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}}, // mobile_bytes_transfer_by_fg_bg {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, {{3, 4, 5, 6}, - {2}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}}, // bluetooth_bytes_transfer {android::util::BLUETOOTH_BYTES_TRANSFER, {{2, 3}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, // kernel_wakelock {android::util::KERNEL_WAKELOCK, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, // subsystem_sleep_state {android::util::SUBSYSTEM_SLEEP_STATE, - {{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}}, + {{}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}}, // on_device_power_measurement - {android::util::ON_DEVICE_POWER_MEASUREMENT, - {{}, {}, 1 * NS_PER_SEC, new PowerStatsPuller()}}, + {android::util::ON_DEVICE_POWER_MEASUREMENT, {{}, 1 * NS_PER_SEC, new PowerStatsPuller()}}, // cpu_time_per_freq {android::util::CPU_TIME_PER_FREQ, - {{3}, - {2}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, + {{3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, // cpu_time_per_uid {android::util::CPU_TIME_PER_UID, {{2, 3}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}}, // cpu_time_per_uid_freq @@ -107,169 +97,140 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_TIME_PER_UID_FREQ, {{4}, - {2, 3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}}, // cpu_active_time // the throttling is 3sec, handled in // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_ACTIVE_TIME, - {{2}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, + {{2}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, // cpu_cluster_time // the throttling is 3sec, handled in // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_CLUSTER_TIME, - {{3}, - {2}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, + {{3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, // wifi_activity_energy_info {android::util::WIFI_ACTIVITY_INFO, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}}, // modem_activity_info {android::util::MODEM_ACTIVITY_INFO, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, // bluetooth_activity_info {android::util::BLUETOOTH_ACTIVITY_INFO, {{}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, // system_elapsed_realtime {android::util::SYSTEM_ELAPSED_REALTIME, {{}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}}, // system_uptime {android::util::SYSTEM_UPTIME, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, // remaining_battery_capacity {android::util::REMAINING_BATTERY_CAPACITY, {{}, - {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, // full_battery_capacity {android::util::FULL_BATTERY_CAPACITY, {{}, - {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, // battery_voltage {android::util::BATTERY_VOLTAGE, - {{}, {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}}, - // battery_voltage + {{}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}}, + // battery_level {android::util::BATTERY_LEVEL, - {{}, {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}}, + {{}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}}, // process_memory_state {android::util::PROCESS_MEMORY_STATE, {{4, 5, 6, 7, 8, 9}, - {2, 3, 10}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, // native_process_memory_state {android::util::NATIVE_PROCESS_MEMORY_STATE, {{3, 4, 5, 6}, - {2, 7}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}}, {android::util::PROCESS_MEMORY_HIGH_WATER_MARK, {{3}, - {2}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}}, // temperature - {android::util::TEMPERATURE, {{}, {}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}}, + {android::util::TEMPERATURE, {{}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}}, // binder_calls {android::util::BINDER_CALLS, {{4, 5, 6, 8, 12}, - {2, 3, 7, 9, 10, 11, 13}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BINDER_CALLS)}}, // binder_calls_exceptions {android::util::BINDER_CALLS_EXCEPTIONS, {{}, - {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}}, // looper_stats {android::util::LOOPER_STATS, {{5, 6, 7, 8, 9}, - {2, 3, 4, 10}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::LOOPER_STATS)}}, // Disk Stats {android::util::DISK_STATS, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_STATS)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_STATS)}}, // Directory usage {android::util::DIRECTORY_USAGE, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}}, // Size of app's code, data, and cache {android::util::APP_SIZE, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}}, // Size of specific categories of files. Eg. Music. {android::util::CATEGORY_SIZE, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}}, // Number of fingerprints registered to each user. {android::util::NUM_FINGERPRINTS, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}}, // ProcStats. {android::util::PROC_STATS, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}}, // ProcStatsPkgProc. {android::util::PROC_STATS_PKG_PROC, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}}, // Disk I/O stats per uid. {android::util::DISK_IO, - {{2,3,4,5,6,7,8,9,10,11}, - {}, + {{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 3 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_IO)}}, // PowerProfile constants for power model calculations. {android::util::POWER_PROFILE, - {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses. {android::util::PROCESS_CPU_TIME, - {{} /* additive fields */, {} /* non additive fields */, - 5 * NS_PER_SEC /* min cool-down in seconds*/, - new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}}, + {{} /* additive fields */, + 5 * NS_PER_SEC /* min cool-down in seconds*/, + new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}}, {android::util::CPU_TIME_PER_THREAD_FREQ, {{7}, - {2, 3, 4, 5, 6}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}}, // DeviceCalculatedPowerUse. {android::util::DEVICE_CALCULATED_POWER_USE, - {{}, {}, 1 * NS_PER_SEC, + {{}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}}, // DeviceCalculatedPowerBlameUid. {android::util::DEVICE_CALCULATED_POWER_BLAME_UID, - {{}, {}, // BatteryStats already merged isolated with host ids so it's unnecessary here. + {{}, // BatteryStats already merged isolated with host ids so it's unnecessary here. 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}}, // DeviceCalculatedPowerBlameOther. {android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER, - {{}, {}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}}, // BuildInformation. {android::util::BUILD_INFORMATION, - {{}, {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}}, + {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index bbf5d9dc69db..335073613a4a 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -36,9 +36,6 @@ typedef struct { // The field numbers of the fields that need to be summed when merging // isolated uid with host uid. std::vector<int> additiveFields; - // The field numbers of the fields that can't be merged when merging - // data belong to isolated uid and host uid. - std::vector<int> nonAdditiveFields; // How long should the puller wait before doing an actual pull again. Default // 1 sec. Set this to 0 if this is handled elsewhere. int64_t coolDownNs = 1 * NS_PER_SEC; diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index ea7fa972cb9c..0b9b6abfd6d6 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -25,67 +25,13 @@ namespace android { namespace os { namespace statsd { +using std::list; using std::map; +using std::set; using std::shared_ptr; +using std::sort; using std::vector; -namespace { -bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs, - const vector<int>& nonAdditiveFields) { - const auto& l_values = lhs->getValues(); - const auto& r_values = rhs->getValues(); - - for (size_t i : nonAdditiveFields) { - // We store everything starting from index 0, so we need to use i-1 - if (!(l_values.size() > i - 1 && r_values.size() > i - 1 && - l_values[i - 1].mValue == r_values[i - 1].mValue)) { - return false; - } - } - return true; -} - -// merge rhs to lhs -// when calling this function, all sanity check should be done already. -// e.g., index boundary, nonAdditiveFields matching etc. -bool mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs, - const vector<int>& additiveFields) { - vector<FieldValue>* host_values = lhs->getMutableValues(); - const auto& child_values = rhs->getValues(); - for (int i : additiveFields) { - Value& host = (*host_values)[i - 1].mValue; - const Value& child = (child_values[i - 1]).mValue; - if (child.getType() != host.getType()) { - return false; - } - switch (child.getType()) { - case INT: - host.setInt(host.int_value + child.int_value); - break; - case LONG: - host.setLong(host.long_value + child.long_value); - break; - default: - ALOGE("Tried to merge 2 fields with unsupported type"); - return false; - } - } - return true; -} - -bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<int>& host_pos, - const vector<int>& nonAdditiveFields, const vector<int>& additiveFields) { - for (const auto& pos : host_pos) { - if (shouldMerge(data[pos], data[child_pos], nonAdditiveFields) && - mergeEvent(data[pos], data[child_pos], additiveFields)) { - return true; - } - } - return false; -} - -} // namespace - /** * Process all data and merge isolated with host if necessary. * For example: @@ -95,7 +41,7 @@ bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<in * int byte_send = 3; * int byte_recv = 4; * } - * additive fields are {3, 4}, non-additive field is {2} + * additive fields are {3, 4} * If we pulled the following events (uid1_child is an isolated uid which maps to uid1): * [uid1, fg, 100, 200] * [uid1_child, fg, 100, 200] @@ -104,65 +50,119 @@ bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<in * We want to merge them and results should be: * [uid1, fg, 200, 400] * [uid1, bg, 100, 200] + * + * All atoms should be of the same tagId. All fields should be present. */ -void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap, - int tagId) { +void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap, + int tagId) { if (StatsPullerManager::kAllPullAtomInfo.find(tagId) == StatsPullerManager::kAllPullAtomInfo.end()) { VLOG("Unknown pull atom id %d", tagId); return; } - int uidField; - auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId); - if (it == android::util::AtomsInfo::kAtomsWithUidField.end()) { - VLOG("No uid to merge for atom %d", tagId); + if ((android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) == + android::util::AtomsInfo::kAtomsWithAttributionChain.end()) && + (android::util::AtomsInfo::kAtomsWithUidField.find(tagId) == + android::util::AtomsInfo::kAtomsWithUidField.end())) { + VLOG("No uid or attribution chain to merge, atom %d", tagId); return; - } else { - uidField = it->second; // uidField is the field number in proto, } - const vector<int>& additiveFields = - StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.additiveFields; - const vector<int>& nonAdditiveFields = - StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.nonAdditiveFields; - - // map of host uid to their position in the original vector - map<int, vector<int>> hostPosition; - vector<bool> toRemove = vector<bool>(data.size(), false); - for (size_t i = 0; i < data.size(); i++) { - vector<FieldValue>* valueList = data[i]->getMutableValues(); - - int uid; - if (uidField > 0 && (int)data[i]->getValues().size() >= uidField && - (data[i]->getValues())[uidField - 1].mValue.getType() == INT) { - uid = (*data[i]->getMutableValues())[uidField - 1].mValue.int_value; - } else { - ALOGE("Malformed log, uid not found. %s", data[i]->ToString().c_str()); - continue; + // 1. Map all isolated uid in-place to host uid + for (shared_ptr<LogEvent>& event : data) { + if (event->GetTagId() != tagId) { + ALOGE("Wrong atom. Expecting %d, got %d", tagId, event->GetTagId()); + return; } - - const int hostUid = uidMap->getHostUidOrSelf(uid); - - if (hostUid != uid) { - (*valueList)[0].mValue.setInt(hostUid); - } - if (hostPosition.find(hostUid) == hostPosition.end()) { - hostPosition[hostUid].push_back(i); + if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) != + android::util::AtomsInfo::kAtomsWithAttributionChain.end()) { + for (auto& value : *(event->getMutableValues())) { + if (value.mField.getPosAtDepth(0) > kAttributionField) { + break; + } + if (isAttributionUidField(value)) { + const int hostUid = uidMap->getHostUidOrSelf(value.mValue.int_value); + value.mValue.setInt(hostUid); + } + } } else { - if (tryMerge(data, i, hostPosition[hostUid], nonAdditiveFields, additiveFields)) { - toRemove[i] = true; - } else { - hostPosition[hostUid].push_back(i); + auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId); + if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { + int uidField = it->second; // uidField is the field number in proto, + // starting from 1 + if (uidField > 0 && (int)event->getValues().size() >= uidField && + (event->getValues())[uidField - 1].mValue.getType() == INT) { + Value& value = (*event->getMutableValues())[uidField - 1].mValue; + const int hostUid = uidMap->getHostUidOrSelf(value.int_value); + value.setInt(hostUid); + } else { + ALOGE("Malformed log, uid not found. %s", event->ToString().c_str()); + return; + } } } } + // 2. sort the data, bit-wise + sort(data.begin(), data.end(), + [](const shared_ptr<LogEvent>& lhs, const shared_ptr<LogEvent>& rhs) { + if (lhs->size() != rhs->size()) { + return lhs->size() < rhs->size(); + } + const std::vector<FieldValue>& lhsValues = lhs->getValues(); + const std::vector<FieldValue>& rhsValues = rhs->getValues(); + for (int i = 0; i < (int)lhs->size(); i++) { + if (lhsValues[i] != rhsValues[i]) { + return lhsValues[i] < rhsValues[i]; + } + } + return false; + }); + vector<shared_ptr<LogEvent>> mergedData; - for (size_t i = 0; i < toRemove.size(); i++) { - if (!toRemove[i]) { + const vector<int>& additiveFieldsVec = + StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.additiveFields; + const set<int> additiveFields(additiveFieldsVec.begin(), additiveFieldsVec.end()); + bool needMerge = true; + + // 3. do the merge. + // The loop invariant is this: for every event, check if it differs on + // non-additive fields, or have different attribution chain length. + // If so, no need to merge, add itself to the result. + // Otherwise, merge the value onto the one immediately next to it. + for (int i = 0; i < (int)data.size() - 1; i++) { + // Size different, must be different chains. + if (data[i]->size() != data[i + 1]->size()) { mergedData.push_back(data[i]); + continue; + } + vector<FieldValue>* lhsValues = data[i]->getMutableValues(); + vector<FieldValue>* rhsValues = data[i + 1]->getMutableValues(); + needMerge = true; + for (int p = 0; p < (int)lhsValues->size(); p++) { + if ((*lhsValues)[p] != (*rhsValues)[p]) { + int pos = (*lhsValues)[p].mField.getPosAtDepth(0); + // Differ on non-additive field, abort. + if (additiveFields.find(pos) == additiveFields.end()) { + needMerge = false; + break; + } + } + } + if (!needMerge) { + mergedData.push_back(data[i]); + continue; + } + // This should be infrequent operation. + for (int p = 0; p < (int)lhsValues->size(); p++) { + int pos = (*lhsValues)[p].mField.getPosAtDepth(0); + if (additiveFields.find(pos) != additiveFields.end()) { + (*rhsValues)[p].mValue += (*lhsValues)[p].mValue; + } } } + mergedData.push_back(data.back()); + data.clear(); data = mergedData; } diff --git a/cmds/statsd/src/external/puller_util.h b/cmds/statsd/src/external/puller_util.h index fd4a4a2a5755..f703e6c589c1 100644 --- a/cmds/statsd/src/external/puller_util.h +++ b/cmds/statsd/src/external/puller_util.h @@ -25,8 +25,8 @@ namespace android { namespace os { namespace statsd { -void mergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data, - const sp<UidMap>& uidMap, int tagId); +void mapAndMergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data, + const sp<UidMap>& uidMap, int tagId); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 625294ce5e49..b9732a596b2d 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -41,13 +41,28 @@ LogEvent::LogEvent(log_msg& msg) { } } -LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper) { +LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex) { mTagId = statsLogEventWrapper.getTagId(); mLogdTimestampNs = statsLogEventWrapper.getWallClockTimeNs(); mElapsedTimestampNs = statsLogEventWrapper.getElapsedRealTimeNs(); mLogUid = 0; + int workChainPosOffset = 0; + if (workChainIndex != -1) { + const WorkChain& wc = statsLogEventWrapper.getWorkChains()[workChainIndex]; + // chains are at field 1, level 2 + int depth = 2; + for (int i = 0; i < (int)wc.uids.size(); i++) { + int pos[] = {1, i + 1, 1}; + mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(wc.uids[i]))); + pos[2]++; + mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(wc.tags[i]))); + mValues.back().mField.decorateLastPos(2); + } + mValues.back().mField.decorateLastPos(1); + workChainPosOffset = 1; + } for (int i = 0; i < (int)statsLogEventWrapper.getElements().size(); i++) { - Field field(statsLogEventWrapper.getTagId(), getSimpleField(i + 1)); + Field field(statsLogEventWrapper.getTagId(), getSimpleField(i + 1 + workChainPosOffset)); switch (statsLogEventWrapper.getElements()[i].type) { case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::INT: mValues.push_back( @@ -79,6 +94,17 @@ LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper) { } } +void LogEvent::createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper, + std::vector<std::shared_ptr<LogEvent>>& logEvents) { + if (statsLogEventWrapper.getWorkChains().size() == 0) { + logEvents.push_back(std::make_shared<LogEvent>(statsLogEventWrapper, -1)); + } else { + for (size_t i = 0; i < statsLogEventWrapper.getWorkChains().size(); i++) { + logEvents.push_back(std::make_shared<LogEvent>(statsLogEventWrapper, i)); + } + } +} + LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) { mLogdTimestampNs = wallClockTimestampNs; mTagId = tagId; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 3d5b2abc7e3a..5408d17b02b2 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -65,7 +65,16 @@ public: */ explicit LogEvent(log_msg& msg); - explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper); + /** + * Creates LogEvent from StatsLogEventWrapper. + */ + static void createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper, + std::vector<std::shared_ptr<LogEvent>>& logEvents); + + /** + * Construct one LogEvent from a StatsLogEventWrapper with the i-th work chain. -1 if no chain. + */ + explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex); /** * Constructs a LogEvent with synthetic data for testing. Must call init() before reading. diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index c3912eebbc11..9fe84dcf93aa 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -165,7 +165,7 @@ private: const bool mSkipZeroDiffOutput; FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition); - FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering); + FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering); FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset); FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset); FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition); diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 4ac55b5c14b6..b317361a5a3d 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -454,6 +454,16 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id()); return false; } + if (!metric.has_value_field()) { + ALOGW("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id()); + return false; + } + std::vector<Matcher> fieldMatchers; + translateFieldMatcher(metric.value_field(), &fieldMatchers); + if (fieldMatchers.size() < 1) { + ALOGW("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id()); + return false; + } int metricIndex = allMetricProducers.size(); metricMap.insert({metric.id(), metricIndex}); diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 6384757b7fc8..90dfa87abeaa 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -394,6 +394,167 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { EXPECT_EQ(1.1f, item16.mValue.float_value); } +TEST(LogEventTest, TestStatsLogEventWrapperNoChain) { + Parcel parcel; + // tag id + parcel.writeInt32(1); + // elapsed realtime + parcel.writeInt64(1111L); + // wallclock time + parcel.writeInt64(2222L); + // no chain + parcel.writeInt32(0); + // 2 data + parcel.writeInt32(2); + // int 6 + parcel.writeInt32(1); + parcel.writeInt32(6); + // long 10 + parcel.writeInt32(2); + parcel.writeInt64(10); + parcel.setDataPosition(0); + + StatsLogEventWrapper statsLogEventWrapper; + EXPECT_EQ(NO_ERROR, statsLogEventWrapper.readFromParcel(&parcel)); + EXPECT_EQ(1, statsLogEventWrapper.getTagId()); + EXPECT_EQ(1111L, statsLogEventWrapper.getElapsedRealTimeNs()); + EXPECT_EQ(2222L, statsLogEventWrapper.getWallClockTimeNs()); + EXPECT_EQ(0, statsLogEventWrapper.getWorkChains().size()); + EXPECT_EQ(2, statsLogEventWrapper.getElements().size()); + EXPECT_EQ(6, statsLogEventWrapper.getElements()[0].int_value); + EXPECT_EQ(10L, statsLogEventWrapper.getElements()[1].long_value); + LogEvent event(statsLogEventWrapper, -1); + EXPECT_EQ(1, event.GetTagId()); + EXPECT_EQ(1111L, event.GetElapsedTimestampNs()); + EXPECT_EQ(2222L, event.GetLogdTimestampNs()); + EXPECT_EQ(2, event.size()); + EXPECT_EQ(6, event.getValues()[0].mValue.int_value); + EXPECT_EQ(10, event.getValues()[1].mValue.long_value); +} + +TEST(LogEventTest, TestStatsLogEventWrapperWithChain) { + Parcel parcel; + // tag id + parcel.writeInt32(1); + // elapsed realtime + parcel.writeInt64(1111L); + // wallclock time + parcel.writeInt64(2222L); + // 3 chains + parcel.writeInt32(3); + // chain1, 2 nodes (1, "tag1") (2, "tag2") + parcel.writeInt32(2); + parcel.writeInt32(1); + parcel.writeString16(String16("tag1")); + parcel.writeInt32(2); + parcel.writeString16(String16("tag2")); + // chain2, 1 node (3, "tag3") + parcel.writeInt32(1); + parcel.writeInt32(3); + parcel.writeString16(String16("tag3")); + // chain3, 2 nodes (4, "") (5, "") + parcel.writeInt32(2); + parcel.writeInt32(4); + parcel.writeString16(String16("")); + parcel.writeInt32(5); + parcel.writeString16(String16("")); + // 2 data + parcel.writeInt32(2); + // int 6 + parcel.writeInt32(1); + parcel.writeInt32(6); + // long 10 + parcel.writeInt32(2); + parcel.writeInt64(10); + parcel.setDataPosition(0); + + StatsLogEventWrapper statsLogEventWrapper; + EXPECT_EQ(NO_ERROR, statsLogEventWrapper.readFromParcel(&parcel)); + EXPECT_EQ(1, statsLogEventWrapper.getTagId()); + EXPECT_EQ(1111L, statsLogEventWrapper.getElapsedRealTimeNs()); + EXPECT_EQ(2222L, statsLogEventWrapper.getWallClockTimeNs()); + EXPECT_EQ(3, statsLogEventWrapper.getWorkChains().size()); + EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].uids.size()); + EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[0].uids[0]); + EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].uids[1]); + EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].tags.size()); + EXPECT_EQ("tag1", statsLogEventWrapper.getWorkChains()[0].tags[0]); + EXPECT_EQ("tag2", statsLogEventWrapper.getWorkChains()[0].tags[1]); + EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[1].uids.size()); + EXPECT_EQ(3, statsLogEventWrapper.getWorkChains()[1].uids[0]); + EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[1].tags.size()); + EXPECT_EQ("tag3", statsLogEventWrapper.getWorkChains()[1].tags[0]); + EXPECT_EQ(2, statsLogEventWrapper.getElements().size()); + EXPECT_EQ(6, statsLogEventWrapper.getElements()[0].int_value); + EXPECT_EQ(10L, statsLogEventWrapper.getElements()[1].long_value); + EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[2].uids.size()); + EXPECT_EQ(4, statsLogEventWrapper.getWorkChains()[2].uids[0]); + EXPECT_EQ(5, statsLogEventWrapper.getWorkChains()[2].uids[1]); + EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[2].tags.size()); + EXPECT_EQ("", statsLogEventWrapper.getWorkChains()[2].tags[0]); + EXPECT_EQ("", statsLogEventWrapper.getWorkChains()[2].tags[1]); + + LogEvent event(statsLogEventWrapper, -1); + EXPECT_EQ(1, event.GetTagId()); + EXPECT_EQ(1111L, event.GetElapsedTimestampNs()); + EXPECT_EQ(2222L, event.GetLogdTimestampNs()); + EXPECT_EQ(2, event.size()); + EXPECT_EQ(6, event.getValues()[0].mValue.int_value); + EXPECT_EQ(10, event.getValues()[1].mValue.long_value); + + LogEvent event1(statsLogEventWrapper, 0); + + EXPECT_EQ(1, event1.GetTagId()); + EXPECT_EQ(1111L, event1.GetElapsedTimestampNs()); + EXPECT_EQ(2222L, event1.GetLogdTimestampNs()); + EXPECT_EQ(6, event1.size()); + EXPECT_EQ(1, event1.getValues()[0].mValue.int_value); + EXPECT_EQ(0x2010101, event1.getValues()[0].mField.getField()); + EXPECT_EQ("tag1", event1.getValues()[1].mValue.str_value); + EXPECT_EQ(0x2010182, event1.getValues()[1].mField.getField()); + EXPECT_EQ(2, event1.getValues()[2].mValue.int_value); + EXPECT_EQ(0x2010201, event1.getValues()[2].mField.getField()); + EXPECT_EQ("tag2", event1.getValues()[3].mValue.str_value); + EXPECT_EQ(0x2018282, event1.getValues()[3].mField.getField()); + EXPECT_EQ(6, event1.getValues()[4].mValue.int_value); + EXPECT_EQ(0x20000, event1.getValues()[4].mField.getField()); + EXPECT_EQ(10, event1.getValues()[5].mValue.long_value); + EXPECT_EQ(0x30000, event1.getValues()[5].mField.getField()); + + LogEvent event2(statsLogEventWrapper, 1); + + EXPECT_EQ(1, event2.GetTagId()); + EXPECT_EQ(1111L, event2.GetElapsedTimestampNs()); + EXPECT_EQ(2222L, event2.GetLogdTimestampNs()); + EXPECT_EQ(4, event2.size()); + EXPECT_EQ(3, event2.getValues()[0].mValue.int_value); + EXPECT_EQ(0x2010101, event2.getValues()[0].mField.getField()); + EXPECT_EQ("tag3", event2.getValues()[1].mValue.str_value); + EXPECT_EQ(0x2018182, event2.getValues()[1].mField.getField()); + EXPECT_EQ(6, event2.getValues()[2].mValue.int_value); + EXPECT_EQ(0x20000, event2.getValues()[2].mField.getField()); + EXPECT_EQ(10, event2.getValues()[3].mValue.long_value); + EXPECT_EQ(0x30000, event2.getValues()[3].mField.getField()); + + LogEvent event3(statsLogEventWrapper, 2); + + EXPECT_EQ(1, event3.GetTagId()); + EXPECT_EQ(1111L, event3.GetElapsedTimestampNs()); + EXPECT_EQ(2222L, event3.GetLogdTimestampNs()); + EXPECT_EQ(6, event3.size()); + EXPECT_EQ(4, event3.getValues()[0].mValue.int_value); + EXPECT_EQ(0x2010101, event3.getValues()[0].mField.getField()); + EXPECT_EQ("", event3.getValues()[1].mValue.str_value); + EXPECT_EQ(0x2010182, event3.getValues()[1].mField.getField()); + EXPECT_EQ(5, event3.getValues()[2].mValue.int_value); + EXPECT_EQ(0x2010201, event3.getValues()[2].mField.getField()); + EXPECT_EQ("", event3.getValues()[3].mValue.str_value); + EXPECT_EQ(0x2018282, event3.getValues()[3].mField.getField()); + EXPECT_EQ(6, event3.getValues()[4].mValue.int_value); + EXPECT_EQ(0x20000, event3.getValues()[4].mField.getField()); + EXPECT_EQ(10, event3.getValues()[5].mValue.long_value); + EXPECT_EQ(0x30000, event3.getValues()[5].mField.getField()); +} TEST(LogEventTest, TestBinaryFieldAtom) { Atom launcherAtom; diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp index fc6e42010710..266ea351b5d4 100644 --- a/cmds/statsd/tests/external/puller_util_test.cpp +++ b/cmds/statsd/tests/external/puller_util_test.cpp @@ -80,7 +80,7 @@ TEST(puller_util, MergeNoDimension) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); vector<vector<int>> actual; extractIntoVector(inputData, actual); @@ -120,7 +120,7 @@ TEST(puller_util, MergeWithDimension) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); vector<vector<int>> actual; extractIntoVector(inputData, actual); @@ -154,7 +154,7 @@ TEST(puller_util, NoMergeHostUidOnly) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); // 20->32->31 // 20->22->21 @@ -190,7 +190,7 @@ TEST(puller_util, IsolatedUidOnly) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); // 20->32->31 // 20->22->21 @@ -231,7 +231,7 @@ TEST(puller_util, MultipleIsolatedUidToOneHostUid) { sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid)); - mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); vector<vector<int>> actual; extractIntoVector(inputData, actual); @@ -256,7 +256,7 @@ TEST(puller_util, NoNeedToMerge) { inputData.push_back(event); sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); - mergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId); EXPECT_EQ(2, (int)inputData.size()); } diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java index 866bd9a17f41..acb9eac3572c 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -43,6 +43,7 @@ public final class StatsLogEventWrapper implements Parcelable { int mTag; long mElapsedTimeNs; long mWallClockTimeNs; + WorkSource mWorkSource = null; public StatsLogEventWrapper(int tag, long elapsedTimeNs, long wallClockTimeNs) { this.mTag = tag; @@ -71,6 +72,17 @@ public final class StatsLogEventWrapper implements Parcelable { }; /** + * Set work source if any. + */ + public void setWorkSource(WorkSource ws) { + if (ws.getWorkChains() == null || ws.getWorkChains().size() == 0) { + Slog.w(TAG, "Empty worksource!"); + return; + } + mWorkSource = ws; + } + + /** * Write a int value. */ public void writeInt(int val) { @@ -119,11 +131,6 @@ public final class StatsLogEventWrapper implements Parcelable { mValues.add(val ? 1 : 0); } - /** - * Writes the stored fields to a byte array. Will first write a new-line character to denote - * END_LIST before writing contents to byte array. - */ - public void writeToParcel(Parcel out, int flags) { if (DEBUG) { Slog.d(TAG, @@ -133,6 +140,34 @@ public final class StatsLogEventWrapper implements Parcelable { out.writeInt(mTag); out.writeLong(mElapsedTimeNs); out.writeLong(mWallClockTimeNs); + if (mWorkSource != null) { + ArrayList<android.os.WorkSource.WorkChain> workChains = mWorkSource.getWorkChains(); + // number of chains + out.writeInt(workChains.size()); + for (int i = 0; i < workChains.size(); i++) { + android.os.WorkSource.WorkChain wc = workChains.get(i); + if (wc.getSize() == 0) { + Slog.w(TAG, "Empty work chain."); + out.writeInt(0); + continue; + } + if (wc.getUids().length != wc.getTags().length + || wc.getUids().length != wc.getSize()) { + Slog.w(TAG, "Malformated work chain."); + out.writeInt(0); + continue; + } + // number of nodes + out.writeInt(wc.getSize()); + for (int j = 0; j < wc.getSize(); j++) { + out.writeInt(wc.getUids()[j]); + out.writeString(wc.getTags()[j] == null ? "" : wc.getTags()[j]); + } + } + } else { + // no chains + out.writeInt(0); + } out.writeInt(mTypes.size()); for (int i = 0; i < mTypes.size(); i++) { out.writeInt(mTypes.get(i)); diff --git a/libs/services/include/android/os/StatsLogEventWrapper.h b/libs/services/include/android/os/StatsLogEventWrapper.h index f60c338bf9c4..8de2ab49f42b 100644 --- a/libs/services/include/android/os/StatsLogEventWrapper.h +++ b/libs/services/include/android/os/StatsLogEventWrapper.h @@ -82,6 +82,11 @@ struct StatsLogValue { STATS_LOG_VALUE_TYPE type; }; +struct WorkChain { + std::vector<int32_t> uids; + std::vector<std::string> tags; +}; + // Represents a parcelable object. Only used to send data from Android OS to statsd. class StatsLogEventWrapper : public android::Parcelable { public: @@ -99,7 +104,9 @@ class StatsLogEventWrapper : public android::Parcelable { int64_t getWallClockTimeNs() const { return mWallClockTimeNs; } - std::vector<StatsLogValue> getElements() const { return mElements; } + const std::vector<StatsLogValue>& getElements() const { return mElements; } + + const std::vector<WorkChain>& getWorkChains() const { return mWorkChains; } private: int mTagId; @@ -109,6 +116,8 @@ class StatsLogEventWrapper : public android::Parcelable { int64_t mWallClockTimeNs; std::vector<StatsLogValue> mElements; + + std::vector<WorkChain> mWorkChains; }; } // Namespace os } // Namespace android diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp index 04c4629b5432..f6dfdef16e19 100644 --- a/libs/services/src/os/StatsLogEventWrapper.cpp +++ b/libs/services/src/os/StatsLogEventWrapper.cpp @@ -58,6 +58,31 @@ status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) { ALOGE("statsd could not read wall clock time from parcel"); return res; } + int numWorkChain = 0; + if ((res = in->readInt32(&numWorkChain)) != OK) { + ALOGE("statsd could not read number of work chains from parcel"); + return res; + } + if (numWorkChain > 0) { + for (int i = 0; i < numWorkChain; i++) { + int numNodes = 0; + if ((res = in->readInt32(&numNodes)) != OK) { + ALOGE( + "statsd could not read number of nodes in work chain from parcel"); + return res; + } + if (numNodes == 0) { + ALOGE("empty work chain"); + return BAD_VALUE; + } + WorkChain wc; + for (int j = 0; j < numNodes; j++) { + wc.uids.push_back(in->readInt32()); + wc.tags.push_back(std::string(String8(in->readString16()).string())); + } + mWorkChains.push_back(wc); + } + } int dataSize = 0; if ((res = in->readInt32(&dataSize)) != OK) { ALOGE("statsd could not read data size from parcel"); |