blob: 71a39e130e1f4b929b9d35d127e10b0007d5274d [file] [log] [blame]
Andy Hung125ff522024-06-28 09:51:30 -07001/*
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-base/logging.h>
19#include <android/binder_manager.h>
20#include <unordered_map>
21#include <aidl/android/hardware/power/stats/IPowerStats.h>
22
23using ::aidl::android::hardware::power::stats::IPowerStats;
24
25namespace android::media::psh_utils {
26
27static auto getPowerStatsService() {
28 [[clang::no_destroy]] static constinit std::mutex m;
29 [[clang::no_destroy]] static constinit
30 std::shared_ptr<IPowerStats> powerStats;
31
32 std::lock_guard l(m);
33 if (powerStats) {
34 return powerStats;
35 }
36 const auto serviceName =
37 std::string(IPowerStats::descriptor)
38 .append("/default");
39 powerStats = IPowerStats::fromBinder(
40 ::ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
41 return powerStats;
42}
43
44int RailEnergyDataProvider::fill(PowerStats *stat) const {
45 auto powerStatsService = getPowerStatsService();
46 if (powerStatsService == nullptr) {
47 LOG(ERROR) << "unable to get power.stats AIDL service";
48 return 1;
49 }
50
51 std::unordered_map<int32_t, ::aidl::android::hardware::power::stats::Channel> channelMap;
52 {
53 std::vector<::aidl::android::hardware::power::stats::Channel> channels;
54 if (!powerStatsService->getEnergyMeterInfo(&channels).isOk()) {
55 LOG(ERROR) << "unable to get energy meter info";
56 return 1;
57 }
58 for (auto& channel : channels) {
59 channelMap.emplace(channel.id, std::move(channel));
60 }
61 }
62
63 std::vector<::aidl::android::hardware::power::stats::EnergyMeasurement> measurements;
64 if (!powerStatsService->readEnergyMeter({}, &measurements).isOk()) {
65 LOG(ERROR) << "unable to get energy measurements";
66 return 1;
67 }
68
69 for (const auto& measurement : measurements) {
70 stat->rail_energy.emplace_back(
71 channelMap.at(measurement.id).subsystem,
72 channelMap.at(measurement.id).name,
73 measurement.energyUWs);
74 }
75
76 // Sort entries first by subsystem_name, then by rail_name.
77 // Sorting is needed to make interval processing efficient.
78 std::sort(stat->rail_energy.begin(), stat->rail_energy.end(),
79 [](const auto& a, const auto& b) {
80 if (a.subsystem_name != b.subsystem_name) {
81 return a.subsystem_name < b.subsystem_name;
82 }
83 return a.rail_name < b.rail_name;
84 });
85
86 return 0;
87}
88
89int PowerEntityResidencyDataProvider::fill(PowerStats* stat) const {
90 auto powerStatsService = getPowerStatsService();
91 if (powerStatsService == nullptr) {
92 LOG(ERROR) << "unable to get power.stats AIDL service";
93 return 1;
94 }
95
96 // these are based on entityId
97 std::unordered_map<int32_t, std::string> entityNames;
98 std::unordered_map<int32_t, std::unordered_map<int32_t, std::string>> stateNames;
99 std::vector<int32_t> powerEntityIds; // ids to use
100
101 {
102 std::vector<::aidl::android::hardware::power::stats::PowerEntity> entities;
103 if (!powerStatsService->getPowerEntityInfo(&entities).isOk()) {
104 LOG(ERROR) << __func__ << ": unable to get entity info";
105 return 1;
106 }
107
108 std::vector<std::string> powerEntityNames;
109 for (const auto& entity : entities) {
110 std::unordered_map<int32_t, std::string> states;
111 for (const auto& state : entity.states) {
112 states.emplace(state.id, state.name);
113 }
114
115 if (std::find(powerEntityNames.begin(), powerEntityNames.end(), entity.name) !=
116 powerEntityNames.end()) {
117 powerEntityIds.emplace_back(entity.id);
118 }
119 entityNames.emplace(entity.id, std::move(entity.name));
120 stateNames.emplace(entity.id, std::move(states));
121 }
122 }
123
124 std::vector<::aidl::android::hardware::power::stats::StateResidencyResult> results;
125 if (!powerStatsService->getStateResidency(powerEntityIds, &results).isOk()) {
126 LOG(ERROR) << __func__ << ": Unable to get state residency";
127 return 1;
128 }
129
130 for (const auto& result : results) {
131 for (const auto& curStateResidency : result.stateResidencyData) {
132 stat->power_entity_state_residency.emplace_back(
133 entityNames.at(result.id),
134 stateNames.at(result.id).at(curStateResidency.id),
135 static_cast<uint64_t>(curStateResidency.totalTimeInStateMs),
136 static_cast<uint64_t>(curStateResidency.totalStateEntryCount));
137 }
138 }
139
140 // Sort entries first by entity_name, then by state_name.
141 // Sorting is needed to make interval processing efficient.
142 std::sort(stat->power_entity_state_residency.begin(),
143 stat->power_entity_state_residency.end(),
144 [](const auto& a, const auto& b) {
145 if (a.entity_name != b.entity_name) {
146 return a.entity_name < b.entity_name;
147 }
148 return a.state_name < b.state_name;
149 });
150 return 0;
151}
152
153} // namespace android::media::psh_utils