/* * 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 #include namespace Aidl = 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 ManagerHalWrapper::prepareSynced(const std::vector&) { return HalResult::unsupported(); } HalResult ManagerHalWrapper::triggerSynced(const std::function&) { return HalResult::unsupported(); } HalResult ManagerHalWrapper::cancelSynced() { return HalResult::unsupported(); } HalResult> ManagerHalWrapper::startSession( const std::vector&, const Aidl::VibrationSessionConfig&, const std::function&) { return HalResult>::unsupported(); } HalResult ManagerHalWrapper::clearSessions() { return HalResult::unsupported(); } // ------------------------------------------------------------------------------------------------- HalResult LegacyManagerHalWrapper::ping() { auto pingFn = [](HalWrapper* hal) { return hal->ping(); }; return mController->doWithRetry(pingFn, "ping"); } void LegacyManagerHalWrapper::tryReconnect() { mController->tryReconnect(); } HalResult LegacyManagerHalWrapper::getCapabilities() { return HalResult::ok(ManagerCapabilities::NONE); } HalResult> LegacyManagerHalWrapper::getVibratorIds() { if (mController->init()) { return HalResult>::ok(std::vector(1, SINGLE_VIBRATOR_ID)); } // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator. return HalResult>::ok(std::vector()); } HalResult> LegacyManagerHalWrapper::getVibrator(int32_t id) { if (id == SINGLE_VIBRATOR_ID && mController->init()) { return HalResult>::ok(mController); } // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator. return HalResult>::failed( (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str()); } // ------------------------------------------------------------------------------------------------- std::shared_ptr AidlManagerHalWrapper::connectToVibrator( int32_t vibratorId, std::shared_ptr callbackScheduler) { std::function>()> reconnectFn = [=, this]() { std::shared_ptr vibrator; auto status = this->getHal()->getVibrator(vibratorId, &vibrator); return HalResultFactory::fromStatus>(std::move(status), vibrator); }; auto result = reconnectFn(); if (!result.isOk()) { return nullptr; } auto vibrator = result.value(); if (!vibrator) { return nullptr; } return std::make_unique(std::move(callbackScheduler), std::move(vibrator), reconnectFn); } HalResult AidlManagerHalWrapper::ping() { return HalResultFactory::fromStatus(AIBinder_ping(getHal()->asBinder().get())); } void AidlManagerHalWrapper::tryReconnect() { auto aidlServiceName = std::string(Aidl::IVibratorManager::descriptor) + "/default"; std::shared_ptr newHandle = Aidl::IVibratorManager::fromBinder( ndk::SpAIBinder(AServiceManager_checkService(aidlServiceName.c_str()))); if (newHandle) { std::lock_guard lock(mHandleMutex); mHandle = std::move(newHandle); } } HalResult AidlManagerHalWrapper::getCapabilities() { std::lock_guard lock(mCapabilitiesMutex); if (mCapabilities.has_value()) { // Return copy of cached value. return HalResult::ok(*mCapabilities); } int32_t cap = 0; auto status = getHal()->getCapabilities(&cap); auto capabilities = static_cast(cap); auto ret = HalResultFactory::fromStatus(std::move(status), capabilities); if (ret.isOk()) { // Cache copy of returned value. mCapabilities.emplace(ret.value()); } return ret; } HalResult> AidlManagerHalWrapper::getVibratorIds() { std::lock_guard lock(mVibratorsMutex); if (mVibratorIds.has_value()) { // Return copy of cached values. return HalResult>::ok(*mVibratorIds); } std::vector ids; auto status = getHal()->getVibratorIds(&ids); auto ret = HalResultFactory::fromStatus>(std::move(status), 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(mCallbackScheduler, connector); mVibrators[id] = std::move(controller); } } return ret; } HalResult> AidlManagerHalWrapper::getVibrator(int32_t id) { // Make sure we cache vibrator ids and initialize the individual controllers. getVibratorIds(); std::lock_guard lock(mVibratorsMutex); auto it = mVibrators.find(id); if (it != mVibrators.end()) { return HalResult>::ok(it->second); } return HalResult>::failed( (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str()); } HalResult AidlManagerHalWrapper::prepareSynced(const std::vector& 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 lock(mVibratorsMutex); for (auto& id : ids) { auto it = mVibrators.find(id); if (it != mVibrators.end()) { it->second->tryReconnect(); } } } return ret; } HalResult AidlManagerHalWrapper::triggerSynced( const std::function& completionCallback) { HalResult capabilities = getCapabilities(); bool supportsCallback = capabilities.isOk() && static_cast(capabilities.value() & ManagerCapabilities::TRIGGER_CALLBACK); auto cb = supportsCallback ? ndk::SharedRefBase::make(completionCallback) : nullptr; return HalResultFactory::fromStatus(getHal()->triggerSynced(cb)); } HalResult> AidlManagerHalWrapper::startSession( const std::vector& ids, const Aidl::VibrationSessionConfig& config, const std::function& completionCallback) { auto cb = ndk::SharedRefBase::make(completionCallback); std::shared_ptr session; auto status = getHal()->startSession(ids, config, cb, &session); return HalResultFactory::fromStatus>(std::move(status), std::move( session)); } HalResult 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 lock(mVibratorsMutex); for (auto& entry : mVibrators) { entry.second->tryReconnect(); } } return ret; } HalResult AidlManagerHalWrapper::clearSessions() { return HalResultFactory::fromStatus(getHal()->clearSessions()); } std::shared_ptr AidlManagerHalWrapper::getHal() { std::lock_guard lock(mHandleMutex); return mHandle; } }; // namespace vibrator }; // namespace android