1 /*
2  * Copyright (C) 2020 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 "PowerStats.h"
18 
19 #include <android-base/logging.h>
20 
21 #include <numeric>
22 
23 namespace aidl {
24 namespace android {
25 namespace hardware {
26 namespace power {
27 namespace stats {
28 
addStateResidencyDataProvider(std::unique_ptr<IStateResidencyDataProvider> p)29 void PowerStats::addStateResidencyDataProvider(std::unique_ptr<IStateResidencyDataProvider> p) {
30     if (!p) {
31         return;
32     }
33 
34     int32_t id = mPowerEntityInfos.size();
35     auto info = p->getInfo();
36 
37     size_t index = mStateResidencyDataProviders.size();
38     mStateResidencyDataProviders.emplace_back(std::move(p));
39 
40     for (const auto& [entityName, states] : info) {
41         PowerEntity i = {
42                 .id = id++,
43                 .name = entityName,
44                 .states = states,
45         };
46         mPowerEntityInfos.emplace_back(i);
47         mStateResidencyDataProviderIndex.emplace_back(index);
48     }
49 }
50 
addEnergyConsumer(std::unique_ptr<IEnergyConsumer> p)51 void PowerStats::addEnergyConsumer(std::unique_ptr<IEnergyConsumer> p) {
52     if (!p) {
53         return;
54     }
55 
56     EnergyConsumerType type = p->getType();
57     std::string name = p->getName();
58     int32_t count = count_if(mEnergyConsumerInfos.begin(), mEnergyConsumerInfos.end(),
59                              [&type](const EnergyConsumer& c) { return type == c.type; });
60     int32_t id = mEnergyConsumers.size();
61     mEnergyConsumerInfos.emplace_back(
62             EnergyConsumer{.id = id, .ordinal = count, .type = type, .name = name});
63     mEnergyConsumers.emplace_back(std::move(p));
64 }
65 
setEnergyMeter(std::unique_ptr<IEnergyMeter> p)66 void PowerStats::setEnergyMeter(std::unique_ptr<IEnergyMeter> p) {
67     mEnergyMeter = std::move(p);
68 }
69 
getPowerEntityInfo(std::vector<PowerEntity> * _aidl_return)70 ndk::ScopedAStatus PowerStats::getPowerEntityInfo(std::vector<PowerEntity>* _aidl_return) {
71     *_aidl_return = mPowerEntityInfos;
72     return ndk::ScopedAStatus::ok();
73 }
74 
getStateResidency(const std::vector<int32_t> & in_powerEntityIds,std::vector<StateResidencyResult> * _aidl_return)75 ndk::ScopedAStatus PowerStats::getStateResidency(const std::vector<int32_t>& in_powerEntityIds,
76                                                  std::vector<StateResidencyResult>* _aidl_return) {
77     if (mPowerEntityInfos.empty()) {
78         return ndk::ScopedAStatus::ok();
79     }
80 
81     // If in_powerEntityIds is empty then return data for all supported entities
82     if (in_powerEntityIds.empty()) {
83         std::vector<int32_t> v(mPowerEntityInfos.size());
84         std::iota(std::begin(v), std::end(v), 0);
85         return getStateResidency(v, _aidl_return);
86     }
87 
88     std::unordered_map<std::string, std::vector<StateResidency>> stateResidencies;
89 
90     for (const int32_t id : in_powerEntityIds) {
91         // check for invalid ids
92         if (id < 0 || id >= mPowerEntityInfos.size()) {
93             return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
94         }
95 
96         // Check to see if we already have data for the given id
97         std::string powerEntityName = mPowerEntityInfos[id].name;
98         if (stateResidencies.find(powerEntityName) == stateResidencies.end()) {
99             mStateResidencyDataProviders.at(mStateResidencyDataProviderIndex.at(id))
100                     ->getStateResidencies(&stateResidencies);
101         }
102 
103         // Append results if we have them
104         auto stateResidency = stateResidencies.find(powerEntityName);
105         if (stateResidency != stateResidencies.end()) {
106             StateResidencyResult res = {
107                     .id = id,
108                     .stateResidencyData = stateResidency->second,
109             };
110             _aidl_return->emplace_back(res);
111         } else {
112             // Failed to get results for the given id.
113             LOG(ERROR) << "Failed to get results for " << powerEntityName;
114         }
115     }
116 
117     return ndk::ScopedAStatus::ok();
118 }
119 
getEnergyConsumerInfo(std::vector<EnergyConsumer> * _aidl_return)120 ndk::ScopedAStatus PowerStats::getEnergyConsumerInfo(std::vector<EnergyConsumer>* _aidl_return) {
121     *_aidl_return = mEnergyConsumerInfos;
122     return ndk::ScopedAStatus::ok();
123 }
124 
getEnergyConsumed(const std::vector<int32_t> & in_energyConsumerIds,std::vector<EnergyConsumerResult> * _aidl_return)125 ndk::ScopedAStatus PowerStats::getEnergyConsumed(const std::vector<int32_t>& in_energyConsumerIds,
126                                                  std::vector<EnergyConsumerResult>* _aidl_return) {
127     if (mEnergyConsumers.empty()) {
128         return ndk::ScopedAStatus::ok();
129     }
130 
131     // If in_powerEntityIds is empty then return data for all supported energy consumers
132     if (in_energyConsumerIds.empty()) {
133         std::vector<int32_t> v(mEnergyConsumerInfos.size());
134         std::iota(std::begin(v), std::end(v), 0);
135         return getEnergyConsumed(v, _aidl_return);
136     }
137 
138     for (const auto id : in_energyConsumerIds) {
139         // check for invalid ids
140         if (id < 0 || id >= mEnergyConsumers.size()) {
141             return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
142         }
143 
144         auto optionalResult = mEnergyConsumers[id]->getEnergyConsumed();
145         if (optionalResult) {
146             EnergyConsumerResult result = optionalResult.value();
147             result.id = id;
148             _aidl_return->emplace_back(result);
149         } else {
150             // Failed to get results for the given id.
151             LOG(ERROR) << "Failed to get results for " << mEnergyConsumerInfos[id].name;
152         }
153     }
154 
155     return ndk::ScopedAStatus::ok();
156 }
157 
getEnergyMeterInfo(std::vector<Channel> * _aidl_return)158 ndk::ScopedAStatus PowerStats::getEnergyMeterInfo(std::vector<Channel>* _aidl_return) {
159     if (!mEnergyMeter) {
160         return ndk::ScopedAStatus::ok();
161     }
162 
163     return mEnergyMeter->getEnergyMeterInfo(_aidl_return);
164 }
165 
readEnergyMeter(const std::vector<int32_t> & in_channelIds,std::vector<EnergyMeasurement> * _aidl_return)166 ndk::ScopedAStatus PowerStats::readEnergyMeter(const std::vector<int32_t>& in_channelIds,
167                                                std::vector<EnergyMeasurement>* _aidl_return) {
168     if (!mEnergyMeter) {
169         return ndk::ScopedAStatus::ok();
170     }
171 
172     return mEnergyMeter->readEnergyMeter(in_channelIds, _aidl_return);
173 }
174 
175 }  // namespace stats
176 }  // namespace power
177 }  // namespace hardware
178 }  // namespace android
179 }  // namespace aidl
180