1 /*
2  * Copyright (C) 2018 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/traced/probes/power/android_power_data_source.h"
18 
19 #include <vector>
20 
21 #include "perfetto/base/logging.h"
22 #include "perfetto/base/task_runner.h"
23 #include "perfetto/base/time.h"
24 #include "perfetto/ext/base/optional.h"
25 #include "perfetto/ext/base/scoped_file.h"
26 #include "perfetto/ext/tracing/core/trace_packet.h"
27 #include "perfetto/ext/tracing/core/trace_writer.h"
28 #include "perfetto/tracing/core/data_source_config.h"
29 #include "src/android_internal/health_hal.h"
30 #include "src/android_internal/lazy_library_loader.h"
31 #include "src/android_internal/power_stats.h"
32 
33 #include "protos/perfetto/common/android_energy_consumer_descriptor.pbzero.h"
34 #include "protos/perfetto/config/power/android_power_config.pbzero.h"
35 #include "protos/perfetto/trace/power/android_energy_estimation_breakdown.pbzero.h"
36 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
37 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
38 #include "protos/perfetto/trace/trace_packet.pbzero.h"
39 
40 namespace perfetto {
41 
42 namespace {
43 constexpr uint32_t kMinPollIntervalMs = 100;
44 constexpr uint32_t kDefaultPollIntervalMs = 1000;
45 constexpr size_t kMaxNumRails = 32;
46 constexpr size_t kMaxNumEnergyConsumer = 32;
47 constexpr size_t kMaxNumPowerEntities = 256;
48 }  // namespace
49 
50 // static
51 const ProbesDataSource::Descriptor AndroidPowerDataSource::descriptor = {
52     /*name*/ "android.power",
53     /*flags*/ Descriptor::kFlagsNone,
54 };
55 
56 // Dynamically loads the libperfetto_android_internal.so library which
57 // allows to proxy calls to android hwbinder in in-tree builds.
58 struct AndroidPowerDataSource::DynamicLibLoader {
59   PERFETTO_LAZY_LOAD(android_internal::GetBatteryCounter, get_battery_counter_);
60   PERFETTO_LAZY_LOAD(android_internal::GetAvailableRails, get_available_rails_);
61   PERFETTO_LAZY_LOAD(android_internal::GetRailEnergyData,
62                      get_rail_energy_data_);
63   PERFETTO_LAZY_LOAD(android_internal::GetEnergyConsumerInfo,
64                      get_energy_consumer_info_);
65   PERFETTO_LAZY_LOAD(android_internal::GetEnergyConsumed, get_energy_consumed_);
66 
GetCounterperfetto::AndroidPowerDataSource::DynamicLibLoader67   base::Optional<int64_t> GetCounter(android_internal::BatteryCounter counter) {
68     if (!get_battery_counter_)
69       return base::nullopt;
70     int64_t value = 0;
71     if (get_battery_counter_(counter, &value))
72       return base::make_optional(value);
73     return base::nullopt;
74   }
75 
GetRailDescriptorsperfetto::AndroidPowerDataSource::DynamicLibLoader76   std::vector<android_internal::RailDescriptor> GetRailDescriptors() {
77     if (!get_available_rails_)
78       return std::vector<android_internal::RailDescriptor>();
79 
80     std::vector<android_internal::RailDescriptor> rail_descriptors(
81         kMaxNumRails);
82     size_t num_rails = rail_descriptors.size();
83     if (!get_available_rails_(&rail_descriptors[0], &num_rails)) {
84       PERFETTO_ELOG("Failed to retrieve rail descriptors.");
85       num_rails = 0;
86     }
87     rail_descriptors.resize(num_rails);
88     return rail_descriptors;
89   }
90 
GetRailEnergyDataperfetto::AndroidPowerDataSource::DynamicLibLoader91   std::vector<android_internal::RailEnergyData> GetRailEnergyData() {
92     if (!get_rail_energy_data_)
93       return std::vector<android_internal::RailEnergyData>();
94 
95     std::vector<android_internal::RailEnergyData> energy_data(kMaxNumRails);
96     size_t num_rails = energy_data.size();
97     if (!get_rail_energy_data_(&energy_data[0], &num_rails)) {
98       PERFETTO_ELOG("Failed to retrieve rail energy data.");
99       num_rails = 0;
100     }
101     energy_data.resize(num_rails);
102     return energy_data;
103   }
104 
GetEnergyConsumerInfoperfetto::AndroidPowerDataSource::DynamicLibLoader105   std::vector<android_internal::EnergyConsumerInfo> GetEnergyConsumerInfo() {
106     if (!get_energy_consumer_info_)
107       return std::vector<android_internal::EnergyConsumerInfo>();
108 
109     std::vector<android_internal::EnergyConsumerInfo> consumers(
110         kMaxNumEnergyConsumer);
111     size_t num_power_entities = consumers.size();
112     if (!get_energy_consumer_info_(&consumers[0], &num_power_entities)) {
113       PERFETTO_ELOG("Failed to retrieve energy consumer info.");
114       num_power_entities = 0;
115     }
116     consumers.resize(num_power_entities);
117     return consumers;
118   }
119 
GetEnergyConsumedperfetto::AndroidPowerDataSource::DynamicLibLoader120   std::vector<android_internal::EnergyEstimationBreakdown> GetEnergyConsumed() {
121     if (!get_energy_consumed_)
122       return std::vector<android_internal::EnergyEstimationBreakdown>();
123 
124     std::vector<android_internal::EnergyEstimationBreakdown> energy_breakdown(
125         kMaxNumPowerEntities);
126     size_t num_power_entities = energy_breakdown.size();
127     if (!get_energy_consumed_(&energy_breakdown[0], &num_power_entities)) {
128       PERFETTO_ELOG("Failed to retrieve energy estimation breakdown.");
129       num_power_entities = 0;
130     }
131     energy_breakdown.resize(num_power_entities);
132     return energy_breakdown;
133   }
134 };
135 
AndroidPowerDataSource(DataSourceConfig cfg,base::TaskRunner * task_runner,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)136 AndroidPowerDataSource::AndroidPowerDataSource(
137     DataSourceConfig cfg,
138     base::TaskRunner* task_runner,
139     TracingSessionID session_id,
140     std::unique_ptr<TraceWriter> writer)
141     : ProbesDataSource(session_id, &descriptor),
142       task_runner_(task_runner),
143       rail_descriptors_logged_(false),
144       energy_consumer_loggged_(false),
145       writer_(std::move(writer)),
146       weak_factory_(this) {
147   using protos::pbzero::AndroidPowerConfig;
148   AndroidPowerConfig::Decoder pcfg(cfg.android_power_config_raw());
149   poll_interval_ms_ = pcfg.battery_poll_ms();
150   rails_collection_enabled_ = pcfg.collect_power_rails();
151   energy_breakdown_collection_enabled_ =
152       pcfg.collect_energy_estimation_breakdown();
153 
154   if (poll_interval_ms_ == 0)
155     poll_interval_ms_ = kDefaultPollIntervalMs;
156 
157   if (poll_interval_ms_ < kMinPollIntervalMs) {
158     PERFETTO_ELOG("Battery poll interval of %" PRIu32
159                   " ms is too low. Capping to %" PRIu32 " ms",
160                   poll_interval_ms_, kMinPollIntervalMs);
161     poll_interval_ms_ = kMinPollIntervalMs;
162   }
163   for (auto counter = pcfg.battery_counters(); counter; ++counter) {
164     auto hal_id = android_internal::BatteryCounter::kUnspecified;
165     switch (*counter) {
166       case AndroidPowerConfig::BATTERY_COUNTER_UNSPECIFIED:
167         break;
168       case AndroidPowerConfig::BATTERY_COUNTER_CHARGE:
169         hal_id = android_internal::BatteryCounter::kCharge;
170         break;
171       case AndroidPowerConfig::BATTERY_COUNTER_CAPACITY_PERCENT:
172         hal_id = android_internal::BatteryCounter::kCapacityPercent;
173         break;
174       case AndroidPowerConfig::BATTERY_COUNTER_CURRENT:
175         hal_id = android_internal::BatteryCounter::kCurrent;
176         break;
177       case AndroidPowerConfig::BATTERY_COUNTER_CURRENT_AVG:
178         hal_id = android_internal::BatteryCounter::kCurrentAvg;
179         break;
180     }
181     PERFETTO_CHECK(static_cast<size_t>(hal_id) < counters_enabled_.size());
182     counters_enabled_.set(static_cast<size_t>(hal_id));
183   }
184 }
185 
186 AndroidPowerDataSource::~AndroidPowerDataSource() = default;
187 
Start()188 void AndroidPowerDataSource::Start() {
189   lib_.reset(new DynamicLibLoader());
190   Tick();
191 }
192 
Tick()193 void AndroidPowerDataSource::Tick() {
194   // Post next task.
195   auto now_ms = base::GetWallTimeMs().count();
196   auto weak_this = weak_factory_.GetWeakPtr();
197   task_runner_->PostDelayedTask(
198       [weak_this] {
199         if (weak_this)
200           weak_this->Tick();
201       },
202       poll_interval_ms_ - static_cast<uint32_t>(now_ms % poll_interval_ms_));
203 
204   WriteBatteryCounters();
205   WritePowerRailsData();
206   WriteEnergyEstimationBreakdown();
207 }
208 
WriteBatteryCounters()209 void AndroidPowerDataSource::WriteBatteryCounters() {
210   if (counters_enabled_.none())
211     return;
212 
213   auto packet = writer_->NewTracePacket();
214   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
215   auto* counters_proto = packet->set_battery();
216 
217   for (size_t i = 0; i < counters_enabled_.size(); i++) {
218     if (!counters_enabled_.test(i))
219       continue;
220     auto counter = static_cast<android_internal::BatteryCounter>(i);
221     auto value = lib_->GetCounter(counter);
222     if (!value.has_value())
223       continue;
224 
225     switch (counter) {
226       case android_internal::BatteryCounter::kUnspecified:
227         PERFETTO_DFATAL("Unspecified counter");
228         break;
229 
230       case android_internal::BatteryCounter::kCharge:
231         counters_proto->set_charge_counter_uah(*value);
232         break;
233 
234       case android_internal::BatteryCounter::kCapacityPercent:
235         counters_proto->set_capacity_percent(static_cast<float>(*value));
236         break;
237 
238       case android_internal::BatteryCounter::kCurrent:
239         counters_proto->set_current_ua(*value);
240         break;
241 
242       case android_internal::BatteryCounter::kCurrentAvg:
243         counters_proto->set_current_avg_ua(*value);
244         break;
245     }
246   }
247 }
248 
WritePowerRailsData()249 void AndroidPowerDataSource::WritePowerRailsData() {
250   if (!rails_collection_enabled_)
251     return;
252 
253   auto packet = writer_->NewTracePacket();
254   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
255   auto* rails_proto = packet->set_power_rails();
256 
257   if (!rail_descriptors_logged_) {
258     // We only add the rail descriptors to the first package, to avoid logging
259     // all rail names etc. on each one.
260     rail_descriptors_logged_ = true;
261     auto rail_descriptors = lib_->GetRailDescriptors();
262     if (rail_descriptors.empty()) {
263       // No rails to collect data for. Don't try again in the next iteration.
264       rails_collection_enabled_ = false;
265       return;
266     }
267 
268     for (const auto& rail_descriptor : rail_descriptors) {
269       auto* rail_desc_proto = rails_proto->add_rail_descriptor();
270       rail_desc_proto->set_index(rail_descriptor.index);
271       rail_desc_proto->set_rail_name(rail_descriptor.rail_name);
272       rail_desc_proto->set_subsys_name(rail_descriptor.subsys_name);
273       rail_desc_proto->set_sampling_rate(rail_descriptor.sampling_rate);
274     }
275   }
276 
277   for (const auto& energy_data : lib_->GetRailEnergyData()) {
278     auto* data = rails_proto->add_energy_data();
279     data->set_index(energy_data.index);
280     data->set_timestamp_ms(energy_data.timestamp);
281     data->set_energy(energy_data.energy);
282   }
283 }
284 
WriteEnergyEstimationBreakdown()285 void AndroidPowerDataSource::WriteEnergyEstimationBreakdown() {
286   if (!energy_breakdown_collection_enabled_)
287     return;
288   auto timestamp = static_cast<uint64_t>(base::GetBootTimeNs().count());
289 
290   TraceWriter::TracePacketHandle packet;
291   protos::pbzero::AndroidEnergyEstimationBreakdown* energy_estimation_proto =
292       nullptr;
293 
294   if (!energy_consumer_loggged_) {
295     energy_consumer_loggged_ = true;
296     packet = writer_->NewTracePacket();
297     energy_estimation_proto = packet->set_android_energy_estimation_breakdown();
298     auto* descriptor_proto =
299         energy_estimation_proto->set_energy_consumer_descriptor();
300     auto consumers = lib_->GetEnergyConsumerInfo();
301     for (const auto& consumer : consumers) {
302       auto* desc_proto = descriptor_proto->add_energy_consumers();
303       desc_proto->set_energy_consumer_id(consumer.energy_consumer_id);
304       desc_proto->set_ordinal(consumer.ordinal);
305       desc_proto->set_type(consumer.type);
306       desc_proto->set_name(consumer.name);
307     }
308   }
309 
310   auto energy_breakdowns = lib_->GetEnergyConsumed();
311   for (const auto& breakdown : energy_breakdowns) {
312     if (breakdown.uid == android_internal::ALL_UIDS_FOR_CONSUMER) {
313       // Finalize packet before calling NewTracePacket.
314       if (packet) {
315         packet->Finalize();
316       }
317       packet = writer_->NewTracePacket();
318       packet->set_timestamp(timestamp);
319       energy_estimation_proto =
320           packet->set_android_energy_estimation_breakdown();
321       energy_estimation_proto->set_energy_consumer_id(
322           breakdown.energy_consumer_id);
323       energy_estimation_proto->set_energy_uws(breakdown.energy_uws);
324     } else {
325       PERFETTO_CHECK(energy_estimation_proto != nullptr);
326       auto* uid_breakdown_proto =
327           energy_estimation_proto->add_per_uid_breakdown();
328       uid_breakdown_proto->set_uid(breakdown.uid);
329       uid_breakdown_proto->set_energy_uws(breakdown.energy_uws);
330     }
331   }
332 }
333 
Flush(FlushRequestID,std::function<void ()> callback)334 void AndroidPowerDataSource::Flush(FlushRequestID,
335                                    std::function<void()> callback) {
336   writer_->Flush(callback);
337 }
338 
339 }  // namespace perfetto
340