• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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