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 #ifndef ANDROID_OS_VIBRATORHALCONTROLLER_H 18 #define ANDROID_OS_VIBRATORHALCONTROLLER_H 19 20 #include <android-base/thread_annotations.h> 21 #include <android/hardware/vibrator/IVibrator.h> 22 23 #include <vibratorservice/VibratorCallbackScheduler.h> 24 #include <vibratorservice/VibratorHalWrapper.h> 25 26 namespace android { 27 28 namespace vibrator { 29 30 std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler); 31 32 template <typename T> 33 using HalFunction = std::function<T(HalWrapper*)>; 34 35 // Controller for Vibrator HAL handle. 36 // This relies on a given Connector to connect to the underlying Vibrator HAL service and reconnects 37 // after each failed api call. This also ensures connecting to the service is thread-safe. 38 class HalController { 39 public: 40 using Connector = 41 std::function<std::shared_ptr<HalWrapper>(std::shared_ptr<CallbackScheduler>)>; 42 HalController()43 HalController() : HalController(std::make_shared<CallbackScheduler>(), &connectHal) {} HalController(std::shared_ptr<CallbackScheduler> callbackScheduler,Connector connector)44 HalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector) 45 : mConnector(connector), 46 mConnectedHal(nullptr), 47 mCallbackScheduler(std::move(callbackScheduler)) {} 48 virtual ~HalController() = default; 49 50 /* Connects to the newest HAL version available, possibly waiting for the registered service to 51 * become available. This will automatically be called at the first API usage if it was not 52 * manually called beforehand. Calling this manually during the setup phase can avoid slowing 53 * the first API call later on. Returns true if any HAL version is available, false otherwise. 54 */ 55 virtual bool init(); 56 57 /* Reloads HAL service instance without waiting. This relies on the HAL version found by init() 58 * to rapidly reconnect to the specific HAL service, or defers to init() if it was never called. 59 */ 60 virtual void tryReconnect(); 61 62 /* Returns info loaded from the connected HAL. This allows partial results to be returned if any 63 * of the Info fields has failed, but also retried on any failure. 64 */ getInfo()65 Info getInfo() { 66 static Info sDefaultInfo = InfoCache().get(); 67 if (!init()) { 68 ALOGV("Skipped getInfo because Vibrator HAL is not available"); 69 return sDefaultInfo; 70 } 71 std::shared_ptr<HalWrapper> hal; 72 { 73 std::lock_guard<std::mutex> lock(mConnectedHalMutex); 74 hal = mConnectedHal; 75 } 76 77 for (int i = 0; i < MAX_RETRIES; i++) { 78 Info result = hal.get()->getInfo(); 79 result.logFailures(); 80 if (result.shouldRetry()) { 81 tryReconnect(); 82 } else { 83 return result; 84 } 85 } 86 87 Info result = hal.get()->getInfo(); 88 result.logFailures(); 89 return result; 90 } 91 92 /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the 93 * result has failed. Parameter functionName is for logging purposes. 94 */ 95 template <typename T> doWithRetry(const HalFunction<HalResult<T>> & halFn,const char * functionName)96 HalResult<T> doWithRetry(const HalFunction<HalResult<T>>& halFn, const char* functionName) { 97 return doWithRetry<T>(halFn, HalResult<T>::unsupported(), functionName); 98 } 99 100 private: 101 static constexpr int MAX_RETRIES = 1; 102 103 Connector mConnector; 104 std::mutex mConnectedHalMutex; 105 // Shared pointer to allow local copies to be used by different threads. 106 std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex); 107 // Shared pointer to allow copies to be passed to possible recreated mConnectedHal instances. 108 std::shared_ptr<CallbackScheduler> mCallbackScheduler; 109 110 /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the 111 * result has failed. Given default value is returned when no HAL is available, and given 112 * function name is for logging purposes. 113 */ 114 template <typename T> doWithRetry(const HalFunction<HalResult<T>> & halFn,HalResult<T> defaultValue,const char * functionName)115 HalResult<T> doWithRetry(const HalFunction<HalResult<T>>& halFn, HalResult<T> defaultValue, 116 const char* functionName) { 117 if (!init()) { 118 ALOGV("Skipped %s because Vibrator HAL is not available", functionName); 119 return defaultValue; 120 } 121 std::shared_ptr<HalWrapper> hal; 122 { 123 std::lock_guard<std::mutex> lock(mConnectedHalMutex); 124 hal = mConnectedHal; 125 } 126 127 HalResult<T> result = doOnce(hal.get(), halFn, functionName); 128 for (int i = 0; i < MAX_RETRIES && result.shouldRetry(); i++) { 129 tryReconnect(); 130 result = doOnce(hal.get(), halFn, functionName); 131 } 132 return result; 133 } 134 135 template <typename T> doOnce(HalWrapper * hal,const HalFunction<HalResult<T>> & halFn,const char * functionName)136 HalResult<T> doOnce(HalWrapper* hal, const HalFunction<HalResult<T>>& halFn, 137 const char* functionName) { 138 HalResult<T> result = halFn(hal); 139 if (result.isFailed()) { 140 ALOGE("Vibrator HAL %s failed: %s", functionName, result.errorMessage()); 141 } 142 return result; 143 } 144 }; 145 146 }; // namespace vibrator 147 148 }; // namespace android 149 150 #endif // ANDROID_OS_VIBRATORHALCONTROLLER_H 151