• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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/linux_power_sysfs_data_source.h"
18 
19 #include <dirent.h>
20 #include <sys/types.h>
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/file_utils.h"
26 #include "perfetto/ext/base/optional.h"
27 #include "perfetto/ext/base/scoped_file.h"
28 #include "perfetto/ext/base/string_utils.h"
29 #include "perfetto/ext/tracing/core/trace_packet.h"
30 #include "perfetto/ext/tracing/core/trace_writer.h"
31 #include "perfetto/tracing/core/data_source_config.h"
32 
33 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
34 #include "protos/perfetto/trace/trace_packet.pbzero.h"
35 
36 namespace perfetto {
37 
38 namespace {
39 constexpr uint32_t kDefaultPollIntervalMs = 1000;
40 
ReadFileAsInt64(std::string path)41 base::Optional<int64_t> ReadFileAsInt64(std::string path) {
42   std::string buf;
43   if (!base::ReadFile(path, &buf))
44     return base::nullopt;
45   return base::StringToInt64(base::StripSuffix(buf, "\n"));
46 }
47 }  // namespace
48 
BatteryInfo(const char * power_supply_dir_path)49 LinuxPowerSysfsDataSource::BatteryInfo::BatteryInfo(
50     const char* power_supply_dir_path) {
51   base::ScopedDir power_supply_dir(opendir(power_supply_dir_path));
52   if (!power_supply_dir)
53     return;
54 
55   for (auto* ent = readdir(power_supply_dir.get()); ent;
56        ent = readdir(power_supply_dir.get())) {
57     if (ent->d_name[0] == '.')
58       continue;
59     std::string dir_name =
60         std::string(power_supply_dir_path) + "/" + ent->d_name;
61     std::string buf;
62     if (!base::ReadFile(dir_name + "/type", &buf) ||
63         base::StripSuffix(buf, "\n") != "Battery")
64       continue;
65     buf.clear();
66     if (!base::ReadFile(dir_name + "/present", &buf) ||
67         base::StripSuffix(buf, "\n") != "1")
68       continue;
69     sysfs_battery_dirs_.push_back(dir_name);
70   }
71 }
72 LinuxPowerSysfsDataSource::BatteryInfo::~BatteryInfo() = default;
73 
num_batteries() const74 size_t LinuxPowerSysfsDataSource::BatteryInfo::num_batteries() const {
75   return sysfs_battery_dirs_.size();
76 }
77 
78 base::Optional<int64_t>
GetChargeCounterUah(size_t battery_idx)79 LinuxPowerSysfsDataSource::BatteryInfo::GetChargeCounterUah(
80     size_t battery_idx) {
81   PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
82   return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/charge_now");
83 }
84 
85 base::Optional<int64_t>
GetCapacityPercent(size_t battery_idx)86 LinuxPowerSysfsDataSource::BatteryInfo::GetCapacityPercent(size_t battery_idx) {
87   PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
88   return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/capacity");
89 }
90 
GetCurrentNowUa(size_t battery_idx)91 base::Optional<int64_t> LinuxPowerSysfsDataSource::BatteryInfo::GetCurrentNowUa(
92     size_t battery_idx) {
93   PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
94   return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/current_now");
95 }
96 
97 base::Optional<int64_t>
GetAverageCurrentUa(size_t battery_idx)98 LinuxPowerSysfsDataSource::BatteryInfo::GetAverageCurrentUa(
99     size_t battery_idx) {
100   PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
101   return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/current_avg");
102 }
103 
104 // static
105 const ProbesDataSource::Descriptor LinuxPowerSysfsDataSource::descriptor = {
106     /*name*/ "linux.sysfs_power",
107     /*flags*/ Descriptor::kFlagsNone,
108     /*fill_descriptor_func*/ nullptr,
109 };
110 
LinuxPowerSysfsDataSource(DataSourceConfig cfg,base::TaskRunner * task_runner,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)111 LinuxPowerSysfsDataSource::LinuxPowerSysfsDataSource(
112     DataSourceConfig cfg,
113     base::TaskRunner* task_runner,
114     TracingSessionID session_id,
115     std::unique_ptr<TraceWriter> writer)
116     : ProbesDataSource(session_id, &descriptor),
117       poll_interval_ms_(kDefaultPollIntervalMs),
118       task_runner_(task_runner),
119       writer_(std::move(writer)),
120       weak_factory_(this) {
121   base::ignore_result(cfg);  // The data source doesn't need any config yet.
122 }
123 
124 LinuxPowerSysfsDataSource::~LinuxPowerSysfsDataSource() = default;
125 
Start()126 void LinuxPowerSysfsDataSource::Start() {
127   battery_info_.reset(new BatteryInfo());
128   Tick();
129 }
130 
Tick()131 void LinuxPowerSysfsDataSource::Tick() {
132   // Post next task.
133   auto now_ms = base::GetWallTimeMs().count();
134   auto weak_this = weak_factory_.GetWeakPtr();
135   task_runner_->PostDelayedTask(
136       [weak_this] {
137         if (weak_this)
138           weak_this->Tick();
139       },
140       poll_interval_ms_ - static_cast<uint32_t>(now_ms % poll_interval_ms_));
141 
142   WriteBatteryCounters();
143 }
144 
WriteBatteryCounters()145 void LinuxPowerSysfsDataSource::WriteBatteryCounters() {
146   auto packet = writer_->NewTracePacket();
147   packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
148 
149   // Query battery counters from sysfs. Report the battery counters for each
150   // battery.
151   for (size_t battery_idx = 0; battery_idx < battery_info_->num_batteries();
152        battery_idx++) {
153     auto* counters_proto = packet->set_battery();
154     auto value = battery_info_->GetChargeCounterUah(battery_idx);
155     if (value)
156       counters_proto->set_charge_counter_uah(*value);
157     value = battery_info_->GetCapacityPercent(battery_idx);
158     if (value)
159       counters_proto->set_capacity_percent(static_cast<float>(*value));
160     value = battery_info_->GetCurrentNowUa(battery_idx);
161     if (value)
162       counters_proto->set_current_ua(*value);
163     value = battery_info_->GetAverageCurrentUa(battery_idx);
164     if (value)
165       counters_proto->set_current_ua(*value);
166   }
167 }
168 
Flush(FlushRequestID,std::function<void ()> callback)169 void LinuxPowerSysfsDataSource::Flush(FlushRequestID,
170                                       std::function<void()> callback) {
171   writer_->Flush(callback);
172 }
173 
174 }  // namespace perfetto
175