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