diff --git a/powerstats/UfsStateResidencyDataProvider.cpp b/powerstats/UfsStateResidencyDataProvider.cpp new file mode 100644 index 00000000..aec77241 --- /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 +#include +#include + +#include +#include + +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> *residencies) { + StateResidency residency; + residency.id = HIBERNATE_STATE_ID; + + // The transform function converts microseconds to milliseconds. + std::function 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{residency}); + return true; +} + +std::unordered_map> UfsStateResidencyDataProvider::getInfo() { + return {{UFS_NAME, std::vector{{HIBERNATE_STATE_ID, "HIBERN8"}} }}; +} + +int64_t UfsStateResidencyDataProvider::readStat(std::string path) { + std::unique_ptr 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/UfsStateResidencyDataProvider.h b/powerstats/UfsStateResidencyDataProvider.h new file mode 100644 index 00000000..f4ef268d --- /dev/null +++ b/powerstats/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 + +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> *residencies) override; + + /* + * See IStateResidencyDataProvider::getInfo + */ + std::unordered_map> getInfo() override; + + private: + int64_t readStat(std::string path); + + const std::string kPrefix; +}; + +} // namespace stats +} // namespace power +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/powerstats/service.cpp b/powerstats/service.cpp index acf4b8a8..0d43367e 100644 --- a/powerstats/service.cpp +++ b/powerstats/service.cpp @@ -19,6 +19,7 @@ #include #include "AocStateResidencyDataProvider.h" #include "DvfsStateResidencyDataProvider.h" +#include "UfsStateResidencyDataProvider.h" #include #include #include @@ -35,6 +36,7 @@ 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::UfsStateResidencyDataProvider; using aidl::android::hardware::power::stats::EnergyConsumerType; using aidl::android::hardware::power::stats::GenericStateResidencyDataProvider; using aidl::android::hardware::power::stats::IioEnergyMeterDataProvider; @@ -506,6 +508,10 @@ void addWifi(std::shared_ptr p) { p->addStateResidencyDataProvider(wifiSdp); } +void addUfs(std::shared_ptr p) { + p->addStateResidencyDataProvider(std::make_shared("/sys/bus/platform/devices/14700000.ufs/ufs_stats/")); +} + /** * Unlike other data providers, which source power entity state residency data from the kernel, * this data provider acts as a general-purpose channel for state residency data providers @@ -544,6 +550,7 @@ int main() { addNFC(p); addPCIe(p); addWifi(p); + addUfs(p); const std::string instance = std::string() + PowerStats::descriptor + "/default"; binder_status_t status = AServiceManager_addService(p->asBinder().get(), instance.c_str());