blob: cefcaf7766bb9760debb0e8e5214b088b3f3ace7 [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 Wang420db782024-11-26 14:44:51 -0800142 mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
143 mServiceStatusListener = nullptr;
Matt Buckley053a1df2024-06-07 02:37:59 +0000144 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800145 }
Xiang Wang420db782024-11-26 14:44:51 -0800146 {
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 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800155}
156
157status_t AThermalManager::notifyStateChange(int32_t status) {
Xiang Wang420db782024-11-26 14:44:51 -0800158 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800159 AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
160
Xiang Wang420db782024-11-26 14:44:51 -0800161 for (auto listener : mStatusListeners) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800162 listener.callback(listener.data, thermalStatus);
163 }
164 return OK;
165}
166
Xiang Wang420db782024-11-26 14:44:51 -0800167status_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
185status_t AThermalManager::addStatusListener(AThermal_StatusCallback callback, void *data) {
186 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800187
188 if (callback == nullptr) {
189 // Callback can not be nullptr
190 return EINVAL;
191 }
Xiang Wang420db782024-11-26 14:44:51 -0800192 for (const auto &cb : mStatusListeners) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800193 // Don't re-add callbacks.
194 if (callback == cb.callback && data == cb.data) {
195 return EINVAL;
196 }
197 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800198
Xiang Wang420db782024-11-26 14:44:51 -0800199 if (mServiceStatusListener != nullptr) {
200 mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
Chris Ye48dbcaa2020-02-10 13:29:01 -0800201 return OK;
202 }
203 bool success = false;
Xiang Wang420db782024-11-26 14:44:51 -0800204 mServiceStatusListener = new ThermalServiceStatusListener(this);
205 if (mServiceStatusListener == nullptr) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800206 return ENOMEM;
207 }
Xiang Wang420db782024-11-26 14:44:51 -0800208 auto ret = mThermalSvc->registerThermalStatusListener(mServiceStatusListener, &success);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800209 if (!success || !ret.isOk()) {
Xiang Wang420db782024-11-26 14:44:51 -0800210 mServiceStatusListener = nullptr;
Chris Ye48dbcaa2020-02-10 13:29:01 -0800211 ALOGE("Failed in registerThermalStatusListener %d", success);
212 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
213 return EPERM;
214 }
215 return EPIPE;
216 }
Xiang Wang420db782024-11-26 14:44:51 -0800217 mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
Chris Ye48dbcaa2020-02-10 13:29:01 -0800218 return OK;
219}
220
Xiang Wang420db782024-11-26 14:44:51 -0800221status_t AThermalManager::removeStatusListener(AThermal_StatusCallback callback, void *data) {
222 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800223
Xiang Wang420db782024-11-26 14:44:51 -0800224 auto it = std::remove_if(mStatusListeners.begin(), mStatusListeners.end(),
225 [&](const StatusListenerCallback &cb) {
226 return callback == cb.callback && data == cb.data;
Chris Ye48dbcaa2020-02-10 13:29:01 -0800227 });
Xiang Wang420db782024-11-26 14:44:51 -0800228 if (it == mStatusListeners.end()) {
Chris Ye48dbcaa2020-02-10 13:29:01 -0800229 // If the listener and data pointer were not previously added.
230 return EINVAL;
231 }
Xiang Wang420db782024-11-26 14:44:51 -0800232 if (mServiceStatusListener == nullptr || mStatusListeners.size() > 1) {
233 mStatusListeners.erase(it, mStatusListeners.end());
234 return OK;
235 }
Chris Ye48dbcaa2020-02-10 13:29:01 -0800236
Chris Ye48dbcaa2020-02-10 13:29:01 -0800237 bool success = false;
Xiang Wang420db782024-11-26 14:44:51 -0800238 auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800239 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 }
Xiang Wang420db782024-11-26 14:44:51 -0800246 mServiceStatusListener = nullptr;
247 mStatusListeners.erase(it, mStatusListeners.end());
248 return OK;
249}
250
251status_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
284status_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());
Chris Ye48dbcaa2020-02-10 13:29:01 -0800309 return OK;
310}
311
312status_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
Chris Forbes1900bef2020-09-15 09:39:18 -0700324status_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
Xiang Wang5f4e8192023-10-25 13:40:35 -0700336status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
337 size_t *size) {
Xiang Wang420db782024-11-26 14:44:51 -0800338 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;
Xiang Wang5f4e8192023-10-25 13:40:35 -0700344 }
Xiang Wang420db782024-11-26 14:44:51 -0800345 return EPIPE;
Xiang Wang5f4e8192023-10-25 13:40:35 -0700346 }
Xiang Wang420db782024-11-26 14:44:51 -0800347 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;
Xiang Wang5f4e8192023-10-25 13:40:35 -0700355 return OK;
356}
357
Chris Ye48dbcaa2020-02-10 13:29:01 -0800358AThermalManager* AThermal_acquireManager() {
359 auto manager = AThermalManager::createAThermalManager();
360
361 return manager;
362}
363
Chris Ye48dbcaa2020-02-10 13:29:01 -0800364void AThermal_releaseManager(AThermalManager *manager) {
365 delete manager;
366}
367
Chris Ye48dbcaa2020-02-10 13:29:01 -0800368AThermalStatus 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
Chris Ye48dbcaa2020-02-10 13:29:01 -0800377int AThermal_registerThermalStatusListener(AThermalManager *manager,
Xiang Wang420db782024-11-26 14:44:51 -0800378 AThermal_StatusCallback callback, void *data) {
379 return manager->addStatusListener(callback, data);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800380}
381
Chris Ye48dbcaa2020-02-10 13:29:01 -0800382int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
Xiang Wang420db782024-11-26 14:44:51 -0800383 AThermal_StatusCallback callback, void *data) {
384 return manager->removeStatusListener(callback, data);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800385}
Chris Forbes1900bef2020-09-15 09:39:18 -0700386
Xiang Wang5f4e8192023-10-25 13:40:35 -0700387float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
Chris Forbes1900bef2020-09-15 09:39:18 -0700388 float result = 0.0f;
389 status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
Chris Forbes1900bef2020-09-15 09:39:18 -0700390 if (ret != OK) {
391 result = std::numeric_limits<float>::quiet_NaN();
392 }
Chris Forbes1900bef2020-09-15 09:39:18 -0700393 return result;
394}
Xiang Wang5f4e8192023-10-25 13:40:35 -0700395
396int 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
405void AThermal_setIThermalServiceForTesting(void *iThermalService) {
406 gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
407}
Xiang Wang420db782024-11-26 14:44:51 -0800408
409int AThermal_registerThermalHeadroomListener(AThermalManager *manager,
410 AThermal_HeadroomCallback callback, void *data) {
411 return manager->addHeadroomListener(callback, data);
412}
413
414int AThermal_unregisterThermalHeadroomListener(AThermalManager *manager,
415 AThermal_HeadroomCallback callback, void *data) {
416 return manager->removeHeadroomListener(callback, data);
417}