Implement vibration session support

Introduce support to start and end vibration sessions in
IVibratorManager HAL, adding support to libvibratorservice.

Test: libvibratorservice_test
Flag: android.os.vibrator.vendor_vibration_effects
Bug: 345414356
Change-Id: Ie2121554c856ba7e45a6a5208402b0c32fa34d40
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index ba35d15..494f88f 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -150,6 +150,23 @@
     return apply(cancelSyncedFn, "cancelSynced");
 }
 
+HalResult<std::shared_ptr<Aidl::IVibrationSession>> ManagerHalController::startSession(
+        const std::vector<int32_t>& ids, const Aidl::VibrationSessionConfig& config,
+        const std::function<void()>& completionCallback) {
+    hal_fn<std::shared_ptr<Aidl::IVibrationSession>> startSessionFn =
+            [&](std::shared_ptr<ManagerHalWrapper> hal) {
+                return hal->startSession(ids, config, completionCallback);
+            };
+    return apply(startSessionFn, "startSession");
+}
+
+HalResult<void> ManagerHalController::clearSessions() {
+    hal_fn<void> clearSessionsFn = [](std::shared_ptr<ManagerHalWrapper> hal) {
+        return hal->clearSessions();
+    };
+    return apply(clearSessionsFn, "clearSessions");
+}
+
 }; // namespace vibrator
 
 }; // namespace android
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
index 93ec781..3db8ff8 100644
--- a/services/vibratorservice/VibratorManagerHalWrapper.cpp
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -29,6 +29,30 @@
 constexpr int32_t SINGLE_VIBRATOR_ID = 0;
 const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id=";
 
+HalResult<void> ManagerHalWrapper::prepareSynced(const std::vector<int32_t>&) {
+    return HalResult<void>::unsupported();
+}
+
+HalResult<void> ManagerHalWrapper::triggerSynced(const std::function<void()>&) {
+    return HalResult<void>::unsupported();
+}
+
+HalResult<void> ManagerHalWrapper::cancelSynced() {
+    return HalResult<void>::unsupported();
+}
+
+HalResult<std::shared_ptr<Aidl::IVibrationSession>> ManagerHalWrapper::startSession(
+        const std::vector<int32_t>&, const Aidl::VibrationSessionConfig&,
+        const std::function<void()>&) {
+    return HalResult<std::shared_ptr<Aidl::IVibrationSession>>::unsupported();
+}
+
+HalResult<void> ManagerHalWrapper::clearSessions() {
+    return HalResult<void>::unsupported();
+}
+
+// -------------------------------------------------------------------------------------------------
+
 HalResult<void> LegacyManagerHalWrapper::ping() {
     auto pingFn = [](HalWrapper* hal) { return hal->ping(); };
     return mController->doWithRetry<void>(pingFn, "ping");
@@ -59,18 +83,6 @@
             (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str());
 }
 
-HalResult<void> LegacyManagerHalWrapper::prepareSynced(const std::vector<int32_t>&) {
-    return HalResult<void>::unsupported();
-}
-
-HalResult<void> LegacyManagerHalWrapper::triggerSynced(const std::function<void()>&) {
-    return HalResult<void>::unsupported();
-}
-
-HalResult<void> LegacyManagerHalWrapper::cancelSynced() {
-    return HalResult<void>::unsupported();
-}
-
 // -------------------------------------------------------------------------------------------------
 
 std::shared_ptr<HalWrapper> AidlManagerHalWrapper::connectToVibrator(
@@ -186,6 +198,17 @@
     return HalResultFactory::fromStatus(getHal()->triggerSynced(cb));
 }
 
+HalResult<std::shared_ptr<Aidl::IVibrationSession>> AidlManagerHalWrapper::startSession(
+        const std::vector<int32_t>& ids, const Aidl::VibrationSessionConfig& config,
+        const std::function<void()>& completionCallback) {
+    auto cb = ndk::SharedRefBase::make<HalCallbackWrapper>(completionCallback);
+    std::shared_ptr<Aidl::IVibrationSession> session;
+    auto status = getHal()->startSession(ids, config, cb, &session);
+    return HalResultFactory::fromStatus<std::shared_ptr<Aidl::IVibrationSession>>(std::move(status),
+                                                                                  std::move(
+                                                                                          session));
+}
+
 HalResult<void> AidlManagerHalWrapper::cancelSynced() {
     auto ret = HalResultFactory::fromStatus(getHal()->cancelSynced());
     if (ret.isOk()) {
@@ -200,6 +223,10 @@
     return ret;
 }
 
+HalResult<void> AidlManagerHalWrapper::clearSessions() {
+    return HalResultFactory::fromStatus(getHal()->clearSessions());
+}
+
 std::shared_ptr<Aidl::IVibratorManager> AidlManagerHalWrapper::getHal() {
     std::lock_guard<std::mutex> lock(mHandleMutex);
     return mHandle;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
index 70c846b..72d4752 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
@@ -62,6 +62,10 @@
     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;
+    HalResult<std::shared_ptr<IVibrationSession>> startSession(
+            const std::vector<int32_t>& ids, const VibrationSessionConfig& config,
+            const std::function<void()>& completionCallback) override final;
+    HalResult<void> clearSessions() override final;
 
 private:
     Connector mConnector;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
index 9e3f221..8d4ca0e 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
@@ -38,7 +38,8 @@
             aidl::android::hardware::vibrator::IVibratorManager::CAP_MIXED_TRIGGER_PERFORM,
     MIXED_TRIGGER_COMPOSE =
             aidl::android::hardware::vibrator::IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE,
-    TRIGGER_CALLBACK = aidl::android::hardware::vibrator::IVibratorManager::CAP_TRIGGER_CALLBACK
+    TRIGGER_CALLBACK = aidl::android::hardware::vibrator::IVibratorManager::CAP_TRIGGER_CALLBACK,
+    START_SESSIONS = aidl::android::hardware::vibrator::IVibratorManager::CAP_START_SESSIONS
 };
 
 inline ManagerCapabilities operator|(ManagerCapabilities lhs, ManagerCapabilities rhs) {
@@ -64,6 +65,9 @@
 // Wrapper for VibratorManager HAL handlers.
 class ManagerHalWrapper {
 public:
+    using IVibrationSession = aidl::android::hardware::vibrator::IVibrationSession;
+    using VibrationSessionConfig = aidl::android::hardware::vibrator::VibrationSessionConfig;
+
     ManagerHalWrapper() = default;
     virtual ~ManagerHalWrapper() = default;
 
@@ -78,9 +82,13 @@
     virtual HalResult<std::vector<int32_t>> getVibratorIds() = 0;
     virtual HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) = 0;
 
-    virtual HalResult<void> prepareSynced(const std::vector<int32_t>& ids) = 0;
-    virtual HalResult<void> triggerSynced(const std::function<void()>& completionCallback) = 0;
-    virtual HalResult<void> cancelSynced() = 0;
+    virtual HalResult<void> prepareSynced(const std::vector<int32_t>& ids);
+    virtual HalResult<void> triggerSynced(const std::function<void()>& completionCallback);
+    virtual HalResult<void> cancelSynced();
+    virtual HalResult<std::shared_ptr<IVibrationSession>> startSession(
+            const std::vector<int32_t>& ids, const VibrationSessionConfig& config,
+            const std::function<void()>& completionCallback);
+    virtual HalResult<void> clearSessions();
 };
 
 // Wrapper for the VibratorManager over single Vibrator HAL.
@@ -98,10 +106,6 @@
     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:
     const std::shared_ptr<HalController> mController;
 };
@@ -126,6 +130,10 @@
     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;
+    HalResult<std::shared_ptr<IVibrationSession>> startSession(
+            const std::vector<int32_t>& ids, const VibrationSessionConfig& config,
+            const std::function<void()>& completionCallback) override final;
+    HalResult<void> clearSessions() override final;
 
 private:
     std::mutex mHandleMutex;
diff --git a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
index c7214e0..b201670 100644
--- a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
@@ -27,6 +27,8 @@
 #include "test_mocks.h"
 #include "test_utils.h"
 
+using aidl::android::hardware::vibrator::IVibrationSession;
+using aidl::android::hardware::vibrator::VibrationSessionConfig;
 using android::vibrator::HalController;
 
 using namespace android;
@@ -34,6 +36,7 @@
 
 static constexpr int MAX_ATTEMPTS = 2;
 static const std::vector<int32_t> VIBRATOR_IDS = {1, 2};
+static const VibrationSessionConfig SESSION_CONFIG;
 static constexpr int VIBRATOR_ID = 1;
 
 // -------------------------------------------------------------------------------------------------
@@ -52,6 +55,11 @@
     MOCK_METHOD(vibrator::HalResult<void>, triggerSynced,
                 (const std::function<void()>& completionCallback), (override));
     MOCK_METHOD(vibrator::HalResult<void>, cancelSynced, (), (override));
+    MOCK_METHOD(vibrator::HalResult<std::shared_ptr<IVibrationSession>>, startSession,
+                (const std::vector<int32_t>& ids, const VibrationSessionConfig& s,
+                 const std::function<void()>& completionCallback),
+                (override));
+    MOCK_METHOD(vibrator::HalResult<void>, clearSessions, (), (override));
 };
 
 // -------------------------------------------------------------------------------------------------
@@ -79,7 +87,8 @@
     void setHalExpectations(int32_t cardinality, vibrator::HalResult<void> voidResult,
                             vibrator::HalResult<vibrator::ManagerCapabilities> capabilitiesResult,
                             vibrator::HalResult<std::vector<int32_t>> idsResult,
-                            vibrator::HalResult<std::shared_ptr<HalController>> vibratorResult) {
+                            vibrator::HalResult<std::shared_ptr<HalController>> vibratorResult,
+                            vibrator::HalResult<std::shared_ptr<IVibrationSession>> sessionResult) {
         EXPECT_CALL(*mMockHal.get(), ping())
                 .Times(Exactly(cardinality))
                 .WillRepeatedly(Return(voidResult));
@@ -101,10 +110,16 @@
         EXPECT_CALL(*mMockHal.get(), cancelSynced())
                 .Times(Exactly(cardinality))
                 .WillRepeatedly(Return(voidResult));
+        EXPECT_CALL(*mMockHal.get(), startSession(_, _, _))
+                .Times(Exactly(cardinality))
+                .WillRepeatedly(Return(sessionResult));
+        EXPECT_CALL(*mMockHal.get(), clearSessions())
+                .Times(Exactly(cardinality))
+                .WillRepeatedly(Return(voidResult));
 
         if (cardinality > 1) {
             // One reconnection for each retry.
-            EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(7 * (cardinality - 1)));
+            EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(9 * (cardinality - 1)));
         } else {
             EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
         }
@@ -127,7 +142,8 @@
                        vibrator::HalResult<vibrator::ManagerCapabilities>::ok(
                                vibrator::ManagerCapabilities::SYNC),
                        vibrator::HalResult<std::vector<int32_t>>::ok(VIBRATOR_IDS),
-                       vibrator::HalResult<std::shared_ptr<HalController>>::ok(nullptr));
+                       vibrator::HalResult<std::shared_ptr<HalController>>::ok(nullptr),
+                       vibrator::HalResult<std::shared_ptr<IVibrationSession>>::ok(nullptr));
 
     ASSERT_TRUE(mController->ping().isOk());
 
@@ -146,6 +162,8 @@
     ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isOk());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isOk());
     ASSERT_TRUE(mController->cancelSynced().isOk());
+    ASSERT_TRUE(mController->startSession(VIBRATOR_IDS, SESSION_CONFIG, []() {}).isOk());
+    ASSERT_TRUE(mController->clearSessions().isOk());
 
     ASSERT_EQ(1, mConnectCounter);
 }
@@ -154,7 +172,8 @@
     setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::unsupported(),
                        vibrator::HalResult<vibrator::ManagerCapabilities>::unsupported(),
                        vibrator::HalResult<std::vector<int32_t>>::unsupported(),
-                       vibrator::HalResult<std::shared_ptr<HalController>>::unsupported());
+                       vibrator::HalResult<std::shared_ptr<HalController>>::unsupported(),
+                       vibrator::HalResult<std::shared_ptr<IVibrationSession>>::unsupported());
 
     ASSERT_TRUE(mController->ping().isUnsupported());
     ASSERT_TRUE(mController->getCapabilities().isUnsupported());
@@ -163,6 +182,8 @@
     ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isUnsupported());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isUnsupported());
     ASSERT_TRUE(mController->cancelSynced().isUnsupported());
+    ASSERT_TRUE(mController->startSession(VIBRATOR_IDS, SESSION_CONFIG, []() {}).isUnsupported());
+    ASSERT_TRUE(mController->clearSessions().isUnsupported());
 
     ASSERT_EQ(1, mConnectCounter);
 }
@@ -171,7 +192,8 @@
     setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::failed("msg"),
                        vibrator::HalResult<vibrator::ManagerCapabilities>::failed("msg"),
                        vibrator::HalResult<std::vector<int32_t>>::failed("msg"),
-                       vibrator::HalResult<std::shared_ptr<HalController>>::failed("msg"));
+                       vibrator::HalResult<std::shared_ptr<HalController>>::failed("msg"),
+                       vibrator::HalResult<std::shared_ptr<IVibrationSession>>::failed("msg"));
 
     ASSERT_TRUE(mController->ping().isFailed());
     ASSERT_TRUE(mController->getCapabilities().isFailed());
@@ -180,6 +202,8 @@
     ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isFailed());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isFailed());
     ASSERT_TRUE(mController->cancelSynced().isFailed());
+    ASSERT_TRUE(mController->startSession(VIBRATOR_IDS, SESSION_CONFIG, []() {}).isFailed());
+    ASSERT_TRUE(mController->clearSessions().isFailed());
 
     ASSERT_EQ(1, mConnectCounter);
 }
@@ -188,7 +212,9 @@
     setHalExpectations(MAX_ATTEMPTS, vibrator::HalResult<void>::transactionFailed("m"),
                        vibrator::HalResult<vibrator::ManagerCapabilities>::transactionFailed("m"),
                        vibrator::HalResult<std::vector<int32_t>>::transactionFailed("m"),
-                       vibrator::HalResult<std::shared_ptr<HalController>>::transactionFailed("m"));
+                       vibrator::HalResult<std::shared_ptr<HalController>>::transactionFailed("m"),
+                       vibrator::HalResult<std::shared_ptr<IVibrationSession>>::transactionFailed(
+                               "m"));
 
     ASSERT_TRUE(mController->ping().isFailed());
     ASSERT_TRUE(mController->getCapabilities().isFailed());
@@ -197,6 +223,8 @@
     ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isFailed());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isFailed());
     ASSERT_TRUE(mController->cancelSynced().isFailed());
+    ASSERT_TRUE(mController->startSession(VIBRATOR_IDS, SESSION_CONFIG, []() {}).isFailed());
+    ASSERT_TRUE(mController->clearSessions().isFailed());
 
     ASSERT_EQ(1, mConnectCounter);
 }
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index ca13c0b..a2f002d 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -69,12 +69,25 @@
     MOCK_METHOD(bool, isRemote, (), (override));
 };
 
+class MockIVibrationSession : public IVibrationSession {
+public:
+    MockIVibrationSession() = default;
+
+    MOCK_METHOD(ndk::ScopedAStatus, close, (), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, abort, (), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t*), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string*), (override));
+    MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override));
+    MOCK_METHOD(bool, isRemote, (), (override));
+};
+
 // -------------------------------------------------------------------------------------------------
 
 class VibratorManagerHalWrapperAidlTest : public Test {
 public:
     void SetUp() override {
         mMockVibrator = ndk::SharedRefBase::make<StrictMock<vibrator::MockIVibrator>>();
+        mMockSession = ndk::SharedRefBase::make<StrictMock<MockIVibrationSession>>();
         mMockHal = ndk::SharedRefBase::make<StrictMock<MockIVibratorManager>>();
         mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
         mWrapper = std::make_unique<vibrator::AidlManagerHalWrapper>(mMockScheduler, mMockHal);
@@ -86,11 +99,13 @@
     std::unique_ptr<vibrator::ManagerHalWrapper> mWrapper = nullptr;
     std::shared_ptr<StrictMock<MockIVibratorManager>> mMockHal = nullptr;
     std::shared_ptr<StrictMock<vibrator::MockIVibrator>> mMockVibrator = nullptr;
+    std::shared_ptr<StrictMock<MockIVibrationSession>> mMockSession = nullptr;
 };
 
 // -------------------------------------------------------------------------------------------------
 
 static const std::vector<int32_t> kVibratorIds = {1, 2};
+static const VibrationSessionConfig kSessionConfig;
 static constexpr int kVibratorId = 1;
 
 TEST_F(VibratorManagerHalWrapperAidlTest, TestGetCapabilitiesDoesNotCacheFailedResult) {
@@ -319,3 +334,35 @@
     ASSERT_TRUE(mWrapper->getVibratorIds().isOk());
     ASSERT_TRUE(mWrapper->cancelSynced().isOk());
 }
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestStartSession) {
+    EXPECT_CALL(*mMockHal.get(), startSession(_, _, _, _))
+            .Times(Exactly(3))
+            .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION)))
+            .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
+            .WillOnce(
+                    DoAll(DoAll(SetArgPointee<3>(mMockSession), Return(ndk::ScopedAStatus::ok()))));
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    ASSERT_TRUE(mWrapper->startSession(kVibratorIds, kSessionConfig, callback).isUnsupported());
+    ASSERT_TRUE(mWrapper->startSession(kVibratorIds, kSessionConfig, callback).isFailed());
+
+    auto result = mWrapper->startSession(kVibratorIds, kSessionConfig, callback);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_NE(nullptr, result.value().get());
+    ASSERT_EQ(0, *callbackCounter.get());
+}
+
+TEST_F(VibratorManagerHalWrapperAidlTest, TestClearSessions) {
+    EXPECT_CALL(*mMockHal.get(), clearSessions())
+            .Times(Exactly(3))
+            .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION)))
+            .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
+            .WillOnce(Return(ndk::ScopedAStatus::ok()));
+
+    ASSERT_TRUE(mWrapper->clearSessions().isUnsupported());
+    ASSERT_TRUE(mWrapper->clearSessions().isFailed());
+    ASSERT_TRUE(mWrapper->clearSessions().isOk());
+}
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
index 7877236..52c865e 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
@@ -29,6 +29,8 @@
 using aidl::android::hardware::vibrator::CompositePrimitive;
 using aidl::android::hardware::vibrator::Effect;
 using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrationSession;
+using aidl::android::hardware::vibrator::VibrationSessionConfig;
 
 using std::chrono::milliseconds;
 
@@ -112,3 +114,12 @@
     ASSERT_TRUE(mWrapper->triggerSynced([]() {}).isUnsupported());
     ASSERT_TRUE(mWrapper->cancelSynced().isUnsupported());
 }
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestSessionOperationsUnsupported) {
+    std::vector<int32_t> vibratorIds;
+    vibratorIds.push_back(0);
+    VibrationSessionConfig config;
+
+    ASSERT_TRUE(mWrapper->startSession(vibratorIds, config, []() {}).isUnsupported());
+    ASSERT_TRUE(mWrapper->clearSessions().isUnsupported());
+}