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