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