Merge "Add wrapper for IVibratorManager.aidl to native vibrator service"
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index fa742c5..75228d6 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -35,7 +35,7 @@
         "libhidlbase",
         "liblog",
         "libutils",
-        "android.hardware.vibrator-cpp",
+        "android.hardware.vibrator-unstable-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 9672644..7fee82f 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "VibratorHalWrapper"
 
 #include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
 #include <android/hardware/vibrator/IVibrator.h>
 #include <hardware/vibrator.h>
 
@@ -73,17 +72,6 @@
         "android::hardware::vibrator::V1_0::Status = ";
 
 template <typename T>
-HalResult<T> HalResult<T>::fromStatus(binder::Status status, T data) {
-    if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
-        return HalResult<T>::unsupported();
-    }
-    if (status.isOk()) {
-        return HalResult<T>::ok(data);
-    }
-    return HalResult<T>::failed(std::string(status.toString8().c_str()));
-}
-
-template <typename T>
 HalResult<T> HalResult<T>::fromStatus(V1_0::Status status, T data) {
     switch (status) {
         case V1_0::Status::OK:
@@ -145,28 +133,16 @@
 
 // -------------------------------------------------------------------------------------------------
 
-class HalCallbackWrapper : public Aidl::BnVibratorCallback {
-public:
-    HalCallbackWrapper(std::function<void()> completionCallback)
-          : mCompletionCallback(completionCallback) {}
-
-    binder::Status onComplete() override {
-        mCompletionCallback();
-        return binder::Status::ok();
-    }
-
-private:
-    const std::function<void()> mCompletionCallback;
-};
-
-// -------------------------------------------------------------------------------------------------
-
 HalResult<void> AidlHalWrapper::ping() {
     return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder());
 }
 
 void AidlHalWrapper::tryReconnect() {
-    sp<Aidl::IVibrator> newHandle = checkVintfService<Aidl::IVibrator>();
+    auto result = mReconnectFn();
+    if (!result.isOk()) {
+        return;
+    }
+    sp<Aidl::IVibrator> newHandle = result.value();
     if (newHandle) {
         std::lock_guard<std::mutex> lock(mHandleMutex);
         mHandle = std::move(newHandle);
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
index 71955af..9c4166c 100644
--- a/services/vibratorservice/VibratorManagerHalWrapper.cpp
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -20,11 +20,14 @@
 
 #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() {
     return mController->ping();
@@ -34,6 +37,10 @@
     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));
@@ -47,7 +54,7 @@
         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("No vibrator with id = " +
+    return HalResult<std::shared_ptr<HalController>>::failed(MISSING_VIBRATOR_MESSAGE_PREFIX +
                                                              std::to_string(id));
 }
 
@@ -63,6 +70,135 @@
     return HalResult<void>::unsupported();
 }
 
+// -------------------------------------------------------------------------------------------------
+
+std::shared_ptr<HalWrapper> AidlManagerHalWrapper::ManagedHalConnector::connect(
+        std::shared_ptr<CallbackScheduler> callbackScheduler) {
+    std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [&]() {
+        sp<Aidl::IVibrator> vibrator;
+        auto result = this->mManager->getHal()->getVibrator(this->mVibratorId, &vibrator);
+        return HalResult<sp<Aidl::IVibrator>>::fromStatus(result, vibrator);
+    };
+    auto result = reconnectFn();
+    if (!result.isOk()) {
+        return nullptr;
+    }
+    auto vibrator = result.value();
+    if (!vibrator) {
+        return nullptr;
+    }
+    return std::move(std::make_unique<AidlHalWrapper>(std::move(callbackScheduler),
+                                                      std::move(vibrator), reconnectFn));
+}
+
+HalResult<void> AidlManagerHalWrapper::ping() {
+    return HalResult<void>::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 ret = HalResult<ManagerCapabilities>::fromStatus(result,
+                                                          static_cast<ManagerCapabilities>(cap));
+    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 = HalResult<std::vector<int32_t>>::fromStatus(result, ids);
+    if (ret.isOk()) {
+        // Cache copy of returned value and the individual controllers.
+        mVibratorIds.emplace(ret.value());
+        for (auto& id : ids) {
+            auto connector = std::make_unique<ManagedHalConnector>(this, id);
+            auto controller =
+                    std::make_unique<HalController>(std::move(connector), mCallbackScheduler);
+            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));
+}
+
+HalResult<void> AidlManagerHalWrapper::prepareSynced(const std::vector<int32_t>& ids) {
+    auto ret = HalResult<void>::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 HalResult<void>::fromStatus(getHal()->triggerSynced(cb));
+}
+
+HalResult<void> AidlManagerHalWrapper::cancelSynced() {
+    auto ret = HalResult<void>::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
diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp
index c1a03a1..d3130f4 100644
--- a/services/vibratorservice/benchmarks/Android.bp
+++ b/services/vibratorservice/benchmarks/Android.bp
@@ -23,7 +23,7 @@
         "liblog",
         "libutils",
         "libvibratorservice",
-        "android.hardware.vibrator-cpp",
+        "android.hardware.vibrator-unstable-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index bcb735d..638b483 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -19,6 +19,7 @@
 
 #include <android-base/thread_annotations.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/BnVibratorCallback.h>
 #include <android/hardware/vibrator/IVibrator.h>
 #include <binder/IServiceManager.h>
 
@@ -40,7 +41,15 @@
     }
     static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
 
-    static HalResult<T> fromStatus(binder::Status status, T data);
+    static HalResult<T> fromStatus(binder::Status status, T data) {
+        if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+            return HalResult<T>::unsupported();
+        }
+        if (status.isOk()) {
+            return HalResult<T>::ok(data);
+        }
+        return HalResult<T>::failed(std::string(status.toString8().c_str()));
+    }
     static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data);
 
     template <typename R>
@@ -99,6 +108,20 @@
           : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {}
 };
 
+class HalCallbackWrapper : public hardware::vibrator::BnVibratorCallback {
+public:
+    HalCallbackWrapper(std::function<void()> completionCallback)
+          : mCompletionCallback(completionCallback) {}
+
+    binder::Status onComplete() override {
+        mCompletionCallback();
+        return binder::Status::ok();
+    }
+
+private:
+    const std::function<void()> mCompletionCallback;
+};
+
 // -------------------------------------------------------------------------------------------------
 
 // Vibrator HAL capabilities.
@@ -178,9 +201,16 @@
 // Wrapper for the AIDL Vibrator HAL.
 class AidlHalWrapper : public HalWrapper {
 public:
-    AidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler,
-                   sp<hardware::vibrator::IVibrator> handle)
-          : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {}
+    AidlHalWrapper(
+            std::shared_ptr<CallbackScheduler> scheduler, sp<hardware::vibrator::IVibrator> handle,
+            std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> reconnectFn =
+                    []() {
+                        return HalResult<sp<hardware::vibrator::IVibrator>>::ok(
+                                checkVintfService<hardware::vibrator::IVibrator>());
+                    })
+          : HalWrapper(std::move(scheduler)),
+            mReconnectFn(reconnectFn),
+            mHandle(std::move(handle)) {}
     virtual ~AidlHalWrapper() = default;
 
     HalResult<void> ping() override final;
@@ -211,6 +241,7 @@
             const std::function<void()>& completionCallback) override final;
 
 private:
+    const std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> mReconnectFn;
     std::mutex mHandleMutex;
     std::mutex mCapabilitiesMutex;
     std::mutex mSupportedEffectsMutex;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
index 99947a5..309d681 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
@@ -17,12 +17,47 @@
 #ifndef ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
 #define ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
 
+#include <android/hardware/vibrator/IVibratorManager.h>
 #include <vibratorservice/VibratorHalController.h>
+#include <unordered_map>
 
 namespace android {
 
 namespace vibrator {
 
+// VibratorManager HAL capabilities.
+enum class ManagerCapabilities : int32_t {
+    NONE = 0,
+    SYNC = hardware::vibrator::IVibratorManager::CAP_SYNC,
+    PREPARE_ON = hardware::vibrator::IVibratorManager::CAP_PREPARE_ON,
+    PREPARE_PERFORM = hardware::vibrator::IVibratorManager::CAP_PREPARE_PERFORM,
+    PREPARE_COMPOSE = hardware::vibrator::IVibratorManager::CAP_PREPARE_COMPOSE,
+    MIXED_TRIGGER_ON = hardware::vibrator::IVibratorManager::IVibratorManager::CAP_MIXED_TRIGGER_ON,
+    MIXED_TRIGGER_PERFORM = hardware::vibrator::IVibratorManager::CAP_MIXED_TRIGGER_PERFORM,
+    MIXED_TRIGGER_COMPOSE = hardware::vibrator::IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE,
+    TRIGGER_CALLBACK = hardware::vibrator::IVibratorManager::CAP_TRIGGER_CALLBACK
+};
+
+inline ManagerCapabilities operator|(ManagerCapabilities lhs, ManagerCapabilities rhs) {
+    using underlying = typename std::underlying_type<ManagerCapabilities>::type;
+    return static_cast<ManagerCapabilities>(static_cast<underlying>(lhs) |
+                                            static_cast<underlying>(rhs));
+}
+
+inline ManagerCapabilities& operator|=(ManagerCapabilities& lhs, ManagerCapabilities rhs) {
+    return lhs = lhs | rhs;
+}
+
+inline ManagerCapabilities operator&(ManagerCapabilities lhs, ManagerCapabilities rhs) {
+    using underlying = typename std::underlying_type<ManagerCapabilities>::type;
+    return static_cast<ManagerCapabilities>(static_cast<underlying>(lhs) &
+                                            static_cast<underlying>(rhs));
+}
+
+inline ManagerCapabilities& operator&=(ManagerCapabilities& lhs, ManagerCapabilities rhs) {
+    return lhs = lhs & rhs;
+}
+
 // Wrapper for VibratorManager HAL handlers.
 class ManagerHalWrapper {
 public:
@@ -36,6 +71,7 @@
      */
     virtual void tryReconnect() = 0;
 
+    virtual HalResult<ManagerCapabilities> getCapabilities() = 0;
     virtual HalResult<std::vector<int32_t>> getVibratorIds() = 0;
     virtual HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) = 0;
 
@@ -55,6 +91,7 @@
     HalResult<void> ping() override final;
     void tryReconnect() override final;
 
+    HalResult<ManagerCapabilities> getCapabilities() override final;
     HalResult<std::vector<int32_t>> getVibratorIds() override final;
     HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final;
 
@@ -66,6 +103,53 @@
     const std::shared_ptr<HalController> mController;
 };
 
+// Wrapper for the AIDL VibratorManager HAL.
+class AidlManagerHalWrapper : public ManagerHalWrapper {
+public:
+    explicit AidlManagerHalWrapper(std::shared_ptr<CallbackScheduler> callbackScheduler,
+                                   sp<hardware::vibrator::IVibratorManager> handle)
+          : mHandle(std::move(handle)), mCallbackScheduler(callbackScheduler) {}
+    virtual ~AidlManagerHalWrapper() = default;
+
+    HalResult<void> ping() override final;
+    void tryReconnect() override final;
+
+    HalResult<ManagerCapabilities> getCapabilities() override final;
+    HalResult<std::vector<int32_t>> getVibratorIds() override final;
+    HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final;
+
+    HalResult<void> prepareSynced(const std::vector<int32_t>& ids) override final;
+    HalResult<void> triggerSynced(const std::function<void()>& completionCallback) override final;
+    HalResult<void> cancelSynced() override final;
+
+private:
+    std::mutex mHandleMutex;
+    std::mutex mCapabilitiesMutex;
+    std::mutex mVibratorsMutex;
+    sp<hardware::vibrator::IVibratorManager> mHandle GUARDED_BY(mHandleMutex);
+    std::optional<ManagerCapabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
+    std::optional<std::vector<int32_t>> mVibratorIds GUARDED_BY(mVibratorsMutex);
+    std::unordered_map<int32_t, std::shared_ptr<HalController>> mVibrators
+            GUARDED_BY(mVibratorsMutex);
+    std::shared_ptr<CallbackScheduler> mCallbackScheduler;
+
+    sp<hardware::vibrator::IVibratorManager> getHal();
+
+    // Connector that creates a HalWrapper from an IVibrator loaded from IVibratorManager.
+    class ManagedHalConnector : public HalConnector {
+    public:
+        ManagedHalConnector(AidlManagerHalWrapper* manager, int32_t vibratorId)
+              : mManager(manager), mVibratorId(vibratorId) {}
+        ~ManagedHalConnector() = default;
+
+        std::shared_ptr<HalWrapper> connect(std::shared_ptr<CallbackScheduler>) override final;
+
+    private:
+        AidlManagerHalWrapper* mManager;
+        const int32_t mVibratorId;
+    };
+};
+
 }; // namespace vibrator
 
 }; // namespace android
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 5fc6d45..6801f76 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -23,6 +23,7 @@
         "VibratorHalWrapperHidlV1_1Test.cpp",
         "VibratorHalWrapperHidlV1_2Test.cpp",
         "VibratorHalWrapperHidlV1_3Test.cpp",
+        "VibratorManagerHalWrapperAidlTest.cpp",
         "VibratorManagerHalWrapperLegacyTest.cpp",
     ],
     cflags: [
@@ -37,7 +38,7 @@
         "liblog",
         "libvibratorservice",
         "libutils",
-        "android.hardware.vibrator-cpp",
+        "android.hardware.vibrator-unstable-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
new file mode 100644
index 0000000..dd71a6a
--- /dev/null
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -0,0 +1,358 @@
+/*
+ * 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 "VibratorManagerHalWrapperAidlTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorManagerHalWrapper.h>
+
+#include "test_utils.h"
+
+using android::binder::Status;
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+using android::hardware::vibrator::IVibratorCallback;
+using android::hardware::vibrator::IVibratorManager;
+
+using namespace android;
+using namespace testing;
+
+class MockBinder : public BBinder {
+public:
+    MOCK_METHOD(status_t, linkToDeath,
+                (const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags), (override));
+    MOCK_METHOD(status_t, unlinkToDeath,
+                (const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+                 wp<DeathRecipient>* outRecipient),
+                (override));
+    MOCK_METHOD(status_t, pingBinder, (), (override));
+};
+
+class MockIVibrator : public IVibrator {
+public:
+    MOCK_METHOD(Status, getCapabilities, (int32_t * ret), (override));
+    MOCK_METHOD(Status, off, (), (override));
+    MOCK_METHOD(Status, on, (int32_t timeout, const sp<IVibratorCallback>& cb), (override));
+    MOCK_METHOD(Status, perform,
+                (Effect e, EffectStrength s, const sp<IVibratorCallback>& cb, int32_t* ret),
+                (override));
+    MOCK_METHOD(Status, getSupportedEffects, (std::vector<Effect> * ret), (override));
+    MOCK_METHOD(Status, setAmplitude, (float amplitude), (override));
+    MOCK_METHOD(Status, setExternalControl, (bool enabled), (override));
+    MOCK_METHOD(Status, getCompositionDelayMax, (int32_t * ret), (override));
+    MOCK_METHOD(Status, getCompositionSizeMax, (int32_t * ret), (override));
+    MOCK_METHOD(Status, getSupportedPrimitives, (std::vector<CompositePrimitive> * ret),
+                (override));
+    MOCK_METHOD(Status, getPrimitiveDuration, (CompositePrimitive p, int32_t* ret), (override));
+    MOCK_METHOD(Status, compose,
+                (const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb),
+                (override));
+    MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
+    MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
+    MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
+    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+class MockIVibratorManager : public IVibratorManager {
+public:
+    MOCK_METHOD(Status, getCapabilities, (int32_t * ret), (override));
+    MOCK_METHOD(Status, getVibratorIds, (std::vector<int32_t> * ret), (override));
+    MOCK_METHOD(Status, getVibrator, (int32_t id, sp<IVibrator>* ret), (override));
+    MOCK_METHOD(Status, prepareSynced, (const std::vector<int32_t>& ids), (override));
+    MOCK_METHOD(Status, triggerSynced, (const sp<IVibratorCallback>& cb), (override));
+    MOCK_METHOD(Status, cancelSynced, (), (override));
+    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorManagerHalWrapperAidlTest : public Test {
+public:
+    void SetUp() override {
+        mMockBinder = new StrictMock<MockBinder>();
+        mMockVibrator = new StrictMock<MockIVibrator>();
+        mMockHal = new StrictMock<MockIVibratorManager>();
+        mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+        mWrapper = std::make_unique<vibrator::AidlManagerHalWrapper>(mMockScheduler, mMockHal);
+        ASSERT_NE(mWrapper, nullptr);
+    }
+
+protected:
+    std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
+    std::unique_ptr<vibrator::ManagerHalWrapper> mWrapper = nullptr;
+    sp<StrictMock<MockIVibratorManager>> mMockHal = nullptr;
+    sp<StrictMock<MockIVibrator>> mMockVibrator = nullptr;
+    sp<StrictMock<MockBinder>> mMockBinder = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+static const std::vector<int32_t> kVibratorIds = {1, 2};
+static constexpr int kVibratorId = 1;
+
+ACTION(TriggerCallback) {
+    if (arg0 != nullptr) {
+        arg0->onComplete();
+    }
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestPing) {
+    EXPECT_CALL(*mMockHal.get(), onAsBinder())
+            .Times(Exactly(2))
+            .WillRepeatedly(Return(mMockBinder.get()));
+    EXPECT_CALL(*mMockBinder.get(), pingBinder())
+            .Times(Exactly(2))
+            .WillOnce(Return(android::OK))
+            .WillRepeatedly(Return(android::DEAD_OBJECT));
+
+    ASSERT_TRUE(mWrapper->ping().isOk());
+    ASSERT_TRUE(mWrapper->ping().isFailed());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetCapabilitiesDoesNotCacheFailedResult) {
+    EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+            .Times(Exactly(3))
+            .WillOnce(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(IVibratorManager::CAP_SYNC), Return(Status())));
+
+    ASSERT_TRUE(mWrapper->getCapabilities().isUnsupported());
+    ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+
+    auto result = mWrapper->getCapabilities();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(vibrator::ManagerCapabilities::SYNC, result.value());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetCapabilitiesCachesResult) {
+    EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(IVibratorManager::CAP_SYNC), Return(Status())));
+
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 10; i++) {
+        threads.push_back(std::thread([&]() {
+            auto result = mWrapper->getCapabilities();
+            ASSERT_TRUE(result.isOk());
+            ASSERT_EQ(vibrator::ManagerCapabilities::SYNC, result.value());
+        }));
+    }
+    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getCapabilities();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(vibrator::ManagerCapabilities::SYNC, result.value());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorIdsDoesNotCacheFailedResult) {
+    EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+            .Times(Exactly(3))
+            .WillOnce(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+    ASSERT_TRUE(mWrapper->getVibratorIds().isUnsupported());
+    ASSERT_TRUE(mWrapper->getVibratorIds().isFailed());
+
+    auto result = mWrapper->getVibratorIds();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(kVibratorIds, result.value());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorIdsCachesResult) {
+    EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 10; i++) {
+        threads.push_back(std::thread([&]() {
+            auto result = mWrapper->getVibratorIds();
+            ASSERT_TRUE(result.isOk());
+            ASSERT_EQ(kVibratorIds, result.value());
+        }));
+    }
+    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getVibratorIds();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(kVibratorIds, result.value());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorWithValidIdReturnsController) {
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+        EXPECT_CALL(*mMockHal.get(), getVibrator(Eq(kVibratorId), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
+    }
+
+    auto result = mWrapper->getVibrator(kVibratorId);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_NE(nullptr, result.value().get());
+    ASSERT_TRUE(result.value().get()->init());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorWithInvalidIdFails) {
+    EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+    ASSERT_TRUE(mWrapper->getVibrator(0).isFailed());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorRecoversVibratorPointer) {
+    EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+    EXPECT_CALL(*mMockHal.get(), getVibrator(Eq(kVibratorId), _))
+            .Times(Exactly(3))
+            .WillOnce(DoAll(SetArgPointee<1>(nullptr),
+                            Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
+
+    EXPECT_CALL(*mMockVibrator.get(), getCapabilities(_))
+            .Times(Exactly(3))
+            .WillOnce(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+
+    // Get vibrator controller is successful even if first getVibrator.
+    auto result = mWrapper->getVibrator(kVibratorId);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_NE(nullptr, result.value().get());
+
+    auto vibrator = result.value();
+    // First getVibrator call fails.
+    ASSERT_FALSE(vibrator->init());
+    // First and second getCapabilities calls fail, reload IVibrator with getVibrator.
+    ASSERT_FALSE(vibrator->getCapabilities().isOk());
+    // Third call to getCapabilities worked after IVibrator reloaded.
+    ASSERT_TRUE(vibrator->getCapabilities().isOk());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestPrepareSynced) {
+    EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+    EXPECT_CALL(*mMockHal.get(), getVibrator(_, _))
+            .Times(Exactly(2))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
+
+    EXPECT_CALL(*mMockHal.get(), prepareSynced(Eq(kVibratorIds)))
+            .Times(Exactly(3))
+            .WillOnce(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(Return(Status()));
+
+    ASSERT_TRUE(mWrapper->getVibratorIds().isOk());
+    ASSERT_TRUE(mWrapper->prepareSynced(kVibratorIds).isUnsupported());
+    ASSERT_TRUE(mWrapper->prepareSynced(kVibratorIds).isFailed());
+    ASSERT_TRUE(mWrapper->prepareSynced(kVibratorIds).isOk());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestTriggerSyncedWithCallbackSupport) {
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<0>(IVibratorManager::CAP_TRIGGER_CALLBACK),
+                                      Return(Status())));
+        EXPECT_CALL(*mMockHal.get(), triggerSynced(_))
+                .Times(Exactly(3))
+                .WillOnce(Return(
+                        Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+                .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+                .WillRepeatedly(DoAll(TriggerCallback(), Return(Status())));
+    }
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    ASSERT_TRUE(mWrapper->triggerSynced(callback).isUnsupported());
+    ASSERT_TRUE(mWrapper->triggerSynced(callback).isFailed());
+    ASSERT_TRUE(mWrapper->triggerSynced(callback).isOk());
+    ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestTriggerSyncedWithoutCallbackSupport) {
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        DoAll(SetArgPointee<0>(IVibratorManager::CAP_SYNC), Return(Status())));
+        EXPECT_CALL(*mMockHal.get(), triggerSynced(Eq(nullptr)))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status()));
+    }
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    ASSERT_TRUE(mWrapper->triggerSynced(callback).isOk());
+    ASSERT_EQ(0, *callbackCounter.get());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestCancelSynced) {
+    EXPECT_CALL(*mMockHal.get(), cancelSynced())
+            .Times(Exactly(3))
+            .WillOnce(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(Return(Status()));
+
+    ASSERT_TRUE(mWrapper->cancelSynced().isUnsupported());
+    ASSERT_TRUE(mWrapper->cancelSynced().isFailed());
+    ASSERT_TRUE(mWrapper->cancelSynced().isOk());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestCancelSyncedReloadsAllControllers) {
+    EXPECT_CALL(*mMockHal.get(), getVibratorIds(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status())));
+
+    EXPECT_CALL(*mMockHal.get(), getVibrator(_, _))
+            .Times(Exactly(2))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
+
+    EXPECT_CALL(*mMockHal.get(), cancelSynced()).Times(Exactly(1)).WillRepeatedly(Return(Status()));
+
+    ASSERT_TRUE(mWrapper->getVibratorIds().isOk());
+    ASSERT_TRUE(mWrapper->cancelSynced().isOk());
+}
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
index d5520a1..6c2aabb 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
@@ -78,6 +78,12 @@
     mWrapper->tryReconnect();
 }
 
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetCapabilities) {
+    auto result = mWrapper->getCapabilities();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(vibrator::ManagerCapabilities::NONE, result.value());
+}
+
 TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorIds) {
     std::vector<int32_t> expectedIds;
     expectedIds.push_back(0);