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