Move slider into gs101 and <device>

from: 026342771c6642980cb4653b1ec4d857a5d8be54

Bug: 167996145
Change-Id: I2ebf7f019afed1cbe9b60dcd82581bd3a52fe109
diff --git a/powerstats/Android.bp b/powerstats/Android.bp
new file mode 100644
index 0000000..07e16f1
--- /dev/null
+++ b/powerstats/Android.bp
@@ -0,0 +1,89 @@
+// Copyright (C) 2020 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.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "//device/google/gs101:device_google_gs101_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "//device/google/gs101:device_google_gs101_license",
+    ],
+}
+
+cc_binary {
+    // TODO(b/167628903) : remove this
+    name: "android.hardware.power.stats@1.0-service.gs101",
+    header_libs: [
+        "device_kernel_headers",
+    ],
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.power.stats@1.0-service.gs101.rc"],
+    vintf_fragments: ["android.hardware.power.stats@1.0-service.gs101.xml"],
+    srcs: [
+        "AocStateResidencyDataProvider.cpp",
+        "DvfsStateResidencyDataProvider.cpp",
+        "RailDataProvider.cpp",
+        "service.cpp",
+        "UfsStateResidencyDataProvider.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+       "libpixelpowerstats",
+    ],
+    shared_libs: [
+        "android.hardware.power.stats@1.0",
+        "pixelpowerstats_provider_aidl_interface-cpp",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    vendor: true,
+}
+
+cc_binary {
+    name: "android.hardware.power.stats-service.pixel",
+    init_rc: ["android.hardware.power.stats-service.pixel.rc"],
+    vintf_fragments: ["android.hardware.power.stats-service.pixel.xml"],
+    srcs: [
+        "AocStateResidencyDataProviderAidl.cpp",
+        "DvfsStateResidencyDataProviderAidl.cpp",
+        "serviceaidl.cpp"
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "android.hardware.power.stats-impl.pixel",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libbinder_ndk",
+        "android.hardware.power.stats-V1-ndk_platform",
+    ],
+    relative_install_path: "hw",
+    vendor: true,
+    proprietary: true,
+}
diff --git a/powerstats/AocStateResidencyDataProvider.cpp b/powerstats/AocStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..41c75bc
--- /dev/null
+++ b/powerstats/AocStateResidencyDataProvider.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#define LOG_TAG "libpixelpowerstats"
+
+#include "AocStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+AocStateResidencyDataProvider::AocStateResidencyDataProvider(
+        std::vector<std::pair<uint32_t, std::string>> ids,
+        std::vector<std::pair<std::string, std::string>> states) {
+    // AoC stats are reported in ticks of 244.140625ns. The transform
+    // function converts ticks to milliseconds.
+    // 1000000 / 244.140625 = 4096.
+    static const uint64_t AOC_CLK = 4096;
+    std::function<uint64_t(uint64_t)> aocTickToMs = [](uint64_t a) { return a / AOC_CLK; };
+    StateResidencyConfig config = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "Counter:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "Cumulative time:",
+            .totalTimeTransform = aocTickToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "Time last entered:",
+            .lastEntryTransform = aocTickToMs,
+    };
+    uint32_t state_id;
+    for (auto &id : ids) {
+        state_id = 1;
+        for (auto &state : states) {
+            std::vector<std::pair<std::string, std::string>> aocStateHeaders = {
+                    std::make_pair(state.first, ""),
+            };
+            std::unique_ptr<GenericStateResidencyDataProvider> sdp(
+                    new GenericStateResidencyDataProvider(id.second + state.second));
+            sdp->addEntity(id.first, PowerEntityConfig(state_id++, "",
+                                                       generateGenericStateResidencyConfigs(
+                                                               config, aocStateHeaders)));
+            mProviders.push_back(std::move(sdp));
+        }
+    }
+}
+
+bool AocStateResidencyDataProvider::getResults(
+        std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
+    for (auto &provider : mProviders) {
+        provider->getResults(results);
+    }
+    return true;
+}
+
+std::vector<PowerEntityStateSpace> AocStateResidencyDataProvider::getStateSpaces() {
+    // Return state spaces based on all configured providers.
+    // States from the same power entity are merged.
+    std::map<uint32_t, PowerEntityStateSpace> stateSpaces;
+    for (auto &provider : mProviders) {
+        for (auto &stateSpace : provider->getStateSpaces()) {
+            auto it = stateSpaces.find(stateSpace.powerEntityId);
+            if (it != stateSpaces.end()) {
+                auto &states = it->second.states;
+                auto size = states.size();
+                states.resize(size + stateSpace.states.size());
+                for (uint32_t i = 0; i < stateSpace.states.size(); i++) {
+                    states[size + i] = stateSpace.states[i];
+                }
+            } else {
+                stateSpaces.insert(std::pair<uint32_t, PowerEntityStateSpace>(
+                        stateSpace.powerEntityId, stateSpace));
+            }
+        }
+    }
+
+    std::vector<PowerEntityStateSpace> ret;
+    for (auto &stateSpace : stateSpaces) {
+        ret.push_back(stateSpace.second);
+    }
+    return ret;
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/powerstats/AocStateResidencyDataProvider.h b/powerstats/AocStateResidencyDataProvider.h
new file mode 100644
index 0000000..eef7ce7
--- /dev/null
+++ b/powerstats/AocStateResidencyDataProvider.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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 HARDWARE_GOOGLE_PIXEL_POWERSTATS_AOCSTATERESIDENCYDATAPROVIDER_H
+#define HARDWARE_GOOGLE_PIXEL_POWERSTATS_AOCSTATERESIDENCYDATAPROVIDER_H
+
+#include <pixelpowerstats/GenericStateResidencyDataProvider.h>
+#include <pixelpowerstats/PowerStats.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+class AocStateResidencyDataProvider : public IStateResidencyDataProvider {
+  public:
+    AocStateResidencyDataProvider(std::vector<std::pair<uint32_t, std::string>> ids,
+                                  std::vector<std::pair<std::string, std::string>> states);
+    ~AocStateResidencyDataProvider() = default;
+    bool getResults(
+            std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) override;
+    std::vector<PowerEntityStateSpace> getStateSpaces() override;
+
+  private:
+    std::vector<std::unique_ptr<GenericStateResidencyDataProvider>> mProviders;
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_GOOGLE_PIXEL_POWERSTATS_AOCSTATERESIDENCYDATAPROVIDER_H
diff --git a/powerstats/AocStateResidencyDataProviderAidl.cpp b/powerstats/AocStateResidencyDataProviderAidl.cpp
new file mode 100644
index 0000000..3759a66
--- /dev/null
+++ b/powerstats/AocStateResidencyDataProviderAidl.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 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 "AocStateResidencyDataProviderAidl.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+AocStateResidencyDataProvider::AocStateResidencyDataProvider(std::vector<std::pair<std::string,
+        std::string>> ids, std::vector<std::pair<std::string, std::string>> states) {
+    // AoC stats are reported in ticks of 244.140625ns. The transform
+    // function converts ticks to milliseconds.
+    // 1000000 / 244.140625 = 4096.
+    static const uint64_t AOC_CLK = 4096;
+    std::function<uint64_t(uint64_t)> aocTickToMs = [](uint64_t a) { return a / AOC_CLK; };
+    GenericStateResidencyDataProvider::StateResidencyConfig config = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "Counter:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "Cumulative time:",
+            .totalTimeTransform = aocTickToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "Time last entered:",
+            .lastEntryTransform = aocTickToMs,
+    };
+    for (const auto &id : ids) {
+        for (const auto &state : states) {
+            std::vector<std::pair<std::string, std::string>> aocStateHeaders = {
+                std::make_pair(state.first, ""),
+            };
+            std::vector<GenericStateResidencyDataProvider::PowerEntityConfig> cfgs;
+            cfgs.emplace_back(generateGenericStateResidencyConfigs(config, aocStateHeaders),
+                    id.first, "");
+            std::unique_ptr<GenericStateResidencyDataProvider> sdp(
+                    new GenericStateResidencyDataProvider(id.second + state.second, cfgs));
+            mProviders[id.first].push_back(std::move(sdp));
+        }
+    }
+}
+
+bool AocStateResidencyDataProvider::getStateResidencies(
+        std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
+    // States from the same power entity are merged.
+    bool ret = true;
+    for (const auto &providerList : mProviders) {
+        int32_t stateId = 0;
+        std::string curEntity = providerList.first;
+        std::vector<StateResidency> stateResidencies;
+
+        // Iterate over each provider in the providerList, appending each of the states
+        for (const auto &provider : providerList.second) {
+            std::unordered_map<std::string, std::vector<StateResidency>> residency;
+            ret &= provider->getStateResidencies(&residency);
+
+            // Each provider should only return data for curEntity but checking anyway
+            if (residency.find(curEntity) != residency.end()) {
+                for (auto &r : residency.at(curEntity)) {
+                    /*
+                     * Modifying stateId here because we are stitching together infos from
+                     * multiple GenericStateResidencyDataProviders. stateId must be modified
+                     * to maintain uniqueness for a given entity
+                     */
+                    r.id = stateId++;
+                    stateResidencies.push_back(r);
+                }
+            }
+        }
+
+        residencies->emplace(curEntity, stateResidencies);
+    }
+    return ret;
+}
+
+std::unordered_map<std::string, std::vector<State>> AocStateResidencyDataProvider::getInfo() {
+    // States from the same power entity are merged
+    std::unordered_map<std::string, std::vector<State>> infos;
+    for (const auto &providerList : mProviders) {
+        int32_t stateId = 0;
+        std::string curEntity = providerList.first;
+        std::vector<State> stateInfos;
+
+        // Iterate over each provider in the providerList, appending each of the states
+        for (const auto &provider : providerList.second) {
+            std::unordered_map<std::string, std::vector<State>> info = provider->getInfo();
+
+            // Each provider should only return data for curEntity but checking anyway
+            if (info.find(curEntity) != info.end()) {
+                for (auto &i : info.at(curEntity)) {
+                    /*
+                     * Modifying stateId because we are stitching together infos from
+                     * multiple GenericStateResidencyDataProviders. stateId must be modified
+                     * to maintain uniqueness for a given entity
+                     */
+                    i.id = stateId++;
+                    stateInfos.push_back(i);
+                }
+            }
+        }
+
+        infos.emplace(curEntity, stateInfos);
+    }
+
+    return infos;
+}
+
+}  // namespace stats
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/powerstats/AocStateResidencyDataProviderAidl.h b/powerstats/AocStateResidencyDataProviderAidl.h
new file mode 100644
index 0000000..5008912
--- /dev/null
+++ b/powerstats/AocStateResidencyDataProviderAidl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#pragma once
+
+#include <dataproviders/GenericStateResidencyDataProvider.h>
+#include <PowerStatsAidl.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+class AocStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider {
+  public:
+    AocStateResidencyDataProvider(std::vector<std::pair<std::string, std::string>> ids,
+                                  std::vector<std::pair<std::string, std::string>> states);
+    ~AocStateResidencyDataProvider() = default;
+    bool getStateResidencies(
+        std::unordered_map<std::string, std::vector<StateResidency>> *residencies) override;
+    std::unordered_map<std::string, std::vector<State>> getInfo() override;
+
+  private:
+    std::unordered_map<std::string /* entity name */,
+        std::vector<std::unique_ptr<GenericStateResidencyDataProvider>> /* providers */> mProviders;
+};
+
+}  // namespace stats
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/powerstats/DvfsStateResidencyDataProvider.cpp b/powerstats/DvfsStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..95289bd
--- /dev/null
+++ b/powerstats/DvfsStateResidencyDataProvider.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#define LOG_TAG "libpixelpowerstats"
+
+#include "DvfsStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <string>
+#include <utility>
+
+using android::base::ParseUint;
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::Trim;
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+DvfsStateResidencyDataProvider::DvfsStateResidencyDataProvider(std::string path, uint64_t clockRate)
+    : mPath(std::move(path)), mClockRate(clockRate) {}
+
+void DvfsStateResidencyDataProvider::addEntity(
+        uint32_t id, std::string name, std::vector<std::pair<std::string, std::string>> states) {
+    mPowerEntities.push_back({id, name, states});
+}
+
+int32_t DvfsStateResidencyDataProvider::matchEntity(char *line) {
+    for (auto const &entity : mPowerEntities) {
+        if (entity.powerEntityName == Trim(std::string(line))) {
+            return entity.powerEntityId;
+        }
+    }
+    return -1;
+}
+
+int32_t DvfsStateResidencyDataProvider::matchState(char *line, int32_t entityId) {
+    uint32_t stateId = 0;
+    for (auto const &entity : mPowerEntities) {
+        if (entityId == entity.powerEntityId) {
+            for (auto const &state : entity.states) {
+                if (StartsWith(Trim(std::string(line)), state.second)) {
+                    return stateId;
+                }
+                stateId++;
+            }
+            return -1;
+        }
+    }
+    return -1;
+}
+
+bool DvfsStateResidencyDataProvider::parseState(char *line, uint64_t &duration, uint64_t &count) {
+    std::vector<std::string> parts = Split(line, " ");
+    if (parts.size() != 7) {
+        return false;
+    }
+    if (!ParseUint(Trim(parts[3]), &count)) {
+        return false;
+    }
+    if (!ParseUint(Trim(parts[6]), &duration)) {
+        return false;
+    }
+    return true;
+}
+
+bool DvfsStateResidencyDataProvider::getResults(
+        std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
+    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(mPath.c_str(), "r"), fclose);
+    if (!fp) {
+        PLOG(ERROR) << __func__ << ":Failed to open file " << mPath
+                    << " Error = " << strerror(errno);
+        return false;
+    }
+
+    for (auto const &stateSpace : getStateSpaces()) {
+        PowerEntityStateResidencyResult result = {.powerEntityId = stateSpace.powerEntityId};
+        result.stateResidencyData.resize(stateSpace.states.size());
+        for (uint32_t i = 0; i < result.stateResidencyData.size(); i++) {
+            result.stateResidencyData[i].powerEntityStateId =
+                    stateSpace.states[i].powerEntityStateId;
+        }
+        results.insert(std::make_pair(stateSpace.powerEntityId, result));
+    }
+
+    size_t len = 0;
+    char *line = nullptr;
+
+    int32_t temp = -1, entityId = -1, stateId = -1;
+    uint64_t duration, count;
+
+    while (getline(&line, &len, fp.get()) != -1) {
+        temp = matchEntity(line);
+        // Assign entityId only when a new valid entity is encountered.
+        if (temp >= 0) {
+            entityId = temp;
+        }
+        if (entityId >= 0) {
+            stateId = matchState(line, entityId);
+            if (stateId >= 0) {
+                if (parseState(line, duration, count)) {
+                    results[entityId].stateResidencyData[stateId].totalTimeInStateMs =
+                            duration / mClockRate;
+                    results[entityId].stateResidencyData[stateId].totalStateEntryCount = count;
+                } else {
+                    LOG(ERROR) << "Failed to parse duration and count from [" << std::string(line)
+                               << "]";
+                    return false;
+                }
+            }
+        }
+    }
+
+    free(line);
+
+    return true;
+}
+
+std::vector<PowerEntityStateSpace> DvfsStateResidencyDataProvider::getStateSpaces() {
+    std::vector<PowerEntityStateSpace> stateSpaces;
+    stateSpaces.reserve(mPowerEntities.size());
+    for (auto const &entity : mPowerEntities) {
+        PowerEntityStateSpace s = {.powerEntityId = entity.powerEntityId};
+        s.states.resize(entity.states.size());
+        uint32_t stateId = 0;
+        for (auto const &state : entity.states) {
+            s.states[stateId] = {.powerEntityStateId = stateId,
+                                 .powerEntityStateName = state.first};
+            stateId++;
+        }
+        stateSpaces.emplace_back(s);
+    }
+    return stateSpaces;
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/powerstats/DvfsStateResidencyDataProvider.h b/powerstats/DvfsStateResidencyDataProvider.h
new file mode 100644
index 0000000..ffa1414
--- /dev/null
+++ b/powerstats/DvfsStateResidencyDataProvider.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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 HARDWARE_GOOGLE_PIXEL_POWERSTATS_DVFSSTATERESIDENCYDATAPROVIDER_H
+#define HARDWARE_GOOGLE_PIXEL_POWERSTATS_DVFSSTATERESIDENCYDATAPROVIDER_H
+
+#include <pixelpowerstats/PowerStats.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+class DvfsStateResidencyDataProvider : public IStateResidencyDataProvider {
+  public:
+    /*
+     * path - path to dvfs sysfs node.
+     * clockRate - clock rate in KHz.
+     */
+    DvfsStateResidencyDataProvider(std::string path, uint64_t clockRate);
+    ~DvfsStateResidencyDataProvider() = default;
+
+    /*
+     * id - the power entity id
+     * name - the power entity name to parse from sysfs node
+     * frequencies - list of pairs (frequency display name, frequency in sysfs
+     *               node).
+     */
+    void addEntity(uint32_t id, std::string name,
+                   std::vector<std::pair<std::string, std::string>> frequencies);
+
+    /*
+     * See IStateResidencyDataProvider::getResults.
+     */
+    bool getResults(
+            std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) override;
+
+    /*
+     * See IStateResidencyDataProvider::getStateSpaces.
+     */
+    std::vector<PowerEntityStateSpace> getStateSpaces() override;
+
+  private:
+    int32_t matchEntity(char *line);
+    int32_t matchState(char *line, int32_t entityId);
+    bool parseState(char *line, uint64_t &duration, uint64_t &count);
+
+    const std::string mPath;
+    const uint64_t mClockRate;
+
+    struct config {
+        // Power entity id.
+        uint32_t powerEntityId;
+
+        // Power entity name to parse.
+        std::string powerEntityName;
+
+        // List of state pairs (name to display, name to parse).
+        std::vector<std::pair<std::string, std::string>> states;
+    };
+    std::vector<config> mPowerEntities;
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_GOOGLE_PIXEL_POWERSTATS_DVFSSTATERESIDENCYDATAPROVIDER_H
diff --git a/powerstats/DvfsStateResidencyDataProviderAidl.cpp b/powerstats/DvfsStateResidencyDataProviderAidl.cpp
new file mode 100644
index 0000000..ca6ea9a
--- /dev/null
+++ b/powerstats/DvfsStateResidencyDataProviderAidl.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 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 "DvfsStateResidencyDataProviderAidl.h"
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <string>
+#include <utility>
+
+using android::base::ParseUint;
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::Trim;
+
+static const std::string nameSuffix = "-DVFS";
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+DvfsStateResidencyDataProvider::DvfsStateResidencyDataProvider(std::string path, uint64_t clockRate,
+        std::vector<Config> cfgs)
+    : mPath(std::move(path)), mClockRate(clockRate), mPowerEntities(std::move(cfgs)) {}
+
+int32_t DvfsStateResidencyDataProvider::matchEntity(char const *line) {
+    for (int32_t i = 0; i < mPowerEntities.size(); i++) {
+        if (mPowerEntities[i].powerEntityName == Trim(std::string(line))) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int32_t DvfsStateResidencyDataProvider::matchState(char const *line, const Config& powerEntity) {
+    for (int32_t i = 0; i < powerEntity.states.size(); i++) {
+        if (StartsWith(Trim(std::string(line)), powerEntity.states[i].second)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+bool DvfsStateResidencyDataProvider::parseState(char const *line, uint64_t *duration,
+        uint64_t *count) {
+    std::vector<std::string> parts = Split(line, " ");
+    if (parts.size() != 7) {
+        return false;
+    }
+    if (!ParseUint(Trim(parts[3]), count)) {
+        return false;
+    }
+    if (!ParseUint(Trim(parts[6]), duration)) {
+        return false;
+    }
+    return true;
+}
+
+bool DvfsStateResidencyDataProvider::getStateResidencies(
+        std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
+    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(mPath.c_str(), "r"), fclose);
+    if (!fp) {
+        PLOG(ERROR) << __func__ << ":Failed to open file " << mPath;
+        return false;
+    }
+
+    for (const Config &powerEntity : mPowerEntities) {
+        std::vector<StateResidency> stateResidency(powerEntity.states.size());
+        for (int32_t i = 0; i < stateResidency.size(); i++) {
+            stateResidency[i].id = i;
+        }
+        residencies->emplace(powerEntity.powerEntityName + nameSuffix, stateResidency);
+    }
+
+    size_t len = 0;
+    char *line = nullptr;
+
+    int32_t temp, powerEntityIndex, stateId = -1;
+    uint64_t duration, count;
+    auto it = residencies->end();
+
+    while (getline(&line, &len, fp.get()) != -1) {
+        temp = matchEntity(line);
+        // Assign new index only when a new valid entity is encountered.
+        if (temp >= 0) {
+            powerEntityIndex = temp;
+            it = residencies->find(mPowerEntities[powerEntityIndex].powerEntityName + nameSuffix);
+        }
+
+        if (it != residencies->end()) {
+            stateId = matchState(line, mPowerEntities[powerEntityIndex]);
+
+            if (stateId >= 0) {
+                if (parseState(line, &duration, &count)) {
+                    it->second[stateId].totalTimeInStateMs =
+                            duration / mClockRate;
+                    it->second[stateId].totalStateEntryCount = count;
+                } else {
+                    LOG(ERROR) << "Failed to parse duration and count from [" << std::string(line)
+                               << "]";
+                    return false;
+                }
+            }
+        }
+    }
+
+    free(line);
+
+    return true;
+}
+
+std::unordered_map<std::string, std::vector<State>> DvfsStateResidencyDataProvider::getInfo() {
+    std::unordered_map<std::string, std::vector<State>> info;
+    for (auto const &entity : mPowerEntities) {
+        std::vector<State> stateInfo(entity.states.size());
+        int32_t stateId = 0;
+        for (auto const &state : entity.states) {
+            stateInfo[stateId] = State{
+                .id = stateId,
+                .name = state.first
+            };
+            stateId++;
+        }
+        info.emplace(entity.powerEntityName + nameSuffix, stateInfo);
+    }
+    return info;
+}
+
+}  // namespace stats
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/powerstats/DvfsStateResidencyDataProviderAidl.h b/powerstats/DvfsStateResidencyDataProviderAidl.h
new file mode 100644
index 0000000..ca8ab22
--- /dev/null
+++ b/powerstats/DvfsStateResidencyDataProviderAidl.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#pragma once
+
+#include <PowerStatsAidl.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+class DvfsStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider {
+  public:
+    class Config {
+      public:
+        // Power entity name to parse.
+        std::string powerEntityName;
+
+        // List of state pairs (name to display, name to parse).
+        std::vector<std::pair<std::string, std::string>> states;
+    };
+    /*
+     * path - path to dvfs sysfs node.
+     * clockRate - clock rate in KHz.
+     */
+    DvfsStateResidencyDataProvider(std::string path, uint64_t clockRate, std::vector<Config> cfgs);
+    ~DvfsStateResidencyDataProvider() = default;
+
+    /*
+     * See IStateResidencyDataProvider::getStateResidencies
+     */
+    bool getStateResidencies(
+        std::unordered_map<std::string, std::vector<StateResidency>> *residencies) override;
+
+    /*
+     * See IStateResidencyDataProvider::getInfo
+     */
+    std::unordered_map<std::string, std::vector<State>> getInfo() override;
+
+  private:
+    int32_t matchEntity(char const *line);
+    int32_t matchState(char const *line, const Config& powerEntity);
+    bool parseState(char const *line, uint64_t *duration, uint64_t *count);
+
+    const std::string mPath;
+    const uint64_t mClockRate;
+    std::vector<Config> mPowerEntities;
+};
+
+}  // namespace stats
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/powerstats/RailDataProvider.cpp b/powerstats/RailDataProvider.cpp
new file mode 100644
index 0000000..d0efc17
--- /dev/null
+++ b/powerstats/RailDataProvider.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "libpixelpowerstats"
+
+#include "RailDataProvider.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <exception>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+#define MAX_FILE_PATH_LEN 128
+#define MAX_DEVICE_NAME_LEN 64
+#define MAX_QUEUE_SIZE 8192
+
+constexpr char kIioDirRoot[] = "/sys/bus/iio/devices/";
+const char *const kDeviceNames[] = {"s2mpg10-odpm", "s2mpg11-odpm"};
+constexpr char kDeviceType[] = "iio:device";
+constexpr uint32_t MAX_SAMPLING_RATE = 10;
+constexpr uint64_t WRITE_TIMEOUT_NS = 1000000000;
+
+#define MAX_RAIL_NAME_LEN 50
+#define STR(s) #s
+#define XSTR(s) STR(s)
+
+void RailDataProvider::findIioPowerMonitorNodes() {
+    struct dirent *ent;
+    int fd;
+    char devName[MAX_DEVICE_NAME_LEN];
+    char filePath[MAX_FILE_PATH_LEN];
+    DIR *iioDir = opendir(kIioDirRoot);
+    if (!iioDir) {
+        ALOGE("Error opening directory: %s, error: %d", kIioDirRoot, errno);
+        return;
+    }
+    while (ent = readdir(iioDir), ent) {
+        if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 &&
+                strlen(ent->d_name) > strlen(kDeviceType) &&
+                strncmp(ent->d_name, kDeviceType, strlen(kDeviceType)) == 0) {
+            snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", ent->d_name, "name");
+            fd = openat(dirfd(iioDir), filePath, O_RDONLY);
+            if (fd < 0) {
+                ALOGW("Failed to open directory: %s, error: %d", filePath, errno);
+                continue;
+            }
+            if (read(fd, devName, MAX_DEVICE_NAME_LEN) < 0) {
+                ALOGW("Failed to read device name from file: %s(%d)", filePath, fd);
+                close(fd);
+                continue;
+            }
+
+            for (const auto &kDeviceName : kDeviceNames) {
+                if (strncmp(devName, kDeviceName, strlen(kDeviceName)) == 0) {
+                    snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", kIioDirRoot, ent->d_name);
+                    mOdpm.devicePaths.push_back(filePath);
+                }
+            }
+            close(fd);
+        }
+    }
+    closedir(iioDir);
+    return;
+}
+
+size_t RailDataProvider::parsePowerRails() {
+    std::string data;
+    std::string railFileName;
+    std::string spsFileName;
+    uint32_t index = 0;
+    uint32_t samplingRate;
+    for (const auto &path : mOdpm.devicePaths) {
+        railFileName = path + "/enabled_rails";
+        spsFileName = path + "/sampling_rate";
+        if (!android::base::ReadFileToString(spsFileName, &data)) {
+            ALOGW("Error reading file: %s", spsFileName.c_str());
+            continue;
+        }
+        samplingRate = strtoul(data.c_str(), NULL, 10);
+        if (!samplingRate || samplingRate == ULONG_MAX) {
+            ALOGE("Error parsing: %s", spsFileName.c_str());
+            break;
+        }
+        if (!android::base::ReadFileToString(railFileName, &data)) {
+            ALOGW("Error reading file: %s", railFileName.c_str());
+            continue;
+        }
+        std::istringstream railNames(data);
+        std::string line;
+        while (std::getline(railNames, line)) {
+            std::vector<std::string> words = android::base::Split(line, ":][");
+            if (words.size() == 4) {
+                const std::string channelName = words[1];
+                if (mOdpm.railsInfo.count(channelName) == 0) {
+                    const std::string subsysName = words[3];
+                    mOdpm.railsInfo.emplace(channelName, RailData{.devicePath = path,
+                                                            .index = index,
+                                                            .subsysName = subsysName,
+                                                            .samplingRate = samplingRate});
+                    index++;
+                } else {
+                    ALOGW("There exists rails with the same name (not supported): %s." \
+                        " Only the last occurrence of rail energy will be provided.",
+                        channelName.c_str());
+                }
+            } else {
+                ALOGW("Unexpected format in file: %s", railFileName.c_str());
+            }
+        }
+    }
+    return index;
+}
+
+int RailDataProvider::parseIioEnergyNodeString(const std::string &contents, OnDeviceMmt &odpm) {
+    std::istringstream energyData(contents);
+    std::string line;
+
+    int ret = 0;
+    uint64_t timestamp = 0;
+    bool timestampRead = false;
+
+    while (std::getline(energyData, line)) {
+        bool parseLineSuccess = false;
+
+        if (timestampRead == false) {
+            /* Read timestamp from boot (ms) */
+            if (sscanf(line.c_str(), "t=%" PRIu64, &timestamp) == 1) {
+                if (timestamp == 0 || timestamp == ULLONG_MAX) {
+                    ALOGW("Potentially wrong timestamp: %" PRIu64, timestamp);
+                }
+                timestampRead = true;
+                parseLineSuccess = true;
+            }
+
+        } else {
+            /* Read rail energy */
+            uint64_t energy = 0;
+            char railNameRaw[MAX_RAIL_NAME_LEN + 1];
+            if (sscanf(line.c_str(),
+                       "CH%*d(T=%*" PRIu64 ")[%" XSTR(MAX_RAIL_NAME_LEN) "[^]]], %" PRIu64,
+                       railNameRaw, &energy) == 2) {
+                std::string railName(railNameRaw);
+
+                /* If the count == 0, the rail may not be enabled */
+                /* The count cannot be > 1; mChannelIds is a map */
+                if (odpm.railsInfo.count(railName) == 1) {
+                    size_t index = odpm.railsInfo[railName].index;
+                    odpm.reading[index].index = index;
+                    odpm.reading[index].timestamp = timestamp;
+                    odpm.reading[index].energy = energy;
+                    if (odpm.reading[index].energy == ULLONG_MAX) {
+                        ALOGW("Potentially wrong energy value on rail: %s", railName.c_str());
+                    }
+                }
+                parseLineSuccess = true;
+            }
+        }
+
+        if (parseLineSuccess == false) {
+            ret = -1;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+int RailDataProvider::parseIioEnergyNode(std::string devName) {
+    int ret;
+    std::string data;
+    std::string fileName = devName + "/energy_value";
+    if (!android::base::ReadFileToString(fileName, &data)) {
+        ALOGE("Error reading file: %s", fileName.c_str());
+        return -1;
+    }
+
+    ret = parseIioEnergyNodeString(data, mOdpm);
+    if (ret != 0) {
+        ALOGW("Unexpected format in file: %s", fileName.c_str());
+    }
+    return ret;
+}
+
+Status RailDataProvider::parseIioEnergyNodes() {
+    Status ret = Status::SUCCESS;
+    if (mOdpm.hwEnabled == false) {
+        return Status::NOT_SUPPORTED;
+    }
+
+    for (const auto &devicePath : mOdpm.devicePaths) {
+        if (parseIioEnergyNode(devicePath) < 0) {
+            ALOGE("Error in parsing power stats");
+            ret = Status::FILESYSTEM_ERROR;
+            break;
+        }
+    }
+    return ret;
+}
+
+RailDataProvider::RailDataProvider() {
+    findIioPowerMonitorNodes();
+    size_t numRails = parsePowerRails();
+    if (mOdpm.devicePaths.empty() || numRails == 0) {
+        mOdpm.hwEnabled = false;
+    } else {
+        mOdpm.hwEnabled = true;
+        mOdpm.reading.resize(numRails);
+    }
+}
+
+Return<void> RailDataProvider::getRailInfo(IPowerStats::getRailInfo_cb _hidl_cb) {
+    hidl_vec<RailInfo> rInfo;
+    Status ret = Status::SUCCESS;
+    size_t index;
+    std::lock_guard<std::mutex> _lock(mOdpm.mLock);
+    if (mOdpm.hwEnabled == false) {
+        ALOGI("getRailInfo not supported");
+        _hidl_cb(rInfo, Status::NOT_SUPPORTED);
+        return Void();
+    }
+    rInfo.resize(mOdpm.railsInfo.size());
+    for (const auto &railData : mOdpm.railsInfo) {
+        index = railData.second.index;
+        rInfo[index].railName = railData.first;
+        rInfo[index].subsysName = railData.second.subsysName;
+        rInfo[index].index = index;
+        rInfo[index].samplingRate = railData.second.samplingRate;
+    }
+    _hidl_cb(rInfo, ret);
+    return Void();
+}
+
+Return<void> RailDataProvider::getEnergyData(const hidl_vec<uint32_t> &railIndices,
+                                             IPowerStats::getEnergyData_cb _hidl_cb) {
+    hidl_vec<EnergyData> eVal;
+    std::lock_guard<std::mutex> _lock(mOdpm.mLock);
+    Status ret = parseIioEnergyNodes();
+
+    if (ret != Status::SUCCESS) {
+        ALOGE("Failed to getEnergyData");
+        _hidl_cb(eVal, ret);
+        return Void();
+    }
+
+    if (railIndices.size() == 0) {
+        eVal.resize(mOdpm.railsInfo.size());
+        memcpy(&eVal[0], &mOdpm.reading[0], mOdpm.reading.size() * sizeof(EnergyData));
+    } else {
+        eVal.resize(railIndices.size());
+        int i = 0;
+        for (const auto &railIndex : railIndices) {
+            if (railIndex >= mOdpm.reading.size()) {
+                ret = Status::INVALID_INPUT;
+                eVal.resize(0);
+                break;
+            }
+            memcpy(&eVal[i], &mOdpm.reading[railIndex], sizeof(EnergyData));
+            i++;
+        }
+    }
+    _hidl_cb(eVal, ret);
+    return Void();
+}
+
+Return<void> RailDataProvider::streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
+                                                IPowerStats::streamEnergyData_cb _hidl_cb) {
+    std::lock_guard<std::mutex> _lock(mOdpm.mLock);
+    if (mOdpm.fmqSynchronized != nullptr) {
+        _hidl_cb(MessageQueueSync::Descriptor(), 0, 0, Status::INSUFFICIENT_RESOURCES);
+        return Void();
+    }
+    uint32_t sps = std::min(samplingRate, MAX_SAMPLING_RATE);
+    uint32_t numSamples = timeMs * sps / 1000;
+    mOdpm.fmqSynchronized.reset(new (std::nothrow) MessageQueueSync(MAX_QUEUE_SIZE, true));
+    if (mOdpm.fmqSynchronized == nullptr || mOdpm.fmqSynchronized->isValid() == false) {
+        mOdpm.fmqSynchronized = nullptr;
+        _hidl_cb(MessageQueueSync::Descriptor(), 0, 0, Status::INSUFFICIENT_RESOURCES);
+        return Void();
+    }
+    std::thread pollThread = std::thread([this, sps, numSamples]() {
+        uint64_t sleepTimeUs = 1000000 / sps;
+        uint32_t currSamples = 0;
+        while (currSamples < numSamples) {
+            mOdpm.mLock.lock();
+            if (parseIioEnergyNodes() == Status::SUCCESS) {
+                mOdpm.fmqSynchronized->writeBlocking(&mOdpm.reading[0], mOdpm.reading.size(),
+                                                     WRITE_TIMEOUT_NS);
+                mOdpm.mLock.unlock();
+                currSamples++;
+                if (usleep(sleepTimeUs) < 0) {
+                    ALOGW("Sleep interrupted");
+                    break;
+                }
+            } else {
+                mOdpm.mLock.unlock();
+                break;
+            }
+        }
+        mOdpm.mLock.lock();
+        mOdpm.fmqSynchronized = nullptr;
+        mOdpm.mLock.unlock();
+        return;
+    });
+    pollThread.detach();
+    _hidl_cb(*(mOdpm.fmqSynchronized)->getDesc(), numSamples, mOdpm.reading.size(),
+             Status::SUCCESS);
+    return Void();
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/powerstats/RailDataProvider.h b/powerstats/RailDataProvider.h
new file mode 100644
index 0000000..61313e2
--- /dev/null
+++ b/powerstats/RailDataProvider.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_HARDWARE_POWERSTATS_RAILDATAPROVIDER_H
+#define ANDROID_HARDWARE_POWERSTATS_RAILDATAPROVIDER_H
+
+#include <fmq/MessageQueue.h>
+#include <pixelpowerstats/PowerStats.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+typedef MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync;
+struct RailData {
+    std::string devicePath;
+    uint32_t index;
+    std::string subsysName;
+    uint32_t samplingRate;
+};
+
+struct OnDeviceMmt {
+    std::mutex mLock;
+    bool hwEnabled;
+    std::vector<std::string> devicePaths;
+    std::map<std::string, RailData> railsInfo;
+    std::vector<EnergyData> reading;
+    std::unique_ptr<MessageQueueSync> fmqSynchronized;
+};
+
+class RailDataProvider : public IRailDataProvider {
+public:
+    RailDataProvider();
+    // Methods from ::android::hardware::power::stats::V1_0::IPowerStats follow.
+    Return<void> getRailInfo(IPowerStats::getRailInfo_cb _hidl_cb) override;
+    Return<void> getEnergyData(const hidl_vec<uint32_t>& railIndices,
+                        IPowerStats::getEnergyData_cb _hidl_cb) override;
+    Return<void> streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
+                        IPowerStats::streamEnergyData_cb _hidl_cb) override;
+ private:
+     OnDeviceMmt mOdpm;
+     void findIioPowerMonitorNodes();
+     size_t parsePowerRails();
+     int parseIioEnergyNodeString(const std::string &contents,
+                    OnDeviceMmt &odpm);
+     int parseIioEnergyNode(std::string devName);
+     Status parseIioEnergyNodes();
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_POWERSTATS_RAILDATAPROVIDER_H
diff --git a/powerstats/UfsStateResidencyDataProvider.cpp b/powerstats/UfsStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..7ca6f3b
--- /dev/null
+++ b/powerstats/UfsStateResidencyDataProvider.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#define LOG_TAG "libpixelpowerstats"
+
+#include "UfsStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <string>
+#include <utility>
+
+using android::base::ParseUint;
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::Trim;
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+const uint32_t HIBERNATE_STATE_ID = 0;
+
+UfsStateResidencyDataProvider::UfsStateResidencyDataProvider(uint32_t powerEntityId)
+    : mPowerEntityId(powerEntityId) {}
+
+bool UfsStateResidencyDataProvider::getResults(
+        std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
+    PowerEntityStateResidencyResult result = {
+            .powerEntityId = mPowerEntityId,
+            .stateResidencyData = {{.powerEntityStateId = HIBERNATE_STATE_ID}}};
+
+    // The transform function converts microseconds to milliseconds.
+    std::function<uint64_t(uint64_t)> usecToMs = [](uint64_t a) { return a / 1000; };
+
+    std::string prefix = "/sys/bus/platform/devices/14700000.ufs/ufs_stats/";
+
+    result.stateResidencyData[0].totalTimeInStateMs =
+            usecToMs(readStat(prefix + "hibern8_total_us"));
+    result.stateResidencyData[0].totalStateEntryCount = readStat(prefix + "hibern8_exit_cnt");
+    result.stateResidencyData[0].lastEntryTimestampMs =
+            usecToMs(readStat(prefix + "last_hibern8_enter_time"));
+    results.insert(std::make_pair(mPowerEntityId, result));
+    return true;
+}
+
+std::vector<PowerEntityStateSpace> UfsStateResidencyDataProvider::getStateSpaces() {
+    return {{.powerEntityId = mPowerEntityId,
+             .states = {{.powerEntityStateId = HIBERNATE_STATE_ID,
+                         .powerEntityStateName = "HIBERN8"}}}};
+}
+
+uint64_t UfsStateResidencyDataProvider::readStat(std::string path) {
+    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path.c_str(), "r"), fclose);
+    if (!fp) {
+        PLOG(ERROR) << __func__ << ":Failed to open file " << path
+                    << " Error = " << strerror(errno);
+        return 0;
+    }
+    const size_t size = 20;
+    char buf[size];
+    (void)fread(&buf, sizeof(char), size, fp.get());
+    uint64_t ret;
+    if (!ParseUint(Trim(std::string(buf)), &ret)) {
+        LOG(ERROR) << "Failed to parse uint64 from [" << std::string(buf) << "]";
+    }
+    return ret;
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/powerstats/UfsStateResidencyDataProvider.h b/powerstats/UfsStateResidencyDataProvider.h
new file mode 100644
index 0000000..8d1ea73
--- /dev/null
+++ b/powerstats/UfsStateResidencyDataProvider.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 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 HARDWARE_GOOGLE_PIXEL_POWERSTATS_UFSSTATERESIDENCYDATAPROVIDER_H
+#define HARDWARE_GOOGLE_PIXEL_POWERSTATS_UFSSTATERESIDENCYDATAPROVIDER_H
+
+#include <pixelpowerstats/PowerStats.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+class UfsStateResidencyDataProvider : public IStateResidencyDataProvider {
+  public:
+    /*
+     * powerEntityId - id for the UFS power entity.
+     */
+    UfsStateResidencyDataProvider(uint32_t powerEntityId);
+    ~UfsStateResidencyDataProvider() = default;
+
+    /*
+     * See IStateResidencyDataProvider::getResults.
+     */
+    bool getResults(
+            std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) override;
+
+    /*
+     * See IStateResidencyDataProvider::getStateSpaces.
+     */
+    std::vector<PowerEntityStateSpace> getStateSpaces() override;
+
+  private:
+    uint64_t readStat(std::string path);
+
+    uint32_t mPowerEntityId;
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_GOOGLE_PIXEL_POWERSTATS_UFSSTATERESIDENCYDATAPROVIDER_H
diff --git a/powerstats/android.hardware.power.stats-service.pixel.rc b/powerstats/android.hardware.power.stats-service.pixel.rc
new file mode 100644
index 0000000..f044b05
--- /dev/null
+++ b/powerstats/android.hardware.power.stats-service.pixel.rc
@@ -0,0 +1,4 @@
+service vendor.power.stats.pixel /vendor/bin/hw/android.hardware.power.stats-service.pixel
+    class hal
+    user system
+    group system
diff --git a/powerstats/android.hardware.power.stats-service.pixel.xml b/powerstats/android.hardware.power.stats-service.pixel.xml
new file mode 100644
index 0000000..3fade2a
--- /dev/null
+++ b/powerstats/android.hardware.power.stats-service.pixel.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.power.stats</name>
+        <fqname>IPowerStats/default</fqname>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/powerstats/android.hardware.power.stats@1.0-service.gs101.rc b/powerstats/android.hardware.power.stats@1.0-service.gs101.rc
new file mode 100644
index 0000000..afc3580
--- /dev/null
+++ b/powerstats/android.hardware.power.stats@1.0-service.gs101.rc
@@ -0,0 +1,5 @@
+service vendor.power.stats-hal-1-0 /vendor/bin/hw/android.hardware.power.stats@1.0-service.gs101
+    interface android.hardware.power.stats@1.0::IPowerStats default
+    class hal
+    user system
+    group system
diff --git a/powerstats/android.hardware.power.stats@1.0-service.gs101.xml b/powerstats/android.hardware.power.stats@1.0-service.gs101.xml
new file mode 100644
index 0000000..2e9956f
--- /dev/null
+++ b/powerstats/android.hardware.power.stats@1.0-service.gs101.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.power.stats</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+           <name>IPowerStats</name>
+           <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/powerstats/service.cpp b/powerstats/service.cpp
new file mode 100644
index 0000000..4cf1f35
--- /dev/null
+++ b/powerstats/service.cpp
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "android.hardware.power.stats@1.0-service.gs101"
+
+#include <android/log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <pixelpowerstats/AidlStateResidencyDataProvider.h>
+#include <pixelpowerstats/GenericStateResidencyDataProvider.h>
+#include <pixelpowerstats/PowerStats.h>
+
+#include "AocStateResidencyDataProvider.h"
+#include "DvfsStateResidencyDataProvider.h"
+#include "RailDataProvider.h"
+#include "UfsStateResidencyDataProvider.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::PowerEntityType;
+using android::hardware::power::stats::V1_0::implementation::PowerStats;
+
+// Pixel specific
+using android::hardware::google::pixel::powerstats::AidlStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::AocStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::DvfsStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::generateGenericStateResidencyConfigs;
+using android::hardware::google::pixel::powerstats::GenericStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::PowerEntityConfig;
+using android::hardware::google::pixel::powerstats::RailDataProvider;
+using android::hardware::google::pixel::powerstats::StateResidencyConfig;
+using android::hardware::google::pixel::powerstats::UfsStateResidencyDataProvider;
+
+// A constant to represnt the number of nanoseconds in one millisecond.
+static const int NS_TO_MS = 1000000;
+
+void addAoCStats(PowerStats *const service) {
+    std::string prefix = "/sys/devices/platform/19000000.aoc/control/";
+
+    // Add AoC cores (a32, ff1, hf0, and hf1)
+    std::vector<std::pair<uint32_t, std::string>> coreIds = {
+            {service->addPowerEntity("AoC-A32", PowerEntityType::SUBSYSTEM), prefix + "a32_"},
+            {service->addPowerEntity("AoC-FF1", PowerEntityType::SUBSYSTEM), prefix + "ff1_"},
+            {service->addPowerEntity("AoC-HF1", PowerEntityType::SUBSYSTEM), prefix + "hf1_"},
+            {service->addPowerEntity("AoC-HF0", PowerEntityType::SUBSYSTEM), prefix + "hf0_"},
+    };
+    std::vector<std::pair<std::string, std::string>> coreStates = {
+            {"DWN", "off"}, {"RET", "retention"}, {"WFI", "wfi"}};
+    service->addStateResidencyDataProvider(new AocStateResidencyDataProvider(coreIds, coreStates));
+
+    // Add AoC voltage stats
+    std::vector<std::pair<uint32_t, std::string>> voltageIds = {
+            {service->addPowerEntity("AoC-Voltage", PowerEntityType::SUBSYSTEM),
+             prefix + "voltage_"},
+    };
+    std::vector<std::pair<std::string, std::string>> voltageStates = {{"NOM", "nominal"},
+                                                                      {"SUD", "super_underdrive"},
+                                                                      {"UUD", "ultra_underdrive"},
+                                                                      {"UD", "underdrive"}};
+    service->addStateResidencyDataProvider(
+            new AocStateResidencyDataProvider(voltageIds, voltageStates));
+
+    // Add AoC monitor mode
+    std::vector<std::pair<uint32_t, std::string>> monitorIds = {
+            {service->addPowerEntity("AoC", PowerEntityType::SUBSYSTEM), prefix + "monitor_"},
+    };
+    std::vector<std::pair<std::string, std::string>> monitorStates = {
+            {"MON", "mode"},
+    };
+    service->addStateResidencyDataProvider(
+            new AocStateResidencyDataProvider(monitorIds, monitorStates));
+}
+
+void addCpuCStateStats(PowerStats *const service) {
+    // CPU stats are reported in nanoseconds. The transform function
+    // converts nanoseconds to milliseconds.
+    std::function<uint64_t(uint64_t)> cpuNsToMs = [](uint64_t a) { return a / NS_TO_MS; };
+    StateResidencyConfig cStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "down_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_down_time_ns:",
+            .totalTimeTransform = cpuNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_down_time_ns:",
+            .lastEntryTransform = cpuNsToMs,
+    };
+
+    sp<GenericStateResidencyDataProvider> cStateSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/1742048c.acpm_stats/core_stats");
+    for (std::string state :
+         {"CORE00", "CORE01", "CORE02", "CORE03", "CORE10", "CORE11", "CORE20", "CORE21"}) {
+        cStateSdp->addEntity(service->addPowerEntity(state, PowerEntityType::SUBSYSTEM),
+                             PowerEntityConfig("CORES:", generateGenericStateResidencyConfigs(
+                                                                 cStateConfig,
+                                                                 {std::make_pair("DOWN", state)})));
+    }
+    for (std::string state : {"CLUSTER0", "CLUSTER1", "CLUSTER2"}) {
+        cStateSdp->addEntity(
+                service->addPowerEntity(state, PowerEntityType::SUBSYSTEM),
+                PowerEntityConfig("CLUSTERS:",
+                                  generateGenericStateResidencyConfigs(
+                                          cStateConfig, {std::make_pair("DOWN", state)})));
+    }
+    service->addStateResidencyDataProvider(cStateSdp);
+}
+
+void addDvfsStats(PowerStats *const service) {
+    sp<DvfsStateResidencyDataProvider> dvfsSdp = new DvfsStateResidencyDataProvider(
+            "/sys/devices/platform/1742048c.acpm_stats/fvp_stats", NS_TO_MS);
+
+    dvfsSdp->addEntity(service->addPowerEntity("MIF-DVFS", PowerEntityType::SUBSYSTEM), "MIF",
+                       {
+                               std::make_pair("3172KHz", "3172000"),
+                               std::make_pair("2730KHz", "2730000"),
+                               std::make_pair("2535KHz", "2535000"),
+                               std::make_pair("2288KHz", "2288000"),
+                               std::make_pair("2028KHz", "2028000"),
+                               std::make_pair("1716KHz", "1716000"),
+                               std::make_pair("1539KHz", "1539000"),
+                               std::make_pair("1352KHz", "1352000"),
+                               std::make_pair("1014KHz", "1014000"),
+                               std::make_pair("845KHz", "845000"),
+                               std::make_pair("676KHz", "676000"),
+                               std::make_pair("546KHz", "546000"),
+                               std::make_pair("421KHz", "421000"),
+                               std::make_pair("0KHz", "0"),
+                       });
+
+    dvfsSdp->addEntity(service->addPowerEntity("CL0-DVFS", PowerEntityType::SUBSYSTEM), "CL0",
+                       {
+                               std::make_pair("2196KHz", "2196000"),
+                               std::make_pair("2098KHz", "2098000"),
+                               std::make_pair("2024KHz", "2024000"),
+                               std::make_pair("1950KHz", "1950000"),
+                               std::make_pair("1868KHz", "1868000"),
+                               std::make_pair("1745KHz", "1745000"),
+                               std::make_pair("1598KHz", "1598000"),
+                               std::make_pair("1459KHz", "1459000"),
+                               std::make_pair("1328KHz", "1328000"),
+                               std::make_pair("1197KHz", "1197000"),
+                               std::make_pair("1098KHz", "1098000"),
+                               std::make_pair("889KHz", "889000"),
+                               std::make_pair("738KHz", "738000"),
+                               std::make_pair("574KHz", "574000"),
+                               std::make_pair("300KHz", "300000"),
+                               std::make_pair("0KHz", "0"),
+                       });
+
+    dvfsSdp->addEntity(service->addPowerEntity("CL1-DVFS", PowerEntityType::SUBSYSTEM), "CL1",
+                       {
+                               std::make_pair("2466KHz", "2466000"),
+                               std::make_pair("2393KHz", "2393000"),
+                               std::make_pair("2348KHz", "2348000"),
+                               std::make_pair("2253KHz", "2253000"),
+                               std::make_pair("2130KHz", "2130000"),
+                               std::make_pair("1999KHz", "1999000"),
+                               std::make_pair("1836KHz", "1836000"),
+                               std::make_pair("1663KHz", "1663000"),
+                               std::make_pair("1491KHz", "1491000"),
+                               std::make_pair("1328KHz", "1328000"),
+                               std::make_pair("1197KHz", "1197000"),
+                               std::make_pair("1024KHz", "1024000"),
+                               std::make_pair("910KHz", "910000"),
+                               std::make_pair("799KHz", "799000"),
+                               std::make_pair("696KHz", "696000"),
+                               std::make_pair("533KHz", "533000"),
+                               std::make_pair("400KHz", "400000"),
+                               std::make_pair("0KHz", "0"),
+                       });
+
+    dvfsSdp->addEntity(service->addPowerEntity("CL2-DVFS", PowerEntityType::SUBSYSTEM), "CL2",
+                       {
+                               std::make_pair("3195KHz", "3195000"),
+                               std::make_pair("3097KHz", "3097000"),
+                               std::make_pair("2999KHz", "2999000"),
+                               std::make_pair("2900KHz", "2900000"),
+                               std::make_pair("2802KHz", "2802000"),
+                               std::make_pair("2704KHz", "2704000"),
+                               std::make_pair("2630KHz", "2630000"),
+                               std::make_pair("2507KHz", "2507000"),
+                               std::make_pair("2401KHz", "2401000"),
+                               std::make_pair("2302KHz", "2302000"),
+                               std::make_pair("2188KHz", "2188000"),
+                               std::make_pair("2048KHz", "2048000"),
+                               std::make_pair("1901KHz", "1901000"),
+                               std::make_pair("1745KHz", "1745000"),
+                               std::make_pair("1582KHz", "1582000"),
+                               std::make_pair("1426KHz", "1426000"),
+                               std::make_pair("1237KHz", "1237000"),
+                               std::make_pair("1106KHz", "1106000"),
+                               std::make_pair("984KHz", "984000"),
+                               std::make_pair("848KHz", "848000"),
+                               std::make_pair("500KHz", "500000"),
+                               std::make_pair("0KHz", "0"),
+                       });
+
+    // TODO(sujee): Complete frequency table for TPU.
+    dvfsSdp->addEntity(service->addPowerEntity("TPU-DVFS", PowerEntityType::SUBSYSTEM), "TPU",
+                       {
+                               std::make_pair("1066MHz", "1066000000"),
+                       });
+
+    service->addStateResidencyDataProvider(dvfsSdp);
+}
+
+void addGPUStats(PowerStats *const service) {
+    StateResidencyConfig gpuStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "count = ",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_time = ",
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_entry_time = ",
+    };
+
+    sp<GenericStateResidencyDataProvider> gpu = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/1c500000.mali/power_stats");
+
+    PowerEntityConfig onOffConfig("Summary stats: (times in ms)",
+                                  generateGenericStateResidencyConfigs(
+                                          gpuStateConfig, {{"DOWN", "OFF:"}, {"UP", "ON:"}}));
+    gpu->addEntity(service->addPowerEntity("GPU", PowerEntityType::SUBSYSTEM), onOffConfig);
+
+    PowerEntityConfig DVFSConfig(
+            "DVFS stats: (times in ms)",
+            generateGenericStateResidencyConfigs(gpuStateConfig, {{"996MHz", "996000:"},
+                                                                  {"885MHz", "885000:"},
+                                                                  {"750MHz", "750000:"},
+                                                                  {"434MHz", "434000:"},
+                                                                  {"302MHz", "302000:"},
+                                                                  {"151MHz", "151000:"}}));
+    gpu->addEntity(service->addPowerEntity("GPU-DVFS", PowerEntityType::SUBSYSTEM), DVFSConfig);
+    service->addStateResidencyDataProvider(gpu);
+}
+
+void addNFCStats(PowerStats *const service) {
+    StateResidencyConfig nfcStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "Cumulative count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "Cumulative duration msec:",
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "Last entry timestamp msec:",
+    };
+    std::vector<std::pair<std::string, std::string>> nfcStateHeaders = {
+            std::make_pair("IDLE", "Idle mode:"),
+            std::make_pair("ACTIVE", "Active mode:"),
+            std::make_pair("ACTIVE-RW", "Active Reader/Writer mode:"),
+    };
+
+    sp<GenericStateResidencyDataProvider> nfcSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/10960000.hsi2c/i2c-4/4-0008/power_stats");
+    nfcSdp->addEntity(service->addPowerEntity("NFC", PowerEntityType::SUBSYSTEM),
+                      PowerEntityConfig("NFC subsystem", generateGenericStateResidencyConfigs(
+                                                                 nfcStateConfig, nfcStateHeaders)));
+    service->addStateResidencyDataProvider(nfcSdp);
+}
+
+void addPCIeStats(PowerStats *const service) {
+    // Add PCIe power entities for Modem and WiFi
+    StateResidencyConfig pcieStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "Cumulative count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "Cumulative duration msec:",
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "Last entry timestamp msec:",
+    };
+    std::vector<std::pair<std::string, std::string>> pcieStateHeaders = {
+            std::make_pair("UP", "Link up:"),
+            std::make_pair("DOWN", "Link down:"),
+    };
+
+    // Add PCIe - Modem
+    sp<GenericStateResidencyDataProvider> pcieModemSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/11920000.pcie/power_stats");
+    uint32_t pcieModemId = service->addPowerEntity("PCIe-Modem", PowerEntityType::SUBSYSTEM);
+    pcieModemSdp->addEntity(
+            pcieModemId,
+            PowerEntityConfig("Version: 1", generateGenericStateResidencyConfigs(
+                                                    pcieStateConfig, pcieStateHeaders)));
+    service->addStateResidencyDataProvider(pcieModemSdp);
+
+    // Add PCIe - WiFi
+    sp<GenericStateResidencyDataProvider> pcieWifiSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/14520000.pcie/power_stats");
+    uint32_t pcieWifiId = service->addPowerEntity("PCIe-WiFi", PowerEntityType::SUBSYSTEM);
+    pcieWifiSdp->addEntity(
+            pcieWifiId,
+            PowerEntityConfig("Version: 1", generateGenericStateResidencyConfigs(
+                                                    pcieStateConfig, pcieStateHeaders)));
+    service->addStateResidencyDataProvider(pcieWifiSdp);
+}
+
+void addSocStats(PowerStats *const service) {
+    // ACPM stats are reported in nanoseconds. The transform function
+    // converts nanoseconds to milliseconds.
+    std::function<uint64_t(uint64_t)> acpmNsToMs = [](uint64_t a) { return a / NS_TO_MS; };
+    StateResidencyConfig lpmStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "success_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_time_ns:",
+            .totalTimeTransform = acpmNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_entry_time_ns:",
+            .lastEntryTransform = acpmNsToMs,
+    };
+    StateResidencyConfig downStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "down_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_down_time_ns:",
+            .totalTimeTransform = acpmNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_down_time_ns:",
+            .lastEntryTransform = acpmNsToMs,
+    };
+    StateResidencyConfig reqStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "req_up_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_req_up_time_ns:",
+            .totalTimeTransform = acpmNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_req_up_time_ns:",
+            .lastEntryTransform = acpmNsToMs,
+
+    };
+    std::vector<std::pair<std::string, std::string>> powerStateHeaders = {
+            std::make_pair("SICD", "SICD"),
+            std::make_pair("SLEEP", "SLEEP"),
+            std::make_pair("SLEEP_SLCMON", "SLEEP_SLCMON"),
+            std::make_pair("STOP", "STOP"),
+    };
+    std::vector<std::pair<std::string, std::string>> mifReqStateHeaders = {
+            std::make_pair("AOC", "AOC"),
+            std::make_pair("GSA", "GSA"),
+    };
+    std::vector<std::pair<std::string, std::string>> slcReqStateHeaders = {
+            std::make_pair("AOC", "AOC"),
+    };
+
+    sp<GenericStateResidencyDataProvider> socSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/1742048c.acpm_stats/soc_stats");
+
+    socSdp->addEntity(service->addPowerEntity("LPM", PowerEntityType::SUBSYSTEM),
+                      PowerEntityConfig("LPM:", generateGenericStateResidencyConfigs(
+                                                        lpmStateConfig, powerStateHeaders)));
+    socSdp->addEntity(service->addPowerEntity("MIF", PowerEntityType::SUBSYSTEM),
+                      PowerEntityConfig("MIF:", generateGenericStateResidencyConfigs(
+                                                        downStateConfig, powerStateHeaders)));
+    socSdp->addEntity(service->addPowerEntity("MIF-REQ", PowerEntityType::SUBSYSTEM),
+                      PowerEntityConfig("MIF_REQ:", generateGenericStateResidencyConfigs(
+                                                            reqStateConfig, mifReqStateHeaders)));
+    socSdp->addEntity(service->addPowerEntity("SLC", PowerEntityType::SUBSYSTEM),
+                      PowerEntityConfig("SLC:", generateGenericStateResidencyConfigs(
+                                                        downStateConfig, powerStateHeaders)));
+    socSdp->addEntity(service->addPowerEntity("SLC-REQ", PowerEntityType::SUBSYSTEM),
+                      PowerEntityConfig("SLC_REQ:", generateGenericStateResidencyConfigs(
+                                                            reqStateConfig, slcReqStateHeaders)));
+
+    service->addStateResidencyDataProvider(socSdp);
+}
+
+void addUfsStats(PowerStats *const service) {
+    sp<UfsStateResidencyDataProvider> ufsSdp = new UfsStateResidencyDataProvider(
+            service->addPowerEntity("UFS", PowerEntityType::SUBSYSTEM));
+    service->addStateResidencyDataProvider(ufsSdp);
+}
+
+void addWifiStats(PowerStats *const service) {
+    sp<GenericStateResidencyDataProvider> wifiSdp =
+            new GenericStateResidencyDataProvider("/sys/wifi/power_stats");
+
+    // The transform function converts microseconds to milliseconds.
+    std::function<uint64_t(uint64_t)> usecToMs = [](uint64_t a) { return a / 1000; };
+    StateResidencyConfig stateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "duration_usec:",
+            .totalTimeTransform = usecToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_entry_timestamp_usec:",
+            .lastEntryTransform = usecToMs,
+    };
+    StateResidencyConfig pcieStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "duration_usec:",
+            .totalTimeTransform = usecToMs,
+    };
+
+    std::vector<std::pair<std::string, std::string>> stateHeaders = {
+            std::make_pair("AWAKE", "AWAKE:"),
+            std::make_pair("ASLEEP", "ASLEEP:"),
+    };
+    std::vector<std::pair<std::string, std::string>> pcieStateHeaders = {
+            std::make_pair("L0", "L0:"),     std::make_pair("L1", "L1:"),
+            std::make_pair("L1_1", "L1_1:"), std::make_pair("L1_2", "L1_2:"),
+            std::make_pair("L2", "L2:"),
+    };
+
+    wifiSdp->addEntity(
+            service->addPowerEntity("WIFI", PowerEntityType::SUBSYSTEM),
+            PowerEntityConfig(generateGenericStateResidencyConfigs(stateConfig, stateHeaders)));
+    wifiSdp->addEntity(service->addPowerEntity("WIFI-PCIE", PowerEntityType::SUBSYSTEM),
+                       PowerEntityConfig(generateGenericStateResidencyConfigs(pcieStateConfig,
+                                                                              pcieStateHeaders)));
+
+    service->addStateResidencyDataProvider(wifiSdp);
+}
+
+int main(int /* argc */, char ** /* argv */) {
+    ALOGI("power.stats service 1.0 is starting.");
+
+    PowerStats *service = new PowerStats();
+
+    // Add rail data provider
+    service->setRailDataProvider(std::make_unique<RailDataProvider>());
+
+    addAoCStats(service);
+    addCpuCStateStats(service);
+    addDvfsStats(service);
+    addGPUStats(service);
+    addNFCStats(service);
+    addPCIeStats(service);
+    addSocStats(service);
+    addUfsStats(service);
+    addWifiStats(service);
+
+    // Add Power Entities that require the Aidl data provider
+    sp<AidlStateResidencyDataProvider> aidlSdp = new AidlStateResidencyDataProvider();
+    uint32_t bluetoothId = service->addPowerEntity("Bluetooth", PowerEntityType::SUBSYSTEM);
+    aidlSdp->addEntity(bluetoothId, "Bluetooth", {"Idle", "Active", "Tx", "Rx"});
+    uint32_t citadelId = service->addPowerEntity("Citadel", PowerEntityType::SUBSYSTEM);
+    aidlSdp->addEntity(citadelId, "Citadel", {"Last-Reset", "Active", "Deep-Sleep"});
+    service->addStateResidencyDataProvider(aidlSdp);
+
+    auto serviceStatus = android::defaultServiceManager()->addService(
+            android::String16("power.stats-vendor"), aidlSdp);
+    if (serviceStatus != android::OK) {
+        ALOGE("Unable to register power.stats-vendor service %d", serviceStatus);
+        return 1;
+    }
+
+    sp<android::ProcessState> ps{android::ProcessState::self()};  // Create non-HW binder threadpool
+    ps->startThreadPool();
+
+    // Configure the threadpool
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status_t status = service->registerAsService();
+    if (status != OK) {
+        ALOGE("Could not register service for power.stats HAL Iface (%d), exiting.", status);
+        return 1;
+    }
+
+    ALOGI("power.stats service is ready");
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("power.stats service is shutting down");
+    return 1;
+}
diff --git a/powerstats/serviceaidl.cpp b/powerstats/serviceaidl.cpp
new file mode 100644
index 0000000..25eb6ea
--- /dev/null
+++ b/powerstats/serviceaidl.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "android.hardware.power.stats-service.pixel"
+
+#include <PowerStatsAidl.h>
+#include "AocStateResidencyDataProviderAidl.h"
+#include "DvfsStateResidencyDataProviderAidl.h"
+#include <dataproviders/DisplayStateResidencyDataProvider.h>
+#include <dataproviders/GenericStateResidencyDataProvider.h>
+#include <dataproviders/IioEnergyMeterDataProvider.h>
+#include <dataproviders/PowerStatsEnergyConsumer.h>
+#include <dataproviders/PowerStatsEnergyAttribution.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <log/log.h>
+
+using aidl::android::hardware::power::stats::AocStateResidencyDataProvider;
+using aidl::android::hardware::power::stats::DisplayStateResidencyDataProvider;
+using aidl::android::hardware::power::stats::DvfsStateResidencyDataProvider;
+using aidl::android::hardware::power::stats::EnergyConsumerType;
+using aidl::android::hardware::power::stats::GenericStateResidencyDataProvider;
+using aidl::android::hardware::power::stats::IioEnergyMeterDataProvider;
+using aidl::android::hardware::power::stats::PowerStats;
+using aidl::android::hardware::power::stats::PowerStatsEnergyConsumer;
+
+constexpr char kBootHwSoCRev[] = "ro.boot.hw.soc.rev";
+
+void addAoC(std::shared_ptr<PowerStats> p) {
+    std::string prefix = "/sys/devices/platform/19000000.aoc/control/";
+
+    // Add AoC cores (a32, ff1, hf0, and hf1)
+    std::vector<std::pair<std::string, std::string>> coreIds = {
+            {"AoC-A32", prefix + "a32_"},
+            {"AoC-FF1", prefix + "ff1_"},
+            {"AoC-HF1", prefix + "hf1_"},
+            {"AoC-HF0", prefix + "hf0_"},
+    };
+    std::vector<std::pair<std::string, std::string>> coreStates = {
+            {"DWN", "off"}, {"RET", "retention"}, {"WFI", "wfi"}};
+    p->addStateResidencyDataProvider(new AocStateResidencyDataProvider(coreIds, coreStates));
+
+    // Add AoC voltage stats
+    std::vector<std::pair<std::string, std::string>> voltageIds = {
+            {"AoC-Voltage", prefix + "voltage_"},
+    };
+    std::vector<std::pair<std::string, std::string>> voltageStates = {{"NOM", "nominal"},
+                                                                      {"SUD", "super_underdrive"},
+                                                                      {"UUD", "ultra_underdrive"},
+                                                                      {"UD", "underdrive"}};
+    p->addStateResidencyDataProvider(
+            new AocStateResidencyDataProvider(voltageIds, voltageStates));
+
+    // Add AoC monitor mode
+    std::vector<std::pair<std::string, std::string>> monitorIds = {
+            {"AoC", prefix + "monitor_"},
+    };
+    std::vector<std::pair<std::string, std::string>> monitorStates = {
+            {"MON", "mode"},
+    };
+    p->addStateResidencyDataProvider(
+            new AocStateResidencyDataProvider(monitorIds, monitorStates));
+}
+
+void addDvfsStats(std::shared_ptr<PowerStats> p) {
+    // A constant to represent the number of nanoseconds in one millisecond
+    const int NS_TO_MS = 1000000;
+
+    std::vector<DvfsStateResidencyDataProvider::Config> cfgs;
+
+    cfgs.push_back({"MIF", {
+        std::make_pair("3172KHz", "3172000"),
+        std::make_pair("2730KHz", "2730000"),
+        std::make_pair("2535KHz", "2535000"),
+        std::make_pair("2288KHz", "2288000"),
+        std::make_pair("2028KHz", "2028000"),
+        std::make_pair("1716KHz", "1716000"),
+        std::make_pair("1539KHz", "1539000"),
+        std::make_pair("1352KHz", "1352000"),
+        std::make_pair("1014KHz", "1014000"),
+        std::make_pair("845KHz", "845000"),
+        std::make_pair("676KHz", "676000"),
+        std::make_pair("546KHz", "546000"),
+        std::make_pair("421KHz", "421000"),
+        std::make_pair("0KHz", "0"),
+    }});
+
+    cfgs.push_back({"CL0", {
+        std::make_pair("2024KHz", "2024000"),
+        std::make_pair("1950KHz", "1950000"),
+        std::make_pair("1868KHz", "1868000"),
+        std::make_pair("1803KHz", "1803000"),
+        std::make_pair("1745KHz", "1745000"),
+        std::make_pair("1704KHz", "1704000"),
+        std::make_pair("1598KHz", "1598000"),
+        std::make_pair("1459KHz", "1459000"),
+        std::make_pair("1401KHz", "1401000"),
+        std::make_pair("1328KHz", "1328000"),
+        std::make_pair("1197KHz", "1197000"),
+        std::make_pair("1098KHz", "1098000"),
+        std::make_pair("930KHz", "930000"),
+        std::make_pair("889KHz", "889000"),
+        std::make_pair("738KHz", "738000"),
+        std::make_pair("574KHz", "574000"),
+        std::make_pair("300KHz", "300000"),
+        std::make_pair("0KHz", "0"),
+    }});
+
+    cfgs.push_back({"CL1", {
+        std::make_pair("2253KHz", "2253000"),
+        std::make_pair("2130KHz", "2130000"),
+        std::make_pair("1999KHz", "1999000"),
+        std::make_pair("1836KHz", "1836000"),
+        std::make_pair("1663KHz", "1663000"),
+        std::make_pair("1491KHz", "1491000"),
+        std::make_pair("1328KHz", "1328000"),
+        std::make_pair("1197KHz", "1197000"),
+        std::make_pair("1024KHz", "1024000"),
+        std::make_pair("910KHz", "910000"),
+        std::make_pair("799KHz", "799000"),
+        std::make_pair("696KHz", "696000"),
+        std::make_pair("533KHz", "533000"),
+        std::make_pair("400KHz", "400000"),
+        std::make_pair("0KHz", "0"),
+    }});
+
+    cfgs.push_back({"CL2", {
+        std::make_pair("2630KHz", "2630000"),
+        std::make_pair("2507KHz", "2507000"),
+        std::make_pair("2401KHz", "2401000"),
+        std::make_pair("2302KHz", "2302000"),
+        std::make_pair("2252KHz", "2252000"),
+        std::make_pair("2188KHz", "2188000"),
+        std::make_pair("2048KHz", "2048000"),
+        std::make_pair("1901KHz", "1901000"),
+        std::make_pair("1826KHz", "1826000"),
+        std::make_pair("1745KHz", "1745000"),
+        std::make_pair("1582KHz", "1582000"),
+        std::make_pair("1426KHz", "1426000"),
+        std::make_pair("1277KHz", "1277000"),
+        std::make_pair("1237KHz", "1237000"),
+        std::make_pair("1106KHz", "1106000"),
+        std::make_pair("984KHz", "984000"),
+        std::make_pair("851KHz", "851000"),
+        std::make_pair("848KHz", "848000"),
+        std::make_pair("500KHz", "500000"),
+        std::make_pair("0KHz", "0"),
+    }});
+
+    cfgs.push_back({"TPU", {
+        std::make_pair("1066MHz", "1066000000"),
+    }});
+
+    p->addStateResidencyDataProvider(new DvfsStateResidencyDataProvider(
+            "/sys/devices/platform/1742048c.acpm_stats/fvp_stats", NS_TO_MS, cfgs));
+}
+
+void addSoC(std::shared_ptr<PowerStats> p) {
+    // A constant to represent the number of nanoseconds in one millisecond.
+    const int NS_TO_MS = 1000000;
+
+    // ACPM stats are reported in nanoseconds. The transform function
+    // converts nanoseconds to milliseconds.
+    std::function<uint64_t(uint64_t)> acpmNsToMs = [](uint64_t a) { return a / NS_TO_MS; };
+    const GenericStateResidencyDataProvider::StateResidencyConfig lpmStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "success_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_time_ns:",
+            .totalTimeTransform = acpmNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_entry_time_ns:",
+            .lastEntryTransform = acpmNsToMs,
+    };
+    const GenericStateResidencyDataProvider::StateResidencyConfig downStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "down_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_down_time_ns:",
+            .totalTimeTransform = acpmNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_down_time_ns:",
+            .lastEntryTransform = acpmNsToMs,
+    };
+    const GenericStateResidencyDataProvider::StateResidencyConfig reqStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "req_up_count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "total_req_up_time_ns:",
+            .totalTimeTransform = acpmNsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_req_up_time_ns:",
+            .lastEntryTransform = acpmNsToMs,
+
+    };
+    const std::vector<std::pair<std::string, std::string>> powerStateHeaders = {
+            std::make_pair("SICD", "SICD"),
+            std::make_pair("SLEEP", "SLEEP"),
+            std::make_pair("SLEEP_SLCMON", "SLEEP_SLCMON"),
+            std::make_pair("STOP", "STOP"),
+    };
+    const std::vector<std::pair<std::string, std::string>> mifReqStateHeaders = {
+            std::make_pair("AOC", "AOC"),
+            std::make_pair("GSA", "GSA"),
+    };
+    const std::vector<std::pair<std::string, std::string>> slcReqStateHeaders = {
+            std::make_pair("AOC", "AOC"),
+    };
+
+    std::vector<GenericStateResidencyDataProvider::PowerEntityConfig> cfgs;
+    cfgs.emplace_back(generateGenericStateResidencyConfigs(lpmStateConfig, powerStateHeaders),
+            "LPM", "LPM:");
+    cfgs.emplace_back(generateGenericStateResidencyConfigs(downStateConfig, powerStateHeaders),
+            "MIF", "MIF:");
+    cfgs.emplace_back(generateGenericStateResidencyConfigs(reqStateConfig, mifReqStateHeaders),
+            "MIF-REQ", "MIF_REQ:");
+    cfgs.emplace_back(generateGenericStateResidencyConfigs(downStateConfig, powerStateHeaders),
+            "SLC", "SLC:");
+    cfgs.emplace_back(generateGenericStateResidencyConfigs(reqStateConfig, slcReqStateHeaders),
+            "SLC-REQ", "SLC_REQ:");
+
+    android::sp<GenericStateResidencyDataProvider> socSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/1742048c.acpm_stats/soc_stats", cfgs);
+
+    p->addStateResidencyDataProvider(socSdp);
+}
+
+void setEnergyMeter(std::shared_ptr<PowerStats> p) {
+    std::vector<const std::string> deviceNames { "s2mpg10-odpm", "s2mpg11-odpm" };
+    p->setEnergyMeterDataProvider(std::make_unique<IioEnergyMeterDataProvider>(deviceNames, true));
+}
+
+void addDisplay(std::shared_ptr<PowerStats> p) {
+    // Add display residency stats
+    android::sp<DisplayStateResidencyDataProvider> displaySdp =
+        new DisplayStateResidencyDataProvider("Display",
+            "/sys/class/backlight/panel0-backlight/state",
+            /*
+             * TODO(b/167216667): Add complete set of display states here. Must account
+             * for ALL devices built using this source
+             */
+            {"Off", "LP: 1440x3040@30", "On: 1440x3040@60", "On: 1440x3040@90", "HBM: 1440x3040@60",
+            "HBM: 1440x3040@90"});
+    p->addStateResidencyDataProvider(displaySdp);
+
+    // Add display energy consumer
+    android::sp<PowerStatsEnergyConsumer> displayConsumer;
+    /*
+     * TODO(b/167216667): Add correct display power model here. Must read from display rail
+     * and include proper coefficients for display states. Must account for ALL devices built
+     * using this source.
+     */
+    displayConsumer = PowerStatsEnergyConsumer::createMeterAndEntityConsumer(p,
+            EnergyConsumerType::DISPLAY, "display", {"PPVAR_VSYS_PWR_DISP"}, "Display",
+            {{"LP: 1440x3040@30", 1},
+             {"On: 1440x3040@60", 2},
+             {"On: 1440x3040@90", 3}});
+
+    p->addEnergyConsumer(displayConsumer);
+}
+
+void addCPUclusters(std::shared_ptr<PowerStats> p)
+{
+    p->addEnergyConsumer(PowerStatsEnergyConsumer::createMeterConsumer(p,
+            EnergyConsumerType::CPU_CLUSTER, "CPUCL0", {"S4M_VDD_CPUCL0"}));
+    p->addEnergyConsumer(PowerStatsEnergyConsumer::createMeterConsumer(p,
+            EnergyConsumerType::CPU_CLUSTER, "CPUCL1", {"S3M_VDD_CPUCL1"}));
+    p->addEnergyConsumer(PowerStatsEnergyConsumer::createMeterConsumer(p,
+            EnergyConsumerType::CPU_CLUSTER, "CPUCL2", {"S2M_VDD_CPUCL2"}));
+}
+
+void addGPU(std::shared_ptr<PowerStats> p) {
+    // Add gpu energy consumer
+    android::sp<PowerStatsEnergyConsumer> gpuConsumer;
+    std::map<std::string, int32_t> stateCoeffs;
+    const int socRev = android::base::GetIntProperty(kBootHwSoCRev, 0);
+
+    // B0/B1 chips have different GPU DVFS operating points than A0/A1 SoC
+    if (socRev >= 2) {
+        stateCoeffs = {
+            {"151000",  10},
+            {"202000",  20},
+            {"251000",  30},
+            {"302000",  40},
+            {"351000",  50},
+            {"400000",  60},
+            {"471000",  70},
+            {"510000",  80},
+            {"572000",  90},
+            {"701000", 100},
+            {"762000", 110},
+            {"848000", 120}};
+    } else {
+        stateCoeffs = {
+            {"151000",  10},
+            {"302000",  20},
+            {"455000",  30},
+            {"572000",  40},
+            {"670000",  50}};
+    }
+
+    gpuConsumer = PowerStatsEnergyConsumer::createMeterAndAttrConsumer(p,
+            EnergyConsumerType::OTHER, "GPU", {"S2S_VDD_G3D"},
+            {{UID_TIME_IN_STATE, "/sys/devices/platform/1c500000.mali/uid_time_in_state"}},
+            stateCoeffs);
+
+    p->addEnergyConsumer(gpuConsumer);
+}
+
+void addMobileRadio(std::shared_ptr<PowerStats> p)
+{
+    // A constant to represent the number of microseconds in one millisecond.
+    const int US_TO_MS = 1000;
+
+    // modem power_stats are reported in microseconds. The transform function
+    // converts microseconds to milliseconds.
+    std::function<uint64_t(uint64_t)> modemUsToMs = [](uint64_t a) { return a / US_TO_MS; };
+    const GenericStateResidencyDataProvider::StateResidencyConfig powerStateConfig = {
+            .entryCountSupported = true,
+            .entryCountPrefix = "count:",
+            .totalTimeSupported = true,
+            .totalTimePrefix = "duration_usec:",
+            .totalTimeTransform = modemUsToMs,
+            .lastEntrySupported = true,
+            .lastEntryPrefix = "last_entry_timestamp_usec:",
+            .lastEntryTransform = modemUsToMs,
+    };
+    const std::vector<std::pair<std::string, std::string>> powerStateHeaders = {
+            std::make_pair("SLEEP", "SLEEP:"),
+    };
+
+    std::vector<GenericStateResidencyDataProvider::PowerEntityConfig> cfgs;
+    cfgs.emplace_back(generateGenericStateResidencyConfigs(powerStateConfig, powerStateHeaders),
+            "MODEM", "");
+
+    android::sp<GenericStateResidencyDataProvider> modemSdp = new GenericStateResidencyDataProvider(
+            "/sys/devices/platform/cpif/modem/power_stats", cfgs);
+
+    p->addStateResidencyDataProvider(modemSdp);
+
+    p->addEnergyConsumer(PowerStatsEnergyConsumer::createMeterConsumer(p,
+            EnergyConsumerType::MOBILE_RADIO, "MODEM", {"VSYS_PWR_MODEM", "VSYS_PWR_RFFE"}));
+}
+
+void addGNSS(std::shared_ptr<PowerStats> p)
+{
+    p->addEnergyConsumer(PowerStatsEnergyConsumer::createMeterConsumer(p,
+            EnergyConsumerType::GNSS, "GPS", {"L9S_GNSS_CORE"}));
+}
+
+int main() {
+    LOG(INFO) << "Pixel PowerStats HAL AIDL Service is starting.";
+
+    // single thread
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    std::shared_ptr<PowerStats> p = ndk::SharedRefBase::make<PowerStats>();
+
+    setEnergyMeter(p);
+
+    addAoC(p);
+    addDisplay(p);
+    addDvfsStats(p);
+    addSoC(p);
+    addCPUclusters(p);
+    addGPU(p);
+    addMobileRadio(p);
+    addGNSS(p);
+
+    const std::string instance = std::string() + PowerStats::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(p->asBinder().get(), instance.c_str());
+    LOG_ALWAYS_FATAL_IF(status != STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}