Merge changes I5930e6b7,I80863a68

* changes:
  Get the waker from the instants table instead of the raw table
  Populate waker_utid arg for sched_waking and sched_wakeup
diff --git a/Android.bp b/Android.bp
index 1b10e3d..e5fd4a3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8680,6 +8680,15 @@
     name: "perfetto_src_traced_probes_power_power",
     srcs: [
         "src/traced/probes/power/android_power_data_source.cc",
+        "src/traced/probes/power/linux_power_sysfs_data_source.cc",
+    ],
+}
+
+// GN: //src/traced/probes/power:unittests
+filegroup {
+    name: "perfetto_src_traced_probes_power_unittests",
+    srcs: [
+        "src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc",
     ],
 }
 
@@ -9394,6 +9403,7 @@
         ":perfetto_src_traced_probes_packages_list_packages_list_parser",
         ":perfetto_src_traced_probes_packages_list_unittests",
         ":perfetto_src_traced_probes_power_power",
+        ":perfetto_src_traced_probes_power_unittests",
         ":perfetto_src_traced_probes_probes_src",
         ":perfetto_src_traced_probes_ps_ps",
         ":perfetto_src_traced_probes_ps_unittests",
diff --git a/BUILD b/BUILD
index c818210..5ce842e 100644
--- a/BUILD
+++ b/BUILD
@@ -1633,6 +1633,8 @@
     srcs = [
         "src/traced/probes/power/android_power_data_source.cc",
         "src/traced/probes/power/android_power_data_source.h",
+        "src/traced/probes/power/linux_power_sysfs_data_source.cc",
+        "src/traced/probes/power/linux_power_sysfs_data_source.h",
     ],
 )
 
diff --git a/docs/data-sources/battery-counters.md b/docs/data-sources/battery-counters.md
index 89f6668..5cc837c 100644
--- a/docs/data-sources/battery-counters.md
+++ b/docs/data-sources/battery-counters.md
@@ -85,7 +85,7 @@
 Config proto:
 [AndroidPowerConfig](/docs/reference/trace-config-proto.autogen#AndroidPowerConfig)
 
-Sample config:
+Sample config (Android):
 
 ```protobuf
 data_sources: {
@@ -101,6 +101,16 @@
 }
 ```
 
+Sample Config (Chrome OS or Linux):
+
+```protobuf
+data_sources: {
+    config {
+        name: "linux.sysfs_power"
+    }
+}
+```
+
 ## Power rails
 
 _This data source has been introduced in Android 10 (Q) and requires the
diff --git a/protos/perfetto/config/ftrace/ftrace_config.proto b/protos/perfetto/config/ftrace/ftrace_config.proto
index 070b481..7a38d74 100644
--- a/protos/perfetto/config/ftrace/ftrace_config.proto
+++ b/protos/perfetto/config/ftrace/ftrace_config.proto
@@ -48,4 +48,20 @@
   // initialized synchronously on the data source start and hence avoiding
   // timing races in tests.
   optional bool initialize_ksyms_synchronously_for_testing = 14;
+
+  // When this boolean is true AND the ftrace_events contains "kmem/rss_stat",
+  // this option causes traced_probes to enable the "kmem/rss_stat_throttled"
+  // event instad if present, and fall back to "kmem/rss_stat" if not present.
+  // The historical context for this is the following:
+  // - Up to Android S (12), the rss_stat was internally throttled in its
+  //   kernel implementation.
+  // - A change introduced in the kernels after S has introduced a new
+  //   "rss_stat_throttled" making the original "rss_stat" event unthrottled
+  //   (hence very spammy).
+  // - Not all Android T/13 devices will receive a new kernel though, hence we
+  //   need to deal with both cases.
+  // For more context: go/rss-stat-throttled.
+  // TODO(kaleshsingh): implement the logic behind this. Right now this flag
+  // does nothing.
+  optional bool throttle_rss_stat = 15;
 }
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 5c83bee..aab9c8d 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -401,6 +401,22 @@
   // initialized synchronously on the data source start and hence avoiding
   // timing races in tests.
   optional bool initialize_ksyms_synchronously_for_testing = 14;
+
+  // When this boolean is true AND the ftrace_events contains "kmem/rss_stat",
+  // this option causes traced_probes to enable the "kmem/rss_stat_throttled"
+  // event instad if present, and fall back to "kmem/rss_stat" if not present.
+  // The historical context for this is the following:
+  // - Up to Android S (12), the rss_stat was internally throttled in its
+  //   kernel implementation.
+  // - A change introduced in the kernels after S has introduced a new
+  //   "rss_stat_throttled" making the original "rss_stat" event unthrottled
+  //   (hence very spammy).
+  // - Not all Android T/13 devices will receive a new kernel though, hence we
+  //   need to deal with both cases.
+  // For more context: go/rss-stat-throttled.
+  // TODO(kaleshsingh): implement the logic behind this. Right now this flag
+  // does nothing.
+  optional bool throttle_rss_stat = 15;
 }
 
 // End of protos/perfetto/config/ftrace/ftrace_config.proto
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 1c58fbc..fcada7e 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -401,6 +401,22 @@
   // initialized synchronously on the data source start and hence avoiding
   // timing races in tests.
   optional bool initialize_ksyms_synchronously_for_testing = 14;
+
+  // When this boolean is true AND the ftrace_events contains "kmem/rss_stat",
+  // this option causes traced_probes to enable the "kmem/rss_stat_throttled"
+  // event instad if present, and fall back to "kmem/rss_stat" if not present.
+  // The historical context for this is the following:
+  // - Up to Android S (12), the rss_stat was internally throttled in its
+  //   kernel implementation.
+  // - A change introduced in the kernels after S has introduced a new
+  //   "rss_stat_throttled" making the original "rss_stat" event unthrottled
+  //   (hence very spammy).
+  // - Not all Android T/13 devices will receive a new kernel though, hence we
+  //   need to deal with both cases.
+  // For more context: go/rss-stat-throttled.
+  // TODO(kaleshsingh): implement the logic behind this. Right now this flag
+  // does nothing.
+  optional bool throttle_rss_stat = 15;
 }
 
 // End of protos/perfetto/config/ftrace/ftrace_config.proto
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index db547fc..4c4b65a 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -101,6 +101,7 @@
     "filesystem:unittests",
     "initial_display_state:unittests",
     "packages_list:unittests",
+    "power:unittests",
     "ps:unittests",
     "sys_stats:unittests",
     "system_info:unittests",
diff --git a/src/traced/probes/power/BUILD.gn b/src/traced/probes/power/BUILD.gn
index fc28f67..0131a92 100644
--- a/src/traced/probes/power/BUILD.gn
+++ b/src/traced/probes/power/BUILD.gn
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import("../../../../gn/test.gni")
+
 source_set("power") {
   public_deps = [ "../../../tracing/core" ]
   deps = [
@@ -28,5 +30,19 @@
   sources = [
     "android_power_data_source.cc",
     "android_power_data_source.h",
+    "linux_power_sysfs_data_source.cc",
+    "linux_power_sysfs_data_source.h",
   ]
 }
+
+perfetto_unittest_source_set("unittests") {
+  testonly = true
+  deps = [
+    ":power",
+    "../../../../gn:default_deps",
+    "../../../../gn:gtest_and_gmock",
+    "../../../../src/tracing/test:test_support",
+    "../../../base:test_support",
+  ]
+  sources = [ "linux_power_sysfs_data_source_unittest.cc" ]
+}
diff --git a/src/traced/probes/power/linux_power_sysfs_data_source.cc b/src/traced/probes/power/linux_power_sysfs_data_source.cc
new file mode 100644
index 0000000..ff1e8b4
--- /dev/null
+++ b/src/traced/probes/power/linux_power_sysfs_data_source.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/traced/probes/power/linux_power_sysfs_data_source.h"
+
+#include <dirent.h>
+#include <sys/types.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/task_runner.h"
+#include "perfetto/base/time.h"
+#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/tracing/core/trace_packet.h"
+#include "perfetto/ext/tracing/core/trace_writer.h"
+#include "perfetto/tracing/core/data_source_config.h"
+
+#include "protos/perfetto/trace/power/battery_counters.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+namespace {
+constexpr uint32_t kDefaultPollIntervalMs = 1000;
+
+base::Optional<int64_t> ReadFileAsInt64(std::string path) {
+  std::string buf;
+  if (!base::ReadFile(path, &buf))
+    return base::nullopt;
+  return base::StringToInt64(base::StripSuffix(buf, "\n"));
+}
+}  // namespace
+
+LinuxPowerSysfsDataSource::BatteryInfo::BatteryInfo(
+    const char* power_supply_dir_path) {
+  base::ScopedDir power_supply_dir(opendir(power_supply_dir_path));
+  if (!power_supply_dir)
+    return;
+
+  for (auto* ent = readdir(power_supply_dir.get()); ent;
+       ent = readdir(power_supply_dir.get())) {
+    if (ent->d_name[0] == '.')
+      continue;
+    std::string dir_name =
+        std::string(power_supply_dir_path) + "/" + ent->d_name;
+    std::string buf;
+    if (!base::ReadFile(dir_name + "/type", &buf) ||
+        base::StripSuffix(buf, "\n") != "Battery")
+      continue;
+    buf.clear();
+    if (!base::ReadFile(dir_name + "/present", &buf) ||
+        base::StripSuffix(buf, "\n") != "1")
+      continue;
+    sysfs_battery_dirs_.push_back(dir_name);
+  }
+}
+LinuxPowerSysfsDataSource::BatteryInfo::~BatteryInfo() = default;
+
+size_t LinuxPowerSysfsDataSource::BatteryInfo::num_batteries() const {
+  return sysfs_battery_dirs_.size();
+}
+
+base::Optional<int64_t>
+LinuxPowerSysfsDataSource::BatteryInfo::GetChargeCounterUah(
+    size_t battery_idx) {
+  PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
+  return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/charge_now");
+}
+
+base::Optional<int64_t>
+LinuxPowerSysfsDataSource::BatteryInfo::GetCapacityPercent(size_t battery_idx) {
+  PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
+  return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/capacity");
+}
+
+base::Optional<int64_t> LinuxPowerSysfsDataSource::BatteryInfo::GetCurrentNowUa(
+    size_t battery_idx) {
+  PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
+  return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/current_now");
+}
+
+base::Optional<int64_t>
+LinuxPowerSysfsDataSource::BatteryInfo::GetAverageCurrentUa(
+    size_t battery_idx) {
+  PERFETTO_CHECK(battery_idx < sysfs_battery_dirs_.size());
+  return ReadFileAsInt64(sysfs_battery_dirs_[battery_idx] + "/current_avg");
+}
+
+// static
+const ProbesDataSource::Descriptor LinuxPowerSysfsDataSource::descriptor = {
+    /*name*/ "linux.sysfs_power",
+    /*flags*/ Descriptor::kFlagsNone,
+};
+
+LinuxPowerSysfsDataSource::LinuxPowerSysfsDataSource(
+    DataSourceConfig cfg,
+    base::TaskRunner* task_runner,
+    TracingSessionID session_id,
+    std::unique_ptr<TraceWriter> writer)
+    : ProbesDataSource(session_id, &descriptor),
+      poll_interval_ms_(kDefaultPollIntervalMs),
+      task_runner_(task_runner),
+      writer_(std::move(writer)),
+      weak_factory_(this) {
+  base::ignore_result(cfg);  // The data source doesn't need any config yet.
+}
+
+LinuxPowerSysfsDataSource::~LinuxPowerSysfsDataSource() = default;
+
+void LinuxPowerSysfsDataSource::Start() {
+  battery_info_.reset(new BatteryInfo());
+  Tick();
+}
+
+void LinuxPowerSysfsDataSource::Tick() {
+  // Post next task.
+  auto now_ms = base::GetWallTimeMs().count();
+  auto weak_this = weak_factory_.GetWeakPtr();
+  task_runner_->PostDelayedTask(
+      [weak_this] {
+        if (weak_this)
+          weak_this->Tick();
+      },
+      poll_interval_ms_ - static_cast<uint32_t>(now_ms % poll_interval_ms_));
+
+  WriteBatteryCounters();
+}
+
+void LinuxPowerSysfsDataSource::WriteBatteryCounters() {
+  auto packet = writer_->NewTracePacket();
+  packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
+
+  // Query battery counters from sysfs. Report the battery counters for each
+  // battery.
+  for (size_t battery_idx = 0; battery_idx < battery_info_->num_batteries();
+       battery_idx++) {
+    auto* counters_proto = packet->set_battery();
+    auto value = battery_info_->GetChargeCounterUah(battery_idx);
+    if (value)
+      counters_proto->set_charge_counter_uah(*value);
+    value = battery_info_->GetCapacityPercent(battery_idx);
+    if (value)
+      counters_proto->set_capacity_percent(static_cast<float>(*value));
+    value = battery_info_->GetCurrentNowUa(battery_idx);
+    if (value)
+      counters_proto->set_current_ua(*value);
+    value = battery_info_->GetAverageCurrentUa(battery_idx);
+    if (value)
+      counters_proto->set_current_ua(*value);
+  }
+}
+
+void LinuxPowerSysfsDataSource::Flush(FlushRequestID,
+                                      std::function<void()> callback) {
+  writer_->Flush(callback);
+}
+
+}  // namespace perfetto
diff --git a/src/traced/probes/power/linux_power_sysfs_data_source.h b/src/traced/probes/power/linux_power_sysfs_data_source.h
new file mode 100644
index 0000000..9838a15
--- /dev/null
+++ b/src/traced/probes/power/linux_power_sysfs_data_source.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACED_PROBES_POWER_LINUX_POWER_SYSFS_DATA_SOURCE_H_
+#define SRC_TRACED_PROBES_POWER_LINUX_POWER_SYSFS_DATA_SOURCE_H_
+
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/weak_ptr.h"
+#include "perfetto/tracing/core/data_source_config.h"
+#include "src/traced/probes/probes_data_source.h"
+
+namespace perfetto {
+class BatteryInfo;
+class TraceWriter;
+
+namespace base {
+class TaskRunner;
+}
+
+class LinuxPowerSysfsDataSource : public ProbesDataSource {
+ public:
+  class BatteryInfo {
+   public:
+    explicit BatteryInfo(
+        const char* power_supply_dir_path = "/sys/class/power_supply");
+    ~BatteryInfo();
+
+    // The current coloumb counter value in µAh.
+    base::Optional<int64_t> GetChargeCounterUah(size_t battery_idx);
+
+    // The battery capacity in percent.
+    base::Optional<int64_t> GetCapacityPercent(size_t battery_idx);
+
+    // The current reading of the battery in µA.
+    base::Optional<int64_t> GetCurrentNowUa(size_t battery_idx);
+
+    // The smoothed current reading of the battery in µA.
+    base::Optional<int64_t> GetAverageCurrentUa(size_t battery_idx);
+
+    size_t num_batteries() const;
+
+   private:
+    // The subdirectories that contain info of a battery power supply, not
+    // USBPD, AC or other types of power supplies.
+    std::vector<std::string> sysfs_battery_dirs_;
+  };
+  static const ProbesDataSource::Descriptor descriptor;
+
+  LinuxPowerSysfsDataSource(DataSourceConfig,
+                            base::TaskRunner*,
+                            TracingSessionID,
+                            std::unique_ptr<TraceWriter> writer);
+
+  ~LinuxPowerSysfsDataSource() override;
+
+  base::WeakPtr<LinuxPowerSysfsDataSource> GetWeakPtr() const;
+
+  // ProbesDataSource implementation.
+  void Start() override;
+  void Flush(FlushRequestID, std::function<void()> callback) override;
+  // Use the default ClearIncrementalState() implementation: this data source
+  // doesn't have any incremental state.
+
+ private:
+  void Tick();
+  void WriteBatteryCounters();
+
+  uint32_t poll_interval_ms_ = 0;
+
+  base::TaskRunner* const task_runner_;
+  std::unique_ptr<TraceWriter> writer_;
+  std::unique_ptr<BatteryInfo> battery_info_;
+  base::WeakPtrFactory<LinuxPowerSysfsDataSource> weak_factory_;  // Keep last.
+};
+
+}  // namespace perfetto
+
+#endif  // SRC_TRACED_PROBES_POWER_LINUX_POWER_SYSFS_DATA_SOURCE_H_
diff --git a/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc b/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc
new file mode 100644
index 0000000..590c926
--- /dev/null
+++ b/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/traced/probes/power/linux_power_sysfs_data_source.h"
+#include "src/base/test/tmp_dir_tree.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace {
+
+TEST(LinuxPowerSysfsDataSourceTest, BatteryCounters) {
+  base::TmpDirTree tmpdir;
+  std::unique_ptr<LinuxPowerSysfsDataSource::BatteryInfo> battery_info_;
+
+  tmpdir.AddDir("BAT0");
+  tmpdir.AddFile("BAT0/type", "Battery\n");
+  tmpdir.AddFile("BAT0/present", "1\n");
+  tmpdir.AddFile("BAT0/capacity", "95\n");         // 95 percent.
+  tmpdir.AddFile("BAT0/charge_now", "3074000\n");  // 3074000 µAh.
+  tmpdir.AddFile("BAT0/current_now", "245000\n");  // 245000 µA.
+  tmpdir.AddFile("BAT0/current_avg", "240000\n");  // 240000 µA.
+
+  battery_info_.reset(
+      new LinuxPowerSysfsDataSource::BatteryInfo(tmpdir.path().c_str()));
+
+  EXPECT_EQ(battery_info_->num_batteries(), 1u);
+  EXPECT_EQ(*battery_info_->GetCapacityPercent(0), 95);
+  EXPECT_EQ(*battery_info_->GetCurrentNowUa(0), 245000);
+  EXPECT_EQ(*battery_info_->GetAverageCurrentUa(0), 240000);
+  EXPECT_EQ(*battery_info_->GetChargeCounterUah(0), 3074000);
+}
+
+TEST(LinuxPowerSysfsDataSourceTest, HidDeviceCounters) {
+  base::TmpDirTree tmpdir;
+  std::unique_ptr<LinuxPowerSysfsDataSource::BatteryInfo> battery_info_;
+
+  // Some HID devices (e.g. stylus) can also report battery info.
+  tmpdir.AddDir("hid-0001-battery");
+  tmpdir.AddFile("hid-0001-battery/type", "Battery\n");
+  tmpdir.AddFile("hid-0001-battery/present", "1\n");
+  tmpdir.AddFile("hid-0001-battery/capacity", "88\n");  // 88 percent.
+  // The HID device only reports the battery capacity in percent.
+
+  battery_info_.reset(
+      new LinuxPowerSysfsDataSource::BatteryInfo(tmpdir.path().c_str()));
+
+  EXPECT_EQ(battery_info_->num_batteries(), 1u);
+  EXPECT_EQ(*battery_info_->GetCapacityPercent(0), 88);
+  EXPECT_EQ(battery_info_->GetCurrentNowUa(0), base::nullopt);
+  EXPECT_EQ(battery_info_->GetAverageCurrentUa(0), base::nullopt);
+  EXPECT_EQ(battery_info_->GetChargeCounterUah(0), base::nullopt);
+}
+
+}  // namespace
+}  // namespace perfetto
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index e33a2a0..b2c4297 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -42,6 +42,7 @@
 #include "src/traced/probes/metatrace/metatrace_data_source.h"
 #include "src/traced/probes/packages_list/packages_list_data_source.h"
 #include "src/traced/probes/power/android_power_data_source.h"
+#include "src/traced/probes/power/linux_power_sysfs_data_source.h"
 #include "src/traced/probes/probes_data_source.h"
 #include "src/traced/probes/ps/process_stats_data_source.h"
 #include "src/traced/probes/sys_stats/sys_stats_data_source.h"
@@ -71,6 +72,7 @@
     &InodeFileDataSource::descriptor,            //
     &SysStatsDataSource::descriptor,             //
     &AndroidPowerDataSource::descriptor,         //
+    &LinuxPowerSysfsDataSource::descriptor,      //
     &AndroidLogDataSource::descriptor,           //
     &PackagesListDataSource::descriptor,         //
     &MetatraceDataSource::descriptor,            //
@@ -176,6 +178,8 @@
     data_source = CreateSysStatsDataSource(session_id, config);
   } else if (config.name() == AndroidPowerDataSource::descriptor.name) {
     data_source = CreateAndroidPowerDataSource(session_id, config);
+  } else if (config.name() == LinuxPowerSysfsDataSource::descriptor.name) {
+    data_source = CreateLinuxPowerSysfsDataSource(session_id, config);
   } else if (config.name() == AndroidLogDataSource::descriptor.name) {
     data_source = CreateAndroidLogDataSource(session_id, config);
   } else if (config.name() == PackagesListDataSource::descriptor.name) {
@@ -289,6 +293,16 @@
                                  endpoint_->CreateTraceWriter(buffer_id)));
 }
 
+std::unique_ptr<ProbesDataSource>
+ProbesProducer::CreateLinuxPowerSysfsDataSource(
+    TracingSessionID session_id,
+    const DataSourceConfig& config) {
+  auto buffer_id = static_cast<BufferID>(config.target_buffer());
+  return std::unique_ptr<ProbesDataSource>(
+      new LinuxPowerSysfsDataSource(config, task_runner_, session_id,
+                                    endpoint_->CreateTraceWriter(buffer_id)));
+}
+
 std::unique_ptr<ProbesDataSource> ProbesProducer::CreateAndroidLogDataSource(
     TracingSessionID session_id,
     const DataSourceConfig& config) {
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index dda1759..6650501 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -87,6 +87,9 @@
   std::unique_ptr<ProbesDataSource> CreateAndroidLogDataSource(
       TracingSessionID session_id,
       const DataSourceConfig& config);
+  std::unique_ptr<ProbesDataSource> CreateLinuxPowerSysfsDataSource(
+      TracingSessionID session_id,
+      const DataSourceConfig& config);
   std::unique_ptr<ProbesDataSource> CreatePackagesListDataSource(
       TracingSessionID session_id,
       const DataSourceConfig& config);
diff --git a/tools/test_data b/tools/test_data
index 4aa2139..cf8ae14 100755
--- a/tools/test_data
+++ b/tools/test_data
@@ -136,7 +136,7 @@
     assert (fs.actual_digest is not None)
     dst_name = '%s/%s-%s' % (args.bucket, os.path.basename(
         fs.path), fs.actual_digest)
-    cmd = ['gsutil', '-q', 'cp', '-a', 'public-read', fs.path, dst_name]
+    cmd = ['gsutil', '-q', 'cp', '-n', '-a', 'public-read', fs.path, dst_name]
     logging.debug(' '.join(cmd))
     subprocess.check_call(cmd)
     with open(fs.path + SUFFIX + '.swp', 'w') as f:
diff --git a/ui/src/controller/record_controller.ts b/ui/src/controller/record_controller.ts
index 4518e87..ca90c31 100644
--- a/ui/src/controller/record_controller.ts
+++ b/ui/src/controller/record_controller.ts
@@ -43,6 +43,7 @@
   isAndroidP,
   isChromeTarget,
   isCrOSTarget,
+  isLinuxTarget,
   RecordConfig,
   RecordingTarget
 } from '../common/state';
@@ -164,15 +165,19 @@
   if (uiCfg.batteryDrain) {
     const ds = new TraceConfig.DataSource();
     ds.config = new DataSourceConfig();
-    ds.config.name = 'android.power';
-    ds.config.androidPowerConfig = new AndroidPowerConfig();
-    ds.config.androidPowerConfig.batteryPollMs = uiCfg.batteryDrainPollMs;
-    ds.config.androidPowerConfig.batteryCounters = [
-      AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CAPACITY_PERCENT,
-      AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CHARGE,
-      AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CURRENT,
-    ];
-    ds.config.androidPowerConfig.collectPowerRails = true;
+    if (isCrOSTarget(target) || isLinuxTarget(target)) {
+      ds.config.name = 'linux.sysfs_power';
+    } else {
+      ds.config.name = 'android.power';
+      ds.config.androidPowerConfig = new AndroidPowerConfig();
+      ds.config.androidPowerConfig.batteryPollMs = uiCfg.batteryDrainPollMs;
+      ds.config.androidPowerConfig.batteryCounters = [
+        AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CAPACITY_PERCENT,
+        AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CHARGE,
+        AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CURRENT,
+      ];
+      ds.config.androidPowerConfig.collectPowerRails = true;
+    }
     if (!isChromeTarget(target) || isCrOSTarget(target)) {
       protoCfg.dataSources.push(ds);
     }
diff --git a/ui/src/frontend/post_message_handler.ts b/ui/src/frontend/post_message_handler.ts
index 68d010f..5309b6b 100644
--- a/ui/src/frontend/post_message_handler.ts
+++ b/ui/src/frontend/post_message_handler.ts
@@ -91,12 +91,11 @@
     throw new Error('Incoming message trace buffer is empty');
   }
 
-  /* Removing this event listener because it is fired multiple times
-   * with the same payload, causing issues such as b/182502595. This can be
-   * reproduced by taking https://jsfiddle.net/primiano/1hd0a4wj/68/ and
-   * replacing 'ui.perfetto.dev' -> 'localhost:10000'. If you open multiple
-   * traces or the same trace multiple times, every tab will receive a message
-   * for every window.open() call.
+  /* Removing this event listener to avoid callers posting the trace multiple
+   * times. If the callers add an event listener which upon receiving 'PONG'
+   * posts the trace to ui.perfetto.dev, the callers can receive multiple 'PONG'
+   * messages and accidentally post the trace multiple times. This was part of
+   * the cause of b/182502595.
    */
   window.removeEventListener('message', postMessageHandler);