1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <aidl/android/hardware/power/CpuHeadroomParams.h>
18 #include <aidl/android/hardware/power/GpuHeadroomParams.h>
19 #include <aidl/android/os/CpuHeadroomParamsInternal.h>
20 #include <aidl/android/os/GpuHeadroomParamsInternal.h>
21 #include <aidl/android/os/IHintManager.h>
22 #include <android/binder_manager.h>
23 #include <android/system_health.h>
24 #include <binder/IServiceManager.h>
25 #include <binder/Status.h>
26
27 using namespace android;
28 using namespace aidl::android::os;
29 namespace hal = aidl::android::hardware::power;
30
31 struct ACpuHeadroomParams : public CpuHeadroomParamsInternal {};
32 struct AGpuHeadroomParams : public GpuHeadroomParamsInternal {};
33
34 const int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50;
35 const int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000;
36 const int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50;
37 const int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000;
38 const int CPU_HEADROOM_MAX_TID_COUNT = 5;
39
40 struct ASystemHealthManager {
41 public:
42 static ASystemHealthManager* getInstance();
43 ASystemHealthManager(std::shared_ptr<IHintManager>& hintManager);
44 ASystemHealthManager() = delete;
45 ~ASystemHealthManager();
46 int getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom);
47 int getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom);
48 int getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis);
49 int getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis);
50
51 private:
52 static ASystemHealthManager* create(std::shared_ptr<IHintManager> hintManager);
53 std::shared_ptr<IHintManager> mHintManager;
54 };
55
getInstance()56 ASystemHealthManager* ASystemHealthManager::getInstance() {
57 static std::once_flag creationFlag;
58 static ASystemHealthManager* instance = nullptr;
59 std::call_once(creationFlag, []() { instance = create(nullptr); });
60 return instance;
61 }
62
ASystemHealthManager(std::shared_ptr<IHintManager> & hintManager)63 ASystemHealthManager::ASystemHealthManager(std::shared_ptr<IHintManager>& hintManager)
64 : mHintManager(std::move(hintManager)) {}
65
~ASystemHealthManager()66 ASystemHealthManager::~ASystemHealthManager() {}
67
create(std::shared_ptr<IHintManager> hintManager)68 ASystemHealthManager* ASystemHealthManager::create(std::shared_ptr<IHintManager> hintManager) {
69 if (!hintManager) {
70 hintManager = IHintManager::fromBinder(
71 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
72 }
73 if (hintManager == nullptr) {
74 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
75 return nullptr;
76 }
77 return new ASystemHealthManager(hintManager);
78 }
79
ASystemHealth_acquireManager()80 ASystemHealthManager* ASystemHealth_acquireManager() {
81 return ASystemHealthManager::getInstance();
82 }
83
getCpuHeadroom(const ACpuHeadroomParams * params,float * outHeadroom)84 int ASystemHealthManager::getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom) {
85 std::optional<hal::CpuHeadroomResult> res;
86 ::ndk::ScopedAStatus ret;
87 CpuHeadroomParamsInternal internalParams;
88 if (!params) {
89 ret = mHintManager->getCpuHeadroom(internalParams, &res);
90 } else {
91 ret = mHintManager->getCpuHeadroom(*params, &res);
92 }
93 if (!ret.isOk()) {
94 LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT,
95 "Invalid ACpuHeadroomParams: %s", ret.getMessage());
96 ALOGE("ASystemHealth_getCpuHeadroom fails: %s", ret.getMessage());
97 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
98 return ENOTSUP;
99 } else if (ret.getExceptionCode() == EX_SECURITY) {
100 return EPERM;
101 }
102 return EPIPE;
103 }
104 *outHeadroom = res->get<hal::CpuHeadroomResult::Tag::globalHeadroom>();
105 return OK;
106 }
107
getGpuHeadroom(const AGpuHeadroomParams * params,float * outHeadroom)108 int ASystemHealthManager::getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom) {
109 std::optional<hal::GpuHeadroomResult> res;
110 ::ndk::ScopedAStatus ret;
111 GpuHeadroomParamsInternal internalParams;
112 if (!params) {
113 ret = mHintManager->getGpuHeadroom(internalParams, &res);
114 } else {
115 ret = mHintManager->getGpuHeadroom(*params, &res);
116 }
117 if (!ret.isOk()) {
118 LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT,
119 "Invalid AGpuHeadroomParams: %s", ret.getMessage());
120 ALOGE("ASystemHealth_getGpuHeadroom fails: %s", ret.getMessage());
121 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
122 return ENOTSUP;
123 }
124 return EPIPE;
125 }
126 *outHeadroom = res->get<hal::GpuHeadroomResult::Tag::globalHeadroom>();
127 return OK;
128 }
129
getCpuHeadroomMinIntervalMillis(int64_t * outMinIntervalMillis)130 int ASystemHealthManager::getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
131 int64_t minIntervalMillis = 0;
132 ::ndk::ScopedAStatus ret = mHintManager->getCpuHeadroomMinIntervalMillis(&minIntervalMillis);
133 if (!ret.isOk()) {
134 ALOGE("ASystemHealth_getCpuHeadroomMinIntervalMillis fails: %s", ret.getMessage());
135 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
136 return ENOTSUP;
137 }
138 return EPIPE;
139 }
140 *outMinIntervalMillis = minIntervalMillis;
141 return OK;
142 }
143
getGpuHeadroomMinIntervalMillis(int64_t * outMinIntervalMillis)144 int ASystemHealthManager::getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
145 int64_t minIntervalMillis = 0;
146 ::ndk::ScopedAStatus ret = mHintManager->getGpuHeadroomMinIntervalMillis(&minIntervalMillis);
147 if (!ret.isOk()) {
148 ALOGE("ASystemHealth_getGpuHeadroomMinIntervalMillis fails: %s", ret.getMessage());
149 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
150 return ENOTSUP;
151 }
152 return EPIPE;
153 }
154 *outMinIntervalMillis = minIntervalMillis;
155 return OK;
156 }
157
ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams * _Nullable params,float * _Nonnull outHeadroom)158 int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams* _Nullable params,
159 float* _Nonnull outHeadroom) {
160 LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__);
161 auto manager = ASystemHealthManager::getInstance();
162 if (manager == nullptr) return ENOTSUP;
163 return manager->getCpuHeadroom(params, outHeadroom);
164 }
165
ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams * _Nullable params,float * _Nonnull outHeadroom)166 int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams* _Nullable params,
167 float* _Nonnull outHeadroom) {
168 LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__);
169 auto manager = ASystemHealthManager::getInstance();
170 if (manager == nullptr) return ENOTSUP;
171 return manager->getGpuHeadroom(params, outHeadroom);
172 }
173
ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t * _Nonnull outMinIntervalMillis)174 int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) {
175 LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr,
176 "%s: outMinIntervalMillis should not be null", __FUNCTION__);
177 auto manager = ASystemHealthManager::getInstance();
178 if (manager == nullptr) return ENOTSUP;
179 return manager->getCpuHeadroomMinIntervalMillis(outMinIntervalMillis);
180 }
181
ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t * _Nonnull outMinIntervalMillis)182 int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) {
183 LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr,
184 "%s: outMinIntervalMillis should not be null", __FUNCTION__);
185 auto manager = ASystemHealthManager::getInstance();
186 if (manager == nullptr) return ENOTSUP;
187 return manager->getGpuHeadroomMinIntervalMillis(outMinIntervalMillis);
188 }
189
ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams * _Nonnull params,int windowMillis)190 void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params,
191 int windowMillis) {
192 LOG_ALWAYS_FATAL_IF(windowMillis < CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN ||
193 windowMillis > CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX,
194 "%s: windowMillis should be in range [50, 10000] but got %d", __FUNCTION__,
195 windowMillis);
196 params->calculationWindowMillis = windowMillis;
197 }
198
AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams * _Nonnull params,int windowMillis)199 void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params,
200 int windowMillis) {
201 LOG_ALWAYS_FATAL_IF(windowMillis < GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN ||
202 windowMillis > GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX,
203 "%s: windowMillis should be in range [50, 10000] but got %d", __FUNCTION__,
204 windowMillis);
205 params->calculationWindowMillis = windowMillis;
206 }
207
ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams * _Nonnull params)208 int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params) {
209 return params->calculationWindowMillis;
210 }
211
AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams * _Nonnull params)212 int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params) {
213 return params->calculationWindowMillis;
214 }
215
ACpuHeadroomParams_setTids(ACpuHeadroomParams * _Nonnull params,const int * _Nonnull tids,int tidsSize)216 void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int* _Nonnull tids,
217 int tidsSize) {
218 LOG_ALWAYS_FATAL_IF(tids == nullptr, "%s: tids should not be null", __FUNCTION__);
219 LOG_ALWAYS_FATAL_IF(tidsSize > CPU_HEADROOM_MAX_TID_COUNT, "%s: tids size should not exceed 5",
220 __FUNCTION__);
221 params->tids.resize(tidsSize);
222 params->tids.clear();
223 for (int i = 0; i < tidsSize; ++i) {
224 LOG_ALWAYS_FATAL_IF(tids[i] <= 0, "ACpuHeadroomParams_setTids: Invalid non-positive tid %d",
225 tids[i]);
226 params->tids[i] = tids[i];
227 }
228 }
229
ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams * _Nonnull params,ACpuHeadroomCalculationType calculationType)230 void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams* _Nonnull params,
231 ACpuHeadroomCalculationType calculationType) {
232 LOG_ALWAYS_FATAL_IF(calculationType < ACpuHeadroomCalculationType::
233 ACPU_HEADROOM_CALCULATION_TYPE_MIN ||
234 calculationType > ACpuHeadroomCalculationType::
235 ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE,
236 "%s: calculationType should be one of ACpuHeadroomCalculationType values "
237 "but got %d",
238 __FUNCTION__, calculationType);
239 params->calculationType = static_cast<hal::CpuHeadroomParams::CalculationType>(calculationType);
240 }
241
ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams * _Nonnull params)242 ACpuHeadroomCalculationType ACpuHeadroomParams_getCalculationType(
243 ACpuHeadroomParams* _Nonnull params) {
244 return static_cast<ACpuHeadroomCalculationType>(params->calculationType);
245 }
246
AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams * _Nonnull params,AGpuHeadroomCalculationType calculationType)247 void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams* _Nonnull params,
248 AGpuHeadroomCalculationType calculationType) {
249 LOG_ALWAYS_FATAL_IF(calculationType < AGpuHeadroomCalculationType::
250 AGPU_HEADROOM_CALCULATION_TYPE_MIN ||
251 calculationType > AGpuHeadroomCalculationType::
252 AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE,
253 "%s: calculationType should be one of AGpuHeadroomCalculationType values "
254 "but got %d",
255 __FUNCTION__, calculationType);
256 params->calculationType = static_cast<hal::GpuHeadroomParams::CalculationType>(calculationType);
257 }
258
AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams * _Nonnull params)259 AGpuHeadroomCalculationType AGpuHeadroomParams_getCalculationType(
260 AGpuHeadroomParams* _Nonnull params) {
261 return static_cast<AGpuHeadroomCalculationType>(params->calculationType);
262 }
263
ACpuHeadroomParams_create()264 ACpuHeadroomParams* _Nonnull ACpuHeadroomParams_create() {
265 return new ACpuHeadroomParams();
266 }
267
AGpuHeadroomParams_create()268 AGpuHeadroomParams* _Nonnull AGpuHeadroomParams_create() {
269 return new AGpuHeadroomParams();
270 }
271
ACpuHeadroomParams_destroy(ACpuHeadroomParams * _Nonnull params)272 void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nonnull params) {
273 delete params;
274 }
275
AGpuHeadroomParams_destroy(AGpuHeadroomParams * _Nonnull params)276 void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nonnull params) {
277 delete params;
278 }
279