aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Hsu <darrenhsu@google.com>2021-12-28 21:31:24 +0800
committerDarren Hsu <darrenhsu@google.com>2022-01-03 20:09:27 +0800
commit673d3b0ab7e0e7614487ac2c879417e2e450a5e7 (patch)
tree825827eeac1bf51caebcb8d7a0ee2b1e5d39e0be
parent9135d780227270039f47f24808a50525b42c4ac4 (diff)
downloadgs-common-673d3b0ab7e0e7614487ac2c879417e2e450a5e7.tar.gz
powerstats: add common data providers in gs common
Bug: 206576142 Test: dumpsys android.hardware.power.stats.IPowerStats/default Change-Id: Iee66356150a8bdfcd1e0b3fe8b8d5ec9f601f543 Signed-off-by: Darren Hsu <darrenhsu@google.com>
-rw-r--r--device.mk3
-rw-r--r--powerstats/Android.bp24
-rw-r--r--powerstats/AocStateResidencyDataProvider.cpp128
-rw-r--r--powerstats/DevfreqStateResidencyDataProvider.cpp111
-rw-r--r--powerstats/DvfsStateResidencyDataProvider.cpp149
-rw-r--r--powerstats/UfsStateResidencyDataProvider.cpp82
-rw-r--r--powerstats/include/AocStateResidencyDataProvider.h45
-rw-r--r--powerstats/include/DevfreqStateResidencyDataProvider.h53
-rw-r--r--powerstats/include/DvfsStateResidencyDataProvider.h68
-rw-r--r--powerstats/include/UfsStateResidencyDataProvider.h52
10 files changed, 715 insertions, 0 deletions
diff --git a/device.mk b/device.mk
index d9ee5e0..d6a156c 100644
--- a/device.mk
+++ b/device.mk
@@ -16,3 +16,6 @@
PRODUCT_COPY_FILES += \
device/google/gs-common/default-talkback-permissions.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/default-permissions/default-talkback-permissions.xml
+
+PRODUCT_SOONG_NAMESPACES += \
+ device/google/gs-common/powerstats
diff --git a/powerstats/Android.bp b/powerstats/Android.bp
new file mode 100644
index 0000000..74935c7
--- /dev/null
+++ b/powerstats/Android.bp
@@ -0,0 +1,24 @@
+soong_namespace {
+ imports: [
+ "hardware/google/pixel",
+ ],
+}
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "android.hardware.power.stats-impl.gs-common",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ defaults: ["powerstats_pixel_defaults"],
+
+ srcs: [
+ "*.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.power.stats-impl.pixel",
+ ],
+}
diff --git a/powerstats/AocStateResidencyDataProvider.cpp b/powerstats/AocStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..c64496d
--- /dev/null
+++ b/powerstats/AocStateResidencyDataProvider.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 "AocStateResidencyDataProvider.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/DevfreqStateResidencyDataProvider.cpp b/powerstats/DevfreqStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..d59e1e5
--- /dev/null
+++ b/powerstats/DevfreqStateResidencyDataProvider.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "DevfreqStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+
+static const std::string nameSuffix = "-DVFS";
+static const std::string pathSuffix = "/time_in_state";
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+DevfreqStateResidencyDataProvider::DevfreqStateResidencyDataProvider(const std::string& name,
+ const std::string& path) : mName(name + nameSuffix), mPath(path + pathSuffix) {}
+
+bool DevfreqStateResidencyDataProvider::extractNum(const char *str, char **str_end, int base,
+ int64_t* num) {
+ // errno can be set to any non-zero value by a library function call
+ // regardless of whether there was an error, so it needs to be cleared
+ // in order to check the error set by strtoll
+ errno = 0;
+ *num = std::strtoll(str, str_end, base);
+ return (errno != ERANGE);
+}
+
+std::vector<std::pair<int64_t, int64_t>> DevfreqStateResidencyDataProvider::parseTimeInState() {
+ // Using FILE* instead of std::ifstream for performance reasons
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(mPath.c_str(), "r"), fclose);
+ if (!fp) {
+ PLOG(ERROR) << "Failed to open file " << mPath;
+ return {};
+ }
+
+ std::vector<std::pair<int64_t, int64_t>> timeInState;
+
+ char *line = nullptr;
+ size_t len = 0;
+ while (getline(&line, &len, fp.get()) != -1) {
+ char* pEnd;
+ int64_t frequencyHz, totalTimeMs;
+ if (!extractNum(line, &pEnd, 10, &frequencyHz) ||
+ !extractNum(pEnd, &pEnd, 10, &totalTimeMs)) {
+ PLOG(ERROR) << "Failed to parse " << mPath;
+ free(line);
+ return {};
+ }
+
+ timeInState.push_back({frequencyHz, totalTimeMs});
+ }
+
+ free(line);
+ return timeInState;
+}
+
+bool DevfreqStateResidencyDataProvider::getStateResidencies(
+ std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
+ std::vector<std::pair<int64_t, int64_t>> timeInState = parseTimeInState();
+
+ if (timeInState.empty()) {
+ return false;
+ }
+
+ int32_t id = 0;
+ std::vector<StateResidency> stateResidencies;
+ for (const auto[frequencyHz, totalTimeMs] : timeInState) {
+ StateResidency s = {.id = id++, .totalTimeInStateMs = totalTimeMs};
+ stateResidencies.push_back(s);
+ }
+
+ residencies->emplace(mName, stateResidencies);
+ return true;
+}
+
+std::unordered_map<std::string, std::vector<State>> DevfreqStateResidencyDataProvider::getInfo() {
+ std::vector<std::pair<int64_t, int64_t>> timeInState = parseTimeInState();
+
+ if (timeInState.empty()) {
+ return {};
+ }
+
+ int32_t id = 0;
+ std::vector<State> states;
+ for (const auto[frequencyHz, totalTimeMs] : timeInState) {
+ State s = {.id = id++, .name = std::to_string(frequencyHz / 1000) + "MHz"};
+ states.push_back(s);
+ }
+
+ return {{mName, states}};
+}
+
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/powerstats/DvfsStateResidencyDataProvider.cpp b/powerstats/DvfsStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..511159e
--- /dev/null
+++ b/powerstats/DvfsStateResidencyDataProvider.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 "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;
+
+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/UfsStateResidencyDataProvider.cpp b/powerstats/UfsStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..aec7724
--- /dev/null
+++ b/powerstats/UfsStateResidencyDataProvider.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "UfsStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <string>
+#include <utility>
+
+using android::base::ParseInt;
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::Trim;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+const int32_t HIBERNATE_STATE_ID = 0;
+const std::string UFS_NAME = "UFS";
+
+UfsStateResidencyDataProvider::UfsStateResidencyDataProvider(std::string prefix) : kPrefix(prefix) {}
+
+bool UfsStateResidencyDataProvider::getStateResidencies(
+ std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
+ StateResidency residency;
+ residency.id = HIBERNATE_STATE_ID;
+
+ // The transform function converts microseconds to milliseconds.
+ std::function<uint64_t(uint64_t)> usecToMs = [](uint64_t a) { return a / 1000; };
+
+ residency.totalTimeInStateMs = usecToMs(readStat(kPrefix + "hibern8_total_us"));
+ residency.totalStateEntryCount = readStat(kPrefix + "hibern8_exit_cnt");
+ residency.lastEntryTimestampMs = usecToMs(readStat(kPrefix + "last_hibern8_enter_time"));
+
+ residencies->emplace(UFS_NAME, std::vector<StateResidency>{residency});
+ return true;
+}
+
+std::unordered_map<std::string, std::vector<State>> UfsStateResidencyDataProvider::getInfo() {
+ return {{UFS_NAME, std::vector<State>{{HIBERNATE_STATE_ID, "HIBERN8"}} }};
+}
+
+int64_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());
+ int64_t ret;
+ if (!ParseInt(Trim(std::string(buf)), &ret)) {
+ LOG(ERROR) << "Failed to parse int64 from [" << std::string(buf) << "]";
+ }
+ return ret;
+}
+
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/powerstats/include/AocStateResidencyDataProvider.h b/powerstats/include/AocStateResidencyDataProvider.h
new file mode 100644
index 0000000..5008912
--- /dev/null
+++ b/powerstats/include/AocStateResidencyDataProvider.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/include/DevfreqStateResidencyDataProvider.h b/powerstats/include/DevfreqStateResidencyDataProvider.h
new file mode 100644
index 0000000..8341b43
--- /dev/null
+++ b/powerstats/include/DevfreqStateResidencyDataProvider.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <PowerStatsAidl.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+class DevfreqStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider {
+ public:
+ DevfreqStateResidencyDataProvider(const std::string& name, const std::string& path);
+ ~DevfreqStateResidencyDataProvider() = 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:
+ bool extractNum(const char *str, char **str_end, int base, int64_t* num);
+ std::vector<std::pair<int64_t, int64_t>> parseTimeInState();
+ const std::string mName;
+ const std::string mPath;
+};
+
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/powerstats/include/DvfsStateResidencyDataProvider.h b/powerstats/include/DvfsStateResidencyDataProvider.h
new file mode 100644
index 0000000..ca8ab22
--- /dev/null
+++ b/powerstats/include/DvfsStateResidencyDataProvider.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/include/UfsStateResidencyDataProvider.h b/powerstats/include/UfsStateResidencyDataProvider.h
new file mode 100644
index 0000000..f4ef268
--- /dev/null
+++ b/powerstats/include/UfsStateResidencyDataProvider.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <PowerStatsAidl.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+
+class UfsStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider {
+ public:
+ UfsStateResidencyDataProvider(std::string prefix);
+ ~UfsStateResidencyDataProvider() = 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:
+ int64_t readStat(std::string path);
+
+ const std::string kPrefix;
+};
+
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+} // namespace aidl