| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "VibratorManagerHalWrapper" |
| |
| #include <utils/Log.h> |
| |
| #include <vibratorservice/VibratorManagerHalWrapper.h> |
| |
| namespace Aidl = android::hardware::vibrator; |
| |
| namespace android { |
| |
| namespace vibrator { |
| |
| constexpr int32_t SINGLE_VIBRATOR_ID = 0; |
| const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id="; |
| |
| HalResult<void> LegacyManagerHalWrapper::ping() { |
| auto pingFn = [](HalWrapper* hal) { return hal->ping(); }; |
| return mController->doWithRetry<void>(pingFn, "ping"); |
| } |
| |
| void LegacyManagerHalWrapper::tryReconnect() { |
| mController->tryReconnect(); |
| } |
| |
| HalResult<ManagerCapabilities> LegacyManagerHalWrapper::getCapabilities() { |
| return HalResult<ManagerCapabilities>::ok(ManagerCapabilities::NONE); |
| } |
| |
| HalResult<std::vector<int32_t>> LegacyManagerHalWrapper::getVibratorIds() { |
| if (mController->init()) { |
| return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>(1, SINGLE_VIBRATOR_ID)); |
| } |
| // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator. |
| return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>()); |
| } |
| |
| HalResult<std::shared_ptr<HalController>> LegacyManagerHalWrapper::getVibrator(int32_t id) { |
| if (id == SINGLE_VIBRATOR_ID && mController->init()) { |
| return HalResult<std::shared_ptr<HalController>>::ok(mController); |
| } |
| // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator. |
| return HalResult<std::shared_ptr<HalController>>::failed( |
| (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str()); |
| } |
| |
| HalResult<void> LegacyManagerHalWrapper::prepareSynced(const std::vector<int32_t>&) { |
| return HalResult<void>::unsupported(); |
| } |
| |
| HalResult<void> LegacyManagerHalWrapper::triggerSynced(const std::function<void()>&) { |
| return HalResult<void>::unsupported(); |
| } |
| |
| HalResult<void> LegacyManagerHalWrapper::cancelSynced() { |
| return HalResult<void>::unsupported(); |
| } |
| |
| // ------------------------------------------------------------------------------------------------- |
| |
| std::shared_ptr<HalWrapper> AidlManagerHalWrapper::connectToVibrator( |
| int32_t vibratorId, std::shared_ptr<CallbackScheduler> callbackScheduler) { |
| std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [=, this]() { |
| sp<Aidl::IVibrator> vibrator; |
| auto result = this->getHal()->getVibrator(vibratorId, &vibrator); |
| return HalResultFactory::fromStatus<sp<Aidl::IVibrator>>(result, vibrator); |
| }; |
| auto result = reconnectFn(); |
| if (!result.isOk()) { |
| return nullptr; |
| } |
| auto vibrator = result.value(); |
| if (!vibrator) { |
| return nullptr; |
| } |
| return std::make_unique<AidlHalWrapper>(std::move(callbackScheduler), std::move(vibrator), |
| reconnectFn); |
| } |
| |
| HalResult<void> AidlManagerHalWrapper::ping() { |
| return HalResultFactory::fromStatus(IInterface::asBinder(getHal())->pingBinder()); |
| } |
| |
| void AidlManagerHalWrapper::tryReconnect() { |
| sp<Aidl::IVibratorManager> newHandle = checkVintfService<Aidl::IVibratorManager>(); |
| if (newHandle) { |
| std::lock_guard<std::mutex> lock(mHandleMutex); |
| mHandle = std::move(newHandle); |
| } |
| } |
| |
| HalResult<ManagerCapabilities> AidlManagerHalWrapper::getCapabilities() { |
| std::lock_guard<std::mutex> lock(mCapabilitiesMutex); |
| if (mCapabilities.has_value()) { |
| // Return copy of cached value. |
| return HalResult<ManagerCapabilities>::ok(*mCapabilities); |
| } |
| int32_t cap = 0; |
| auto result = getHal()->getCapabilities(&cap); |
| auto capabilities = static_cast<ManagerCapabilities>(cap); |
| auto ret = HalResultFactory::fromStatus<ManagerCapabilities>(result, capabilities); |
| if (ret.isOk()) { |
| // Cache copy of returned value. |
| mCapabilities.emplace(ret.value()); |
| } |
| return ret; |
| } |
| |
| HalResult<std::vector<int32_t>> AidlManagerHalWrapper::getVibratorIds() { |
| std::lock_guard<std::mutex> lock(mVibratorsMutex); |
| if (mVibratorIds.has_value()) { |
| // Return copy of cached values. |
| return HalResult<std::vector<int32_t>>::ok(*mVibratorIds); |
| } |
| std::vector<int32_t> ids; |
| auto result = getHal()->getVibratorIds(&ids); |
| auto ret = HalResultFactory::fromStatus<std::vector<int32_t>>(result, ids); |
| if (ret.isOk()) { |
| // Cache copy of returned value and the individual controllers. |
| mVibratorIds.emplace(ret.value()); |
| for (auto& id : ids) { |
| HalController::Connector connector = [&, id](auto scheduler) { |
| return this->connectToVibrator(id, scheduler); |
| }; |
| auto controller = std::make_unique<HalController>(mCallbackScheduler, connector); |
| mVibrators[id] = std::move(controller); |
| } |
| } |
| return ret; |
| } |
| |
| HalResult<std::shared_ptr<HalController>> AidlManagerHalWrapper::getVibrator(int32_t id) { |
| // Make sure we cache vibrator ids and initialize the individual controllers. |
| getVibratorIds(); |
| std::lock_guard<std::mutex> lock(mVibratorsMutex); |
| auto it = mVibrators.find(id); |
| if (it != mVibrators.end()) { |
| return HalResult<std::shared_ptr<HalController>>::ok(it->second); |
| } |
| return HalResult<std::shared_ptr<HalController>>::failed( |
| (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str()); |
| } |
| |
| HalResult<void> AidlManagerHalWrapper::prepareSynced(const std::vector<int32_t>& ids) { |
| auto ret = HalResultFactory::fromStatus(getHal()->prepareSynced(ids)); |
| if (ret.isOk()) { |
| // Force reload of all vibrator controllers that were prepared for a sync operation here. |
| // This will trigger calls to getVibrator(id) on each controller, so they can use the |
| // latest service provided by this manager. |
| std::lock_guard<std::mutex> lock(mVibratorsMutex); |
| for (auto& id : ids) { |
| auto it = mVibrators.find(id); |
| if (it != mVibrators.end()) { |
| it->second->tryReconnect(); |
| } |
| } |
| } |
| return ret; |
| } |
| |
| HalResult<void> AidlManagerHalWrapper::triggerSynced( |
| const std::function<void()>& completionCallback) { |
| HalResult<ManagerCapabilities> capabilities = getCapabilities(); |
| bool supportsCallback = capabilities.isOk() && |
| static_cast<int32_t>(capabilities.value() & ManagerCapabilities::TRIGGER_CALLBACK); |
| auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr; |
| return HalResultFactory::fromStatus(getHal()->triggerSynced(cb)); |
| } |
| |
| HalResult<void> AidlManagerHalWrapper::cancelSynced() { |
| auto ret = HalResultFactory::fromStatus(getHal()->cancelSynced()); |
| if (ret.isOk()) { |
| // Force reload of all vibrator controllers that were prepared for a sync operation before. |
| // This will trigger calls to getVibrator(id) on each controller, so they can use the |
| // latest service provided by this manager. |
| std::lock_guard<std::mutex> lock(mVibratorsMutex); |
| for (auto& entry : mVibrators) { |
| entry.second->tryReconnect(); |
| } |
| } |
| return ret; |
| } |
| |
| sp<Aidl::IVibratorManager> AidlManagerHalWrapper::getHal() { |
| std::lock_guard<std::mutex> lock(mHandleMutex); |
| return mHandle; |
| } |
| |
| }; // namespace vibrator |
| |
| }; // namespace android |