• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::kHandlesIncrementalState,
54     /*fill_descriptor_func*/ nullptr,
55 };
56 
57 // Dynamically loads the libperfetto_android_internal.so library which
58 // allows to proxy calls to android hwbinder in in-tree builds.
59 struct AndroidPowerDataSource::DynamicLibLoader {
60   PERFETTO_LAZY_LOAD(android_internal::GetBatteryCounter, get_battery_counter_);
61   PERFETTO_LAZY_LOAD(android_internal::GetAvailableRails, get_available_rails_);
62   PERFETTO_LAZY_LOAD(android_internal::GetRailEnergyData,
63                      get_rail_energy_data_);
64   PERFETTO_LAZY_LOAD(android_internal::GetEnergyConsumerInfo,
65                      get_energy_consumer_info_);
66   PERFETTO_LAZY_LOAD(android_internal::GetEnergyConsumed, get_energy_consumed_);
67 
GetCounterperfetto::AndroidPowerDataSource::DynamicLibLoader68   base::Optional<int64_t> GetCounter(android_internal::BatteryCounter counter) {
69     if (!get_battery_counter_)
70       return base::nullopt;
71     int64_t value = 0;
72     if (get_battery_counter_(counter, &value))
73       return base::make_optional(value);
74     return base::nullopt;
75   }
76 
GetRailDescriptorsperfetto::AndroidPowerDataSource::DynamicLibLoader77   std::vector<android_internal::RailDescriptor> GetRailDescriptors() {
78     if (!get_available_rails_)
79       return std::vector<android_internal::RailDescriptor>();
80 
81     std::vector<android_internal::RailDescriptor> rail_descriptors(
82         kMaxNumRails);
83     size_t num_rails = rail_descriptors.size();
84     if (!get_available_rails_(&rail_descriptors[0], &num_rails)) {
85       PERFETTO_ELOG("Failed to retrieve rail descriptors.");
86       num_rails = 0;
87     }
88     rail_descriptors.resize(num_rails);
89     return rail_descriptors;
90   }
91 
GetRailEnergyDataperfetto::AndroidPowerDataSource::DynamicLibLoader92   std::vector<android_internal::RailEnergyData> GetRailEnergyData() {
93     if (!get_rail_energy_data_)
94       return std::vector<android_internal::RailEnergyData>();
95 
96     std::vector<android_internal::RailEnergyData> energy_data(kMaxNumRails);
97     size_t num_rails = energy_data.size();
98     if (!get_rail_energy_data_(&energy_data[0], &num_rails)) {
99       PERFETTO_ELOG("Failed to retrieve rail energy data.");
100       num_rails = 0;
101     }
102     energy_data.resize(num_rails);
103     return energy_data;
104   }
105 
GetEnergyConsumerInfoperfetto::AndroidPowerDataSource::DynamicLibLoader106   std::vector<android_internal::EnergyConsumerInfo> GetEnergyConsumerInfo() {
107     if (!get_energy_consumer_info_)
108       return std::vector<android_internal::EnergyConsumerInfo>();
109 
110     std::vector<android_internal::EnergyConsumerInfo> consumers(
111         kMaxNumEnergyConsumer);
112     size_t num_power_entities = consumers.size();
113     if (!get_energy_consumer_info_(&consumers[0], &num_power_entities)) {
114       PERFETTO_ELOG("Failed to retrieve energy consumer info.");
115       num_power_entities = 0;
116     }
117     consumers.resize(num_power_entities);
118     return consumers;
119   }
120 
GetEnergyConsumedperfetto::AndroidPowerDataSource::DynamicLibLoader121   std::vector<android_internal::EnergyEstimationBreakdown> GetEnergyConsumed() {
122     if (!get_energy_consumed_)
123       return std::vector<android_internal::EnergyEstimationBreakdown>();
124 
125     std::vector<android_internal::EnergyEstimationBreakdown> energy_breakdown(
126         kMaxNumPowerEntities);
127     size_t num_power_entities = energy_breakdown.size();
128     if (!get_energy_consumed_(&energy_breakdown[0], &num_power_entities)) {
129       PERFETTO_ELOG("Failed to retrieve energy estimation breakdown.");
130       num_power_entities = 0;
131     }
132     energy_breakdown.resize(num_power_entities);
133     return energy_breakdown;
134   }
135 };
136 
AndroidPowerDataSource(DataSourceConfig cfg,base::TaskRunner * task_runner,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)137 AndroidPowerDataSource::AndroidPowerDataSource(
138     DataSourceConfig cfg,
139     base::TaskRunner* task_runner,
140     TracingSessionID session_id,
141     std::unique_ptr<TraceWriter> writer)
142     : ProbesDataSource(session_id, &descriptor),
143       task_runner_(task_runner),
144       writer_(std::move(writer)),
145       weak_factory_(this) {
146   using protos::pbzero::AndroidPowerConfig;
147   AndroidPowerConfig::Decoder pcfg(cfg.android_power_config_raw());
148   poll_interval_ms_ = pcfg.battery_poll_ms();
149   rails_collection_enabled_ = pcfg.collect_power_rails();
150   energy_breakdown_collection_enabled_ =
151       pcfg.collect_energy_estimation_breakdown();
152 
153   if (poll_interval_ms_ == 0)
154     poll_interval_ms_ = kDefaultPollIntervalMs;
155 
156   if (poll_interval_ms_ < kMinPollIntervalMs) {
157     PERFETTO_ELOG("Battery poll interval of %" PRIu32
158                   " ms is too low. Capping to %" PRIu32 " ms",
159                   poll_interval_ms_, kMinPollIntervalMs);
160     poll_interval_ms_ = kMinPollIntervalMs;
161   }
162   for (auto counter = pcfg.battery_counters(); counter; ++counter) {
163     auto hal_id = android_internal::BatteryCounter::kUnspecified;
164     switch (*counter) {
165       case AndroidPowerConfig::BATTERY_COUNTER_UNSPECIFIED:
166         break;
167       case AndroidPowerConfig::BATTERY_COUNTER_CHARGE:
168         hal_id = android_internal::BatteryCounter::kCharge;
169         break;
170       case AndroidPowerConfig::BATTERY_COUNTER_CAPACITY_PERCENT:
171         hal_id = android_internal::BatteryCounter::kCapacityPercent;
172         break;
173       case AndroidPowerConfig::BATTERY_COUNTER_CURRENT:
174         hal_id = android_internal::BatteryCounter::kCurrent;
175         break;
176       case AndroidPowerConfig::BATTERY_COUNTER_CURRENT_AVG:
177         hal_id = android_internal::BatteryCounter::kCurrentAvg;
178         break;
179     }
180     PERFETTO_CHECK(static_cast<size_t>(hal_id) < counters_enabled_.size());
181     counters_enabled_.set(static_cast<size_t>(hal_id));
182   }
183 }
184 
185 AndroidPowerDataSource::~AndroidPowerDataSource() = default;
186 
Start()187 void AndroidPowerDataSource::Start() {
188   lib_.reset(new DynamicLibLoader());
189   Tick();
190 }
191 
Tick()192 void AndroidPowerDataSource::Tick() {
193   // Post next task.
194   auto now_ms = base::GetWallTimeMs().count();
195   auto weak_this = weak_factory_.GetWeakPtr();
196   task_runner_->PostDelayedTask(
197       [weak_this] {
198         if (weak_this)
199           weak_this->Tick();
200       },
201       poll_interval_ms_ - static_cast<uint32_t>(now_ms % poll_interval_ms_));
202 
203   if (should_emit_descriptors_) {
204     // We write incremental state cleared in its own packet to avoid the subtle
205     // code we'd need if we were to set this on the first enabled data source.
206     auto packet = writer_->NewTracePacket();
207     packet->set_sequence_flags(
208         protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
209   }
210 
211   WriteBatteryCounters();
212   WritePowerRailsData();
213   WriteEnergyEstimationBreakdown();
214 
215   should_emit_descriptors_ = false;
216 }
217 
WriteBatteryCounters()218 void AndroidPowerDataSource::WriteBatteryCounters() {
219   if (counters_enabled_.none())
220     return;
221 
222   auto packet = writer_->NewTracePacket();
223   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
224   auto* counters_proto = packet->set_battery();
225 
226   for (size_t i = 0; i < counters_enabled_.size(); i++) {
227     if (!counters_enabled_.test(i))
228       continue;
229     auto counter = static_cast<android_internal::BatteryCounter>(i);
230     auto value = lib_->GetCounter(counter);
231     if (!value.has_value())
232       continue;
233 
234     switch (counter) {
235       case android_internal::BatteryCounter::kUnspecified:
236         PERFETTO_DFATAL("Unspecified counter");
237         break;
238 
239       case android_internal::BatteryCounter::kCharge:
240         counters_proto->set_charge_counter_uah(*value);
241         break;
242 
243       case android_internal::BatteryCounter::kCapacityPercent:
244         counters_proto->set_capacity_percent(static_cast<float>(*value));
245         break;
246 
247       case android_internal::BatteryCounter::kCurrent:
248         counters_proto->set_current_ua(*value);
249         break;
250 
251       case android_internal::BatteryCounter::kCurrentAvg:
252         counters_proto->set_current_avg_ua(*value);
253         break;
254     }
255   }
256 }
257 
WritePowerRailsData()258 void AndroidPowerDataSource::WritePowerRailsData() {
259   if (!rails_collection_enabled_)
260     return;
261 
262   auto packet = writer_->NewTracePacket();
263   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
264   packet->set_sequence_flags(
265       protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
266 
267   auto* rails_proto = packet->set_power_rails();
268   if (should_emit_descriptors_) {
269     auto rail_descriptors = lib_->GetRailDescriptors();
270     if (rail_descriptors.empty()) {
271       // No rails to collect data for. Don't try again.
272       rails_collection_enabled_ = false;
273       return;
274     }
275 
276     for (const auto& rail_descriptor : rail_descriptors) {
277       auto* rail_desc_proto = rails_proto->add_rail_descriptor();
278       rail_desc_proto->set_index(rail_descriptor.index);
279       rail_desc_proto->set_rail_name(rail_descriptor.rail_name);
280       rail_desc_proto->set_subsys_name(rail_descriptor.subsys_name);
281       rail_desc_proto->set_sampling_rate(rail_descriptor.sampling_rate);
282     }
283   }
284 
285   for (const auto& energy_data : lib_->GetRailEnergyData()) {
286     auto* data = rails_proto->add_energy_data();
287     data->set_index(energy_data.index);
288     data->set_timestamp_ms(energy_data.timestamp);
289     data->set_energy(energy_data.energy);
290   }
291 }
292 
WriteEnergyEstimationBreakdown()293 void AndroidPowerDataSource::WriteEnergyEstimationBreakdown() {
294   if (!energy_breakdown_collection_enabled_)
295     return;
296   auto timestamp = static_cast<uint64_t>(base::GetBootTimeNs().count());
297 
298   TraceWriter::TracePacketHandle packet;
299   protos::pbzero::AndroidEnergyEstimationBreakdown* energy_estimation_proto =
300       nullptr;
301 
302   if (should_emit_descriptors_) {
303     packet = writer_->NewTracePacket();
304     energy_estimation_proto = packet->set_android_energy_estimation_breakdown();
305     auto* descriptor_proto =
306         energy_estimation_proto->set_energy_consumer_descriptor();
307     auto consumers = lib_->GetEnergyConsumerInfo();
308     for (const auto& consumer : consumers) {
309       auto* desc_proto = descriptor_proto->add_energy_consumers();
310       desc_proto->set_energy_consumer_id(consumer.energy_consumer_id);
311       desc_proto->set_ordinal(consumer.ordinal);
312       desc_proto->set_type(consumer.type);
313       desc_proto->set_name(consumer.name);
314     }
315   }
316 
317   auto energy_breakdowns = lib_->GetEnergyConsumed();
318   for (const auto& breakdown : energy_breakdowns) {
319     if (breakdown.uid == android_internal::ALL_UIDS_FOR_CONSUMER) {
320       // Finalize packet before calling NewTracePacket.
321       if (packet) {
322         packet->Finalize();
323       }
324       packet = writer_->NewTracePacket();
325       packet->set_timestamp(timestamp);
326       packet->set_sequence_flags(
327           protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
328 
329       energy_estimation_proto =
330           packet->set_android_energy_estimation_breakdown();
331       energy_estimation_proto->set_energy_consumer_id(
332           breakdown.energy_consumer_id);
333       energy_estimation_proto->set_energy_uws(breakdown.energy_uws);
334     } else {
335       PERFETTO_CHECK(energy_estimation_proto != nullptr);
336       auto* uid_breakdown_proto =
337           energy_estimation_proto->add_per_uid_breakdown();
338       uid_breakdown_proto->set_uid(breakdown.uid);
339       uid_breakdown_proto->set_energy_uws(breakdown.energy_uws);
340     }
341   }
342 }
343 
Flush(FlushRequestID,std::function<void ()> callback)344 void AndroidPowerDataSource::Flush(FlushRequestID,
345                                    std::function<void()> callback) {
346   writer_->Flush(callback);
347 }
348 
ClearIncrementalState()349 void AndroidPowerDataSource::ClearIncrementalState() {
350   should_emit_descriptors_ = true;
351 }
352 
353 }  // namespace perfetto
354