Chris Ye | 48dbcaa | 2020-02-10 13:29:01 -0800 | [diff] [blame^] | 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; |
| 36 | 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 | |
| 63 | binder::Status ThermalServiceListener::onStatusChange(int32_t status) { |
| 64 | if (mMgr != nullptr) { |
| 65 | mMgr->notifyStateChange(status); |
| 66 | } |
| 67 | return binder::Status::ok(); |
| 68 | } |
| 69 | |
| 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 | |
| 81 | AThermalManager::AThermalManager(sp<IThermalService> service) |
| 82 | : mThermalSvc(service), |
| 83 | mServiceListener(nullptr) { |
| 84 | } |
| 85 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 258 | int AThermal_unregisterThermalStatusListener(AThermalManager *manager, |
| 259 | AThermal_StatusCallback callback, void *data) { |
| 260 | return manager->removeListener(callback, data); |
| 261 | } |