summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/src/external/StatsCompanionServicePuller.cpp2
-rw-r--r--cmds/statsd/src/external/StatsPuller.cpp7
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp99
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.h3
-rw-r--r--cmds/statsd/src/external/puller_util.cpp196
-rw-r--r--cmds/statsd/src/external/puller_util.h4
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp30
-rw-r--r--cmds/statsd/src/logd/LogEvent.h11
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp10
-rw-r--r--cmds/statsd/tests/LogEvent_test.cpp161
-rw-r--r--cmds/statsd/tests/external/puller_util_test.cpp12
-rw-r--r--core/java/android/os/StatsLogEventWrapper.java45
-rw-r--r--libs/services/include/android/os/StatsLogEventWrapper.h11
-rw-r--r--libs/services/src/os/StatsLogEventWrapper.cpp25
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");