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