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 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 }
148 mServiceStatusListener = nullptr;
149 }
150 }
151 {
152 std::scoped_lock<std::mutex> headroomListenerLock(mHeadroomListenerMutex);
153 mHeadroomListeners.clear();
154 if (mServiceHeadroomListener != nullptr) {
155 bool success = false;
156 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 }
162 mServiceHeadroomListener = nullptr;
163 }
164 }
165 }
166
notifyStateChange(int32_t status)167 status_t AThermalManager::notifyStateChange(int32_t status) {
168 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
169 AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
170
171 for (auto listener : mStatusListeners) {
172 listener.callback(listener.data, thermalStatus);
173 }
174 return OK;
175 }
176
notifyHeadroomChange(float headroom,float forecastHeadroom,int32_t forecastSeconds,const::std::vector<float> & thresholds)177 status_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
addStatusListener(AThermal_StatusCallback callback,void * data)195 status_t AThermalManager::addStatusListener(AThermal_StatusCallback callback, void *data) {
196 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
197
198 if (callback == nullptr) {
199 // Callback can not be nullptr
200 return EINVAL;
201 }
202 for (const auto &cb : mStatusListeners) {
203 // Don't re-add callbacks.
204 if (callback == cb.callback && data == cb.data) {
205 return EINVAL;
206 }
207 }
208
209 if (mServiceStatusListener != nullptr) {
210 mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
211 return OK;
212 }
213 bool success = false;
214 mServiceStatusListener = new ThermalServiceStatusListener(this);
215 if (mServiceStatusListener == nullptr) {
216 return ENOMEM;
217 }
218 auto ret = mThermalSvc->registerThermalStatusListener(mServiceStatusListener, &success);
219 if (!success || !ret.isOk()) {
220 mServiceStatusListener = nullptr;
221 ALOGE("Failed in registerThermalStatusListener %d", success);
222 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
223 return EPERM;
224 }
225 return EPIPE;
226 }
227 mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
228 return OK;
229 }
230
removeStatusListener(AThermal_StatusCallback callback,void * data)231 status_t AThermalManager::removeStatusListener(AThermal_StatusCallback callback, void *data) {
232 std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
233
234 auto it = std::remove_if(mStatusListeners.begin(), mStatusListeners.end(),
235 [&](const StatusListenerCallback &cb) {
236 return callback == cb.callback && data == cb.data;
237 });
238 if (it == mStatusListeners.end()) {
239 // If the listener and data pointer were not previously added.
240 return EINVAL;
241 }
242 if (mServiceStatusListener == nullptr || mStatusListeners.size() > 1) {
243 mStatusListeners.erase(it, mStatusListeners.end());
244 return OK;
245 }
246
247 bool success = false;
248 auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
249 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 }
256 mServiceStatusListener = nullptr;
257 mStatusListeners.erase(it, mStatusListeners.end());
258 return OK;
259 }
260
addHeadroomListener(AThermal_HeadroomCallback callback,void * data)261 status_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
removeHeadroomListener(AThermal_HeadroomCallback callback,void * data)294 status_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());
319 return OK;
320 }
321
getCurrentThermalStatus(int32_t * status)322 status_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
getThermalHeadroom(int32_t forecastSeconds,float * result)334 status_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
getThermalHeadroomThresholds(const AThermalHeadroomThreshold ** result,size_t * size)346 status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
347 size_t *size) {
348 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;
354 }
355 return EPIPE;
356 }
357 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;
365 return OK;
366 }
367
AThermal_acquireManager()368 AThermalManager* AThermal_acquireManager() {
369 auto manager = AThermalManager::createAThermalManager();
370
371 return manager;
372 }
373
AThermal_releaseManager(AThermalManager * manager)374 void AThermal_releaseManager(AThermalManager *manager) {
375 delete manager;
376 }
377
AThermal_getCurrentThermalStatus(AThermalManager * manager)378 AThermalStatus 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
AThermal_registerThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)387 int AThermal_registerThermalStatusListener(AThermalManager *manager,
388 AThermal_StatusCallback callback, void *data) {
389 return manager->addStatusListener(callback, data);
390 }
391
AThermal_unregisterThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)392 int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
393 AThermal_StatusCallback callback, void *data) {
394 return manager->removeStatusListener(callback, data);
395 }
396
AThermal_getThermalHeadroom(AThermalManager * manager,int forecastSeconds)397 float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
398 float result = 0.0f;
399 status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
400 if (ret != OK) {
401 result = std::numeric_limits<float>::quiet_NaN();
402 }
403 return result;
404 }
405
AThermal_getThermalHeadroomThresholds(AThermalManager * manager,const AThermalHeadroomThreshold ** outThresholds,size_t * size)406 int 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
AThermal_setIThermalServiceForTesting(void * iThermalService)415 void AThermal_setIThermalServiceForTesting(void *iThermalService) {
416 gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
417 }
418
AThermal_registerThermalHeadroomListener(AThermalManager * manager,AThermal_HeadroomCallback callback,void * data)419 int AThermal_registerThermalHeadroomListener(AThermalManager *manager,
420 AThermal_HeadroomCallback callback, void *data) {
421 return manager->addHeadroomListener(callback, data);
422 }
423
AThermal_unregisterThermalHeadroomListener(AThermalManager * manager,AThermal_HeadroomCallback callback,void * data)424 int AThermal_unregisterThermalHeadroomListener(AThermalManager *manager,
425 AThermal_HeadroomCallback callback, void *data) {
426 return manager->removeHeadroomListener(callback, data);
427 }
428