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 <optional>
20 #include <vector>
21
22 #include "perfetto/base/logging.h"
23 #include "perfetto/base/task_runner.h"
24 #include "perfetto/base/time.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/android_entity_state_residency.pbzero.h"
37 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
38 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
39 #include "protos/perfetto/trace/trace_packet.pbzero.h"
40
41 namespace perfetto {
42
43 namespace {
44 constexpr uint32_t kMinPollIntervalMs = 100;
45 constexpr uint32_t kDefaultPollIntervalMs = 1000;
46 constexpr size_t kMaxNumRails = 32;
47 constexpr size_t kMaxNumEnergyConsumer = 32;
48 constexpr size_t kMaxNumPowerEntities = 1024;
49 } // namespace
50
51 // static
52 const ProbesDataSource::Descriptor AndroidPowerDataSource::descriptor = {
53 /*name*/ "android.power",
54 /*flags*/ Descriptor::kHandlesIncrementalState,
55 /*fill_descriptor_func*/ nullptr,
56 };
57
58 // Dynamically loads the libperfetto_android_internal.so library which
59 // allows to proxy calls to android hwbinder in in-tree builds.
60 struct AndroidPowerDataSource::DynamicLibLoader {
61 PERFETTO_LAZY_LOAD(android_internal::GetBatteryCounter, get_battery_counter_);
62 PERFETTO_LAZY_LOAD(android_internal::GetAvailableRails, get_available_rails_);
63 PERFETTO_LAZY_LOAD(android_internal::GetRailEnergyData,
64 get_rail_energy_data_);
65 PERFETTO_LAZY_LOAD(android_internal::GetEnergyConsumerInfo,
66 get_energy_consumer_info_);
67 PERFETTO_LAZY_LOAD(android_internal::GetEnergyConsumed, get_energy_consumed_);
68 PERFETTO_LAZY_LOAD(android_internal::GetPowerEntityStates,
69 get_power_entity_states_);
70 PERFETTO_LAZY_LOAD(android_internal::GetPowerEntityStateResidency,
71 get_power_entity_state_residency_);
72
GetCounterperfetto::AndroidPowerDataSource::DynamicLibLoader73 std::optional<int64_t> GetCounter(android_internal::BatteryCounter counter) {
74 if (!get_battery_counter_)
75 return std::nullopt;
76 int64_t value = 0;
77 if (get_battery_counter_(counter, &value))
78 return std::make_optional(value);
79 return std::nullopt;
80 }
81
GetRailDescriptorsperfetto::AndroidPowerDataSource::DynamicLibLoader82 std::vector<android_internal::RailDescriptor> GetRailDescriptors() {
83 if (!get_available_rails_)
84 return std::vector<android_internal::RailDescriptor>();
85
86 std::vector<android_internal::RailDescriptor> rail_descriptors(
87 kMaxNumRails);
88 size_t num_rails = rail_descriptors.size();
89 if (!get_available_rails_(&rail_descriptors[0], &num_rails)) {
90 PERFETTO_ELOG("Failed to retrieve rail descriptors.");
91 num_rails = 0;
92 }
93 rail_descriptors.resize(num_rails);
94 return rail_descriptors;
95 }
96
GetRailEnergyDataperfetto::AndroidPowerDataSource::DynamicLibLoader97 std::vector<android_internal::RailEnergyData> GetRailEnergyData() {
98 if (!get_rail_energy_data_)
99 return std::vector<android_internal::RailEnergyData>();
100
101 std::vector<android_internal::RailEnergyData> energy_data(kMaxNumRails);
102 size_t num_rails = energy_data.size();
103 if (!get_rail_energy_data_(&energy_data[0], &num_rails)) {
104 PERFETTO_ELOG("Failed to retrieve rail energy data.");
105 num_rails = 0;
106 }
107 energy_data.resize(num_rails);
108 return energy_data;
109 }
110
GetEnergyConsumerInfoperfetto::AndroidPowerDataSource::DynamicLibLoader111 std::vector<android_internal::EnergyConsumerInfo> GetEnergyConsumerInfo() {
112 if (!get_energy_consumer_info_)
113 return std::vector<android_internal::EnergyConsumerInfo>();
114
115 std::vector<android_internal::EnergyConsumerInfo> consumers(
116 kMaxNumEnergyConsumer);
117 size_t num_power_entities = consumers.size();
118 if (!get_energy_consumer_info_(&consumers[0], &num_power_entities)) {
119 PERFETTO_ELOG("Failed to retrieve energy consumer info.");
120 num_power_entities = 0;
121 }
122 consumers.resize(num_power_entities);
123 return consumers;
124 }
125
GetEnergyConsumedperfetto::AndroidPowerDataSource::DynamicLibLoader126 std::vector<android_internal::EnergyEstimationBreakdown> GetEnergyConsumed() {
127 if (!get_energy_consumed_)
128 return std::vector<android_internal::EnergyEstimationBreakdown>();
129
130 std::vector<android_internal::EnergyEstimationBreakdown> energy_breakdown(
131 kMaxNumPowerEntities);
132 size_t num_power_entities = energy_breakdown.size();
133 if (!get_energy_consumed_(&energy_breakdown[0], &num_power_entities)) {
134 PERFETTO_ELOG("Failed to retrieve energy estimation breakdown.");
135 num_power_entities = 0;
136 }
137 energy_breakdown.resize(num_power_entities);
138 return energy_breakdown;
139 }
140
GetPowerEntityStatesperfetto::AndroidPowerDataSource::DynamicLibLoader141 std::vector<android_internal::PowerEntityState> GetPowerEntityStates() {
142 if (!get_power_entity_states_)
143 return std::vector<android_internal::PowerEntityState>();
144
145 std::vector<android_internal::PowerEntityState> entity(
146 kMaxNumPowerEntities);
147 size_t num_power_entities = entity.size();
148 if (!get_power_entity_states_(&entity[0], &num_power_entities)) {
149 PERFETTO_ELOG("Failed to retrieve power entities.");
150 num_power_entities = 0;
151 }
152 entity.resize(num_power_entities);
153 return entity;
154 }
155
156 std::vector<android_internal::PowerEntityStateResidency>
GetPowerEntityStateResidencyperfetto::AndroidPowerDataSource::DynamicLibLoader157 GetPowerEntityStateResidency() {
158 if (!get_power_entity_state_residency_)
159 return std::vector<android_internal::PowerEntityStateResidency>();
160
161 std::vector<android_internal::PowerEntityStateResidency> entity(
162 kMaxNumPowerEntities);
163 size_t num_power_entities = entity.size();
164 if (!get_power_entity_state_residency_(&entity[0], &num_power_entities)) {
165 PERFETTO_ELOG("Failed to retrieve power entities.");
166 num_power_entities = 0;
167 }
168 entity.resize(num_power_entities);
169 return entity;
170 }
171 };
172
AndroidPowerDataSource(DataSourceConfig cfg,base::TaskRunner * task_runner,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)173 AndroidPowerDataSource::AndroidPowerDataSource(
174 DataSourceConfig cfg,
175 base::TaskRunner* task_runner,
176 TracingSessionID session_id,
177 std::unique_ptr<TraceWriter> writer)
178 : ProbesDataSource(session_id, &descriptor),
179 task_runner_(task_runner),
180 writer_(std::move(writer)),
181 weak_factory_(this) {
182 using protos::pbzero::AndroidPowerConfig;
183 AndroidPowerConfig::Decoder pcfg(cfg.android_power_config_raw());
184 poll_interval_ms_ = pcfg.battery_poll_ms();
185 rails_collection_enabled_ = pcfg.collect_power_rails();
186 energy_breakdown_collection_enabled_ =
187 pcfg.collect_energy_estimation_breakdown();
188 entity_state_residency_collection_enabled_ =
189 pcfg.collect_entity_state_residency();
190
191 if (poll_interval_ms_ == 0)
192 poll_interval_ms_ = kDefaultPollIntervalMs;
193
194 if (poll_interval_ms_ < kMinPollIntervalMs) {
195 PERFETTO_ELOG("Battery poll interval of %" PRIu32
196 " ms is too low. Capping to %" PRIu32 " ms",
197 poll_interval_ms_, kMinPollIntervalMs);
198 poll_interval_ms_ = kMinPollIntervalMs;
199 }
200 for (auto counter = pcfg.battery_counters(); counter; ++counter) {
201 auto hal_id = android_internal::BatteryCounter::kUnspecified;
202 switch (*counter) {
203 case AndroidPowerConfig::BATTERY_COUNTER_UNSPECIFIED:
204 break;
205 case AndroidPowerConfig::BATTERY_COUNTER_CHARGE:
206 hal_id = android_internal::BatteryCounter::kCharge;
207 break;
208 case AndroidPowerConfig::BATTERY_COUNTER_CAPACITY_PERCENT:
209 hal_id = android_internal::BatteryCounter::kCapacityPercent;
210 break;
211 case AndroidPowerConfig::BATTERY_COUNTER_CURRENT:
212 hal_id = android_internal::BatteryCounter::kCurrent;
213 break;
214 case AndroidPowerConfig::BATTERY_COUNTER_CURRENT_AVG:
215 hal_id = android_internal::BatteryCounter::kCurrentAvg;
216 break;
217 case AndroidPowerConfig::BATTERY_COUNTER_VOLTAGE:
218 hal_id = android_internal::BatteryCounter::kVoltage;
219 break;
220 }
221 PERFETTO_CHECK(static_cast<size_t>(hal_id) < counters_enabled_.size());
222 counters_enabled_.set(static_cast<size_t>(hal_id));
223 }
224 }
225
226 AndroidPowerDataSource::~AndroidPowerDataSource() = default;
227
Start()228 void AndroidPowerDataSource::Start() {
229 lib_.reset(new DynamicLibLoader());
230 Tick();
231 }
232
Tick()233 void AndroidPowerDataSource::Tick() {
234 // Post next task.
235 auto now_ms = base::GetWallTimeMs().count();
236 auto weak_this = weak_factory_.GetWeakPtr();
237 task_runner_->PostDelayedTask(
238 [weak_this] {
239 if (weak_this)
240 weak_this->Tick();
241 },
242 poll_interval_ms_ - static_cast<uint32_t>(now_ms % poll_interval_ms_));
243
244 if (should_emit_descriptors_) {
245 // We write incremental state cleared in its own packet to avoid the subtle
246 // code we'd need if we were to set this on the first enabled data source.
247 auto packet = writer_->NewTracePacket();
248 packet->set_sequence_flags(
249 protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
250 }
251
252 WriteBatteryCounters();
253 WritePowerRailsData();
254 WriteEnergyEstimationBreakdown();
255 WriteEntityStateResidency();
256
257 should_emit_descriptors_ = false;
258 }
259
WriteBatteryCounters()260 void AndroidPowerDataSource::WriteBatteryCounters() {
261 if (counters_enabled_.none())
262 return;
263
264 auto packet = writer_->NewTracePacket();
265 packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
266 auto* counters_proto = packet->set_battery();
267
268 for (size_t i = 0; i < counters_enabled_.size(); i++) {
269 if (!counters_enabled_.test(i))
270 continue;
271 auto counter = static_cast<android_internal::BatteryCounter>(i);
272 auto value = lib_->GetCounter(counter);
273 if (!value.has_value())
274 continue;
275
276 switch (counter) {
277 case android_internal::BatteryCounter::kUnspecified:
278 PERFETTO_DFATAL("Unspecified counter");
279 break;
280
281 case android_internal::BatteryCounter::kCharge:
282 counters_proto->set_charge_counter_uah(*value);
283 break;
284
285 case android_internal::BatteryCounter::kCapacityPercent:
286 counters_proto->set_capacity_percent(static_cast<float>(*value));
287 break;
288
289 case android_internal::BatteryCounter::kCurrent:
290 counters_proto->set_current_ua(*value);
291 break;
292
293 case android_internal::BatteryCounter::kCurrentAvg:
294 counters_proto->set_current_avg_ua(*value);
295 break;
296
297 case android_internal::BatteryCounter::kVoltage:
298 counters_proto->set_voltage_uv(*value);
299 break;
300 }
301 }
302 }
303
WritePowerRailsData()304 void AndroidPowerDataSource::WritePowerRailsData() {
305 if (!rails_collection_enabled_)
306 return;
307
308 auto packet = writer_->NewTracePacket();
309 packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
310 packet->set_sequence_flags(
311 protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
312
313 auto* rails_proto = packet->set_power_rails();
314 if (should_emit_descriptors_) {
315 auto rail_descriptors = lib_->GetRailDescriptors();
316 if (rail_descriptors.empty()) {
317 // No rails to collect data for. Don't try again.
318 rails_collection_enabled_ = false;
319 return;
320 }
321
322 for (const auto& rail_descriptor : rail_descriptors) {
323 auto* rail_desc_proto = rails_proto->add_rail_descriptor();
324 rail_desc_proto->set_index(rail_descriptor.index);
325 rail_desc_proto->set_rail_name(rail_descriptor.rail_name);
326 rail_desc_proto->set_subsys_name(rail_descriptor.subsys_name);
327 rail_desc_proto->set_sampling_rate(rail_descriptor.sampling_rate);
328 }
329 }
330
331 for (const auto& energy_data : lib_->GetRailEnergyData()) {
332 auto* data = rails_proto->add_energy_data();
333 data->set_index(energy_data.index);
334 data->set_timestamp_ms(energy_data.timestamp);
335 data->set_energy(energy_data.energy);
336 }
337 }
338
WriteEnergyEstimationBreakdown()339 void AndroidPowerDataSource::WriteEnergyEstimationBreakdown() {
340 if (!energy_breakdown_collection_enabled_)
341 return;
342 auto timestamp = static_cast<uint64_t>(base::GetBootTimeNs().count());
343
344 TraceWriter::TracePacketHandle packet;
345 protos::pbzero::AndroidEnergyEstimationBreakdown* energy_estimation_proto =
346 nullptr;
347
348 if (should_emit_descriptors_) {
349 packet = writer_->NewTracePacket();
350 energy_estimation_proto = packet->set_android_energy_estimation_breakdown();
351 auto* descriptor_proto =
352 energy_estimation_proto->set_energy_consumer_descriptor();
353 auto consumers = lib_->GetEnergyConsumerInfo();
354 for (const auto& consumer : consumers) {
355 auto* desc_proto = descriptor_proto->add_energy_consumers();
356 desc_proto->set_energy_consumer_id(consumer.energy_consumer_id);
357 desc_proto->set_ordinal(consumer.ordinal);
358 desc_proto->set_type(consumer.type);
359 desc_proto->set_name(consumer.name);
360 }
361 }
362
363 auto energy_breakdowns = lib_->GetEnergyConsumed();
364 for (const auto& breakdown : energy_breakdowns) {
365 if (breakdown.uid == android_internal::ALL_UIDS_FOR_CONSUMER) {
366 // Finalize packet before calling NewTracePacket.
367 if (packet) {
368 packet->Finalize();
369 }
370 packet = writer_->NewTracePacket();
371 packet->set_timestamp(timestamp);
372 packet->set_sequence_flags(
373 protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
374
375 energy_estimation_proto =
376 packet->set_android_energy_estimation_breakdown();
377 energy_estimation_proto->set_energy_consumer_id(
378 breakdown.energy_consumer_id);
379 energy_estimation_proto->set_energy_uws(breakdown.energy_uws);
380 } else {
381 PERFETTO_CHECK(energy_estimation_proto != nullptr);
382 auto* uid_breakdown_proto =
383 energy_estimation_proto->add_per_uid_breakdown();
384 uid_breakdown_proto->set_uid(breakdown.uid);
385 uid_breakdown_proto->set_energy_uws(breakdown.energy_uws);
386 }
387 }
388 }
389
WriteEntityStateResidency()390 void AndroidPowerDataSource::WriteEntityStateResidency() {
391 if (!entity_state_residency_collection_enabled_)
392 return;
393
394 auto packet = writer_->NewTracePacket();
395 packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
396 packet->set_sequence_flags(
397 protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
398
399 auto* outer_proto = packet->set_entity_state_residency();
400 if (should_emit_descriptors_) {
401 auto entity_states = lib_->GetPowerEntityStates();
402 if (entity_states.empty()) {
403 // No entities to collect data for. Don't try again.
404 entity_state_residency_collection_enabled_ = false;
405 return;
406 }
407
408 for (const auto& entity_state : entity_states) {
409 auto* entity_state_proto = outer_proto->add_power_entity_state();
410 entity_state_proto->set_entity_index(entity_state.entity_id);
411 entity_state_proto->set_state_index(entity_state.state_id);
412 entity_state_proto->set_entity_name(entity_state.entity_name);
413 entity_state_proto->set_state_name(entity_state.state_name);
414 }
415 }
416
417 for (const auto& residency_data : lib_->GetPowerEntityStateResidency()) {
418 auto* data = outer_proto->add_residency();
419 data->set_entity_index(residency_data.entity_id);
420 data->set_state_index(residency_data.state_id);
421 data->set_total_time_in_state_ms(residency_data.total_time_in_state_ms);
422 data->set_total_state_entry_count(residency_data.total_state_entry_count);
423 data->set_last_entry_timestamp_ms(residency_data.last_entry_timestamp_ms);
424 }
425 }
426
Flush(FlushRequestID,std::function<void ()> callback)427 void AndroidPowerDataSource::Flush(FlushRequestID,
428 std::function<void()> callback) {
429 writer_->Flush(callback);
430 }
431
ClearIncrementalState()432 void AndroidPowerDataSource::ClearIncrementalState() {
433 should_emit_descriptors_ = true;
434 }
435
436 } // namespace perfetto
437