blob: 93e6ed814c34ac0b77a7f7764e85e3b50ddc82a8 [file] [log] [blame]
Chris Ye48dbcaa2020-02-10 13:29:01 -08001/*
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
Xiang Wang5f4e8192023-10-25 13:40:35 -070019#include <android-base/thread_annotations.h>
Xiang Wang420db782024-11-26 14:44:51 -080020#include <android/os/BnThermalHeadroomListener.h>
Chris Ye48dbcaa2020-02-10 13:29:01 -080021#include <android/os/BnThermalStatusListener.h>
22#include <android/os/IThermalService.h>
Xiang Wang5f4e8192023-10-25 13:40:35 -070023#include <android/thermal.h>
Chris Ye48dbcaa2020-02-10 13:29:01 -080024#include <binder/IServiceManager.h>
Xiang Wang5f4e8192023-10-25 13:40:35 -070025#include <thermal_private.h>
Chris Ye48dbcaa2020-02-10 13:29:01 -080026#include <utils/Log.h>
27
Xiang Wang5f4e8192023-10-25 13:40:35 -070028#include <cerrno>
29#include <limits>
30#include <thread>
31
Chris Ye48dbcaa2020-02-10 13:29:01 -080032using android::sp;
33
34using namespace android;
35using namespace android::os;
36
Xiang Wang420db782024-11-26 14:44:51 -080037struct ThermalServiceStatusListener : public BnThermalStatusListener {
Xiang Wang5f4e8192023-10-25 13:40:35 -070038public:
39 virtual binder::Status onStatusChange(int32_t status) override;
Xiang Wang420db782024-11-26 14:44:51 -080040 ThermalServiceStatusListener(AThermalManager *manager) {
Xiang Wang5f4e8192023-10-25 13:40:35 -070041 mMgr = manager;
42 }
43
44private:
45 AThermalManager *mMgr;
Chris Ye48dbcaa2020-02-10 13:29:01 -080046};
47
Xiang Wang420db782024-11-26 14:44:51 -080048struct ThermalServiceHeadroomListener : public BnThermalHeadroomListener {
49public:
50 virtual binder::Status onHeadroomChange(float headroom, float forecastHeadroom,
51 int32_t forecastSeconds,
52 const ::std::vector<float> &thresholds) override;
53 ThermalServiceHeadroomListener(AThermalManager *manager) {
54 mMgr = manager;
55 }
56
57private:
58 AThermalManager *mMgr;
59};
60
61struct StatusListenerCallback {
Chris Ye48dbcaa2020-02-10 13:29:01 -080062 AThermal_StatusCallback callback;
63 void* data;
64};
65
Xiang Wang420db782024-11-26 14:44:51 -080066struct HeadroomListenerCallback {
67 AThermal_HeadroomCallback callback;
68 void *data;
69};
70
Xiang Wang5f4e8192023-10-25 13:40:35 -070071static IThermalService *gIThermalServiceForTesting = nullptr;
72
Chris Ye48dbcaa2020-02-10 13:29:01 -080073struct AThermalManager {
Xiang Wang5f4e8192023-10-25 13:40:35 -070074public:
75 static AThermalManager *createAThermalManager();
76 AThermalManager() = delete;
77 ~AThermalManager();
78 status_t notifyStateChange(int32_t status);
Xiang Wang420db782024-11-26 14:44:51 -080079 status_t notifyHeadroomChange(float headroom, float forecastHeadroom, int32_t forecastSeconds,
80 const ::std::vector<float> &thresholds);
Xiang Wang5f4e8192023-10-25 13:40:35 -070081 status_t getCurrentThermalStatus(int32_t *status);
Xiang Wang420db782024-11-26 14:44:51 -080082 status_t addStatusListener(AThermal_StatusCallback, void *data);
83 status_t removeStatusListener(AThermal_StatusCallback, void *data);
Xiang Wang5f4e8192023-10-25 13:40:35 -070084 status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
85 status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size);
Xiang Wang420db782024-11-26 14:44:51 -080086 status_t addHeadroomListener(AThermal_HeadroomCallback, void *data);
87 status_t removeHeadroomListener(AThermal_HeadroomCallback, void *data);
Xiang Wang5f4e8192023-10-25 13:40:35 -070088
89private:
90 AThermalManager(sp<IThermalService> service);
91 sp<IThermalService> mThermalSvc;
Xiang Wang420db782024-11-26 14:44:51 -080092 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);
Chris Ye48dbcaa2020-02-10 13:29:01 -080099};
100
Xiang Wang420db782024-11-26 14:44:51 -0800101binder::Status ThermalServiceStatusListener::onStatusChange(int32_t status) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800102 if (mMgr != nullptr) {
103 mMgr->notifyStateChange(status);
104 }
105 return binder::Status::ok();
106}
107
Xiang Wang420db782024-11-26 14:44:51 -0800108binder::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
Chris Ye48dbcaa2020-02-10 13:29:01 -0800117AThermalManager* AThermalManager::createAThermalManager() {
Xiang Wang5f4e8192023-10-25 13:40:35 -0700118 if (gIThermalServiceForTesting) {
119 return new AThermalManager(gIThermalServiceForTesting);
120 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800121 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
131AThermalManager::AThermalManager(sp<IThermalService> service)
Xiang Wang420db782024-11-26 14:44:51 -0800132 : mThermalSvc(std::move(service)),
133 mServiceStatusListener(nullptr),
134 mServiceHeadroomListener(nullptr) {}
Chris Ye48dbcaa2020-02-10 13:29:01 -0800135
136AThermalManager::~AThermalManager() {
Matt Buckley053a1df2024-06-07 02:37:59 +0000137 {
Xiang Wang420db782024-11-26 14:44:51 -0800138 std::scoped_lock<std::mutex> listenerLock(mStatusListenerMutex);
139 mStatusListeners.clear();
140 if (mServiceStatusListener != nullptr) {
Matt Buckley053a1df2024-06-07 02:37:59 +0000141 bool success = false;
Xiang Wang9aa43de2025-02-28 11:26:38 -0800142 auto ret =
143 mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
144 if (!success || !ret.isOk()) {
145 ALOGE("Failed in unregisterThermalStatusListener when AThermalManager is being "
146 "destroyed %d", success);
147 }
Xiang Wang420db782024-11-26 14:44:51 -0800148 mServiceStatusListener = nullptr;
Matt Buckley053a1df2024-06-07 02:37:59 +0000149 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800150 }
Xiang Wang420db782024-11-26 14:44:51 -0800151 {
152 std::scoped_lock<std::mutex> headroomListenerLock(mHeadroomListenerMutex);
153 mHeadroomListeners.clear();
154 if (mServiceHeadroomListener != nullptr) {
155 bool success = false;
Xiang Wang9aa43de2025-02-28 11:26:38 -0800156 auto ret = mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener,
157 &success);
158 if (!success || !ret.isOk()) {
159 ALOGE("Failed in unregisterThermalHeadroomListener when AThermalManager is being "
160 "destroyed %d", success);
161 }
Xiang Wang420db782024-11-26 14:44:51 -0800162 mServiceHeadroomListener = nullptr;
163 }
164 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800165}
166
167status_t AThermalManager::notifyStateChange(int32_t status) {
Xiang Wang420db782024-11-26 14:44:51 -0800168 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800169 AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
170
Xiang Wang420db782024-11-26 14:44:51 -0800171 for (auto listener : mStatusListeners) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800172 listener.callback(listener.data, thermalStatus);
173 }
174 return OK;
175}
176
Xiang Wang420db782024-11-26 14:44:51 -0800177status_t AThermalManager::notifyHeadroomChange(float headroom, float forecastHeadroom,
178 int32_t forecastSeconds,
179 const ::std::vector<float> &thresholds) {
180 std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
181 size_t thresholdsCount = thresholds.size();
182 auto t = new AThermalHeadroomThreshold[thresholdsCount];
183 for (int i = 0; i < (int)thresholdsCount; i++) {
184 t[i].headroom = thresholds[i];
185 t[i].thermalStatus = static_cast<AThermalStatus>(i);
186 }
187 for (auto listener : mHeadroomListeners) {
188 listener.callback(listener.data, headroom, forecastHeadroom, forecastSeconds, t,
189 thresholdsCount);
190 }
191 delete[] t;
192 return OK;
193}
194
195status_t AThermalManager::addStatusListener(AThermal_StatusCallback callback, void *data) {
196 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800197
198 if (callback == nullptr) {
199 // Callback can not be nullptr
200 return EINVAL;
201 }
Xiang Wang420db782024-11-26 14:44:51 -0800202 for (const auto &cb : mStatusListeners) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800203 // Don't re-add callbacks.
204 if (callback == cb.callback && data == cb.data) {
205 return EINVAL;
206 }
207 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800208
Xiang Wang420db782024-11-26 14:44:51 -0800209 if (mServiceStatusListener != nullptr) {
210 mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
Chris Ye48dbcaa2020-02-10 13:29:01 -0800211 return OK;
212 }
213 bool success = false;
Xiang Wang420db782024-11-26 14:44:51 -0800214 mServiceStatusListener = new ThermalServiceStatusListener(this);
215 if (mServiceStatusListener == nullptr) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800216 return ENOMEM;
217 }
Xiang Wang420db782024-11-26 14:44:51 -0800218 auto ret = mThermalSvc->registerThermalStatusListener(mServiceStatusListener, &success);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800219 if (!success || !ret.isOk()) {
Xiang Wang420db782024-11-26 14:44:51 -0800220 mServiceStatusListener = nullptr;
Chris Ye48dbcaa2020-02-10 13:29:01 -0800221 ALOGE("Failed in registerThermalStatusListener %d", success);
222 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
223 return EPERM;
224 }
225 return EPIPE;
226 }
Xiang Wang420db782024-11-26 14:44:51 -0800227 mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
Chris Ye48dbcaa2020-02-10 13:29:01 -0800228 return OK;
229}
230
Xiang Wang420db782024-11-26 14:44:51 -0800231status_t AThermalManager::removeStatusListener(AThermal_StatusCallback callback, void *data) {
232 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800233
Xiang Wang420db782024-11-26 14:44:51 -0800234 auto it = std::remove_if(mStatusListeners.begin(), mStatusListeners.end(),
235 [&](const StatusListenerCallback &cb) {
236 return callback == cb.callback && data == cb.data;
Chris Ye48dbcaa2020-02-10 13:29:01 -0800237 });
Xiang Wang420db782024-11-26 14:44:51 -0800238 if (it == mStatusListeners.end()) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800239 // If the listener and data pointer were not previously added.
240 return EINVAL;
241 }
Xiang Wang420db782024-11-26 14:44:51 -0800242 if (mServiceStatusListener == nullptr || mStatusListeners.size() > 1) {
243 mStatusListeners.erase(it, mStatusListeners.end());
244 return OK;
245 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800246
Chris Ye48dbcaa2020-02-10 13:29:01 -0800247 bool success = false;
Xiang Wang420db782024-11-26 14:44:51 -0800248 auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800249 if (!success || !ret.isOk()) {
250 ALOGE("Failed in unregisterThermalStatusListener %d", success);
251 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
252 return EPERM;
253 }
254 return EPIPE;
255 }
Xiang Wang420db782024-11-26 14:44:51 -0800256 mServiceStatusListener = nullptr;
257 mStatusListeners.erase(it, mStatusListeners.end());
258 return OK;
259}
260
261status_t AThermalManager::addHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
262 std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
263 if (callback == nullptr) {
264 return EINVAL;
265 }
266 for (const auto &cb : mHeadroomListeners) {
267 if (callback == cb.callback && data == cb.data) {
268 return EINVAL;
269 }
270 }
271
272 if (mServiceHeadroomListener != nullptr) {
273 mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
274 return OK;
275 }
276 bool success = false;
277 mServiceHeadroomListener = new ThermalServiceHeadroomListener(this);
278 if (mServiceHeadroomListener == nullptr) {
279 return ENOMEM;
280 }
281 auto ret = mThermalSvc->registerThermalHeadroomListener(mServiceHeadroomListener, &success);
282 if (!success || !ret.isOk()) {
283 ALOGE("Failed in registerThermalHeadroomListener %d", success);
284 mServiceHeadroomListener = nullptr;
285 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
286 return EPERM;
287 }
288 return EPIPE;
289 }
290 mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
291 return OK;
292}
293
294status_t AThermalManager::removeHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
295 std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
296
297 auto it = std::remove_if(mHeadroomListeners.begin(), mHeadroomListeners.end(),
298 [&](const HeadroomListenerCallback &cb) {
299 return callback == cb.callback && data == cb.data;
300 });
301 if (it == mHeadroomListeners.end()) {
302 return EINVAL;
303 }
304 if (mServiceHeadroomListener == nullptr || mHeadroomListeners.size() > 1) {
305 mHeadroomListeners.erase(it, mHeadroomListeners.end());
306 return OK;
307 }
308 bool success = false;
309 auto ret = mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
310 if (!success || !ret.isOk()) {
311 ALOGE("Failed in unregisterThermalHeadroomListener %d", success);
312 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
313 return EPERM;
314 }
315 return EPIPE;
316 }
317 mServiceHeadroomListener = nullptr;
318 mHeadroomListeners.erase(it, mHeadroomListeners.end());
Chris Ye48dbcaa2020-02-10 13:29:01 -0800319 return OK;
320}
321
322status_t AThermalManager::getCurrentThermalStatus(int32_t *status) {
323 binder::Status ret = mThermalSvc->getCurrentThermalStatus(status);
324
325 if (!ret.isOk()) {
326 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
327 return EPERM;
328 }
329 return EPIPE;
330 }
331 return OK;
332}
333
Chris Forbes1900bef2020-09-15 09:39:18 -0700334status_t AThermalManager::getThermalHeadroom(int32_t forecastSeconds, float *result) {
335 binder::Status ret = mThermalSvc->getThermalHeadroom(forecastSeconds, result);
336
337 if (!ret.isOk()) {
338 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
339 return EPERM;
340 }
341 return EPIPE;
342 }
343 return OK;
344}
345
Xiang Wang5f4e8192023-10-25 13:40:35 -0700346status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
347 size_t *size) {
Xiang Wang420db782024-11-26 14:44:51 -0800348 auto thresholds = std::make_unique<std::vector<float>>();
349 binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get());
350 if (!ret.isOk()) {
351 if (ret.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
352 // feature is not enabled
353 return ENOSYS;
Xiang Wang5f4e8192023-10-25 13:40:35 -0700354 }
Xiang Wang420db782024-11-26 14:44:51 -0800355 return EPIPE;
Xiang Wang5f4e8192023-10-25 13:40:35 -0700356 }
Xiang Wang420db782024-11-26 14:44:51 -0800357 size_t thresholdsCount = thresholds->size();
358 auto t = new AThermalHeadroomThreshold[thresholdsCount];
359 for (int i = 0; i < (int)thresholdsCount; i++) {
360 t[i].headroom = (*thresholds)[i];
361 t[i].thermalStatus = static_cast<AThermalStatus>(i);
362 }
363 *size = thresholdsCount;
364 *result = t;
Xiang Wang5f4e8192023-10-25 13:40:35 -0700365 return OK;
366}
367
Chris Ye48dbcaa2020-02-10 13:29:01 -0800368AThermalManager* AThermal_acquireManager() {
369 auto manager = AThermalManager::createAThermalManager();
370
371 return manager;
372}
373
Chris Ye48dbcaa2020-02-10 13:29:01 -0800374void AThermal_releaseManager(AThermalManager *manager) {
375 delete manager;
376}
377
Chris Ye48dbcaa2020-02-10 13:29:01 -0800378AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
379 int32_t status = 0;
380 status_t ret = manager->getCurrentThermalStatus(&status);
381 if (ret != OK) {
382 return AThermalStatus::ATHERMAL_STATUS_ERROR;
383 }
384 return static_cast<AThermalStatus>(status);
385}
386
Chris Ye48dbcaa2020-02-10 13:29:01 -0800387int AThermal_registerThermalStatusListener(AThermalManager *manager,
Xiang Wang420db782024-11-26 14:44:51 -0800388 AThermal_StatusCallback callback, void *data) {
389 return manager->addStatusListener(callback, data);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800390}
391
Chris Ye48dbcaa2020-02-10 13:29:01 -0800392int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
Xiang Wang420db782024-11-26 14:44:51 -0800393 AThermal_StatusCallback callback, void *data) {
394 return manager->removeStatusListener(callback, data);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800395}
Chris Forbes1900bef2020-09-15 09:39:18 -0700396
Xiang Wang5f4e8192023-10-25 13:40:35 -0700397float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
Chris Forbes1900bef2020-09-15 09:39:18 -0700398 float result = 0.0f;
399 status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
Chris Forbes1900bef2020-09-15 09:39:18 -0700400 if (ret != OK) {
401 result = std::numeric_limits<float>::quiet_NaN();
402 }
Chris Forbes1900bef2020-09-15 09:39:18 -0700403 return result;
404}
Xiang Wang5f4e8192023-10-25 13:40:35 -0700405
406int AThermal_getThermalHeadroomThresholds(AThermalManager *manager,
407 const AThermalHeadroomThreshold **outThresholds,
408 size_t *size) {
409 if (outThresholds == nullptr || *outThresholds != nullptr || size == nullptr) {
410 return EINVAL;
411 }
412 return manager->getThermalHeadroomThresholds(outThresholds, size);
413}
414
415void AThermal_setIThermalServiceForTesting(void *iThermalService) {
416 gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
417}
Xiang Wang420db782024-11-26 14:44:51 -0800418
419int AThermal_registerThermalHeadroomListener(AThermalManager *manager,
420 AThermal_HeadroomCallback callback, void *data) {
421 return manager->addHeadroomListener(callback, data);
422}
423
424int AThermal_unregisterThermalHeadroomListener(AThermalManager *manager,
425 AThermal_HeadroomCallback callback, void *data) {
426 return manager->removeHeadroomListener(callback, data);
427}