• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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