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