xref: /aosp_15_r20/frameworks/av/media/psh_utils/PowerStatsProvider.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "PowerStatsProvider.h"
18 #include <android/hardware/power/stats/IPowerStats.h>
19 #include <android-base/logging.h>
20 #include <mediautils/ServiceSingleton.h>
21 #include <unordered_map>
22 
23 using ::android::hardware::power::stats::IPowerStats;
24 
25 namespace android::media::psh_utils {
26 
getPowerStatsService()27 static auto getPowerStatsService() {
28     return mediautils::getService<IPowerStats>();
29 }
30 
fill(PowerStats * stat) const31 status_t RailEnergyDataProvider::fill(PowerStats *stat) const {
32     if (stat == nullptr) return BAD_VALUE;
33     auto powerStatsService = getPowerStatsService();
34     if (powerStatsService == nullptr) {
35         return NO_INIT;
36     }
37 
38     std::unordered_map<int32_t, ::android::hardware::power::stats::Channel> channelMap;
39     {
40         std::vector<::android::hardware::power::stats::Channel> channels;
41         if (!powerStatsService->getEnergyMeterInfo(&channels).isOk()) {
42             LOG(ERROR) << "unable to get energy meter info";
43             return INVALID_OPERATION;
44         }
45         for (auto& channel : channels) {
46           channelMap.emplace(channel.id, std::move(channel));
47         }
48     }
49 
50     std::vector<::android::hardware::power::stats::EnergyMeasurement> measurements;
51     if (!powerStatsService->readEnergyMeter({}, &measurements).isOk()) {
52         LOG(ERROR) << "unable to get energy measurements";
53         return INVALID_OPERATION;
54     }
55 
56     for (const auto& measurement : measurements) {
57         stat->rail_energy.emplace_back(
58             channelMap.at(measurement.id).subsystem,
59             channelMap.at(measurement.id).name,
60             measurement.energyUWs);
61     }
62 
63     // Sort entries first by subsystem_name, then by rail_name.
64     // Sorting is needed to make interval processing efficient.
65     std::sort(stat->rail_energy.begin(), stat->rail_energy.end(),
66               [](const auto& a, const auto& b) {
67                   if (a.subsystem_name != b.subsystem_name) {
68                       return a.subsystem_name < b.subsystem_name;
69                   }
70                   return a.rail_name < b.rail_name;
71               });
72 
73     return NO_ERROR;
74 }
75 
fill(PowerStats * stat) const76 status_t PowerEntityResidencyDataProvider::fill(PowerStats* stat) const {
77     if (stat == nullptr) return BAD_VALUE;
78     auto powerStatsService = getPowerStatsService();
79     if (powerStatsService == nullptr) {
80         return NO_INIT;
81     }
82 
83     // these are based on entityId
84     std::unordered_map<int32_t, std::string> entityNames;
85     std::unordered_map<int32_t, std::unordered_map<int32_t, std::string>> stateNames;
86     std::vector<int32_t> powerEntityIds; // ids to use
87 
88     {
89         std::vector<::android::hardware::power::stats::PowerEntity> entities;
90         if (!powerStatsService->getPowerEntityInfo(&entities).isOk()) {
91             LOG(ERROR) << __func__ << ": unable to get entity info";
92             return INVALID_OPERATION;
93         }
94 
95         std::vector<std::string> powerEntityNames;
96         for (const auto& entity : entities) {
97             std::unordered_map<int32_t, std::string> states;
98             for (const auto& state : entity.states) {
99                 states.emplace(state.id, state.name);
100             }
101 
102             if (std::find(powerEntityNames.begin(), powerEntityNames.end(), entity.name) !=
103                 powerEntityNames.end()) {
104                 powerEntityIds.emplace_back(entity.id);
105             }
106             entityNames.emplace(entity.id, std::move(entity.name));
107             stateNames.emplace(entity.id, std::move(states));
108         }
109     }
110 
111     std::vector<::android::hardware::power::stats::StateResidencyResult> results;
112     if (!powerStatsService->getStateResidency(powerEntityIds, &results).isOk()) {
113         LOG(ERROR) << __func__ << ": Unable to get state residency";
114         return INVALID_OPERATION;
115     }
116 
117     for (const auto& result : results) {
118         for (const auto& curStateResidency : result.stateResidencyData) {
119           stat->power_entity_state_residency.emplace_back(
120               entityNames.at(result.id),
121               stateNames.at(result.id).at(curStateResidency.id),
122               static_cast<uint64_t>(curStateResidency.totalTimeInStateMs),
123               static_cast<uint64_t>(curStateResidency.totalStateEntryCount));
124         }
125     }
126 
127     // Sort entries first by entity_name, then by state_name.
128     // Sorting is needed to make interval processing efficient.
129     std::sort(stat->power_entity_state_residency.begin(),
130               stat->power_entity_state_residency.end(),
131               [](const auto& a, const auto& b) {
132                   if (a.entity_name != b.entity_name) {
133                       return a.entity_name < b.entity_name;
134                   }
135                   return a.state_name < b.state_name;
136               });
137     return NO_ERROR;
138 }
139 
140 } // namespace android::media::psh_utils
141