Home | History | Annotate | Download | only in power
      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 
     50   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 
     80   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 
     89   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 
    101   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 
    112   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 
    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 
    166 void AndroidPowerDataSource::Start() {
    167   lib_.reset(new DynamicLibLoader());
    168   if (!lib_->is_loaded())
    169     return;
    170   Tick();
    171 }
    172 
    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 
    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 
    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 
    264 void AndroidPowerDataSource::Flush(FlushRequestID,
    265                                    std::function<void()> callback) {
    266   writer_->Flush(callback);
    267 }
    268 
    269 }  // namespace perfetto
    270