Add getSupportedPrimitives to vibrator HAL wrapper

Expose the IVibrator.aidl getSupportedPrimitives method to be used by
the VibratorService.

Fix: b/163484172
Test: atest libvibratorservice_test
Change-Id: I6dfa0df6993837c45365a2f2c051cb1462b9d155
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index a9da74f..46175ad 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -28,6 +28,7 @@
 #include <vibratorservice/VibratorHalWrapper.h>
 
 using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 
@@ -201,6 +202,12 @@
     return apply(getSupportedEffectsFn, "getSupportedEffects");
 }
 
+HalResult<std::vector<CompositePrimitive>> HalController::getSupportedPrimitives() {
+    hal_fn<std::vector<CompositePrimitive>> getSupportedPrimitivesFn =
+            [](std::shared_ptr<HalWrapper> hal) { return hal->getSupportedPrimitives(); };
+    return apply(getSupportedPrimitivesFn, "getSupportedPrimitives");
+}
+
 HalResult<milliseconds> HalController::performEffect(
         Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     hal_fn<milliseconds> performEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index ee891de..ce20aeb 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -27,6 +27,7 @@
 #include <vibratorservice/VibratorHalWrapper.h>
 
 using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 
@@ -221,6 +222,13 @@
                                            mSupportedEffects);
 }
 
+HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitives() {
+    std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex);
+    return loadCached<std::vector<
+            CompositePrimitive>>(std::bind(&AidlHalWrapper::getSupportedPrimitivesInternal, this),
+                                 mSupportedPrimitives);
+}
+
 HalResult<milliseconds> AidlHalWrapper::performEffect(
         Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     HalResult<Capabilities> capabilities = getCapabilities();
@@ -260,6 +268,12 @@
     return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
 }
 
+HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitivesInternal() {
+    std::vector<CompositePrimitive> supportedPrimitives;
+    auto result = getHal()->getSupportedPrimitives(&supportedPrimitives);
+    return HalResult<std::vector<CompositePrimitive>>::fromStatus(result, supportedPrimitives);
+}
+
 sp<Aidl::IVibrator> AidlHalWrapper::getHal() {
     std::lock_guard<std::mutex> lock(mHandleMutex);
     return mHandle;
@@ -337,6 +351,12 @@
 }
 
 template <typename I>
+HalResult<std::vector<CompositePrimitive>> HidlHalWrapper<I>::getSupportedPrimitives() {
+    ALOGV("Skipped getSupportedPrimitives because Vibrator HAL AIDL is not available");
+    return HalResult<std::vector<CompositePrimitive>>::unsupported();
+}
+
+template <typename I>
 HalResult<void> HidlHalWrapper<I>::performComposedEffect(const std::vector<CompositeEffect>&,
                                                          const std::function<void()>&) {
     ALOGV("Skipped composed effect because Vibrator HAL AIDL is not available");
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index daf2c8c..3b61f42 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -69,6 +69,8 @@
 
     HalResult<Capabilities> getCapabilities() final override;
     HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() final override;
+    HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
+            final override;
 
     HalResult<std::chrono::milliseconds> performEffect(
             hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 6e36bd6..7b99bbb 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -156,6 +156,8 @@
 
     virtual HalResult<Capabilities> getCapabilities() = 0;
     virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() = 0;
+    virtual HalResult<std::vector<hardware::vibrator::CompositePrimitive>>
+    getSupportedPrimitives() = 0;
 
     virtual HalResult<std::chrono::milliseconds> performEffect(
             hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -194,6 +196,8 @@
 
     HalResult<Capabilities> getCapabilities() override final;
     HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() override final;
+    HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
+            override final;
 
     HalResult<std::chrono::milliseconds> performEffect(
             hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -207,14 +211,18 @@
     std::mutex mHandleMutex;
     std::mutex mCapabilitiesMutex;
     std::mutex mSupportedEffectsMutex;
+    std::mutex mSupportedPrimitivesMutex;
     sp<hardware::vibrator::IVibrator> mHandle GUARDED_BY(mHandleMutex);
     std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
     std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
             GUARDED_BY(mSupportedEffectsMutex);
+    std::optional<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives
+            GUARDED_BY(mSupportedPrimitivesMutex);
 
     // Loads directly from IVibrator handle, skipping caches.
     HalResult<Capabilities> getCapabilitiesInternal();
     HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
+    HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitivesInternal();
     sp<hardware::vibrator::IVibrator> getHal();
 };
 
@@ -242,6 +250,8 @@
 
     HalResult<Capabilities> getCapabilities() override final;
     HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() override final;
+    HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
+            override final;
 
     HalResult<void> performComposedEffect(
             const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index 8155df0..f04e016 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -65,6 +65,8 @@
     MOCK_METHOD(vibrator::HalResult<void>, alwaysOnDisable, (int32_t id), (override));
     MOCK_METHOD(vibrator::HalResult<vibrator::Capabilities>, getCapabilities, (), (override));
     MOCK_METHOD(vibrator::HalResult<std::vector<Effect>>, getSupportedEffects, (), (override));
+    MOCK_METHOD(vibrator::HalResult<std::vector<CompositePrimitive>>, getSupportedPrimitives, (),
+                (override));
     MOCK_METHOD(vibrator::HalResult<milliseconds>, performEffect,
                 (Effect effect, EffectStrength strength,
                  const std::function<void()>& completionCallback),
@@ -132,6 +134,7 @@
                             vibrator::HalResult<void> voidResult,
                             vibrator::HalResult<vibrator::Capabilities> capabilitiesResult,
                             vibrator::HalResult<std::vector<Effect>> effectsResult,
+                            vibrator::HalResult<std::vector<CompositePrimitive>> primitivesResult,
                             vibrator::HalResult<milliseconds> durationResult) {
         EXPECT_CALL(*mMockHal.get(), ping())
                 .Times(Exactly(cardinality))
@@ -161,6 +164,9 @@
         EXPECT_CALL(*mMockHal.get(), getSupportedEffects())
                 .Times(Exactly(cardinality))
                 .WillRepeatedly(Return(effectsResult));
+        EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives())
+                .Times(Exactly(cardinality))
+                .WillRepeatedly(Return(primitivesResult));
         EXPECT_CALL(*mMockHal.get(), performEffect(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _))
                 .Times(Exactly(cardinality))
                 .WillRepeatedly(Return(durationResult));
@@ -170,7 +176,7 @@
 
         if (cardinality > 1) {
             // One reconnection call after each failure.
-            EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(11 * cardinality));
+            EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(12 * cardinality));
         }
     }
 };
@@ -187,9 +193,12 @@
 }
 
 TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
-    std::vector<Effect> supportedEffects;
-    supportedEffects.push_back(Effect::CLICK);
-    supportedEffects.push_back(Effect::TICK);
+    std::vector<Effect> effects;
+    effects.push_back(Effect::CLICK);
+    effects.push_back(Effect::TICK);
+    std::vector<CompositePrimitive> primitives;
+    primitives.push_back(CompositePrimitive::CLICK);
+    primitives.push_back(CompositePrimitive::THUD);
     std::vector<CompositeEffect> compositeEffects;
     compositeEffects.push_back(
             vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f));
@@ -199,7 +208,8 @@
     setHalExpectations(/* cardinality= */ 1, compositeEffects, vibrator::HalResult<void>::ok(),
                        vibrator::HalResult<vibrator::Capabilities>::ok(
                                vibrator::Capabilities::ON_CALLBACK),
-                       vibrator::HalResult<std::vector<Effect>>::ok(supportedEffects),
+                       vibrator::HalResult<std::vector<Effect>>::ok(effects),
+                       vibrator::HalResult<std::vector<CompositePrimitive>>::ok(primitives),
                        vibrator::HalResult<milliseconds>::ok(100ms));
 
     ASSERT_TRUE(mController->ping().isOk());
@@ -216,7 +226,11 @@
 
     auto getSupportedEffectsResult = mController->getSupportedEffects();
     ASSERT_TRUE(getSupportedEffectsResult.isOk());
-    ASSERT_EQ(supportedEffects, getSupportedEffectsResult.value());
+    ASSERT_EQ(effects, getSupportedEffectsResult.value());
+
+    auto getSupportedPrimitivesResult = mController->getSupportedPrimitives();
+    ASSERT_TRUE(getSupportedPrimitivesResult.isOk());
+    ASSERT_EQ(primitives, getSupportedPrimitivesResult.value());
 
     auto performEffectResult =
             mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {});
@@ -233,6 +247,7 @@
                        vibrator::HalResult<void>::unsupported(),
                        vibrator::HalResult<vibrator::Capabilities>::unsupported(),
                        vibrator::HalResult<std::vector<Effect>>::unsupported(),
+                       vibrator::HalResult<std::vector<CompositePrimitive>>::unsupported(),
                        vibrator::HalResult<milliseconds>::unsupported());
 
     ASSERT_EQ(0, mConnectCounter);
@@ -247,6 +262,7 @@
     ASSERT_TRUE(mController->alwaysOnDisable(1).isUnsupported());
     ASSERT_TRUE(mController->getCapabilities().isUnsupported());
     ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
+    ASSERT_TRUE(mController->getSupportedPrimitives().isUnsupported());
     ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
                         .isUnsupported());
     ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
@@ -260,6 +276,7 @@
                        vibrator::HalResult<void>::failed("message"),
                        vibrator::HalResult<vibrator::Capabilities>::failed("message"),
                        vibrator::HalResult<std::vector<Effect>>::failed("message"),
+                       vibrator::HalResult<std::vector<CompositePrimitive>>::failed("message"),
                        vibrator::HalResult<milliseconds>::failed("message"));
 
     ASSERT_EQ(0, mConnectCounter);
@@ -273,6 +290,7 @@
     ASSERT_TRUE(mController->alwaysOnDisable(1).isFailed());
     ASSERT_TRUE(mController->getCapabilities().isFailed());
     ASSERT_TRUE(mController->getSupportedEffects().isFailed());
+    ASSERT_TRUE(mController->getSupportedPrimitives().isFailed());
     ASSERT_TRUE(
             mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {}).isFailed());
     ASSERT_TRUE(
@@ -331,13 +349,14 @@
     ASSERT_TRUE(mController->alwaysOnDisable(1).isUnsupported());
     ASSERT_TRUE(mController->getCapabilities().isUnsupported());
     ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
+    ASSERT_TRUE(mController->getSupportedPrimitives().isUnsupported());
     ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
                         .isUnsupported());
     ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
                         .isUnsupported());
 
     // One connection attempt per api call.
-    ASSERT_EQ(11, mConnectCounter);
+    ASSERT_EQ(12, mConnectCounter);
 }
 
 TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 3e06c95..96b76ba 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -367,6 +367,50 @@
     ASSERT_EQ(supportedEffects, result.value());
 }
 
+TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedPrimitivesDoesNotCacheFailedResult) {
+    std::vector<CompositePrimitive> supportedPrimitives;
+    supportedPrimitives.push_back(CompositePrimitive::CLICK);
+    supportedPrimitives.push_back(CompositePrimitive::THUD);
+
+    EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
+            .Times(Exactly(3))
+            .WillOnce(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
+
+    ASSERT_TRUE(mWrapper->getSupportedPrimitives().isUnsupported());
+    ASSERT_TRUE(mWrapper->getSupportedPrimitives().isFailed());
+
+    auto result = mWrapper->getSupportedPrimitives();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(supportedPrimitives, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedPrimitivesCachesResult) {
+    std::vector<CompositePrimitive> supportedPrimitives;
+    supportedPrimitives.push_back(CompositePrimitive::CLICK);
+    supportedPrimitives.push_back(CompositePrimitive::THUD);
+
+    EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
+
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 10; i++) {
+        threads.push_back(std::thread([&]() {
+            auto result = mWrapper->getSupportedPrimitives();
+            ASSERT_TRUE(result.isOk());
+            ASSERT_EQ(supportedPrimitives, result.value());
+        }));
+    }
+    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getSupportedPrimitives();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(supportedPrimitives, result.value());
+}
+
 TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
     {
         InSequence seq;
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 7eb4059..06aa36f 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -236,6 +236,10 @@
     ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
 }
 
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedPrimitivesUnsupported) {
+    ASSERT_TRUE(mWrapper->getSupportedPrimitives().isUnsupported());
+}
+
 TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) {
     {
         InSequence seq;