blob: 545c423908a0888fd1d0c60076d26b0d0025ec14 [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
19#include <cerrno>
20#include <thread>
21
22#include <android/thermal.h>
23#include <android/os/BnThermalStatusListener.h>
24#include <android/os/IThermalService.h>
25#include <binder/IServiceManager.h>
26#include <utils/Log.h>
27
28using android::sp;
29
30using namespace android;
31using namespace android::os;
32
33struct ThermalServiceListener : public BnThermalStatusListener {
34 public:
35 virtual binder::Status onStatusChange(int32_t status) override;
36 ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
37 private:
38 AThermalManager *mMgr;
39};
40
41struct ListenerCallback {
42 AThermal_StatusCallback callback;
43 void* data;
44};
45
46struct AThermalManager {
47 public:
48 static AThermalManager* createAThermalManager();
49 AThermalManager() = delete;
50 ~AThermalManager();
51 status_t notifyStateChange(int32_t status);
52 status_t getCurrentThermalStatus(int32_t *status);
53 status_t addListener(AThermal_StatusCallback, void *data);
54 status_t removeListener(AThermal_StatusCallback, void *data);
55 private:
56 AThermalManager(sp<IThermalService> service);
57 sp<IThermalService> mThermalSvc;
58 sp<ThermalServiceListener> mServiceListener;
59 std::vector<ListenerCallback> mListeners;
60 std::mutex mMutex;
61};
62
63binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
64 if (mMgr != nullptr) {
65 mMgr->notifyStateChange(status);
66 }
67 return binder::Status::ok();
68}
69
70AThermalManager* AThermalManager::createAThermalManager() {
71 sp<IBinder> binder =
72 defaultServiceManager()->checkService(String16("thermalservice"));
73
74 if (binder == nullptr) {
75 ALOGE("%s: Thermal service is not ready ", __FUNCTION__);
76 return nullptr;
77 }
78 return new AThermalManager(interface_cast<IThermalService>(binder));
79}
80
81AThermalManager::AThermalManager(sp<IThermalService> service)
82 : mThermalSvc(service),
83 mServiceListener(nullptr) {
84}
85
86AThermalManager::~AThermalManager() {
87 std::unique_lock<std::mutex> lock(mMutex);
88
89 mListeners.clear();
90 if (mServiceListener != nullptr) {
91 bool success = false;
92 mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
93 mServiceListener = nullptr;
94 }
95}
96
97status_t AThermalManager::notifyStateChange(int32_t status) {
98 std::unique_lock<std::mutex> lock(mMutex);
99 AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
100
101 for (auto listener : mListeners) {
102 listener.callback(listener.data, thermalStatus);
103 }
104 return OK;
105}
106
107status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
108 std::unique_lock<std::mutex> lock(mMutex);
109
110 if (callback == nullptr) {
111 // Callback can not be nullptr
112 return EINVAL;
113 }
114 for (const auto& cb : mListeners) {
115 // Don't re-add callbacks.
116 if (callback == cb.callback && data == cb.data) {
117 return EINVAL;
118 }
119 }
120 mListeners.emplace_back(ListenerCallback{callback, data});
121
122 if (mServiceListener != nullptr) {
123 return OK;
124 }
125 bool success = false;
126 mServiceListener = new ThermalServiceListener(this);
127 if (mServiceListener == nullptr) {
128 return ENOMEM;
129 }
130 auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success);
131 if (!success || !ret.isOk()) {
132 ALOGE("Failed in registerThermalStatusListener %d", success);
133 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
134 return EPERM;
135 }
136 return EPIPE;
137 }
138 return OK;
139}
140
141status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
142 std::unique_lock<std::mutex> lock(mMutex);
143
144 auto it = std::remove_if(mListeners.begin(),
145 mListeners.end(),
146 [&](const ListenerCallback& cb) {
147 return callback == cb.callback &&
148 data == cb.data;
149 });
150 if (it == mListeners.end()) {
151 // If the listener and data pointer were not previously added.
152 return EINVAL;
153 }
154 mListeners.erase(it, mListeners.end());
155
156 if (!mListeners.empty()) {
157 return OK;
158 }
159 if (mServiceListener == nullptr) {
160 return OK;
161 }
162 bool success = false;
163 auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
164 if (!success || !ret.isOk()) {
165 ALOGE("Failed in unregisterThermalStatusListener %d", success);
166 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
167 return EPERM;
168 }
169 return EPIPE;
170 }
171 mServiceListener = nullptr;
172 return OK;
173}
174
175status_t AThermalManager::getCurrentThermalStatus(int32_t *status) {
176 binder::Status ret = mThermalSvc->getCurrentThermalStatus(status);
177
178 if (!ret.isOk()) {
179 if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
180 return EPERM;
181 }
182 return EPIPE;
183 }
184 return OK;
185}
186
187/**
188 * Acquire an instance of the thermal manager. This must be freed using
189 * {@link AThermal_releaseManager}.
190 *
191 * @return manager instance on success, nullptr on failure.
192 */
193AThermalManager* AThermal_acquireManager() {
194 auto manager = AThermalManager::createAThermalManager();
195
196 return manager;
197}
198
199/**
200 * Release the thermal manager pointer acquired by
201 * {@link AThermal_acquireManager}.
202 *
203 * @param manager The manager to be released.
204 *
205 */
206void AThermal_releaseManager(AThermalManager *manager) {
207 delete manager;
208}
209
210/**
211 * Gets the current thermal status.
212 *
213 * @param manager The manager instance to use to query the thermal status,
214 * acquired by {@link AThermal_acquireManager}.
215 *
216 * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
217*/
218AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
219 int32_t status = 0;
220 status_t ret = manager->getCurrentThermalStatus(&status);
221 if (ret != OK) {
222 return AThermalStatus::ATHERMAL_STATUS_ERROR;
223 }
224 return static_cast<AThermalStatus>(status);
225}
226
227/**
228 * Register the thermal status listener for thermal status change.
229 *
230 * @param manager The manager instance to use to register.
231 * acquired by {@link AThermal_acquireManager}.
232 * @param callback The callback function to be called when thermal status updated.
233 * @param data The data pointer to be passed when callback is called.
234 *
235 * @return 0 on success
236 * EINVAL if the listener and data pointer were previously added and not removed.
237 * EPERM if the required permission is not held.
238 * EPIPE if communication with the system service has failed.
239 */
240int AThermal_registerThermalStatusListener(AThermalManager *manager,
241 AThermal_StatusCallback callback, void *data) {
242 return manager->addListener(callback, data);
243}
244
245/**
246 * Unregister the thermal status listener previously resgistered.
247 *
248 * @param manager The manager instance to use to unregister.
249 * acquired by {@link AThermal_acquireManager}.
250 * @param callback The callback function to be called when thermal status updated.
251 * @param data The data pointer to be passed when callback is called.
252 *
253 * @return 0 on success
254 * EINVAL if the listener and data pointer were not previously added.
255 * EPERM if the required permission is not held.
256 * EPIPE if communication with the system service has failed.
257 */
258int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
259 AThermal_StatusCallback callback, void *data) {
260 return manager->removeListener(callback, data);
261}