1 /*
2 * Copyright (C) 2021 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 "src/android_internal/power_stats.h"
18
19 #include "perfetto/ext/base/utils.h"
20
21 #include <string.h>
22
23 #include <algorithm>
24 #include <memory>
25 #include <vector>
26
27 // Legacy HAL interfacte for devices shipped before Android S.
28 #include <android/hardware/power/stats/1.0/IPowerStats.h>
29
30 // AIDL interface for Android S+.
31 #include <android/hardware/power/stats/IPowerStats.h>
32
33 #include <binder/IServiceManager.h>
34
35 namespace perfetto {
36 namespace android_internal {
37
38 namespace hal = android::hardware::power::stats::V1_0;
39 namespace aidl = android::hardware::power::stats;
40
41 namespace {
42
43 // Common interface for data from power stats service. Devices prior to
44 // Android S, uses the HAL interface while device from Android S or later
45 // uses the AIDL interfact.
46 class PowerStatsDataProvider {
47 public:
48 virtual bool GetAvailableRails(RailDescriptor*, size_t* size_of_arr) = 0;
49 virtual bool GetRailEnergyData(RailEnergyData*, size_t* size_of_arr) = 0;
50
51 // Available from Android S+.
52 virtual bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers,
53 size_t* size_of_arr) = 0;
54 virtual bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
55 size_t* size_of_arr) = 0;
56 virtual ~PowerStatsDataProvider() = default;
57 };
58
59 class PowerStatsHalDataProvider : public PowerStatsDataProvider {
60 public:
61 bool GetAvailableRails(RailDescriptor*, size_t* size_of_arr) override;
62 bool GetRailEnergyData(RailEnergyData*, size_t* size_of_arr) override;
63 bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers,
64 size_t* size_of_arr) override;
65 bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
66 size_t* size_of_arr) override;
67
68 PowerStatsHalDataProvider() = default;
69 ~PowerStatsHalDataProvider() override = default;
70
71 private:
72 android::sp<hal::IPowerStats> svc_;
73 hal::IPowerStats* MaybeGetService();
74 };
75
76 class PowerStatsAidlDataProvider : public PowerStatsDataProvider {
77 public:
78 static constexpr char INSTANCE[] =
79 "android.hardware.power.stats.IPowerStats/default";
80
81 bool GetAvailableRails(RailDescriptor*, size_t* size_of_arr) override;
82 bool GetRailEnergyData(RailEnergyData*, size_t* size_of_arr) override;
83 bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers,
84 size_t* size_of_arr) override;
85 bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
86 size_t* size_of_arr) override;
87
88 PowerStatsAidlDataProvider() = default;
89 ~PowerStatsAidlDataProvider() override = default;
90
91 private:
92 android::sp<aidl::IPowerStats> svc_;
93
94 aidl::IPowerStats* MaybeGetService();
95 void ResetService();
96 };
97
GetDataProvider()98 PowerStatsDataProvider* GetDataProvider() {
99 static std::unique_ptr<PowerStatsDataProvider> data_provider;
100 if (data_provider == nullptr) {
101 const android::sp<android::IServiceManager> sm =
102 android::defaultServiceManager();
103 if (sm->isDeclared(
104 android::String16(PowerStatsAidlDataProvider::INSTANCE))) {
105 data_provider = std::make_unique<PowerStatsAidlDataProvider>();
106 } else {
107 data_provider = std::make_unique<PowerStatsHalDataProvider>();
108 }
109 }
110 return data_provider.get();
111 }
112
113 } // anonymous namespace
114
GetAvailableRails(RailDescriptor * descriptor,size_t * size_of_arr)115 bool GetAvailableRails(RailDescriptor* descriptor, size_t* size_of_arr) {
116 return GetDataProvider()->GetAvailableRails(descriptor, size_of_arr);
117 }
118
GetRailEnergyData(RailEnergyData * data,size_t * size_of_arr)119 bool GetRailEnergyData(RailEnergyData* data, size_t* size_of_arr) {
120 return GetDataProvider()->GetRailEnergyData(data, size_of_arr);
121 }
122
GetEnergyConsumerInfo(EnergyConsumerInfo * consumers,size_t * size_of_arr)123 bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers, size_t* size_of_arr) {
124 return GetDataProvider()->GetEnergyConsumerInfo(consumers, size_of_arr);
125 }
126
GetEnergyConsumed(EnergyEstimationBreakdown * breakdown,size_t * size_of_arr)127 bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
128 size_t* size_of_arr) {
129 return GetDataProvider()->GetEnergyConsumed(breakdown, size_of_arr);
130 }
131
132 /*** Power Stats HAL Implemenation *******************************************/
133
134 using android::hardware::hidl_vec;
135 using android::hardware::Return;
136
MaybeGetService()137 hal::IPowerStats* PowerStatsHalDataProvider::MaybeGetService() {
138 if (svc_ == nullptr) {
139 svc_ = hal::IPowerStats::tryGetService();
140 }
141 return svc_.get();
142 }
143
GetAvailableRails(RailDescriptor * rail_descriptors,size_t * size_of_arr)144 bool PowerStatsHalDataProvider::GetAvailableRails(
145 RailDescriptor* rail_descriptors,
146 size_t* size_of_arr) {
147 const size_t in_array_size = *size_of_arr;
148 *size_of_arr = 0;
149 hal::IPowerStats* svc = MaybeGetService();
150 if (svc == nullptr) {
151 return false;
152 }
153
154 hal::Status status;
155 auto rails_cb = [rail_descriptors, size_of_arr, &in_array_size, &status](
156 hidl_vec<hal::RailInfo> r, hal::Status s) {
157 status = s;
158 if (status == hal::Status::SUCCESS) {
159 *size_of_arr = std::min(in_array_size, r.size());
160 for (int i = 0; i < *size_of_arr; ++i) {
161 const hal::RailInfo& rail_info = r[i];
162 RailDescriptor& descriptor = rail_descriptors[i];
163
164 descriptor.index = rail_info.index;
165 descriptor.sampling_rate = rail_info.samplingRate;
166
167 strncpy(descriptor.rail_name, rail_info.railName.c_str(),
168 sizeof(descriptor.rail_name));
169 strncpy(descriptor.subsys_name, rail_info.subsysName.c_str(),
170 sizeof(descriptor.subsys_name));
171 descriptor.rail_name[sizeof(descriptor.rail_name) - 1] = '\0';
172 descriptor.subsys_name[sizeof(descriptor.subsys_name) - 1] = '\0';
173 }
174 }
175 };
176
177 Return<void> ret = svc->getRailInfo(rails_cb);
178 return status == hal::Status::SUCCESS;
179 }
180
GetRailEnergyData(RailEnergyData * rail_energy_array,size_t * size_of_arr)181 bool PowerStatsHalDataProvider::GetRailEnergyData(
182 RailEnergyData* rail_energy_array,
183 size_t* size_of_arr) {
184 const size_t in_array_size = *size_of_arr;
185 *size_of_arr = 0;
186
187 hal::IPowerStats* svc = MaybeGetService();
188 if (svc == nullptr) {
189 return false;
190 }
191
192 hal::Status status;
193 auto energy_cb = [rail_energy_array, size_of_arr, &in_array_size, &status](
194 hidl_vec<hal::EnergyData> m, hal::Status s) {
195 status = s;
196 if (status == hal::Status::SUCCESS) {
197 *size_of_arr = std::min(in_array_size, m.size());
198 for (int i = 0; i < *size_of_arr; ++i) {
199 const hal::EnergyData& measurement = m[i];
200 RailEnergyData& element = rail_energy_array[i];
201
202 element.index = measurement.index;
203 element.timestamp = measurement.timestamp;
204 element.energy = measurement.energy;
205 }
206 }
207 };
208
209 Return<void> ret = svc_->getEnergyData(hidl_vec<uint32_t>(), energy_cb);
210 return status == hal::Status::SUCCESS;
211 }
212
GetEnergyConsumerInfo(EnergyConsumerInfo *,size_t *)213 bool PowerStatsHalDataProvider::GetEnergyConsumerInfo(EnergyConsumerInfo*,
214 size_t*) {
215 return false;
216 }
217
GetEnergyConsumed(EnergyEstimationBreakdown *,size_t *)218 bool PowerStatsHalDataProvider::GetEnergyConsumed(EnergyEstimationBreakdown*,
219 size_t*) {
220 return false;
221 }
222
223 /*** End of Power Stats HAL Implemenation *************************************/
224
225 /*** Power Stats AIDL Implemenation *******************************************/
MaybeGetService()226 aidl::IPowerStats* PowerStatsAidlDataProvider::MaybeGetService() {
227 if (svc_ == nullptr) {
228 svc_ = android::checkDeclaredService<aidl::IPowerStats>(
229 android::String16(INSTANCE));
230 }
231 return svc_.get();
232 }
233
ResetService()234 void PowerStatsAidlDataProvider::ResetService() {
235 svc_.clear();
236 }
237
GetAvailableRails(RailDescriptor * descriptor,size_t * size_of_arr)238 bool PowerStatsAidlDataProvider::GetAvailableRails(RailDescriptor* descriptor,
239 size_t* size_of_arr) {
240 const size_t in_array_size = *size_of_arr;
241 *size_of_arr = 0;
242
243 aidl::IPowerStats* svc = MaybeGetService();
244 if (svc_ == nullptr) {
245 return false;
246 }
247
248 std::vector<aidl::Channel> results;
249 android::binder::Status status = svc->getEnergyMeterInfo(&results);
250 if (!status.isOk()) {
251 if (status.transactionError() == android::DEAD_OBJECT) {
252 // Service has died. Reset it to attempt to acquire a new one next time.
253 ResetService();
254 }
255 return false;
256 }
257
258 size_t max_size = std::min(in_array_size, results.size());
259 for (const auto& result : results) {
260 if (*size_of_arr >= max_size) {
261 break;
262 }
263 auto& cur = descriptor[(*size_of_arr)++];
264 cur.index = result.id;
265 cur.sampling_rate = 0;
266 strncpy(cur.rail_name, result.name.c_str(), sizeof(cur.rail_name));
267 strncpy(cur.subsys_name, result.subsystem.c_str(), sizeof(cur.subsys_name));
268 cur.rail_name[sizeof(cur.rail_name) - 1] = '\0';
269 cur.subsys_name[sizeof(cur.subsys_name) - 1] = '\0';
270 }
271 return true;
272 }
273
GetRailEnergyData(RailEnergyData * data,size_t * size_of_arr)274 bool PowerStatsAidlDataProvider::GetRailEnergyData(RailEnergyData* data,
275 size_t* size_of_arr) {
276 const size_t in_array_size = *size_of_arr;
277 *size_of_arr = 0;
278
279 aidl::IPowerStats* svc = MaybeGetService();
280 if (svc == nullptr) {
281 return false;
282 }
283
284 std::vector<int> ids;
285 std::vector<aidl::EnergyMeasurement> results;
286 android::binder::Status status = svc->readEnergyMeter(ids, &results);
287 if (!status.isOk()) {
288 if (status.transactionError() == android::DEAD_OBJECT) {
289 // Service has died. Reset it to attempt to acquire a new one next time.
290 ResetService();
291 }
292 return false;
293 }
294
295 size_t max_size = std::min(in_array_size, results.size());
296 for (const auto& result : results) {
297 if (*size_of_arr >= max_size) {
298 break;
299 }
300 auto& cur = data[(*size_of_arr)++];
301 cur.index = result.id;
302 cur.timestamp = result.timestampMs;
303 cur.energy = result.energyUWs;
304 }
305 return true;
306 }
307
GetEnergyConsumerInfo(EnergyConsumerInfo * consumers,size_t * size_of_arr)308 bool PowerStatsAidlDataProvider::GetEnergyConsumerInfo(
309 EnergyConsumerInfo* consumers,
310 size_t* size_of_arr) {
311 const size_t in_array_size = *size_of_arr;
312 *size_of_arr = 0;
313
314 aidl::IPowerStats* svc = MaybeGetService();
315 if (svc == nullptr) {
316 return false;
317 }
318 std::vector<aidl::EnergyConsumer> results;
319 android::binder::Status status = svc->getEnergyConsumerInfo(&results);
320
321 if (!status.isOk()) {
322 if (status.transactionError() == android::DEAD_OBJECT) {
323 // Service has died. Reset it to attempt to acquire a new one next time.
324 ResetService();
325 }
326 return false;
327 }
328 size_t max_size = std::min(in_array_size, results.size());
329 for (const auto& result : results) {
330 if (*size_of_arr >= max_size) {
331 break;
332 }
333 auto& cur = consumers[(*size_of_arr)++];
334 cur.energy_consumer_id = result.id;
335 cur.ordinal = result.ordinal;
336 strncpy(cur.type, aidl::toString(result.type).c_str(), sizeof(cur.type));
337 cur.type[sizeof(cur.type) - 1] = '\0';
338 strncpy(cur.name, result.name.c_str(), sizeof(cur.name));
339 cur.name[sizeof(cur.name) - 1] = '\0';
340 }
341 return true;
342 }
GetEnergyConsumed(EnergyEstimationBreakdown * breakdown,size_t * size_of_arr)343 bool PowerStatsAidlDataProvider::GetEnergyConsumed(
344 EnergyEstimationBreakdown* breakdown,
345 size_t* size_of_arr) {
346 const size_t in_array_size = *size_of_arr;
347 *size_of_arr = 0;
348
349 aidl::IPowerStats* svc = MaybeGetService();
350 if (svc == nullptr) {
351 return false;
352 }
353
354 std::vector<int> ids;
355 std::vector<aidl::EnergyConsumerResult> results;
356 android::binder::Status status = svc->getEnergyConsumed(ids, &results);
357
358 if (!status.isOk()) {
359 if (status.transactionError() == android::DEAD_OBJECT) {
360 // Service has died. Reset it to attempt to acquire a new one next time.
361 ResetService();
362 }
363 return false;
364 }
365
366 size_t max_size = std::min(in_array_size, results.size());
367 // Iterate through all consumer ID.
368 for (const auto& result : results) {
369 if (*size_of_arr >= max_size) {
370 break;
371 }
372 auto& cur = breakdown[(*size_of_arr)++];
373 cur.energy_consumer_id = result.id;
374 cur.uid = ALL_UIDS_FOR_CONSUMER;
375 cur.energy_uws = result.energyUWs;
376
377 // Iterate through all UIDs for this consumer.
378 for (const auto& attribution : result.attribution) {
379 if (*size_of_arr >= max_size) {
380 break;
381 }
382 auto& cur = breakdown[(*size_of_arr)++];
383 cur.energy_consumer_id = result.id;
384 cur.uid = attribution.uid;
385 cur.energy_uws = attribution.energyUWs;
386 }
387 }
388 return true;
389 }
390 /*** End of Power Stats AIDL Implemenation ************************************/
391
392 } // namespace android_internal
393 } // namespace perfetto
394