• 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 <cerrno>
20 #include <thread>
21 #include <limits>
22 
23 #include <android/thermal.h>
24 #include <android/os/BnThermalStatusListener.h>
25 #include <android/os/IThermalService.h>
26 #include <binder/IServiceManager.h>
27 #include <utils/Log.h>
28 
29 using android::sp;
30 
31 using namespace android;
32 using namespace android::os;
33 
34 struct ThermalServiceListener : public BnThermalStatusListener {
35     public:
36         virtual binder::Status onStatusChange(int32_t status) override;
ThermalServiceListenerThermalServiceListener37         ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
38     private:
39         AThermalManager *mMgr;
40 };
41 
42 struct ListenerCallback {
43     AThermal_StatusCallback callback;
44     void* data;
45 };
46 
47 struct AThermalManager {
48    public:
49         static AThermalManager* createAThermalManager();
50         AThermalManager() = delete;
51         ~AThermalManager();
52         status_t notifyStateChange(int32_t status);
53         status_t getCurrentThermalStatus(int32_t *status);
54         status_t addListener(AThermal_StatusCallback, void *data);
55         status_t removeListener(AThermal_StatusCallback, void *data);
56         status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
57    private:
58        AThermalManager(sp<IThermalService> service);
59        sp<IThermalService> mThermalSvc;
60        sp<ThermalServiceListener> mServiceListener;
61        std::vector<ListenerCallback> mListeners;
62        std::mutex mMutex;
63 };
64 
onStatusChange(int32_t status)65 binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
66     if (mMgr != nullptr) {
67         mMgr->notifyStateChange(status);
68     }
69     return binder::Status::ok();
70 }
71 
createAThermalManager()72 AThermalManager* AThermalManager::createAThermalManager() {
73     sp<IBinder> binder =
74             defaultServiceManager()->checkService(String16("thermalservice"));
75 
76     if (binder == nullptr) {
77         ALOGE("%s: Thermal service is not ready ", __FUNCTION__);
78         return nullptr;
79     }
80     return new AThermalManager(interface_cast<IThermalService>(binder));
81 }
82 
AThermalManager(sp<IThermalService> service)83 AThermalManager::AThermalManager(sp<IThermalService> service)
84     : mThermalSvc(service),
85       mServiceListener(nullptr) {
86 }
87 
~AThermalManager()88 AThermalManager::~AThermalManager() {
89     std::unique_lock<std::mutex> lock(mMutex);
90 
91     mListeners.clear();
92     if (mServiceListener != nullptr) {
93         bool success = false;
94         mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
95         mServiceListener = nullptr;
96     }
97 }
98 
notifyStateChange(int32_t status)99 status_t AThermalManager::notifyStateChange(int32_t status) {
100     std::unique_lock<std::mutex> lock(mMutex);
101     AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
102 
103     for (auto listener : mListeners) {
104         listener.callback(listener.data, thermalStatus);
105     }
106     return OK;
107 }
108 
addListener(AThermal_StatusCallback callback,void * data)109 status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
110     std::unique_lock<std::mutex> lock(mMutex);
111 
112     if (callback == nullptr) {
113         // Callback can not be nullptr
114         return EINVAL;
115     }
116     for (const auto& cb : mListeners) {
117         // Don't re-add callbacks.
118         if (callback == cb.callback && data == cb.data) {
119             return EINVAL;
120         }
121     }
122     mListeners.emplace_back(ListenerCallback{callback, data});
123 
124     if (mServiceListener != nullptr) {
125         return OK;
126     }
127     bool success = false;
128     mServiceListener = new ThermalServiceListener(this);
129     if (mServiceListener == nullptr) {
130         return ENOMEM;
131     }
132     auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success);
133     if (!success || !ret.isOk()) {
134         ALOGE("Failed in registerThermalStatusListener %d", success);
135         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
136             return EPERM;
137         }
138         return EPIPE;
139     }
140     return OK;
141 }
142 
removeListener(AThermal_StatusCallback callback,void * data)143 status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
144     std::unique_lock<std::mutex> lock(mMutex);
145 
146     auto it = std::remove_if(mListeners.begin(),
147                              mListeners.end(),
148                              [&](const ListenerCallback& cb) {
149                                     return callback == cb.callback &&
150                                            data == cb.data;
151                              });
152     if (it == mListeners.end()) {
153         // If the listener and data pointer were not previously added.
154         return EINVAL;
155     }
156     mListeners.erase(it, mListeners.end());
157 
158     if (!mListeners.empty()) {
159         return OK;
160     }
161     if (mServiceListener == nullptr) {
162         return OK;
163     }
164     bool success = false;
165     auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
166     if (!success || !ret.isOk()) {
167         ALOGE("Failed in unregisterThermalStatusListener %d", success);
168         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
169             return EPERM;
170         }
171         return EPIPE;
172     }
173     mServiceListener = nullptr;
174     return OK;
175 }
176 
getCurrentThermalStatus(int32_t * status)177 status_t AThermalManager::getCurrentThermalStatus(int32_t *status) {
178     binder::Status ret = mThermalSvc->getCurrentThermalStatus(status);
179 
180     if (!ret.isOk()) {
181         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
182             return EPERM;
183         }
184         return EPIPE;
185     }
186     return OK;
187 }
188 
getThermalHeadroom(int32_t forecastSeconds,float * result)189 status_t AThermalManager::getThermalHeadroom(int32_t forecastSeconds, float *result) {
190     binder::Status ret = mThermalSvc->getThermalHeadroom(forecastSeconds, result);
191 
192     if (!ret.isOk()) {
193         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
194             return EPERM;
195         }
196         return EPIPE;
197     }
198     return OK;
199 }
200 
201 /**
202   * Acquire an instance of the thermal manager. This must be freed using
203   * {@link AThermal_releaseManager}.
204   *
205   * @return manager instance on success, nullptr on failure.
206  */
AThermal_acquireManager()207 AThermalManager* AThermal_acquireManager() {
208     auto manager = AThermalManager::createAThermalManager();
209 
210     return manager;
211 }
212 
213 /**
214  * Release the thermal manager pointer acquired by
215  * {@link AThermal_acquireManager}.
216  *
217  * @param manager The manager to be released.
218  *
219  */
AThermal_releaseManager(AThermalManager * manager)220 void AThermal_releaseManager(AThermalManager *manager) {
221     delete manager;
222 }
223 
224 /**
225   * Gets the current thermal status.
226   *
227   * @param manager The manager instance to use to query the thermal status,
228   * acquired by {@link AThermal_acquireManager}.
229   *
230   * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
231 */
AThermal_getCurrentThermalStatus(AThermalManager * manager)232 AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
233     int32_t status = 0;
234     status_t ret = manager->getCurrentThermalStatus(&status);
235     if (ret != OK) {
236         return AThermalStatus::ATHERMAL_STATUS_ERROR;
237     }
238     return static_cast<AThermalStatus>(status);
239 }
240 
241 /**
242  * Register the thermal status listener for thermal status change.
243  *
244  * @param manager The manager instance to use to register.
245  * acquired by {@link AThermal_acquireManager}.
246  * @param callback The callback function to be called when thermal status updated.
247  * @param data The data pointer to be passed when callback is called.
248  *
249  * @return 0 on success
250  *         EINVAL if the listener and data pointer were previously added and not removed.
251  *         EPERM if the required permission is not held.
252  *         EPIPE if communication with the system service has failed.
253  */
AThermal_registerThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)254 int AThermal_registerThermalStatusListener(AThermalManager *manager,
255         AThermal_StatusCallback callback, void *data) {
256     return manager->addListener(callback, data);
257 }
258 
259 /**
260  * Unregister the thermal status listener previously resgistered.
261  *
262  * @param manager The manager instance to use to unregister.
263  * acquired by {@link AThermal_acquireManager}.
264  * @param callback The callback function to be called when thermal status updated.
265  * @param data The data pointer to be passed when callback is called.
266  *
267  * @return 0 on success
268  *         EINVAL if the listener and data pointer were not previously added.
269  *         EPERM if the required permission is not held.
270  *         EPIPE if communication with the system service has failed.
271  */
AThermal_unregisterThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)272 int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
273         AThermal_StatusCallback callback, void *data) {
274     return manager->removeListener(callback, data);
275 }
276 
277 /**
278  * Provides an estimate of how much thermal headroom the device currently has
279  * before hitting severe throttling.
280  *
281  * Note that this only attempts to track the headroom of slow-moving sensors,
282  * such as the skin temperature sensor. This means that there is no benefit to
283  * calling this function more frequently than about once per second, and attempts
284  * to call significantly more frequently may result in the function returning {@code NaN}.
285  *
286  * See also PowerManager#getThermalHeadroom.
287  *
288  * @param manager The manager instance to use
289  * @param forecastSeconds how many seconds in the future to forecast
290  * @return a value greater than or equal to 0.0 where 1.0 indicates the SEVERE throttling
291  *  	   threshold. Returns NaN if the device does not support this functionality or if
292  * 	       this function is called significantly faster than once per second.
293  */
AThermal_getThermalHeadroom(AThermalManager * manager,int forecastSeconds)294 float AThermal_getThermalHeadroom(AThermalManager *manager,
295         int forecastSeconds) {
296     float result = 0.0f;
297     status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
298 
299     if (ret != OK) {
300         result = std::numeric_limits<float>::quiet_NaN();
301     }
302 
303     return result;
304 }
305