Statsd pulls on-device power measurements
Pulls power rail measurements into statslog.
Bug: 119034725
Test: cts-tradefed run cts-dev -m CtsStatsdHostTestCases -t android.cts.statsd.atom.HostAtomTests
(after enabling OPTINAL_TESTS_ENABLED)
Change-Id: If083ae50160d508a9d180f748f9515557d35d8a1
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 6547b3a..7f38372 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -72,6 +72,7 @@
"src/external/StatsPuller.cpp",
"src/external/StatsCompanionServicePuller.cpp",
"src/external/SubsystemSleepStatePuller.cpp",
+ "src/external/PowerStatsPuller.cpp",
"src/external/ResourceHealthManagerPuller.cpp",
"src/external/ResourceThermalManagerPuller.cpp",
"src/external/StatsPullerManager.cpp",
@@ -134,6 +135,7 @@
"android.hardware.health@2.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
+ "android.hardware.power.stats@1.0",
"android.hardware.thermal@1.0",
"libpackagelistparser",
"libsysutils",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 5620184..21e7203 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -190,6 +190,7 @@
ProcessCpuTime process_cpu_time = 10035;
NativeProcessMemoryState native_process_memory_state = 10036;
CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
+ OnDevicePowerMeasurement on_device_power_measurement = 10038;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -2262,6 +2263,27 @@
}
/**
+ * Pulls on-device power measurement information.
+ * Data defined by hardware/interfaces/power/stats/1.0/types.hal.
+ * Pulled from:
+ * frameworks/base/cmds/statsd/src/external/PowerStatsPuller.cpp
+ */
+message OnDevicePowerMeasurement {
+ // Name of the subsystem (to which the rail belongs).
+ optional string subsystem_name = 1;
+
+ // Rail name. The rail lies within the subsystem.
+ optional string rail_name = 2;
+
+ // Time (in ms since boot) at which the rail energy value was measured.
+ // This may differ slightly from the time that statsd logs this information.
+ optional uint64 measurement_timestamp_millis = 3;
+
+ // Accumulated energy used via the rail since device boot in uWs.
+ optional uint64 energy_microwatt_secs = 4;
+}
+
+/**
* Pulls Cpu time per frequency.
* Pulls the time the cpu spend on the frequency index. Frequency index
* starts from highest to lowest. The value should be monotonically
diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp
new file mode 100644
index 0000000..71e5fa0
--- /dev/null
+++ b/cmds/statsd/src/external/PowerStatsPuller.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+
+#include <vector>
+
+#include "PowerStatsPuller.h"
+#include "stats_log_util.h"
+
+using android::hardware::hidl_vec;
+using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::EnergyData;
+using android::hardware::power::stats::V1_0::RailInfo;
+using android::hardware::power::stats::V1_0::Status;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
+std::mutex gPowerStatsHalMutex;
+bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
+std::vector<RailInfo> gRailInfo;
+
+bool getPowerStatsHal() {
+ if (gPowerStatsHal == nullptr && gPowerStatsExist) {
+ gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
+ if (gPowerStatsHal == nullptr) {
+ ALOGW("Couldn't load power.stats HAL service");
+ gPowerStatsExist = false;
+ }
+ }
+ return gPowerStatsHal != nullptr;
+}
+
+PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWER_MEASUREMENT) {
+}
+
+bool PowerStatsPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ if (!getPowerStatsHal()) {
+ ALOGE("power.stats Hal not loaded");
+ return false;
+ }
+
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+
+ data->clear();
+
+ // Pull getRailInfo if necessary
+ if (gRailInfo.empty()) {
+ bool resultSuccess = true;
+ Return<void> ret = gPowerStatsHal->getRailInfo(
+ [&resultSuccess](const hidl_vec<RailInfo> &list, Status status) {
+ resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
+ if (status != Status::SUCCESS) return;
+
+ gRailInfo.reserve(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ gRailInfo.push_back(list[i]);
+ }
+ });
+ if (!resultSuccess || !ret.isOk()) {
+ ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
+ gPowerStatsHal = nullptr;
+ return false;
+ }
+ // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
+ if (gRailInfo.empty()) {
+ ALOGE("power.stats has no rail information");
+ gPowerStatsExist = false; // No rail info, so never try again.
+ return false;
+ }
+ }
+
+ // Pull getEnergyData and write the data out
+ const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
+ bool resultSuccess = true;
+ Return<void> ret = gPowerStatsHal->getEnergyData(desiredRailIndices,
+ [&data, wallClockTimestampNs, elapsedTimestampNs, &resultSuccess]
+ (hidl_vec<EnergyData> energyDataList, Status status) {
+ resultSuccess = (status == Status::SUCCESS);
+ if (!resultSuccess) return;
+
+ for (size_t i = 0; i < energyDataList.size(); i++) {
+ const EnergyData& energyData = energyDataList[i];
+
+ if (energyData.index >= gRailInfo.size()) {
+ ALOGE("power.stats getEnergyData() returned an invalid rail index %u.",
+ energyData.index);
+ resultSuccess = false;
+ return;
+ }
+ const RailInfo& rail = gRailInfo[energyData.index];
+
+ auto ptr = make_shared<LogEvent>(android::util::ON_DEVICE_POWER_MEASUREMENT,
+ wallClockTimestampNs, elapsedTimestampNs);
+ ptr->write(rail.subsysName);
+ ptr->write(rail.railName);
+ ptr->write(energyData.timestamp);
+ ptr->write(energyData.energy);
+ ptr->init();
+ data->push_back(ptr);
+
+ VLOG("power.stat: %s.%s: %llu, %llu",
+ rail.subsysName.c_str(),
+ rail.railName.c_str(),
+ (unsigned long long)energyData.timestamp,
+ (unsigned long long)energyData.energy);
+ }
+ });
+ if (!resultSuccess || !ret.isOk()) {
+ ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
+ gPowerStatsHal = nullptr;
+ return false;
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/PowerStatsPuller.h b/cmds/statsd/src/external/PowerStatsPuller.h
new file mode 100644
index 0000000..dd5ff8f
--- /dev/null
+++ b/cmds/statsd/src/external/PowerStatsPuller.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Reads hal for power.stats
+ */
+class PowerStatsPuller : public StatsPuller {
+public:
+ PowerStatsPuller();
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 9633980..8378ae1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -26,6 +26,7 @@
#include "../logd/LogEvent.h"
#include "../stats_log_util.h"
#include "../statscompanion_util.h"
+#include "PowerStatsPuller.h"
#include "ResourceHealthManagerPuller.h"
#include "ResourceThermalManagerPuller.h"
#include "StatsCompanionServicePuller.h"
@@ -86,6 +87,9 @@
// subsystem_sleep_state
{android::util::SUBSYSTEM_SLEEP_STATE,
{{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}},
+ // on_device_power_measurement
+ {android::util::ON_DEVICE_POWER_MEASUREMENT,
+ {{}, {}, 1 * NS_PER_SEC, new PowerStatsPuller()}},
// cpu_time_per_freq
{android::util::CPU_TIME_PER_FREQ,
{{3},