Media: Update PowerStats with more test cases.

Flag: com.android.media.audioserver.power_stats
Test: atest powerstats_collector_tests
Bug: 350114693
Change-Id: I9e89e6b2598bca30eabc5e9c30592c4eb6dfeed3
diff --git a/media/psh_utils/PowerStatsProvider.cpp b/media/psh_utils/PowerStatsProvider.cpp
index 71a39e1..94df933 100644
--- a/media/psh_utils/PowerStatsProvider.cpp
+++ b/media/psh_utils/PowerStatsProvider.cpp
@@ -41,11 +41,12 @@
     return powerStats;
 }
 
-int RailEnergyDataProvider::fill(PowerStats *stat) const {
+status_t RailEnergyDataProvider::fill(PowerStats *stat) const {
+    if (stat == nullptr) return BAD_VALUE;
     auto powerStatsService = getPowerStatsService();
     if (powerStatsService == nullptr) {
         LOG(ERROR) << "unable to get power.stats AIDL service";
-        return 1;
+        return NO_INIT;
     }
 
     std::unordered_map<int32_t, ::aidl::android::hardware::power::stats::Channel> channelMap;
@@ -53,7 +54,7 @@
         std::vector<::aidl::android::hardware::power::stats::Channel> channels;
         if (!powerStatsService->getEnergyMeterInfo(&channels).isOk()) {
             LOG(ERROR) << "unable to get energy meter info";
-            return 1;
+            return INVALID_OPERATION;
         }
         for (auto& channel : channels) {
           channelMap.emplace(channel.id, std::move(channel));
@@ -63,7 +64,7 @@
     std::vector<::aidl::android::hardware::power::stats::EnergyMeasurement> measurements;
     if (!powerStatsService->readEnergyMeter({}, &measurements).isOk()) {
         LOG(ERROR) << "unable to get energy measurements";
-        return 1;
+        return INVALID_OPERATION;
     }
 
     for (const auto& measurement : measurements) {
@@ -83,14 +84,15 @@
                   return a.rail_name < b.rail_name;
               });
 
-    return 0;
+    return NO_ERROR;
 }
 
-int PowerEntityResidencyDataProvider::fill(PowerStats* stat) const {
+status_t PowerEntityResidencyDataProvider::fill(PowerStats* stat) const {
+    if (stat == nullptr) return BAD_VALUE;
     auto powerStatsService = getPowerStatsService();
     if (powerStatsService == nullptr) {
         LOG(ERROR) << "unable to get power.stats AIDL service";
-        return 1;
+        return NO_INIT;
     }
 
     // these are based on entityId
@@ -102,7 +104,7 @@
         std::vector<::aidl::android::hardware::power::stats::PowerEntity> entities;
         if (!powerStatsService->getPowerEntityInfo(&entities).isOk()) {
             LOG(ERROR) << __func__ << ": unable to get entity info";
-            return 1;
+            return INVALID_OPERATION;
         }
 
         std::vector<std::string> powerEntityNames;
@@ -124,7 +126,7 @@
     std::vector<::aidl::android::hardware::power::stats::StateResidencyResult> results;
     if (!powerStatsService->getStateResidency(powerEntityIds, &results).isOk()) {
         LOG(ERROR) << __func__ << ": Unable to get state residency";
-        return 1;
+        return INVALID_OPERATION;
     }
 
     for (const auto& result : results) {
@@ -147,7 +149,7 @@
                   }
                   return a.state_name < b.state_name;
               });
-    return 0;
+    return NO_ERROR;
 }
 
 } // namespace android::media::psh_utils
diff --git a/media/psh_utils/PowerStatsProvider.h b/media/psh_utils/PowerStatsProvider.h
index 367e684..2be1872 100644
--- a/media/psh_utils/PowerStatsProvider.h
+++ b/media/psh_utils/PowerStatsProvider.h
@@ -23,12 +23,12 @@
 
 class RailEnergyDataProvider : public PowerStatsProvider {
 public:
-    int fill(PowerStats* stat) const override;
+    status_t fill(PowerStats* stat) const override;
 };
 
 class PowerEntityResidencyDataProvider : public PowerStatsProvider {
 public:
-    int fill(PowerStats* stat) const override;
+    status_t fill(PowerStats* stat) const override;
 };
 
 } // namespace android::media::psh_utils
diff --git a/media/psh_utils/include/psh_utils/PowerStatsCollector.h b/media/psh_utils/include/psh_utils/PowerStatsCollector.h
index a3ff53c..437b93d 100644
--- a/media/psh_utils/include/psh_utils/PowerStatsCollector.h
+++ b/media/psh_utils/include/psh_utils/PowerStatsCollector.h
@@ -18,6 +18,7 @@
 
 #include "PowerStats.h"
 #include <memory>
+#include <utils/Errors.h> // status_t
 
 namespace android::media::psh_utils {
 
@@ -25,7 +26,7 @@
 class PowerStatsProvider {
 public:
     virtual ~PowerStatsProvider() = default;
-    virtual int fill(PowerStats* stat) const = 0;
+    virtual status_t fill(PowerStats* stat) const = 0;
 };
 
 class PowerStatsCollector {
diff --git a/media/psh_utils/tests/powerstats_collector_tests.cpp b/media/psh_utils/tests/powerstats_collector_tests.cpp
index 6c83978..b007be3 100644
--- a/media/psh_utils/tests/powerstats_collector_tests.cpp
+++ b/media/psh_utils/tests/powerstats_collector_tests.cpp
@@ -18,8 +18,16 @@
 #include <gtest/gtest.h>
 #include <utils/Log.h>
 
+using namespace android::media::psh_utils;
+
+template <typename T>
+void inRange(const T& a, const T& b, const T& c) {
+    ASSERT_GE(a, std::min(b, c));
+    ASSERT_LE(a, std::max(b, c));
+}
+
 TEST(powerstat_collector_tests, basic) {
-    const auto& psc = android::media::psh_utils::PowerStatsCollector::getCollector();
+    const auto& psc = PowerStatsCollector::getCollector();
 
     // This test is used for debugging the string through logcat, we validate a non-empty string.
     auto powerStats = psc.getStats();
@@ -27,19 +35,108 @@
     EXPECT_FALSE(powerStats->toString().empty());
 }
 
-TEST(powerstat_collector_tests, arithmetic) {
-    android::media::psh_utils::PowerStats ps1, ps2;
-    ps1.metadata.duration_ms = 5;
-    ps2.metadata.duration_ms = 10;
+TEST(powerstat_collector_tests, metadata) {
+    PowerStats ps1, ps2;
 
-    // duration follows add / subtract rules.
-    android::media::psh_utils::PowerStats ps3 = ps1 + ps2;
-    android::media::psh_utils::PowerStats ps4 = ps2 + ps1;
+    constexpr uint64_t kDurationMs1 = 5;
+    constexpr uint64_t kDurationMs2 = 10;
+    ps1.metadata.duration_ms = kDurationMs1;
+    ps2.metadata.duration_ms = kDurationMs2;
+
+    constexpr uint64_t kDurationMonotonicMs1 = 3;
+    constexpr uint64_t kDurationMonotonicMs2 = 9;
+    ps1.metadata.duration_monotonic_ms = kDurationMonotonicMs1;
+    ps2.metadata.duration_monotonic_ms = kDurationMonotonicMs2;
+
+    constexpr uint64_t kStartTimeSinceBootMs1 = 1616;
+    constexpr uint64_t kStartTimeEpochMs1 = 1121;
+    constexpr uint64_t kStartTimeMonotonicMs1 = 1525;
+    constexpr uint64_t kStartTimeSinceBootMs2 = 2616;
+    constexpr uint64_t kStartTimeEpochMs2 = 2121;
+    constexpr uint64_t kStartTimeMonotonicMs2 = 2525;
+
+    ps1.metadata.start_time_since_boot_ms = kStartTimeSinceBootMs1;
+    ps1.metadata.start_time_epoch_ms = kStartTimeEpochMs1;
+    ps1.metadata.start_time_monotonic_ms = kStartTimeMonotonicMs1;
+    ps2.metadata.start_time_since_boot_ms = kStartTimeSinceBootMs2;
+    ps2.metadata.start_time_epoch_ms = kStartTimeEpochMs2;
+    ps2.metadata.start_time_monotonic_ms = kStartTimeMonotonicMs2;
+
+    PowerStats ps3 = ps1 + ps2;
+    PowerStats ps4 = ps2 + ps1;
     EXPECT_EQ(ps3, ps4);
-    EXPECT_EQ(15, ps3.metadata.duration_ms);
+    EXPECT_EQ(kDurationMs1 + kDurationMs2,
+            ps3.metadata.duration_ms);
+    EXPECT_EQ(kDurationMonotonicMs1 + kDurationMonotonicMs2,
+            ps3.metadata.duration_monotonic_ms);
 
-    android::media::psh_utils::PowerStats ps5 = ps2 - ps1;
-    android::media::psh_utils::PowerStats ps6 = ps5 + ps1;
-    EXPECT_EQ(ps6, ps2);
-    EXPECT_EQ(5, ps5.metadata.duration_ms);
+    EXPECT_NO_FATAL_FAILURE(inRange(ps3.metadata.start_time_since_boot_ms,
+            kStartTimeSinceBootMs1, kStartTimeSinceBootMs2));
+    EXPECT_NO_FATAL_FAILURE(inRange(ps3.metadata.start_time_epoch_ms,
+            kStartTimeEpochMs1, kStartTimeEpochMs2));
+    EXPECT_NO_FATAL_FAILURE(inRange(ps3.metadata.start_time_monotonic_ms,
+            kStartTimeMonotonicMs1, kStartTimeMonotonicMs2));
+
+    PowerStats ps5 = ps2 - ps1;
+    EXPECT_EQ(kDurationMs2 - kDurationMs1,
+            ps5.metadata.duration_ms);
+    EXPECT_EQ(kDurationMonotonicMs2 - kDurationMonotonicMs1,
+            ps5.metadata.duration_monotonic_ms);
+
+    EXPECT_NO_FATAL_FAILURE(inRange(ps5.metadata.start_time_since_boot_ms,
+            kStartTimeSinceBootMs1, kStartTimeSinceBootMs2));
+    EXPECT_NO_FATAL_FAILURE(inRange(ps5.metadata.start_time_epoch_ms,
+            kStartTimeEpochMs1, kStartTimeEpochMs2));
+    EXPECT_NO_FATAL_FAILURE(inRange(ps5.metadata.start_time_monotonic_ms,
+         kStartTimeMonotonicMs1, kStartTimeMonotonicMs2));
+}
+
+TEST(powerstat_collector_tests, state_residency) {
+    PowerStats ps1, ps2;
+
+    constexpr uint64_t kTimeMs1 = 5;
+    constexpr uint64_t kTimeMs2 = 10;
+    constexpr uint64_t kEntryCount1 = 15;
+    constexpr uint64_t kEntryCount2 = 18;
+
+    ps1.power_entity_state_residency.emplace_back(
+            PowerStats::StateResidency{"", "", kTimeMs1, kEntryCount1});
+    ps2.power_entity_state_residency.emplace_back(
+            PowerStats::StateResidency{"", "", kTimeMs2, kEntryCount2});
+
+    PowerStats ps3 = ps1 + ps2;
+    PowerStats ps4 = ps2 + ps1;
+    EXPECT_EQ(ps3, ps4);
+    EXPECT_EQ(kTimeMs1 + kTimeMs2,
+            ps3.power_entity_state_residency[0].time_ms);
+    EXPECT_EQ(kEntryCount1 + kEntryCount2,
+            ps3.power_entity_state_residency[0].entry_count);
+
+    PowerStats ps5 = ps2 - ps1;
+    EXPECT_EQ(kTimeMs2 - kTimeMs1,
+            ps5.power_entity_state_residency[0].time_ms);
+    EXPECT_EQ(kEntryCount2 - kEntryCount1,
+            ps5.power_entity_state_residency[0].entry_count);
+}
+
+TEST(powerstat_collector_tests, rail_energy) {
+    PowerStats ps1, ps2;
+
+    constexpr uint64_t kEnergyUws1 = 5;
+    constexpr uint64_t kEnergyUws2 = 10;
+
+    ps1.rail_energy.emplace_back(
+            PowerStats::RailEnergy{"", "", kEnergyUws1});
+    ps2.rail_energy.emplace_back(
+            PowerStats::RailEnergy{"", "", kEnergyUws2});
+
+    PowerStats ps3 = ps1 + ps2;
+    PowerStats ps4 = ps2 + ps1;
+    EXPECT_EQ(ps3, ps4);
+    EXPECT_EQ(kEnergyUws1 + kEnergyUws2,
+            ps3.rail_energy[0].energy_uws);
+
+    PowerStats ps5 = ps2 - ps1;
+    EXPECT_EQ(kEnergyUws2 - kEnergyUws1,
+            ps5.rail_energy[0].energy_uws);
 }