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