xref: /aosp_15_r20/frameworks/base/native/android/thermal.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2020 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 "thermal"
18 
19 #include <android-base/thread_annotations.h>
20 #include <android/os/BnThermalHeadroomListener.h>
21 #include <android/os/BnThermalStatusListener.h>
22 #include <android/os/IThermalService.h>
23 #include <android/thermal.h>
24 #include <binder/IServiceManager.h>
25 #include <thermal_private.h>
26 #include <utils/Log.h>
27 
28 #include <cerrno>
29 #include <limits>
30 #include <thread>
31 
32 using android::sp;
33 
34 using namespace android;
35 using namespace android::os;
36 
37 struct ThermalServiceStatusListener : public BnThermalStatusListener {
38 public:
39     virtual binder::Status onStatusChange(int32_t status) override;
ThermalServiceStatusListenerThermalServiceStatusListener40     ThermalServiceStatusListener(AThermalManager *manager) {
41         mMgr = manager;
42     }
43 
44 private:
45     AThermalManager *mMgr;
46 };
47 
48 struct ThermalServiceHeadroomListener : public BnThermalHeadroomListener {
49 public:
50     virtual binder::Status onHeadroomChange(float headroom, float forecastHeadroom,
51                                             int32_t forecastSeconds,
52                                             const ::std::vector<float> &thresholds) override;
ThermalServiceHeadroomListenerThermalServiceHeadroomListener53     ThermalServiceHeadroomListener(AThermalManager *manager) {
54         mMgr = manager;
55     }
56 
57 private:
58     AThermalManager *mMgr;
59 };
60 
61 struct StatusListenerCallback {
62     AThermal_StatusCallback callback;
63     void* data;
64 };
65 
66 struct HeadroomListenerCallback {
67     AThermal_HeadroomCallback callback;
68     void *data;
69 };
70 
71 static IThermalService *gIThermalServiceForTesting = nullptr;
72 
73 struct AThermalManager {
74 public:
75     static AThermalManager *createAThermalManager();
76     AThermalManager() = delete;
77     ~AThermalManager();
78     status_t notifyStateChange(int32_t status);
79     status_t notifyHeadroomChange(float headroom, float forecastHeadroom, int32_t forecastSeconds,
80                                   const ::std::vector<float> &thresholds);
81     status_t getCurrentThermalStatus(int32_t *status);
82     status_t addStatusListener(AThermal_StatusCallback, void *data);
83     status_t removeStatusListener(AThermal_StatusCallback, void *data);
84     status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
85     status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size);
86     status_t addHeadroomListener(AThermal_HeadroomCallback, void *data);
87     status_t removeHeadroomListener(AThermal_HeadroomCallback, void *data);
88 
89 private:
90     AThermalManager(sp<IThermalService> service);
91     sp<IThermalService> mThermalSvc;
92     std::mutex mStatusListenerMutex;
93     sp<ThermalServiceStatusListener> mServiceStatusListener GUARDED_BY(mStatusListenerMutex);
94     std::vector<StatusListenerCallback> mStatusListeners GUARDED_BY(mStatusListenerMutex);
95 
96     std::mutex mHeadroomListenerMutex;
97     sp<ThermalServiceHeadroomListener> mServiceHeadroomListener GUARDED_BY(mHeadroomListenerMutex);
98     std::vector<HeadroomListenerCallback> mHeadroomListeners GUARDED_BY(mHeadroomListenerMutex);
99 };
100 
onStatusChange(int32_t status)101 binder::Status ThermalServiceStatusListener::onStatusChange(int32_t status) {
102     if (mMgr != nullptr) {
103         mMgr->notifyStateChange(status);
104     }
105     return binder::Status::ok();
106 }
107 
onHeadroomChange(float headroom,float forecastHeadroom,int32_t forecastSeconds,const::std::vector<float> & thresholds)108 binder::Status ThermalServiceHeadroomListener::onHeadroomChange(
109         float headroom, float forecastHeadroom, int32_t forecastSeconds,
110         const ::std::vector<float> &thresholds) {
111     if (mMgr != nullptr) {
112         mMgr->notifyHeadroomChange(headroom, forecastHeadroom, forecastSeconds, thresholds);
113     }
114     return binder::Status::ok();
115 }
116 
createAThermalManager()117 AThermalManager* AThermalManager::createAThermalManager() {
118     if (gIThermalServiceForTesting) {
119         return new AThermalManager(gIThermalServiceForTesting);
120     }
121     sp<IBinder> binder =
122             defaultServiceManager()->checkService(String16("thermalservice"));
123 
124     if (binder == nullptr) {
125         ALOGE("%s: Thermal service is not ready ", __FUNCTION__);
126         return nullptr;
127     }
128     return new AThermalManager(interface_cast<IThermalService>(binder));
129 }
130 
AThermalManager(sp<IThermalService> service)131 AThermalManager::AThermalManager(sp<IThermalService> service)
132       : mThermalSvc(std::move(service)),
133         mServiceStatusListener(nullptr),
134         mServiceHeadroomListener(nullptr) {}
135 
~AThermalManager()136 AThermalManager::~AThermalManager() {
137     {
138         std::scoped_lock<std::mutex> listenerLock(mStatusListenerMutex);
139         mStatusListeners.clear();
140         if (mServiceStatusListener != nullptr) {
141             bool success = false;
142             mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
143             mServiceStatusListener = nullptr;
144         }
145     }
146     {
147         std::scoped_lock<std::mutex> headroomListenerLock(mHeadroomListenerMutex);
148         mHeadroomListeners.clear();
149         if (mServiceHeadroomListener != nullptr) {
150             bool success = false;
151             mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
152             mServiceHeadroomListener = nullptr;
153         }
154     }
155 }
156 
notifyStateChange(int32_t status)157 status_t AThermalManager::notifyStateChange(int32_t status) {
158     std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
159     AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
160 
161     for (auto listener : mStatusListeners) {
162         listener.callback(listener.data, thermalStatus);
163     }
164     return OK;
165 }
166 
notifyHeadroomChange(float headroom,float forecastHeadroom,int32_t forecastSeconds,const::std::vector<float> & thresholds)167 status_t AThermalManager::notifyHeadroomChange(float headroom, float forecastHeadroom,
168                                                int32_t forecastSeconds,
169                                                const ::std::vector<float> &thresholds) {
170     std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
171     size_t thresholdsCount = thresholds.size();
172     auto t = new AThermalHeadroomThreshold[thresholdsCount];
173     for (int i = 0; i < (int)thresholdsCount; i++) {
174         t[i].headroom = thresholds[i];
175         t[i].thermalStatus = static_cast<AThermalStatus>(i);
176     }
177     for (auto listener : mHeadroomListeners) {
178         listener.callback(listener.data, headroom, forecastHeadroom, forecastSeconds, t,
179                           thresholdsCount);
180     }
181     delete[] t;
182     return OK;
183 }
184 
addStatusListener(AThermal_StatusCallback callback,void * data)185 status_t AThermalManager::addStatusListener(AThermal_StatusCallback callback, void *data) {
186     std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
187 
188     if (callback == nullptr) {
189         // Callback can not be nullptr
190         return EINVAL;
191     }
192     for (const auto &cb : mStatusListeners) {
193         // Don't re-add callbacks.
194         if (callback == cb.callback && data == cb.data) {
195             return EINVAL;
196         }
197     }
198 
199     if (mServiceStatusListener != nullptr) {
200         mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
201         return OK;
202     }
203     bool success = false;
204     mServiceStatusListener = new ThermalServiceStatusListener(this);
205     if (mServiceStatusListener == nullptr) {
206         return ENOMEM;
207     }
208     auto ret = mThermalSvc->registerThermalStatusListener(mServiceStatusListener, &success);
209     if (!success || !ret.isOk()) {
210         mServiceStatusListener = nullptr;
211         ALOGE("Failed in registerThermalStatusListener %d", success);
212         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
213             return EPERM;
214         }
215         return EPIPE;
216     }
217     mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
218     return OK;
219 }
220 
removeStatusListener(AThermal_StatusCallback callback,void * data)221 status_t AThermalManager::removeStatusListener(AThermal_StatusCallback callback, void *data) {
222     std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
223 
224     auto it = std::remove_if(mStatusListeners.begin(), mStatusListeners.end(),
225                              [&](const StatusListenerCallback &cb) {
226                                  return callback == cb.callback && data == cb.data;
227                              });
228     if (it == mStatusListeners.end()) {
229         // If the listener and data pointer were not previously added.
230         return EINVAL;
231     }
232     if (mServiceStatusListener == nullptr || mStatusListeners.size() > 1) {
233         mStatusListeners.erase(it, mStatusListeners.end());
234         return OK;
235     }
236 
237     bool success = false;
238     auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
239     if (!success || !ret.isOk()) {
240         ALOGE("Failed in unregisterThermalStatusListener %d", success);
241         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
242             return EPERM;
243         }
244         return EPIPE;
245     }
246     mServiceStatusListener = nullptr;
247     mStatusListeners.erase(it, mStatusListeners.end());
248     return OK;
249 }
250 
addHeadroomListener(AThermal_HeadroomCallback callback,void * data)251 status_t AThermalManager::addHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
252     std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
253     if (callback == nullptr) {
254         return EINVAL;
255     }
256     for (const auto &cb : mHeadroomListeners) {
257         if (callback == cb.callback && data == cb.data) {
258             return EINVAL;
259         }
260     }
261 
262     if (mServiceHeadroomListener != nullptr) {
263         mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
264         return OK;
265     }
266     bool success = false;
267     mServiceHeadroomListener = new ThermalServiceHeadroomListener(this);
268     if (mServiceHeadroomListener == nullptr) {
269         return ENOMEM;
270     }
271     auto ret = mThermalSvc->registerThermalHeadroomListener(mServiceHeadroomListener, &success);
272     if (!success || !ret.isOk()) {
273         ALOGE("Failed in registerThermalHeadroomListener %d", success);
274         mServiceHeadroomListener = nullptr;
275         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
276             return EPERM;
277         }
278         return EPIPE;
279     }
280     mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
281     return OK;
282 }
283 
removeHeadroomListener(AThermal_HeadroomCallback callback,void * data)284 status_t AThermalManager::removeHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
285     std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
286 
287     auto it = std::remove_if(mHeadroomListeners.begin(), mHeadroomListeners.end(),
288                              [&](const HeadroomListenerCallback &cb) {
289                                  return callback == cb.callback && data == cb.data;
290                              });
291     if (it == mHeadroomListeners.end()) {
292         return EINVAL;
293     }
294     if (mServiceHeadroomListener == nullptr || mHeadroomListeners.size() > 1) {
295         mHeadroomListeners.erase(it, mHeadroomListeners.end());
296         return OK;
297     }
298     bool success = false;
299     auto ret = mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
300     if (!success || !ret.isOk()) {
301         ALOGE("Failed in unregisterThermalHeadroomListener %d", success);
302         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
303             return EPERM;
304         }
305         return EPIPE;
306     }
307     mServiceHeadroomListener = nullptr;
308     mHeadroomListeners.erase(it, mHeadroomListeners.end());
309     return OK;
310 }
311 
getCurrentThermalStatus(int32_t * status)312 status_t AThermalManager::getCurrentThermalStatus(int32_t *status) {
313     binder::Status ret = mThermalSvc->getCurrentThermalStatus(status);
314 
315     if (!ret.isOk()) {
316         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
317             return EPERM;
318         }
319         return EPIPE;
320     }
321     return OK;
322 }
323 
getThermalHeadroom(int32_t forecastSeconds,float * result)324 status_t AThermalManager::getThermalHeadroom(int32_t forecastSeconds, float *result) {
325     binder::Status ret = mThermalSvc->getThermalHeadroom(forecastSeconds, result);
326 
327     if (!ret.isOk()) {
328         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
329             return EPERM;
330         }
331         return EPIPE;
332     }
333     return OK;
334 }
335 
getThermalHeadroomThresholds(const AThermalHeadroomThreshold ** result,size_t * size)336 status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
337                                                        size_t *size) {
338     auto thresholds = std::make_unique<std::vector<float>>();
339     binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get());
340     if (!ret.isOk()) {
341         if (ret.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
342             // feature is not enabled
343             return ENOSYS;
344         }
345         return EPIPE;
346     }
347     size_t thresholdsCount = thresholds->size();
348     auto t = new AThermalHeadroomThreshold[thresholdsCount];
349     for (int i = 0; i < (int)thresholdsCount; i++) {
350         t[i].headroom = (*thresholds)[i];
351         t[i].thermalStatus = static_cast<AThermalStatus>(i);
352     }
353     *size = thresholdsCount;
354     *result = t;
355     return OK;
356 }
357 
AThermal_acquireManager()358 AThermalManager* AThermal_acquireManager() {
359     auto manager = AThermalManager::createAThermalManager();
360 
361     return manager;
362 }
363 
AThermal_releaseManager(AThermalManager * manager)364 void AThermal_releaseManager(AThermalManager *manager) {
365     delete manager;
366 }
367 
AThermal_getCurrentThermalStatus(AThermalManager * manager)368 AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
369     int32_t status = 0;
370     status_t ret = manager->getCurrentThermalStatus(&status);
371     if (ret != OK) {
372         return AThermalStatus::ATHERMAL_STATUS_ERROR;
373     }
374     return static_cast<AThermalStatus>(status);
375 }
376 
AThermal_registerThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)377 int AThermal_registerThermalStatusListener(AThermalManager *manager,
378                                            AThermal_StatusCallback callback, void *data) {
379     return manager->addStatusListener(callback, data);
380 }
381 
AThermal_unregisterThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)382 int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
383                                              AThermal_StatusCallback callback, void *data) {
384     return manager->removeStatusListener(callback, data);
385 }
386 
AThermal_getThermalHeadroom(AThermalManager * manager,int forecastSeconds)387 float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
388     float result = 0.0f;
389     status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
390     if (ret != OK) {
391         result = std::numeric_limits<float>::quiet_NaN();
392     }
393     return result;
394 }
395 
AThermal_getThermalHeadroomThresholds(AThermalManager * manager,const AThermalHeadroomThreshold ** outThresholds,size_t * size)396 int AThermal_getThermalHeadroomThresholds(AThermalManager *manager,
397                                           const AThermalHeadroomThreshold **outThresholds,
398                                           size_t *size) {
399     if (outThresholds == nullptr || *outThresholds != nullptr || size == nullptr) {
400         return EINVAL;
401     }
402     return manager->getThermalHeadroomThresholds(outThresholds, size);
403 }
404 
AThermal_setIThermalServiceForTesting(void * iThermalService)405 void AThermal_setIThermalServiceForTesting(void *iThermalService) {
406     gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
407 }
408 
AThermal_registerThermalHeadroomListener(AThermalManager * manager,AThermal_HeadroomCallback callback,void * data)409 int AThermal_registerThermalHeadroomListener(AThermalManager *manager,
410                                              AThermal_HeadroomCallback callback, void *data) {
411     return manager->addHeadroomListener(callback, data);
412 }
413 
AThermal_unregisterThermalHeadroomListener(AThermalManager * manager,AThermal_HeadroomCallback callback,void * data)414 int AThermal_unregisterThermalHeadroomListener(AThermalManager *manager,
415                                                AThermal_HeadroomCallback callback, void *data) {
416     return manager->removeHeadroomListener(callback, data);
417 }
418