xref: /aosp_15_r20/external/perfetto/src/android_internal/power_stats.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 bool GetPowerEntityStates(PowerEntityState* state,
57                                     size_t* size_of_arr) = 0;
58   virtual bool GetPowerEntityStateResidency(PowerEntityStateResidency* state,
59                                             size_t* size_of_arr) = 0;
60   virtual ~PowerStatsDataProvider() = default;
61 };
62 
63 class PowerStatsHalDataProvider : public PowerStatsDataProvider {
64  public:
65   bool GetAvailableRails(RailDescriptor*, size_t* size_of_arr) override;
66   bool GetRailEnergyData(RailEnergyData*, size_t* size_of_arr) override;
67   bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers,
68                              size_t* size_of_arr) override;
69   bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
70                          size_t* size_of_arr) override;
71   bool GetPowerEntityStates(PowerEntityState* state,
72                             size_t* size_of_arr) override;
73   bool GetPowerEntityStateResidency(PowerEntityStateResidency* state,
74                                     size_t* size_of_arr) override;
75 
76   PowerStatsHalDataProvider() = default;
77   ~PowerStatsHalDataProvider() override = default;
78 
79  private:
80   android::sp<hal::IPowerStats> svc_;
81   hal::IPowerStats* MaybeGetService();
82 };
83 
84 class PowerStatsAidlDataProvider : public PowerStatsDataProvider {
85  public:
86   static constexpr char INSTANCE[] =
87       "android.hardware.power.stats.IPowerStats/default";
88 
89   bool GetAvailableRails(RailDescriptor*, size_t* size_of_arr) override;
90   bool GetRailEnergyData(RailEnergyData*, size_t* size_of_arr) override;
91   bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers,
92                              size_t* size_of_arr) override;
93   bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
94                          size_t* size_of_arr) override;
95   bool GetPowerEntityStates(PowerEntityState* state,
96                             size_t* size_of_arr) override;
97   bool GetPowerEntityStateResidency(PowerEntityStateResidency* state,
98                                     size_t* size_of_arr) override;
99 
100   PowerStatsAidlDataProvider() = default;
101   ~PowerStatsAidlDataProvider() override = default;
102 
103  private:
104   android::sp<aidl::IPowerStats> svc_;
105 
106   aidl::IPowerStats* MaybeGetService();
107   void ResetService();
108 };
109 
GetDataProvider()110 PowerStatsDataProvider* GetDataProvider() {
111   static std::unique_ptr<PowerStatsDataProvider> data_provider;
112   if (data_provider == nullptr) {
113     const android::sp<android::IServiceManager> sm =
114         android::defaultServiceManager();
115     if (sm->isDeclared(
116             android::String16(PowerStatsAidlDataProvider::INSTANCE))) {
117       data_provider = std::make_unique<PowerStatsAidlDataProvider>();
118     } else {
119       data_provider = std::make_unique<PowerStatsHalDataProvider>();
120     }
121   }
122   return data_provider.get();
123 }
124 
125 }  // anonymous namespace
126 
GetAvailableRails(RailDescriptor * descriptor,size_t * size_of_arr)127 bool GetAvailableRails(RailDescriptor* descriptor, size_t* size_of_arr) {
128   return GetDataProvider()->GetAvailableRails(descriptor, size_of_arr);
129 }
130 
GetRailEnergyData(RailEnergyData * data,size_t * size_of_arr)131 bool GetRailEnergyData(RailEnergyData* data, size_t* size_of_arr) {
132   return GetDataProvider()->GetRailEnergyData(data, size_of_arr);
133 }
134 
GetEnergyConsumerInfo(EnergyConsumerInfo * consumers,size_t * size_of_arr)135 bool GetEnergyConsumerInfo(EnergyConsumerInfo* consumers, size_t* size_of_arr) {
136   return GetDataProvider()->GetEnergyConsumerInfo(consumers, size_of_arr);
137 }
138 
GetEnergyConsumed(EnergyEstimationBreakdown * breakdown,size_t * size_of_arr)139 bool GetEnergyConsumed(EnergyEstimationBreakdown* breakdown,
140                        size_t* size_of_arr) {
141   return GetDataProvider()->GetEnergyConsumed(breakdown, size_of_arr);
142 }
143 
GetPowerEntityStates(PowerEntityState * state,size_t * size_of_arr)144 bool GetPowerEntityStates(PowerEntityState* state, size_t* size_of_arr) {
145   return GetDataProvider()->GetPowerEntityStates(state, size_of_arr);
146 }
147 
GetPowerEntityStateResidency(PowerEntityStateResidency * residency,size_t * size_of_arr)148 bool GetPowerEntityStateResidency(PowerEntityStateResidency* residency,
149                                   size_t* size_of_arr) {
150   return GetDataProvider()->GetPowerEntityStateResidency(residency,
151                                                          size_of_arr);
152 }
153 
154 /*** Power Stats HAL Implemenation *******************************************/
155 
156 using android::hardware::hidl_vec;
157 using android::hardware::Return;
158 
MaybeGetService()159 hal::IPowerStats* PowerStatsHalDataProvider::MaybeGetService() {
160   if (svc_ == nullptr) {
161     svc_ = hal::IPowerStats::tryGetService();
162   }
163   return svc_.get();
164 }
165 
GetAvailableRails(RailDescriptor * rail_descriptors,size_t * size_of_arr)166 bool PowerStatsHalDataProvider::GetAvailableRails(
167     RailDescriptor* rail_descriptors,
168     size_t* size_of_arr) {
169   const size_t in_array_size = *size_of_arr;
170   *size_of_arr = 0;
171   hal::IPowerStats* svc = MaybeGetService();
172   if (svc == nullptr) {
173     return false;
174   }
175 
176   hal::Status status;
177   auto rails_cb = [rail_descriptors, size_of_arr, &in_array_size, &status](
178                       hidl_vec<hal::RailInfo> r, hal::Status s) {
179     status = s;
180     if (status == hal::Status::SUCCESS) {
181       *size_of_arr = std::min(in_array_size, r.size());
182       for (int i = 0; i < *size_of_arr; ++i) {
183         const hal::RailInfo& rail_info = r[i];
184         RailDescriptor& descriptor = rail_descriptors[i];
185 
186         descriptor.index = rail_info.index;
187         descriptor.sampling_rate = rail_info.samplingRate;
188 
189         strlcpy(descriptor.rail_name, rail_info.railName.c_str(),
190                 sizeof(descriptor.rail_name));
191         strlcpy(descriptor.subsys_name, rail_info.subsysName.c_str(),
192                 sizeof(descriptor.subsys_name));
193       }
194     }
195   };
196 
197   Return<void> ret = svc->getRailInfo(rails_cb);
198   return status == hal::Status::SUCCESS;
199 }
200 
GetRailEnergyData(RailEnergyData * rail_energy_array,size_t * size_of_arr)201 bool PowerStatsHalDataProvider::GetRailEnergyData(
202     RailEnergyData* rail_energy_array,
203     size_t* size_of_arr) {
204   const size_t in_array_size = *size_of_arr;
205   *size_of_arr = 0;
206 
207   hal::IPowerStats* svc = MaybeGetService();
208   if (svc == nullptr) {
209     return false;
210   }
211 
212   hal::Status status;
213   auto energy_cb = [rail_energy_array, size_of_arr, &in_array_size, &status](
214                        hidl_vec<hal::EnergyData> m, hal::Status s) {
215     status = s;
216     if (status == hal::Status::SUCCESS) {
217       *size_of_arr = std::min(in_array_size, m.size());
218       for (int i = 0; i < *size_of_arr; ++i) {
219         const hal::EnergyData& measurement = m[i];
220         RailEnergyData& element = rail_energy_array[i];
221 
222         element.index = measurement.index;
223         element.timestamp = measurement.timestamp;
224         element.energy = measurement.energy;
225       }
226     }
227   };
228 
229   Return<void> ret = svc_->getEnergyData(hidl_vec<uint32_t>(), energy_cb);
230   return status == hal::Status::SUCCESS;
231 }
232 
GetEnergyConsumerInfo(EnergyConsumerInfo *,size_t *)233 bool PowerStatsHalDataProvider::GetEnergyConsumerInfo(EnergyConsumerInfo*,
234                                                       size_t*) {
235   return false;
236 }
237 
GetEnergyConsumed(EnergyEstimationBreakdown *,size_t *)238 bool PowerStatsHalDataProvider::GetEnergyConsumed(EnergyEstimationBreakdown*,
239                                                   size_t*) {
240   return false;
241 }
242 
GetPowerEntityStates(PowerEntityState *,size_t *)243 bool PowerStatsHalDataProvider::GetPowerEntityStates(PowerEntityState*,
244                                                      size_t*) {
245   return false;
246 }
247 
GetPowerEntityStateResidency(PowerEntityStateResidency *,size_t *)248 bool PowerStatsHalDataProvider::GetPowerEntityStateResidency(
249     PowerEntityStateResidency*,
250     size_t*) {
251   return false;
252 }
253 
254 /*** End of Power Stats HAL Implemenation *************************************/
255 
256 /*** Power Stats AIDL Implemenation *******************************************/
MaybeGetService()257 aidl::IPowerStats* PowerStatsAidlDataProvider::MaybeGetService() {
258   if (svc_ == nullptr) {
259     svc_ = android::checkDeclaredService<aidl::IPowerStats>(
260         android::String16(INSTANCE));
261   }
262   return svc_.get();
263 }
264 
ResetService()265 void PowerStatsAidlDataProvider::ResetService() {
266   svc_.clear();
267 }
268 
GetAvailableRails(RailDescriptor * descriptor,size_t * size_of_arr)269 bool PowerStatsAidlDataProvider::GetAvailableRails(RailDescriptor* descriptor,
270                                                    size_t* size_of_arr) {
271   const size_t in_array_size = *size_of_arr;
272   *size_of_arr = 0;
273 
274   aidl::IPowerStats* svc = MaybeGetService();
275   if (svc_ == nullptr) {
276     return false;
277   }
278 
279   std::vector<aidl::Channel> results;
280   android::binder::Status status = svc->getEnergyMeterInfo(&results);
281   if (!status.isOk()) {
282     if (status.transactionError() == android::DEAD_OBJECT) {
283       // Service has died.  Reset it to attempt to acquire a new one next time.
284       ResetService();
285     }
286     return false;
287   }
288 
289   size_t max_size = std::min(in_array_size, results.size());
290   for (const auto& result : results) {
291     if (*size_of_arr >= max_size) {
292       break;
293     }
294     auto& cur = descriptor[(*size_of_arr)++];
295     cur.index = result.id;
296     cur.sampling_rate = 0;
297     strlcpy(cur.rail_name, result.name.c_str(), sizeof(cur.rail_name));
298     strlcpy(cur.subsys_name, result.subsystem.c_str(), sizeof(cur.subsys_name));
299   }
300   return true;
301 }
302 
GetRailEnergyData(RailEnergyData * data,size_t * size_of_arr)303 bool PowerStatsAidlDataProvider::GetRailEnergyData(RailEnergyData* data,
304                                                    size_t* size_of_arr) {
305   const size_t in_array_size = *size_of_arr;
306   *size_of_arr = 0;
307 
308   aidl::IPowerStats* svc = MaybeGetService();
309   if (svc == nullptr) {
310     return false;
311   }
312 
313   std::vector<int> ids;
314   std::vector<aidl::EnergyMeasurement> results;
315   android::binder::Status status = svc->readEnergyMeter(ids, &results);
316   if (!status.isOk()) {
317     if (status.transactionError() == android::DEAD_OBJECT) {
318       // Service has died.  Reset it to attempt to acquire a new one next time.
319       ResetService();
320     }
321     return false;
322   }
323 
324   size_t max_size = std::min(in_array_size, results.size());
325   for (const auto& result : results) {
326     if (*size_of_arr >= max_size) {
327       break;
328     }
329     auto& cur = data[(*size_of_arr)++];
330     cur.index = result.id;
331     cur.timestamp = result.timestampMs;
332     cur.energy = result.energyUWs;
333   }
334   return true;
335 }
336 
GetEnergyConsumerInfo(EnergyConsumerInfo * consumers,size_t * size_of_arr)337 bool PowerStatsAidlDataProvider::GetEnergyConsumerInfo(
338     EnergyConsumerInfo* consumers,
339     size_t* size_of_arr) {
340   const size_t in_array_size = *size_of_arr;
341   *size_of_arr = 0;
342 
343   aidl::IPowerStats* svc = MaybeGetService();
344   if (svc == nullptr) {
345     return false;
346   }
347   std::vector<aidl::EnergyConsumer> results;
348   android::binder::Status status = svc->getEnergyConsumerInfo(&results);
349 
350   if (!status.isOk()) {
351     if (status.transactionError() == android::DEAD_OBJECT) {
352       // Service has died.  Reset it to attempt to acquire a new one next time.
353       ResetService();
354     }
355     return false;
356   }
357   size_t max_size = std::min(in_array_size, results.size());
358   for (const auto& result : results) {
359     if (*size_of_arr >= max_size) {
360       break;
361     }
362     auto& cur = consumers[(*size_of_arr)++];
363     cur.energy_consumer_id = result.id;
364     cur.ordinal = result.ordinal;
365     strlcpy(cur.type, aidl::toString(result.type).c_str(), sizeof(cur.type));
366     strlcpy(cur.name, result.name.c_str(), sizeof(cur.name));
367   }
368   return true;
369 }
GetEnergyConsumed(EnergyEstimationBreakdown * breakdown,size_t * size_of_arr)370 bool PowerStatsAidlDataProvider::GetEnergyConsumed(
371     EnergyEstimationBreakdown* breakdown,
372     size_t* size_of_arr) {
373   const size_t in_array_size = *size_of_arr;
374   *size_of_arr = 0;
375 
376   aidl::IPowerStats* svc = MaybeGetService();
377   if (svc == nullptr) {
378     return false;
379   }
380 
381   std::vector<int> ids;
382   std::vector<aidl::EnergyConsumerResult> results;
383   android::binder::Status status = svc->getEnergyConsumed(ids, &results);
384 
385   if (!status.isOk()) {
386     if (status.transactionError() == android::DEAD_OBJECT) {
387       // Service has died.  Reset it to attempt to acquire a new one next time.
388       ResetService();
389     }
390     return false;
391   }
392 
393   size_t max_size = std::min(in_array_size, results.size());
394   // Iterate through all consumer ID.
395   for (const auto& result : results) {
396     if (*size_of_arr >= max_size) {
397       break;
398     }
399     auto& cur = breakdown[(*size_of_arr)++];
400     cur.energy_consumer_id = result.id;
401     cur.uid = ALL_UIDS_FOR_CONSUMER;
402     cur.energy_uws = result.energyUWs;
403 
404     // Iterate through all UIDs for this consumer.
405     for (const auto& attribution : result.attribution) {
406       if (*size_of_arr >= max_size) {
407         break;
408       }
409       auto& cur = breakdown[(*size_of_arr)++];
410       cur.energy_consumer_id = result.id;
411       cur.uid = attribution.uid;
412       cur.energy_uws = attribution.energyUWs;
413     }
414   }
415   return true;
416 }
417 
GetPowerEntityStates(PowerEntityState * entity_state,size_t * size_of_arr)418 bool PowerStatsAidlDataProvider::GetPowerEntityStates(
419     PowerEntityState* entity_state,
420     size_t* size_of_arr) {
421   const size_t in_array_size = *size_of_arr;
422   *size_of_arr = 0;
423 
424   aidl::IPowerStats* svc = MaybeGetService();
425   if (svc == nullptr) {
426     return false;
427   }
428 
429   std::vector<aidl::PowerEntity> entities;
430   android::binder::Status status = svc->getPowerEntityInfo(&entities);
431 
432   if (!status.isOk()) {
433     if (status.transactionError() == android::DEAD_OBJECT) {
434       // Service has died.  Reset it to attempt to acquire a new one next time.
435       ResetService();
436     }
437     return false;
438   }
439 
440   // Iterate through all entities.
441   for (const auto& entity : entities) {
442     if (*size_of_arr >= in_array_size) {
443       break;
444     }
445 
446     // Iterate through all states for this entity.
447     for (const auto& state : entity.states) {
448       if (*size_of_arr >= in_array_size) {
449         break;
450       }
451       auto& cur = entity_state[(*size_of_arr)++];
452       cur.entity_id = entity.id;
453       strlcpy(cur.entity_name, entity.name.c_str(), sizeof(cur.entity_name));
454       cur.state_id = state.id;
455       strlcpy(cur.state_name, state.name.c_str(), sizeof(cur.state_name));
456     }
457   }
458   return true;
459 }
460 
GetPowerEntityStateResidency(PowerEntityStateResidency * residency,size_t * size_of_arr)461 bool PowerStatsAidlDataProvider::GetPowerEntityStateResidency(
462     PowerEntityStateResidency* residency,
463     size_t* size_of_arr) {
464   const size_t in_array_size = *size_of_arr;
465   *size_of_arr = 0;
466 
467   aidl::IPowerStats* svc = MaybeGetService();
468   if (svc == nullptr) {
469     return false;
470   }
471 
472   std::vector<int> ids;
473   std::vector<aidl::StateResidencyResult> entities;
474   android::binder::Status status = svc->getStateResidency(ids, &entities);
475 
476   if (!status.isOk()) {
477     if (status.transactionError() == android::DEAD_OBJECT) {
478       // Service has died.  Reset it to attempt to acquire a new one next time.
479       ResetService();
480     }
481     return false;
482   }
483 
484   // Iterate through all entities.
485   for (const auto& entity : entities) {
486     if (*size_of_arr >= in_array_size) {
487       break;
488     }
489 
490     // Iterate through all states for this entity.
491     for (const auto& stateResidencyData : entity.stateResidencyData) {
492       if (*size_of_arr >= in_array_size) {
493         break;
494       }
495       auto& cur = residency[(*size_of_arr)++];
496       cur.entity_id = entity.id;
497       cur.state_id = stateResidencyData.id;
498       cur.total_time_in_state_ms = stateResidencyData.totalTimeInStateMs;
499       cur.total_state_entry_count = stateResidencyData.totalStateEntryCount;
500       cur.last_entry_timestamp_ms = stateResidencyData.lastEntryTimestampMs;
501     }
502   }
503   return true;
504 }
505 
506 /*** End of Power Stats AIDL Implemenation ************************************/
507 
508 }  // namespace android_internal
509 }  // namespace perfetto
510