diff --git a/universal7885-common/powerstats/Android.bp b/universal7885-common/powerstats/Android.bp new file mode 100644 index 0000000..c264cfb --- /dev/null +++ b/universal7885-common/powerstats/Android.bp @@ -0,0 +1,16 @@ +cc_binary { + name: "android.hardware.power.stats-service.exynos7", + srcs: [ + "*.cc", + ], + relative_install_path: "hw", + vendor: true, + defaults: [ + "eureka_defaults", + "powerstats_pixel_defaults", + ], + cflags: ["-Wno-thread-safety-negative"], + shared_libs: ["android.hardware.power.stats-impl.pixel"], + init_rc: ["android.hardware.power.stats-service.exynos7.rc"], + vintf_fragments: ["android.hardware.power.stats-service.exynos7.xml"], +} diff --git a/universal7885-common/powerstats/DevFreq.cc b/universal7885-common/powerstats/DevFreq.cc new file mode 100644 index 0000000..dc44c7b --- /dev/null +++ b/universal7885-common/powerstats/DevFreq.cc @@ -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 "DevFreq.h" + +#include + +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> DevfreqStateResidencyDataProvider::parseTimeInState() { + // Using FILE* instead of std::ifstream for performance reasons + std::unique_ptr fp(fopen(mPath.c_str(), "r"), fclose); + if (!fp) { + PLOG(ERROR) << "Failed to open file " << mPath; + return {}; + } + + std::vector> 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> *residencies) { + std::vector> timeInState = parseTimeInState(); + + if (timeInState.empty()) { + return false; + } + + int32_t id = 0; + std::vector 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> DevfreqStateResidencyDataProvider::getInfo() { + std::vector> timeInState = parseTimeInState(); + + if (timeInState.empty()) { + return {}; + } + + int32_t id = 0; + std::vector 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/universal7885-common/powerstats/DevFreq.h b/universal7885-common/powerstats/DevFreq.h new file mode 100644 index 0000000..8341b43 --- /dev/null +++ b/universal7885-common/powerstats/DevFreq.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 + +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> *residencies) override; + + /* + * See IStateResidencyDataProvider::getInfo + */ + std::unordered_map> getInfo() override; + + private: + bool extractNum(const char *str, char **str_end, int base, int64_t* num); + std::vector> parseTimeInState(); + const std::string mName; + const std::string mPath; +}; + +} // namespace stats +} // namespace power +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/universal7885-common/powerstats/android.hardware.power.stats-service.exynos7.rc b/universal7885-common/powerstats/android.hardware.power.stats-service.exynos7.rc new file mode 100644 index 0000000..810df8a --- /dev/null +++ b/universal7885-common/powerstats/android.hardware.power.stats-service.exynos7.rc @@ -0,0 +1,4 @@ +service vendor.power.stats-hal /vendor/bin/hw/android.hardware.power.stats-service.exynos7 + class hal + user system + group system diff --git a/universal7885-common/powerstats/android.hardware.power.stats-service.exynos7.xml b/universal7885-common/powerstats/android.hardware.power.stats-service.exynos7.xml new file mode 100644 index 0000000..750836f --- /dev/null +++ b/universal7885-common/powerstats/android.hardware.power.stats-service.exynos7.xml @@ -0,0 +1,6 @@ + + + android.hardware.power.stats + IPowerStats/default + + diff --git a/universal7885-common/powerstats/main.cc b/universal7885-common/powerstats/main.cc new file mode 100644 index 0000000..230d0ca --- /dev/null +++ b/universal7885-common/powerstats/main.cc @@ -0,0 +1,70 @@ +/* + * 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 "DevFreq.h" +#include + +#include +#include +#include +#include +#include + +using aidl::android::hardware::power::stats::DevfreqStateResidencyDataProvider; +using aidl::android::hardware::power::stats::PowerStats; + +void addDevFreq(std::shared_ptr p) { + p->addStateResidencyDataProvider( + std::make_unique( + "MIF", "/sys/devices/platform/17000010.devfreq_mif/devfreq/" + "17000010.devfreq_mif")); + p->addStateResidencyDataProvider( + std::make_unique( + "INT", "/sys/devices/platform/17000020.devfreq_int/devfreq/" + "17000020.devfreq_int")); + p->addStateResidencyDataProvider( + std::make_unique( + "DISP", "/sys/devices/platform/17000040.devfreq_disp/devfreq/" + "17000040.devfreq_disp")); + p->addStateResidencyDataProvider( + std::make_unique( + "CAM", "/sys/devices/platform/17000050.devfreq_cam/devfreq/" + "17000050.devfreq_cam")); + p->addStateResidencyDataProvider( + std::make_unique( + "AUD", "/sys/devices/platform/17000060.devfreq_aud/devfreq/" + "17000060.devfreq_aud")); + p->addStateResidencyDataProvider( + std::make_unique( + "FSYS", "/sys/devices/platform/17000070.devfreq_fsys/devfreq/" + "17000070.devfreq_fsys")); +} + + +int main() { + LOG(INFO) << "PowerStats HAL AIDL Service is starting."; + // single thread + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr p = ndk::SharedRefBase::make(); + addDevFreq(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 +} diff --git a/universal7885-common/sepolicy/vendor/file_contexts b/universal7885-common/sepolicy/vendor/file_contexts index 72b64ed..176932c 100644 --- a/universal7885-common/sepolicy/vendor/file_contexts +++ b/universal7885-common/sepolicy/vendor/file_contexts @@ -214,6 +214,7 @@ /(vendor|system/vendor)/bin/hw/android\.hardware\.usb@[0-9]\.[0-9]-service\.a10 u:object_r:hal_usb_default_exec:s0 /(vendor|system/vendor)/bin/hw/vendor\.samsung\.hardware\.gnss@[0-9]\.[0-9]-service u:object_r:hal_gnss_default_exec:s0 /(vendor|system/vendor)/bin/hw/android\.hardware\.sensors@[0-9]\.[0-9]-service\.a10 u:object_r:hal_sensors_default_exec:s0 +/(vendor|system/vendor)/bin/hw/android\.hardware\.power\.stats-service\.exynos7 u:object_r:hal_power_stats_default_exec:s0 /(vendor|system/vendor)/firmware(/.*)? u:object_r:vendor_firmware_file:s0 /factory(/.*)? u:object_r:sec_efs_file:s0 diff --git a/universal7885-common/universal7885-common.mk b/universal7885-common/universal7885-common.mk index 294f02d..c35c564 100644 --- a/universal7885-common/universal7885-common.mk +++ b/universal7885-common/universal7885-common.mk @@ -257,6 +257,10 @@ PRODUCT_PACKAGES += \ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/configs/power/powerhint.json:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.json +# Power Stats impl +PRODUCT_PACKAGES += \ + android.hardware.power.stats-service.exynos7 + # Protobuf PRODUCT_PACKAGES += \ libprotobuf-cpp-full-vendorcompat \