• 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_hal.h"
32 
33 #include "protos/perfetto/config/power/android_power_config.pbzero.h"
34 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
35 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
36 #include "protos/perfetto/trace/trace_packet.pbzero.h"
37 
38 namespace perfetto {
39 
40 namespace {
41 constexpr uint32_t kMinPollIntervalMs = 100;
42 constexpr size_t kMaxNumRails = 32;
43 }  // namespace
44 
45 // static
46 const ProbesDataSource::Descriptor AndroidPowerDataSource::descriptor = {
47     /*name*/ "android.power",
48     /*flags*/ Descriptor::kFlagsNone,
49 };
50 
51 // Dynamically loads the libperfetto_android_internal.so library which
52 // allows to proxy calls to android hwbinder in in-tree builds.
53 struct AndroidPowerDataSource::DynamicLibLoader {
54   PERFETTO_LAZY_LOAD(android_internal::GetBatteryCounter, get_battery_counter_);
55   PERFETTO_LAZY_LOAD(android_internal::GetAvailableRails, get_available_rails_);
56   PERFETTO_LAZY_LOAD(android_internal::GetRailEnergyData,
57                      get_rail_energy_data_);
58 
GetCounterperfetto::AndroidPowerDataSource::DynamicLibLoader59   base::Optional<int64_t> GetCounter(android_internal::BatteryCounter counter) {
60     if (!get_battery_counter_)
61       return base::nullopt;
62     int64_t value = 0;
63     if (get_battery_counter_(counter, &value))
64       return base::make_optional(value);
65     return base::nullopt;
66   }
67 
GetRailDescriptorsperfetto::AndroidPowerDataSource::DynamicLibLoader68   std::vector<android_internal::RailDescriptor> GetRailDescriptors() {
69     if (!get_available_rails_)
70       return std::vector<android_internal::RailDescriptor>();
71 
72     std::vector<android_internal::RailDescriptor> rail_descriptors(
73         kMaxNumRails);
74     size_t num_rails = rail_descriptors.size();
75     get_available_rails_(&rail_descriptors[0], &num_rails);
76     rail_descriptors.resize(num_rails);
77     return rail_descriptors;
78   }
79 
GetRailEnergyDataperfetto::AndroidPowerDataSource::DynamicLibLoader80   std::vector<android_internal::RailEnergyData> GetRailEnergyData() {
81     if (!get_rail_energy_data_)
82       return std::vector<android_internal::RailEnergyData>();
83 
84     std::vector<android_internal::RailEnergyData> energy_data(kMaxNumRails);
85     size_t num_rails = energy_data.size();
86     get_rail_energy_data_(&energy_data[0], &num_rails);
87     energy_data.resize(num_rails);
88     return energy_data;
89   }
90 };
91 
AndroidPowerDataSource(DataSourceConfig cfg,base::TaskRunner * task_runner,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)92 AndroidPowerDataSource::AndroidPowerDataSource(
93     DataSourceConfig cfg,
94     base::TaskRunner* task_runner,
95     TracingSessionID session_id,
96     std::unique_ptr<TraceWriter> writer)
97     : ProbesDataSource(session_id, &descriptor),
98       task_runner_(task_runner),
99       rail_descriptors_logged_(false),
100       writer_(std::move(writer)),
101       weak_factory_(this) {
102   using protos::pbzero::AndroidPowerConfig;
103   AndroidPowerConfig::Decoder pcfg(cfg.android_power_config_raw());
104   poll_interval_ms_ = pcfg.battery_poll_ms();
105   rails_collection_enabled_ = pcfg.collect_power_rails();
106 
107   if (poll_interval_ms_ < kMinPollIntervalMs) {
108     PERFETTO_ELOG("Battery poll interval of %" PRIu32
109                   " ms is too low. Capping to %" PRIu32 " ms",
110                   poll_interval_ms_, kMinPollIntervalMs);
111     poll_interval_ms_ = kMinPollIntervalMs;
112   }
113   for (auto counter = pcfg.battery_counters(); counter; ++counter) {
114     auto hal_id = android_internal::BatteryCounter::kUnspecified;
115     switch (*counter) {
116       case AndroidPowerConfig::BATTERY_COUNTER_UNSPECIFIED:
117         break;
118       case AndroidPowerConfig::BATTERY_COUNTER_CHARGE:
119         hal_id = android_internal::BatteryCounter::kCharge;
120         break;
121       case AndroidPowerConfig::BATTERY_COUNTER_CAPACITY_PERCENT:
122         hal_id = android_internal::BatteryCounter::kCapacityPercent;
123         break;
124       case AndroidPowerConfig::BATTERY_COUNTER_CURRENT:
125         hal_id = android_internal::BatteryCounter::kCurrent;
126         break;
127       case AndroidPowerConfig::BATTERY_COUNTER_CURRENT_AVG:
128         hal_id = android_internal::BatteryCounter::kCurrentAvg;
129         break;
130     }
131     PERFETTO_CHECK(static_cast<size_t>(hal_id) < counters_enabled_.size());
132     counters_enabled_.set(static_cast<size_t>(hal_id));
133   }
134 }
135 
136 AndroidPowerDataSource::~AndroidPowerDataSource() = default;
137 
Start()138 void AndroidPowerDataSource::Start() {
139   lib_.reset(new DynamicLibLoader());
140   Tick();
141 }
142 
Tick()143 void AndroidPowerDataSource::Tick() {
144   // Post next task.
145   auto now_ms = base::GetWallTimeMs().count();
146   auto weak_this = weak_factory_.GetWeakPtr();
147   task_runner_->PostDelayedTask(
148       [weak_this] {
149         if (weak_this)
150           weak_this->Tick();
151       },
152       poll_interval_ms_ - (now_ms % poll_interval_ms_));
153 
154   WriteBatteryCounters();
155   WritePowerRailsData();
156 }
157 
WriteBatteryCounters()158 void AndroidPowerDataSource::WriteBatteryCounters() {
159   if (counters_enabled_.none())
160     return;
161 
162   auto packet = writer_->NewTracePacket();
163   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
164   auto* counters_proto = packet->set_battery();
165 
166   for (size_t i = 0; i < counters_enabled_.size(); i++) {
167     if (!counters_enabled_.test(i))
168       continue;
169     auto counter = static_cast<android_internal::BatteryCounter>(i);
170     auto value = lib_->GetCounter(counter);
171     if (!value.has_value())
172       continue;
173 
174     switch (counter) {
175       case android_internal::BatteryCounter::kUnspecified:
176         PERFETTO_DFATAL("Unspecified counter");
177         break;
178 
179       case android_internal::BatteryCounter::kCharge:
180         counters_proto->set_charge_counter_uah(*value);
181         break;
182 
183       case android_internal::BatteryCounter::kCapacityPercent:
184         counters_proto->set_capacity_percent(static_cast<float>(*value));
185         break;
186 
187       case android_internal::BatteryCounter::kCurrent:
188         counters_proto->set_current_ua(*value);
189         break;
190 
191       case android_internal::BatteryCounter::kCurrentAvg:
192         counters_proto->set_current_avg_ua(*value);
193         break;
194     }
195   }
196 }
197 
WritePowerRailsData()198 void AndroidPowerDataSource::WritePowerRailsData() {
199   if (!rails_collection_enabled_)
200     return;
201 
202   auto packet = writer_->NewTracePacket();
203   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
204   auto* rails_proto = packet->set_power_rails();
205 
206   if (!rail_descriptors_logged_) {
207     // We only add the rail descriptors to the first package, to avoid logging
208     // all rail names etc. on each one.
209     rail_descriptors_logged_ = true;
210     auto rail_descriptors = lib_->GetRailDescriptors();
211     if (rail_descriptors.size() == 0) {
212       // No rails to collect data for. Don't try again in the next iteration.
213       rails_collection_enabled_ = false;
214       return;
215     }
216 
217     for (const auto& rail_descriptor : rail_descriptors) {
218       auto* rail_desc_proto = rails_proto->add_rail_descriptor();
219       rail_desc_proto->set_index(rail_descriptor.index);
220       rail_desc_proto->set_rail_name(rail_descriptor.rail_name);
221       rail_desc_proto->set_subsys_name(rail_descriptor.subsys_name);
222       rail_desc_proto->set_sampling_rate(rail_descriptor.sampling_rate);
223     }
224   }
225 
226   for (const auto& energy_data : lib_->GetRailEnergyData()) {
227     auto* data = rails_proto->add_energy_data();
228     data->set_index(energy_data.index);
229     data->set_timestamp_ms(energy_data.timestamp);
230     data->set_energy(energy_data.energy);
231   }
232 }
233 
Flush(FlushRequestID,std::function<void ()> callback)234 void AndroidPowerDataSource::Flush(FlushRequestID,
235                                    std::function<void()> callback) {
236   writer_->Flush(callback);
237 }
238 
239 }  // namespace perfetto
240