/* * Copyright (C) 2024 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 #include #include #include #include #include #include #include #include using namespace android; using namespace aidl::android::os; namespace hal = aidl::android::hardware::power; struct ACpuHeadroomParams : public CpuHeadroomParamsInternal {}; struct AGpuHeadroomParams : public GpuHeadroomParamsInternal {}; const int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; const int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; const int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; const int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; const int CPU_HEADROOM_MAX_TID_COUNT = 5; struct ASystemHealthManager { public: static ASystemHealthManager* getInstance(); ASystemHealthManager(std::shared_ptr& hintManager); ASystemHealthManager() = delete; ~ASystemHealthManager(); int getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom); int getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom); int getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis); int getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis); private: static ASystemHealthManager* create(std::shared_ptr hintManager); std::shared_ptr mHintManager; }; ASystemHealthManager* ASystemHealthManager::getInstance() { static std::once_flag creationFlag; static ASystemHealthManager* instance = nullptr; std::call_once(creationFlag, []() { instance = create(nullptr); }); return instance; } ASystemHealthManager::ASystemHealthManager(std::shared_ptr& hintManager) : mHintManager(std::move(hintManager)) {} ASystemHealthManager::~ASystemHealthManager() {} ASystemHealthManager* ASystemHealthManager::create(std::shared_ptr hintManager) { if (!hintManager) { hintManager = IHintManager::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService("performance_hint"))); } if (hintManager == nullptr) { ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); return nullptr; } return new ASystemHealthManager(hintManager); } ASystemHealthManager* ASystemHealth_acquireManager() { return ASystemHealthManager::getInstance(); } int ASystemHealthManager::getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom) { std::optional res; ::ndk::ScopedAStatus ret; CpuHeadroomParamsInternal internalParams; if (!params) { ret = mHintManager->getCpuHeadroom(internalParams, &res); } else { ret = mHintManager->getCpuHeadroom(*params, &res); } if (!ret.isOk()) { LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT, "Invalid ACpuHeadroomParams: %s", ret.getMessage()); ALOGE("ASystemHealth_getCpuHeadroom fails: %s", ret.getMessage()); if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) { return ENOTSUP; } else if (ret.getExceptionCode() == EX_SECURITY) { return EPERM; } return EPIPE; } *outHeadroom = res->get(); return OK; } int ASystemHealthManager::getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom) { std::optional res; ::ndk::ScopedAStatus ret; GpuHeadroomParamsInternal internalParams; if (!params) { ret = mHintManager->getGpuHeadroom(internalParams, &res); } else { ret = mHintManager->getGpuHeadroom(*params, &res); } if (!ret.isOk()) { LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT, "Invalid AGpuHeadroomParams: %s", ret.getMessage()); ALOGE("ASystemHealth_getGpuHeadroom fails: %s", ret.getMessage()); if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) { return ENOTSUP; } return EPIPE; } *outHeadroom = res->get(); return OK; } int ASystemHealthManager::getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) { int64_t minIntervalMillis = 0; ::ndk::ScopedAStatus ret = mHintManager->getCpuHeadroomMinIntervalMillis(&minIntervalMillis); if (!ret.isOk()) { ALOGE("ASystemHealth_getCpuHeadroomMinIntervalMillis fails: %s", ret.getMessage()); if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) { return ENOTSUP; } return EPIPE; } *outMinIntervalMillis = minIntervalMillis; return OK; } int ASystemHealthManager::getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) { int64_t minIntervalMillis = 0; ::ndk::ScopedAStatus ret = mHintManager->getGpuHeadroomMinIntervalMillis(&minIntervalMillis); if (!ret.isOk()) { ALOGE("ASystemHealth_getGpuHeadroomMinIntervalMillis fails: %s", ret.getMessage()); if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) { return ENOTSUP; } return EPIPE; } *outMinIntervalMillis = minIntervalMillis; return OK; } int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams* _Nullable params, float* _Nonnull outHeadroom) { LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__); auto manager = ASystemHealthManager::getInstance(); if (manager == nullptr) return ENOTSUP; return manager->getCpuHeadroom(params, outHeadroom); } int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams* _Nullable params, float* _Nonnull outHeadroom) { LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__); auto manager = ASystemHealthManager::getInstance(); if (manager == nullptr) return ENOTSUP; return manager->getGpuHeadroom(params, outHeadroom); } int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) { LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr, "%s: outMinIntervalMillis should not be null", __FUNCTION__); auto manager = ASystemHealthManager::getInstance(); if (manager == nullptr) return ENOTSUP; return manager->getCpuHeadroomMinIntervalMillis(outMinIntervalMillis); } int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) { LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr, "%s: outMinIntervalMillis should not be null", __FUNCTION__); auto manager = ASystemHealthManager::getInstance(); if (manager == nullptr) return ENOTSUP; return manager->getGpuHeadroomMinIntervalMillis(outMinIntervalMillis); } void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params, int windowMillis) { LOG_ALWAYS_FATAL_IF(windowMillis < CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN || windowMillis > CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX, "%s: windowMillis should be in range [50, 10000] but got %d", __FUNCTION__, windowMillis); params->calculationWindowMillis = windowMillis; } void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params, int windowMillis) { LOG_ALWAYS_FATAL_IF(windowMillis < GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN || windowMillis > GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX, "%s: windowMillis should be in range [50, 10000] but got %d", __FUNCTION__, windowMillis); params->calculationWindowMillis = windowMillis; } int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params) { return params->calculationWindowMillis; } int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params) { return params->calculationWindowMillis; } void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int* _Nonnull tids, int tidsSize) { LOG_ALWAYS_FATAL_IF(tids == nullptr, "%s: tids should not be null", __FUNCTION__); LOG_ALWAYS_FATAL_IF(tidsSize > CPU_HEADROOM_MAX_TID_COUNT, "%s: tids size should not exceed 5", __FUNCTION__); params->tids.resize(tidsSize); params->tids.clear(); for (int i = 0; i < tidsSize; ++i) { LOG_ALWAYS_FATAL_IF(tids[i] <= 0, "ACpuHeadroomParams_setTids: Invalid non-positive tid %d", tids[i]); params->tids[i] = tids[i]; } } void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams* _Nonnull params, ACpuHeadroomCalculationType calculationType) { LOG_ALWAYS_FATAL_IF(calculationType < ACpuHeadroomCalculationType:: ACPU_HEADROOM_CALCULATION_TYPE_MIN || calculationType > ACpuHeadroomCalculationType:: ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE, "%s: calculationType should be one of ACpuHeadroomCalculationType values " "but got %d", __FUNCTION__, calculationType); params->calculationType = static_cast(calculationType); } ACpuHeadroomCalculationType ACpuHeadroomParams_getCalculationType( ACpuHeadroomParams* _Nonnull params) { return static_cast(params->calculationType); } void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams* _Nonnull params, AGpuHeadroomCalculationType calculationType) { LOG_ALWAYS_FATAL_IF(calculationType < AGpuHeadroomCalculationType:: AGPU_HEADROOM_CALCULATION_TYPE_MIN || calculationType > AGpuHeadroomCalculationType:: AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE, "%s: calculationType should be one of AGpuHeadroomCalculationType values " "but got %d", __FUNCTION__, calculationType); params->calculationType = static_cast(calculationType); } AGpuHeadroomCalculationType AGpuHeadroomParams_getCalculationType( AGpuHeadroomParams* _Nonnull params) { return static_cast(params->calculationType); } ACpuHeadroomParams* _Nonnull ACpuHeadroomParams_create() { return new ACpuHeadroomParams(); } AGpuHeadroomParams* _Nonnull AGpuHeadroomParams_create() { return new AGpuHeadroomParams(); } void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nonnull params) { delete params; } void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nonnull params) { delete params; }