• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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