• 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 
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 
28 using android::sp;
29 
30 using namespace android;
31 using namespace android::os;
32 
33 struct ThermalServiceListener : public BnThermalStatusListener {
34     public:
35         virtual binder::Status onStatusChange(int32_t status) override;
ThermalServiceListenerThermalServiceListener36         ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
37     private:
38         AThermalManager *mMgr;
39 };
40 
41 struct ListenerCallback {
42     AThermal_StatusCallback callback;
43     void* data;
44 };
45 
46 struct 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 
onStatusChange(int32_t status)63 binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
64     if (mMgr != nullptr) {
65         mMgr->notifyStateChange(status);
66     }
67     return binder::Status::ok();
68 }
69 
createAThermalManager()70 AThermalManager* 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 
AThermalManager(sp<IThermalService> service)81 AThermalManager::AThermalManager(sp<IThermalService> service)
82     : mThermalSvc(service),
83       mServiceListener(nullptr) {
84 }
85 
~AThermalManager()86 AThermalManager::~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 
notifyStateChange(int32_t status)97 status_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 
addListener(AThermal_StatusCallback callback,void * data)107 status_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 
removeListener(AThermal_StatusCallback callback,void * data)141 status_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 
getCurrentThermalStatus(int32_t * status)175 status_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  */
AThermal_acquireManager()193 AThermalManager* 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  */
AThermal_releaseManager(AThermalManager * manager)206 void 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 */
AThermal_getCurrentThermalStatus(AThermalManager * manager)218 AThermalStatus 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  */
AThermal_registerThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)240 int 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  */
AThermal_unregisterThermalStatusListener(AThermalManager * manager,AThermal_StatusCallback callback,void * data)258 int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
259         AThermal_StatusCallback callback, void *data) {
260     return manager->removeListener(callback, data);
261 }
262