blob: b43f2f16a7cb599e79c4e2b863ed6c9264d8fe08 [file] [log] [blame]
Chris Ye48dbcaa2020-02-10 13:29:01 -08001/*
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
Xiang Wang5f4e8192023-10-25 13:40:35 -070019#include <android-base/thread_annotations.h>
Chris Ye48dbcaa2020-02-10 13:29:01 -080020#include <android/os/BnThermalStatusListener.h>
21#include <android/os/IThermalService.h>
Xiang Wang5f4e8192023-10-25 13:40:35 -070022#include <android/thermal.h>
Chris Ye48dbcaa2020-02-10 13:29:01 -080023#include <binder/IServiceManager.h>
Xiang Wang5f4e8192023-10-25 13:40:35 -070024#include <thermal_private.h>
Chris Ye48dbcaa2020-02-10 13:29:01 -080025#include <utils/Log.h>
26
Xiang Wang5f4e8192023-10-25 13:40:35 -070027#include <cerrno>
28#include <limits>
29#include <thread>
30
Chris Ye48dbcaa2020-02-10 13:29:01 -080031using android::sp;
32
33using namespace android;
34using namespace android::os;
35
36struct ThermalServiceListener : public BnThermalStatusListener {
Xiang Wang5f4e8192023-10-25 13:40:35 -070037public:
38 virtual binder::Status onStatusChange(int32_t status) override;
39 ThermalServiceListener(AThermalManager *manager) {
40 mMgr = manager;
41 }
42
43private:
44 AThermalManager *mMgr;
Chris Ye48dbcaa2020-02-10 13:29:01 -080045};
46
47struct ListenerCallback {
48 AThermal_StatusCallback callback;
49 void* data;
50};
51
Xiang Wang5f4e8192023-10-25 13:40:35 -070052static IThermalService *gIThermalServiceForTesting = nullptr;
53
Chris Ye48dbcaa2020-02-10 13:29:01 -080054struct AThermalManager {
Xiang Wang5f4e8192023-10-25 13:40:35 -070055public:
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
66private:
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);
Chris Ye48dbcaa2020-02-10 13:29:01 -080075};
76
77binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
78 if (mMgr != nullptr) {
79 mMgr->notifyStateChange(status);
80 }
81 return binder::Status::ok();
82}
83
84AThermalManager* AThermalManager::createAThermalManager() {
Xiang Wang5f4e8192023-10-25 13:40:35 -070085 if (gIThermalServiceForTesting) {
86 return new AThermalManager(gIThermalServiceForTesting);
87 }
Chris Ye48dbcaa2020-02-10 13:29:01 -080088 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
98AThermalManager::AThermalManager(sp<IThermalService> service)
Xiang Wang5f4e8192023-10-25 13:40:35 -070099 : mThermalSvc(std::move(service)), mServiceListener(nullptr) {}
Chris Ye48dbcaa2020-02-10 13:29:01 -0800100
101AThermalManager::~AThermalManager() {
Xiang Wang5f4e8192023-10-25 13:40:35 -0700102 std::unique_lock<std::mutex> listenerLock(mListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800103
104 mListeners.clear();
105 if (mServiceListener != nullptr) {
106 bool success = false;
107 mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
108 mServiceListener = nullptr;
109 }
Xiang Wang5f4e8192023-10-25 13:40:35 -0700110 listenerLock.unlock();
111 std::unique_lock<std::mutex> lock(mThresholdsMutex);
112 delete[] mThresholds;
Chris Ye48dbcaa2020-02-10 13:29:01 -0800113}
114
115status_t AThermalManager::notifyStateChange(int32_t status) {
Xiang Wang5f4e8192023-10-25 13:40:35 -0700116 std::unique_lock<std::mutex> lock(mListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800117 AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
118
119 for (auto listener : mListeners) {
120 listener.callback(listener.data, thermalStatus);
121 }
122 return OK;
123}
124
125status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
Xiang Wang5f4e8192023-10-25 13:40:35 -0700126 std::unique_lock<std::mutex> lock(mListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800127
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
159status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
Xiang Wang5f4e8192023-10-25 13:40:35 -0700160 std::unique_lock<std::mutex> lock(mListenerMutex);
Chris Ye48dbcaa2020-02-10 13:29:01 -0800161
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
193status_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
Chris Forbes1900bef2020-09-15 09:39:18 -0700205status_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
Xiang Wang5f4e8192023-10-25 13:40:35 -0700217status_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
Chris Ye48dbcaa2020-02-10 13:29:01 -0800243/**
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 */
249AThermalManager* 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 */
262void 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*/
274AThermalStatus 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 */
296int 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 */
314int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
315 AThermal_StatusCallback callback, void *data) {
316 return manager->removeListener(callback, data);
317}
Chris Forbes1900bef2020-09-15 09:39:18 -0700318
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 */
Xiang Wang5f4e8192023-10-25 13:40:35 -0700336float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
Chris Forbes1900bef2020-09-15 09:39:18 -0700337 float result = 0.0f;
338 status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
Chris Forbes1900bef2020-09-15 09:39:18 -0700339 if (ret != OK) {
340 result = std::numeric_limits<float>::quiet_NaN();
341 }
Chris Forbes1900bef2020-09-15 09:39:18 -0700342 return result;
343}
Xiang Wang5f4e8192023-10-25 13:40:35 -0700344
345int 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
354void AThermal_setIThermalServiceForTesting(void *iThermalService) {
355 gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
356}