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 #define LOG_TAG "system_health"
18
19 #include <aidl/android/hardware/power/CpuHeadroomParams.h>
20 #include <aidl/android/hardware/power/GpuHeadroomParams.h>
21 #include <aidl/android/os/CpuHeadroomParamsInternal.h>
22 #include <aidl/android/os/GpuHeadroomParamsInternal.h>
23 #include <aidl/android/os/IHintManager.h>
24 #include <android/binder_manager.h>
25 #include <android/system_health.h>
26 #include <binder/IServiceManager.h>
27 #include <binder/Status.h>
28 #include <system_health_private.h>
29
30 #include <list>
31 #include <map>
32 #include <memory>
33 #include <mutex>
34 #include <optional>
35 #include <utility>
36
37 #include "android-base/thread_annotations.h"
38 #include "utils/SystemClock.h"
39
40 using namespace android;
41 using namespace aidl::android::os;
42 namespace hal = aidl::android::hardware::power;
43
44 struct ACpuHeadroomParams : public CpuHeadroomParamsInternal {};
45 struct AGpuHeadroomParams : public GpuHeadroomParamsInternal {};
46
47 struct ASystemHealthManager {
48 public:
49 static ASystemHealthManager* getInstance();
50
51 ASystemHealthManager(std::shared_ptr<IHintManager>& hintManager,
52 IHintManager::HintManagerClientData&& clientData);
53 ASystemHealthManager() = delete;
54 ~ASystemHealthManager();
55 int getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom);
56 int getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom);
57 int getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis);
58 int getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis);
59 int getMaxCpuHeadroomTidsSize(size_t* outSize);
60 int getCpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
61 int32_t* _Nonnull outMaxMillis);
62 int getGpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
63 int32_t* _Nonnull outMaxMillis);
64
65 private:
66 static ASystemHealthManager* create(std::shared_ptr<IHintManager> hintManager);
67 std::shared_ptr<IHintManager> mHintManager;
68 IHintManager::HintManagerClientData mClientData;
69 };
70
71 static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
72 static std::shared_ptr<ASystemHealthManager> gSystemHealthManagerForTesting = nullptr;
73
getInstance()74 ASystemHealthManager* ASystemHealthManager::getInstance() {
75 static std::once_flag creationFlag;
76 static ASystemHealthManager* instance = nullptr;
77 if (gSystemHealthManagerForTesting) {
78 return gSystemHealthManagerForTesting.get();
79 }
80 if (gIHintManagerForTesting) {
81 gSystemHealthManagerForTesting =
82 std::shared_ptr<ASystemHealthManager>(create(*gIHintManagerForTesting));
83 return gSystemHealthManagerForTesting.get();
84 }
85 std::call_once(creationFlag, []() { instance = create(nullptr); });
86 return instance;
87 }
88
ASystemHealthManager(std::shared_ptr<IHintManager> & hintManager,IHintManager::HintManagerClientData && clientData)89 ASystemHealthManager::ASystemHealthManager(std::shared_ptr<IHintManager>& hintManager,
90 IHintManager::HintManagerClientData&& clientData)
91 : mHintManager(std::move(hintManager)), mClientData(clientData) {}
92
93 ASystemHealthManager::~ASystemHealthManager() = default;
94
create(std::shared_ptr<IHintManager> hintManager)95 ASystemHealthManager* ASystemHealthManager::create(std::shared_ptr<IHintManager> hintManager) {
96 if (!hintManager) {
97 hintManager = IHintManager::fromBinder(
98 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
99 }
100 if (hintManager == nullptr) {
101 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
102 return nullptr;
103 }
104 IHintManager::HintManagerClientData clientData;
105 ndk::ScopedAStatus ret = hintManager->getClientData(&clientData);
106 if (!ret.isOk()) {
107 ALOGE("%s: PerformanceHint service is not initialized %s", __FUNCTION__, ret.getMessage());
108 return nullptr;
109 }
110 return new ASystemHealthManager(hintManager, std::move(clientData));
111 }
112
getCpuHeadroom(const ACpuHeadroomParams * params,float * outHeadroom)113 int ASystemHealthManager::getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom) {
114 if (!mClientData.supportInfo.headroom.isCpuSupported) return ENOTSUP;
115 std::optional<hal::CpuHeadroomResult> res;
116 ::ndk::ScopedAStatus ret;
117 CpuHeadroomParamsInternal internalParams;
118 if (!params) {
119 ret = mHintManager->getCpuHeadroom(internalParams, &res);
120 } else {
121 LOG_ALWAYS_FATAL_IF((int)params->tids.size() > mClientData.maxCpuHeadroomThreads,
122 "%s: tids size should not exceed %d", __FUNCTION__,
123 mClientData.maxCpuHeadroomThreads);
124 LOG_ALWAYS_FATAL_IF(params->calculationWindowMillis <
125 mClientData.supportInfo.headroom
126 .cpuMinCalculationWindowMillis ||
127 params->calculationWindowMillis >
128 mClientData.supportInfo.headroom
129 .cpuMaxCalculationWindowMillis,
130 "%s: calculationWindowMillis should be in range [%d, %d] but got %d",
131 __FUNCTION__,
132 mClientData.supportInfo.headroom.cpuMinCalculationWindowMillis,
133 mClientData.supportInfo.headroom.cpuMaxCalculationWindowMillis,
134 params->calculationWindowMillis);
135 ret = mHintManager->getCpuHeadroom(*params, &res);
136 }
137 if (!ret.isOk()) {
138 LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT,
139 "Invalid ACpuHeadroomParams: %s", ret.getMessage());
140 ALOGE("ASystemHealth_getCpuHeadroom fails: %s", ret.getMessage());
141 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
142 return ENOTSUP;
143 } else if (ret.getExceptionCode() == EX_SECURITY) {
144 return EPERM;
145 }
146 return EPIPE;
147 }
148 *outHeadroom = res ? res->get<hal::CpuHeadroomResult::Tag::globalHeadroom>()
149 : std::numeric_limits<float>::quiet_NaN();
150 return OK;
151 }
152
getGpuHeadroom(const AGpuHeadroomParams * params,float * outHeadroom)153 int ASystemHealthManager::getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom) {
154 if (!mClientData.supportInfo.headroom.isGpuSupported) return ENOTSUP;
155 std::optional<hal::GpuHeadroomResult> res;
156 ::ndk::ScopedAStatus ret;
157 GpuHeadroomParamsInternal internalParams;
158 if (!params) {
159 ret = mHintManager->getGpuHeadroom(internalParams, &res);
160 } else {
161 LOG_ALWAYS_FATAL_IF(params->calculationWindowMillis <
162 mClientData.supportInfo.headroom
163 .gpuMinCalculationWindowMillis ||
164 params->calculationWindowMillis >
165 mClientData.supportInfo.headroom
166 .gpuMaxCalculationWindowMillis,
167 "%s: calculationWindowMillis should be in range [%d, %d] but got %d",
168 __FUNCTION__,
169 mClientData.supportInfo.headroom.gpuMinCalculationWindowMillis,
170 mClientData.supportInfo.headroom.gpuMaxCalculationWindowMillis,
171 params->calculationWindowMillis);
172 ret = mHintManager->getGpuHeadroom(*params, &res);
173 }
174 if (!ret.isOk()) {
175 LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT,
176 "Invalid AGpuHeadroomParams: %s", ret.getMessage());
177 ALOGE("ASystemHealth_getGpuHeadroom fails: %s", ret.getMessage());
178 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
179 return ENOTSUP;
180 }
181 return EPIPE;
182 }
183 *outHeadroom = res ? res->get<hal::GpuHeadroomResult::Tag::globalHeadroom>()
184 : std::numeric_limits<float>::quiet_NaN();
185 return OK;
186 }
187
getCpuHeadroomMinIntervalMillis(int64_t * outMinIntervalMillis)188 int ASystemHealthManager::getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
189 if (!mClientData.supportInfo.headroom.isCpuSupported) return ENOTSUP;
190 *outMinIntervalMillis = mClientData.supportInfo.headroom.cpuMinIntervalMillis;
191 return OK;
192 }
193
getGpuHeadroomMinIntervalMillis(int64_t * outMinIntervalMillis)194 int ASystemHealthManager::getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
195 if (!mClientData.supportInfo.headroom.isGpuSupported) return ENOTSUP;
196 *outMinIntervalMillis = mClientData.supportInfo.headroom.gpuMinIntervalMillis;
197 return OK;
198 }
199
getMaxCpuHeadroomTidsSize(size_t * outSize)200 int ASystemHealthManager::getMaxCpuHeadroomTidsSize(size_t* outSize) {
201 if (!mClientData.supportInfo.headroom.isGpuSupported) return ENOTSUP;
202 *outSize = mClientData.maxCpuHeadroomThreads;
203 return OK;
204 }
205
getCpuHeadroomCalculationWindowRange(int32_t * _Nonnull outMinMillis,int32_t * _Nonnull outMaxMillis)206 int ASystemHealthManager::getCpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
207 int32_t* _Nonnull outMaxMillis) {
208 if (!mClientData.supportInfo.headroom.isCpuSupported) return ENOTSUP;
209 *outMinMillis = mClientData.supportInfo.headroom.cpuMinCalculationWindowMillis;
210 *outMaxMillis = mClientData.supportInfo.headroom.cpuMaxCalculationWindowMillis;
211 return OK;
212 }
213
getGpuHeadroomCalculationWindowRange(int32_t * _Nonnull outMinMillis,int32_t * _Nonnull outMaxMillis)214 int ASystemHealthManager::getGpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
215 int32_t* _Nonnull outMaxMillis) {
216 if (!mClientData.supportInfo.headroom.isGpuSupported) return ENOTSUP;
217 *outMinMillis = mClientData.supportInfo.headroom.gpuMinCalculationWindowMillis;
218 *outMaxMillis = mClientData.supportInfo.headroom.gpuMaxCalculationWindowMillis;
219 return OK;
220 }
221
ASystemHealth_getMaxCpuHeadroomTidsSize(size_t * _Nonnull outSize)222 int ASystemHealth_getMaxCpuHeadroomTidsSize(size_t* _Nonnull outSize) {
223 LOG_ALWAYS_FATAL_IF(outSize == nullptr, "%s: outSize should not be null", __FUNCTION__);
224 auto manager = ASystemHealthManager::getInstance();
225 if (manager == nullptr) return ENOTSUP;
226 return manager->getMaxCpuHeadroomTidsSize(outSize);
227 }
228
ASystemHealth_getCpuHeadroomCalculationWindowRange(int32_t * _Nonnull outMinMillis,int32_t * _Nonnull outMaxMillis)229 int ASystemHealth_getCpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
230 int32_t* _Nonnull outMaxMillis) {
231 LOG_ALWAYS_FATAL_IF(outMinMillis == nullptr, "%s: outMinMillis should not be null",
232 __FUNCTION__);
233 LOG_ALWAYS_FATAL_IF(outMaxMillis == nullptr, "%s: outMaxMillis should not be null",
234 __FUNCTION__);
235 auto manager = ASystemHealthManager::getInstance();
236 if (manager == nullptr) return ENOTSUP;
237 return manager->getCpuHeadroomCalculationWindowRange(outMinMillis, outMaxMillis);
238 }
239
ASystemHealth_getGpuHeadroomCalculationWindowRange(int32_t * _Nonnull outMinMillis,int32_t * _Nonnull outMaxMillis)240 int ASystemHealth_getGpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
241 int32_t* _Nonnull outMaxMillis) {
242 LOG_ALWAYS_FATAL_IF(outMinMillis == nullptr, "%s: outMinMillis should not be null",
243 __FUNCTION__);
244 LOG_ALWAYS_FATAL_IF(outMaxMillis == nullptr, "%s: outMaxMillis should not be null",
245 __FUNCTION__);
246 auto manager = ASystemHealthManager::getInstance();
247 if (manager == nullptr) return ENOTSUP;
248 return manager->getGpuHeadroomCalculationWindowRange(outMinMillis, outMaxMillis);
249 }
250
ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams * _Nullable params,float * _Nonnull outHeadroom)251 int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams* _Nullable params,
252 float* _Nonnull outHeadroom) {
253 LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__);
254 auto manager = ASystemHealthManager::getInstance();
255 if (manager == nullptr) return ENOTSUP;
256 return manager->getCpuHeadroom(params, outHeadroom);
257 }
258
ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams * _Nullable params,float * _Nonnull outHeadroom)259 int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams* _Nullable params,
260 float* _Nonnull outHeadroom) {
261 LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__);
262 auto manager = ASystemHealthManager::getInstance();
263 if (manager == nullptr) return ENOTSUP;
264 return manager->getGpuHeadroom(params, outHeadroom);
265 }
266
ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t * _Nonnull outMinIntervalMillis)267 int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) {
268 LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr,
269 "%s: outMinIntervalMillis should not be null", __FUNCTION__);
270 auto manager = ASystemHealthManager::getInstance();
271 if (manager == nullptr) return ENOTSUP;
272 return manager->getCpuHeadroomMinIntervalMillis(outMinIntervalMillis);
273 }
274
ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t * _Nonnull outMinIntervalMillis)275 int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) {
276 LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr,
277 "%s: outMinIntervalMillis should not be null", __FUNCTION__);
278 auto manager = ASystemHealthManager::getInstance();
279 if (manager == nullptr) return ENOTSUP;
280 return manager->getGpuHeadroomMinIntervalMillis(outMinIntervalMillis);
281 }
282
ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams * _Nonnull params,int windowMillis)283 void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params,
284 int windowMillis) {
285 LOG_ALWAYS_FATAL_IF(windowMillis <= 0, "%s: windowMillis should be positive but got %d",
286 __FUNCTION__, windowMillis);
287 params->calculationWindowMillis = windowMillis;
288 }
289
AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams * _Nonnull params,int windowMillis)290 void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params,
291 int windowMillis) {
292 LOG_ALWAYS_FATAL_IF(windowMillis <= 0, "%s: windowMillis should be positive but got %d",
293 __FUNCTION__, windowMillis);
294 params->calculationWindowMillis = windowMillis;
295 }
296
ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams * _Nonnull params)297 int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params) {
298 return params->calculationWindowMillis;
299 }
300
AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams * _Nonnull params)301 int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params) {
302 return params->calculationWindowMillis;
303 }
304
ACpuHeadroomParams_setTids(ACpuHeadroomParams * _Nonnull params,const int * _Nonnull tids,size_t tidsSize)305 void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int* _Nonnull tids,
306 size_t tidsSize) {
307 LOG_ALWAYS_FATAL_IF(tids == nullptr, "%s: tids should not be null", __FUNCTION__);
308 params->tids.resize(tidsSize);
309 for (int i = 0; i < (int)tidsSize; ++i) {
310 LOG_ALWAYS_FATAL_IF(tids[i] <= 0, "ACpuHeadroomParams_setTids: Invalid non-positive tid %d",
311 tids[i]);
312 params->tids[i] = tids[i];
313 }
314 }
315
ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams * _Nonnull params,ACpuHeadroomCalculationType calculationType)316 void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams* _Nonnull params,
317 ACpuHeadroomCalculationType calculationType) {
318 LOG_ALWAYS_FATAL_IF(calculationType < ACpuHeadroomCalculationType::
319 ACPU_HEADROOM_CALCULATION_TYPE_MIN ||
320 calculationType > ACpuHeadroomCalculationType::
321 ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE,
322 "%s: calculationType should be one of ACpuHeadroomCalculationType values "
323 "but got %d",
324 __FUNCTION__, calculationType);
325 params->calculationType = static_cast<hal::CpuHeadroomParams::CalculationType>(calculationType);
326 }
327
ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams * _Nonnull params)328 ACpuHeadroomCalculationType ACpuHeadroomParams_getCalculationType(
329 ACpuHeadroomParams* _Nonnull params) {
330 return static_cast<ACpuHeadroomCalculationType>(params->calculationType);
331 }
332
AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams * _Nonnull params,AGpuHeadroomCalculationType calculationType)333 void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams* _Nonnull params,
334 AGpuHeadroomCalculationType calculationType) {
335 LOG_ALWAYS_FATAL_IF(calculationType < AGpuHeadroomCalculationType::
336 AGPU_HEADROOM_CALCULATION_TYPE_MIN ||
337 calculationType > AGpuHeadroomCalculationType::
338 AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE,
339 "%s: calculationType should be one of AGpuHeadroomCalculationType values "
340 "but got %d",
341 __FUNCTION__, calculationType);
342 params->calculationType = static_cast<hal::GpuHeadroomParams::CalculationType>(calculationType);
343 }
344
AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams * _Nonnull params)345 AGpuHeadroomCalculationType AGpuHeadroomParams_getCalculationType(
346 AGpuHeadroomParams* _Nonnull params) {
347 return static_cast<AGpuHeadroomCalculationType>(params->calculationType);
348 }
349
ACpuHeadroomParams_create()350 ACpuHeadroomParams* _Nonnull ACpuHeadroomParams_create() {
351 return new ACpuHeadroomParams();
352 }
353
AGpuHeadroomParams_create()354 AGpuHeadroomParams* _Nonnull AGpuHeadroomParams_create() {
355 return new AGpuHeadroomParams();
356 }
357
ACpuHeadroomParams_destroy(ACpuHeadroomParams * _Nullable params)358 void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nullable params) {
359 delete params;
360 }
361
AGpuHeadroomParams_destroy(AGpuHeadroomParams * _Nullable params)362 void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nullable params) {
363 delete params;
364 }
365
ASystemHealth_setIHintManagerForTesting(void * iManager)366 void ASystemHealth_setIHintManagerForTesting(void* iManager) {
367 if (iManager == nullptr) {
368 gSystemHealthManagerForTesting = nullptr;
369 }
370 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
371 }
372