blob: 112c3236b6328ca17e0d81cb3e98d7146800222c [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"
Andy Hung125ff522024-06-28 09:51:30 -070018#include <aidl/android/hardware/power/stats/IPowerStats.h>
Andy Hung11745072024-08-15 14:19:16 -070019#include <android-base/logging.h>
20#include <psh_utils/ServiceSingleton.h>
21#include <unordered_map>
Andy Hung125ff522024-06-28 09:51:30 -070022
23using ::aidl::android::hardware::power::stats::IPowerStats;
24
25namespace android::media::psh_utils {
26
27static auto getPowerStatsService() {
Andy Hung11745072024-08-15 14:19:16 -070028 return getServiceSingleton<IPowerStats>();
Andy Hung125ff522024-06-28 09:51:30 -070029}
30
Andy Hung1ada5f92024-08-05 15:07:48 -070031status_t RailEnergyDataProvider::fill(PowerStats *stat) const {
32 if (stat == nullptr) return BAD_VALUE;
Andy Hung125ff522024-06-28 09:51:30 -070033 auto powerStatsService = getPowerStatsService();
34 if (powerStatsService == nullptr) {
Andy Hung1ada5f92024-08-05 15:07:48 -070035 return NO_INIT;
Andy Hung125ff522024-06-28 09:51:30 -070036 }
37
38 std::unordered_map<int32_t, ::aidl::android::hardware::power::stats::Channel> channelMap;
39 {
40 std::vector<::aidl::android::hardware::power::stats::Channel> channels;
41 if (!powerStatsService->getEnergyMeterInfo(&channels).isOk()) {
42 LOG(ERROR) << "unable to get energy meter info";
Andy Hung1ada5f92024-08-05 15:07:48 -070043 return INVALID_OPERATION;
Andy Hung125ff522024-06-28 09:51:30 -070044 }
45 for (auto& channel : channels) {
46 channelMap.emplace(channel.id, std::move(channel));
47 }
48 }
49
50 std::vector<::aidl::android::hardware::power::stats::EnergyMeasurement> measurements;
51 if (!powerStatsService->readEnergyMeter({}, &measurements).isOk()) {
52 LOG(ERROR) << "unable to get energy measurements";
Andy Hung1ada5f92024-08-05 15:07:48 -070053 return INVALID_OPERATION;
Andy Hung125ff522024-06-28 09:51:30 -070054 }
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
Andy Hung1ada5f92024-08-05 15:07:48 -070073 return NO_ERROR;
Andy Hung125ff522024-06-28 09:51:30 -070074}
75
Andy Hung1ada5f92024-08-05 15:07:48 -070076status_t PowerEntityResidencyDataProvider::fill(PowerStats* stat) const {
77 if (stat == nullptr) return BAD_VALUE;
Andy Hung125ff522024-06-28 09:51:30 -070078 auto powerStatsService = getPowerStatsService();
79 if (powerStatsService == nullptr) {
Andy Hung1ada5f92024-08-05 15:07:48 -070080 return NO_INIT;
Andy Hung125ff522024-06-28 09:51:30 -070081 }
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<::aidl::android::hardware::power::stats::PowerEntity> entities;
90 if (!powerStatsService->getPowerEntityInfo(&entities).isOk()) {
91 LOG(ERROR) << __func__ << ": unable to get entity info";
Andy Hung1ada5f92024-08-05 15:07:48 -070092 return INVALID_OPERATION;
Andy Hung125ff522024-06-28 09:51:30 -070093 }
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<::aidl::android::hardware::power::stats::StateResidencyResult> results;
112 if (!powerStatsService->getStateResidency(powerEntityIds, &results).isOk()) {
113 LOG(ERROR) << __func__ << ": Unable to get state residency";
Andy Hung1ada5f92024-08-05 15:07:48 -0700114 return INVALID_OPERATION;
Andy Hung125ff522024-06-28 09:51:30 -0700115 }
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 });
Andy Hung1ada5f92024-08-05 15:07:48 -0700137 return NO_ERROR;
Andy Hung125ff522024-06-28 09:51:30 -0700138}
139
140} // namespace android::media::psh_utils