Introduce vibration session HAL support

Introduce support to IVibratorManager HAL for vibration sessions. A
session can be started with vendor extension parcelable to support
vendor vibration sessions in the platform.

Vibration sessions allows vibrator commands to be triggered without
resetting the vibrator motor state.

Some updates to the default Vibrator implementation were required to
make sure the vibration and session callbacks are handled by the off()
method as expected by the API docs.

Fix: 345417514
Test: VtsHalVibratorManagerTargetTest
Flag: EXEMPT HAL API changes
Change-Id: Id55ce2f23656c21734f9a18f016676250eb4227b
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 4b26640..0ac5bc0 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -19,6 +19,7 @@
     ],
     export_include_dirs: ["include"],
     srcs: [
+        "VibrationSession.cpp",
         "Vibrator.cpp",
         "VibratorManager.cpp",
     ],
diff --git a/vibrator/aidl/default/VibrationSession.cpp b/vibrator/aidl/default/VibrationSession.cpp
new file mode 100644
index 0000000..cfb6608
--- /dev/null
+++ b/vibrator/aidl/default/VibrationSession.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "vibrator-impl/VibrationSession.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+static constexpr int32_t SESSION_END_DELAY_MS = 50;
+
+ndk::ScopedAStatus VibrationSession::close() {
+    LOG(VERBOSE) << "Vibration Session close";
+    mManager->closeSession(SESSION_END_DELAY_MS);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibrationSession::abort() {
+    LOG(VERBOSE) << "Vibration Session abort";
+    mManager->abortSession();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 4f8c2b8..34be008 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -45,11 +45,62 @@
 // Service specific error code used for vendor vibration effects.
 static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1;
 
+void Vibrator::dispatchVibrate(int32_t timeoutMs,
+                               const std::shared_ptr<IVibratorCallback>& callback) {
+    std::lock_guard lock(mMutex);
+    if (mIsVibrating) {
+        // Already vibrating, ignore new request.
+        return;
+    }
+    mVibrationCallback = callback;
+    mIsVibrating = true;
+    // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
+    // which may be asynchronously destructed.
+    std::thread([timeoutMs, callback, sharedThis = this->ref<Vibrator>()] {
+        LOG(VERBOSE) << "Starting delayed callback on another thread";
+        usleep(timeoutMs * 1000);
+
+        if (sharedThis) {
+            std::lock_guard lock(sharedThis->mMutex);
+            sharedThis->mIsVibrating = false;
+            if (sharedThis->mVibrationCallback && (callback == sharedThis->mVibrationCallback)) {
+                LOG(VERBOSE) << "Notifying callback onComplete";
+                if (!sharedThis->mVibrationCallback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+                sharedThis->mVibrationCallback = nullptr;
+            }
+            if (sharedThis->mGlobalVibrationCallback) {
+                LOG(VERBOSE) << "Notifying global callback onComplete";
+                if (!sharedThis->mGlobalVibrationCallback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+                sharedThis->mGlobalVibrationCallback = nullptr;
+            }
+        }
+    }).detach();
+}
+
+void Vibrator::setGlobalVibrationCallback(const std::shared_ptr<IVibratorCallback>& callback) {
+    std::lock_guard lock(mMutex);
+    if (mIsVibrating) {
+        mGlobalVibrationCallback = callback;
+    } else if (callback) {
+        std::thread([callback] {
+            LOG(VERBOSE) << "Notifying global callback onComplete";
+            if (!callback->onComplete().isOk()) {
+                LOG(ERROR) << "Failed to call onComplete";
+            }
+        }).detach();
+    }
+}
+
 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
     LOG(VERBOSE) << "Vibrator reporting capabilities";
     std::lock_guard lock(mMutex);
     if (mCapabilities == 0) {
-        if (!getInterfaceVersion(&mVersion).isOk()) {
+        int32_t version;
+        if (!getInterfaceVersion(&version).isOk()) {
             return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
         }
         mCapabilities = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
@@ -59,9 +110,9 @@
                         IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
                         IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
 
-        if (mVersion >= 3) {
-            mCapabilities |= (IVibrator::CAP_PERFORM_VENDOR_EFFECTS |
-                              IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2);
+        if (version >= 3) {
+            mCapabilities |=
+                    IVibrator::CAP_PERFORM_VENDOR_EFFECTS | IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2;
         }
     }
 
@@ -71,25 +122,35 @@
 
 ndk::ScopedAStatus Vibrator::off() {
     LOG(VERBOSE) << "Vibrator off";
+    std::lock_guard lock(mMutex);
+    std::shared_ptr<IVibratorCallback> callback = mVibrationCallback;
+    std::shared_ptr<IVibratorCallback> globalCallback = mGlobalVibrationCallback;
+    mIsVibrating = false;
+    mVibrationCallback = nullptr;
+    mGlobalVibrationCallback = nullptr;
+    if (callback || globalCallback) {
+        std::thread([callback, globalCallback] {
+            if (callback) {
+                LOG(VERBOSE) << "Notifying callback onComplete";
+                if (!callback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+            }
+            if (globalCallback) {
+                LOG(VERBOSE) << "Notifying global callback onComplete";
+                if (!globalCallback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+            }
+        }).detach();
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
                                 const std::shared_ptr<IVibratorCallback>& callback) {
     LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
-    if (callback != nullptr) {
-        // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
-        // which may be asynchronously destructed.
-        // If "this" is needed, use [sharedThis = this->ref<Vibrator>()].
-        std::thread([timeoutMs, callback] {
-            LOG(VERBOSE) << "Starting on on another thread";
-            usleep(timeoutMs * 1000);
-            LOG(VERBOSE) << "Notifying on complete";
-            if (!callback->onComplete().isOk()) {
-                LOG(ERROR) << "Failed to call onComplete";
-            }
-        }).detach();
-    }
+    dispatchVibrate(timeoutMs, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -107,16 +168,7 @@
     }
 
     constexpr size_t kEffectMillis = 100;
-
-    if (callback != nullptr) {
-        std::thread([callback] {
-            LOG(VERBOSE) << "Starting perform on another thread";
-            usleep(kEffectMillis * 1000);
-            LOG(VERBOSE) << "Notifying perform complete";
-            callback->onComplete();
-        }).detach();
-    }
-
+    dispatchVibrate(kEffectMillis, callback);
     *_aidl_return = kEffectMillis;
     return ndk::ScopedAStatus::ok();
 }
@@ -150,15 +202,7 @@
         return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION);
     }
 
-    if (callback != nullptr) {
-        std::thread([callback, durationMs] {
-            LOG(VERBOSE) << "Starting perform on another thread for durationMs:" << durationMs;
-            usleep(durationMs * 1000);
-            LOG(VERBOSE) << "Notifying perform vendor effect complete";
-            callback->onComplete();
-        }).detach();
-    }
-
+    dispatchVibrate(durationMs, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -237,28 +281,14 @@
         }
     }
 
-    // The thread may theoretically outlive the vibrator, so take a proper reference to it.
-    std::thread([sharedThis = this->ref<Vibrator>(), composite, callback] {
-        LOG(VERBOSE) << "Starting compose on another thread";
+    int32_t totalDuration = 0;
+    for (auto& e : composite) {
+        int32_t durationMs;
+        getPrimitiveDuration(e.primitive, &durationMs);
+        totalDuration += e.delayMs + durationMs;
+    }
 
-        for (auto& e : composite) {
-            if (e.delayMs) {
-                usleep(e.delayMs * 1000);
-            }
-            LOG(VERBOSE) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
-                         << e.scale;
-
-            int32_t durationMs;
-            sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
-            usleep(durationMs * 1000);
-        }
-
-        if (callback != nullptr) {
-            LOG(VERBOSE) << "Notifying perform complete";
-            callback->onComplete();
-        }
-    }).detach();
-
+    dispatchVibrate(totalDuration, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -460,15 +490,7 @@
         }
     }
 
-    std::thread([totalDuration, callback] {
-        LOG(VERBOSE) << "Starting composePwle on another thread";
-        usleep(totalDuration * 1000);
-        if (callback != nullptr) {
-            LOG(VERBOSE) << "Notifying compose PWLE complete";
-            callback->onComplete();
-        }
-    }).detach();
-
+    dispatchVibrate(totalDuration, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -543,6 +565,7 @@
 
 ndk::ScopedAStatus Vibrator::composePwleV2(const std::vector<PwleV2Primitive>& composite,
                                            const std::shared_ptr<IVibratorCallback>& callback) {
+    LOG(VERBOSE) << "Vibrator compose PWLE V2";
     int32_t capabilities = 0;
     if (!getCapabilities(&capabilities).isOk()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
@@ -576,15 +599,7 @@
         totalEffectDuration += e.timeMillis;
     }
 
-    std::thread([totalEffectDuration, callback] {
-        LOG(VERBOSE) << "Starting composePwleV2 on another thread";
-        usleep(totalEffectDuration * 1000);
-        if (callback != nullptr) {
-            LOG(VERBOSE) << "Notifying compose PWLE V2 complete";
-            callback->onComplete();
-        }
-    }).detach();
-
+    dispatchVibrate(totalEffectDuration, callback);
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/vibrator/aidl/default/VibratorManager.cpp b/vibrator/aidl/default/VibratorManager.cpp
index 26edf5a..c3be468 100644
--- a/vibrator/aidl/default/VibratorManager.cpp
+++ b/vibrator/aidl/default/VibratorManager.cpp
@@ -15,6 +15,9 @@
  */
 
 #include "vibrator-impl/VibratorManager.h"
+#include "vibrator-impl/VibrationSession.h"
+
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
 
 #include <android-base/logging.h>
 #include <thread>
@@ -26,25 +29,52 @@
 
 static constexpr int32_t kDefaultVibratorId = 1;
 
+class VibratorCallback : public BnVibratorCallback {
+  public:
+    VibratorCallback(const std::function<void()>& callback) : mCallback(callback) {}
+    ndk::ScopedAStatus onComplete() override {
+        mCallback();
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    std::function<void()> mCallback;
+};
+
 ndk::ScopedAStatus VibratorManager::getCapabilities(int32_t* _aidl_return) {
-    LOG(INFO) << "Vibrator manager reporting capabilities";
-    *_aidl_return =
-            IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON |
-            IVibratorManager::CAP_PREPARE_PERFORM | IVibratorManager::CAP_PREPARE_COMPOSE |
-            IVibratorManager::CAP_MIXED_TRIGGER_ON | IVibratorManager::CAP_MIXED_TRIGGER_PERFORM |
-            IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE | IVibratorManager::CAP_TRIGGER_CALLBACK;
+    LOG(VERBOSE) << "Vibrator manager reporting capabilities";
+    std::lock_guard lock(mMutex);
+    if (mCapabilities == 0) {
+        int32_t version;
+        if (!getInterfaceVersion(&version).isOk()) {
+            return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+        }
+        mCapabilities = IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON |
+                        IVibratorManager::CAP_PREPARE_PERFORM |
+                        IVibratorManager::CAP_PREPARE_COMPOSE |
+                        IVibratorManager::CAP_MIXED_TRIGGER_ON |
+                        IVibratorManager::CAP_MIXED_TRIGGER_PERFORM |
+                        IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE |
+                        IVibratorManager::CAP_TRIGGER_CALLBACK;
+
+        if (version >= 3) {
+            mCapabilities |= IVibratorManager::CAP_START_SESSIONS;
+        }
+    }
+
+    *_aidl_return = mCapabilities;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::getVibratorIds(std::vector<int32_t>* _aidl_return) {
-    LOG(INFO) << "Vibrator manager getting vibrator ids";
+    LOG(VERBOSE) << "Vibrator manager getting vibrator ids";
     *_aidl_return = {kDefaultVibratorId};
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::getVibrator(int32_t vibratorId,
                                                 std::shared_ptr<IVibrator>* _aidl_return) {
-    LOG(INFO) << "Vibrator manager getting vibrator " << vibratorId;
+    LOG(VERBOSE) << "Vibrator manager getting vibrator " << vibratorId;
     if (vibratorId == kDefaultVibratorId) {
         *_aidl_return = mDefaultVibrator;
         return ndk::ScopedAStatus::ok();
@@ -55,32 +85,131 @@
 }
 
 ndk::ScopedAStatus VibratorManager::prepareSynced(const std::vector<int32_t>& vibratorIds) {
-    LOG(INFO) << "Vibrator Manager prepare synced";
-    if (vibratorIds.size() == 1 && vibratorIds[0] == kDefaultVibratorId) {
-        return ndk::ScopedAStatus::ok();
-    } else {
+    LOG(VERBOSE) << "Vibrator Manager prepare synced";
+    if (vibratorIds.size() != 1 || vibratorIds[0] != kDefaultVibratorId) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    std::lock_guard lock(mMutex);
+    if (mIsPreparing) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mIsPreparing = true;
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::triggerSynced(
         const std::shared_ptr<IVibratorCallback>& callback) {
-    LOG(INFO) << "Vibrator Manager trigger synced";
+    LOG(VERBOSE) << "Vibrator Manager trigger synced";
+    std::lock_guard lock(mMutex);
+    if (!mIsPreparing) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     std::thread([callback] {
         if (callback != nullptr) {
-            LOG(INFO) << "Notifying perform complete";
+            LOG(VERBOSE) << "Notifying perform complete";
             callback->onComplete();
         }
     }).detach();
-
+    mIsPreparing = false;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::cancelSynced() {
-    LOG(INFO) << "Vibrator Manager cancel synced";
+    LOG(VERBOSE) << "Vibrator Manager cancel synced";
+    std::lock_guard lock(mMutex);
+    mIsPreparing = false;
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus VibratorManager::startSession(const std::vector<int32_t>& vibratorIds,
+                                                 const VibrationSessionConfig&,
+                                                 const std::shared_ptr<IVibratorCallback>& callback,
+                                                 std::shared_ptr<IVibrationSession>* _aidl_return) {
+    LOG(VERBOSE) << "Vibrator Manager start session";
+    *_aidl_return = nullptr;
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if ((capabilities & IVibratorManager::CAP_START_SESSIONS) == 0) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+    if (vibratorIds.size() != 1 || vibratorIds[0] != kDefaultVibratorId) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    std::lock_guard lock(mMutex);
+    if (mIsPreparing || mSession) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mSessionCallback = callback;
+    mSession = ndk::SharedRefBase::make<VibrationSession>(this->ref<VibratorManager>());
+    *_aidl_return = static_cast<std::shared_ptr<IVibrationSession>>(mSession);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibratorManager::clearSessions() {
+    LOG(VERBOSE) << "Vibrator Manager clear sessions";
+    abortSession();
+    return ndk::ScopedAStatus::ok();
+}
+
+void VibratorManager::abortSession() {
+    std::shared_ptr<IVibrationSession> session;
+    {
+        std::lock_guard lock(mMutex);
+        session = mSession;
+    }
+    if (session) {
+        mDefaultVibrator->off();
+        clearSession(session);
+    }
+}
+
+void VibratorManager::closeSession(int32_t delayMs) {
+    std::shared_ptr<IVibrationSession> session;
+    {
+        std::lock_guard lock(mMutex);
+        if (mIsClosingSession) {
+            // Already closing session, ignore this.
+            return;
+        }
+        session = mSession;
+        mIsClosingSession = true;
+    }
+    if (session) {
+        auto callback = ndk::SharedRefBase::make<VibratorCallback>(
+                [session, delayMs, sharedThis = this->ref<VibratorManager>()] {
+                    LOG(VERBOSE) << "Closing session after vibrator became idle";
+                    usleep(delayMs * 1000);
+
+                    if (sharedThis) {
+                        sharedThis->clearSession(session);
+                    }
+                });
+        mDefaultVibrator->setGlobalVibrationCallback(callback);
+    }
+}
+
+void VibratorManager::clearSession(const std::shared_ptr<IVibrationSession>& session) {
+    std::lock_guard lock(mMutex);
+    if (mSession != session) {
+        // Probably a delayed call from an old session that was already cleared, ignore it.
+        return;
+    }
+    std::shared_ptr<IVibratorCallback> callback = mSessionCallback;
+    mSession = nullptr;
+    mSessionCallback = nullptr;  // make sure any delayed call will not trigger this again.
+    mIsClosingSession = false;
+    if (callback) {
+        std::thread([callback] {
+            LOG(VERBOSE) << "Notifying session complete";
+            if (!callback->onComplete().isOk()) {
+                LOG(ERROR) << "Failed to call onComplete";
+            }
+        }).detach();
+    }
+}
+
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/VibrationSession.h b/vibrator/aidl/default/include/vibrator-impl/VibrationSession.h
new file mode 100644
index 0000000..98bdd1c
--- /dev/null
+++ b/vibrator/aidl/default/include/vibrator-impl/VibrationSession.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/vibrator/BnVibrationSession.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorCallback.h>
+#include <android-base/thread_annotations.h>
+
+#include "vibrator-impl/VibratorManager.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+class VibrationSession : public BnVibrationSession {
+  public:
+    VibrationSession(std::shared_ptr<VibratorManager> manager) : mManager(std::move(manager)) {};
+
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus abort() override;
+
+  private:
+    mutable std::mutex mMutex;
+    std::shared_ptr<VibratorManager> mManager;
+};
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 28bc763..4637c5a 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -25,6 +25,7 @@
 namespace vibrator {
 
 class Vibrator : public BnVibrator {
+  public:
     ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
     ndk::ScopedAStatus off() override;
     ndk::ScopedAStatus on(int32_t timeoutMs,
@@ -66,10 +67,16 @@
     ndk::ScopedAStatus composePwleV2(const std::vector<PwleV2Primitive>& composite,
                                      const std::shared_ptr<IVibratorCallback>& callback) override;
 
+    void setGlobalVibrationCallback(const std::shared_ptr<IVibratorCallback>& callback);
+
   private:
     mutable std::mutex mMutex;
-    int32_t mVersion GUARDED_BY(mMutex) = 0;  // current Hal version
+    bool mIsVibrating GUARDED_BY(mMutex) = false;
     int32_t mCapabilities GUARDED_BY(mMutex) = 0;
+    std::shared_ptr<IVibratorCallback> mVibrationCallback GUARDED_BY(mMutex) = nullptr;
+    std::shared_ptr<IVibratorCallback> mGlobalVibrationCallback GUARDED_BY(mMutex) = nullptr;
+
+    void dispatchVibrate(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>& callback);
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h b/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
index 319eb05..fe30394 100644
--- a/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
+++ b/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
@@ -17,6 +17,9 @@
 #pragma once
 
 #include <aidl/android/hardware/vibrator/BnVibratorManager.h>
+#include <android-base/thread_annotations.h>
+
+#include "vibrator-impl/Vibrator.h"
 
 namespace aidl {
 namespace android {
@@ -25,7 +28,8 @@
 
 class VibratorManager : public BnVibratorManager {
   public:
-    VibratorManager(std::shared_ptr<IVibrator> vibrator) : mDefaultVibrator(std::move(vibrator)){};
+    VibratorManager(std::shared_ptr<Vibrator> vibrator) : mDefaultVibrator(std::move(vibrator)) {};
+
     ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
     ndk::ScopedAStatus getVibratorIds(std::vector<int32_t>* _aidl_return) override;
     ndk::ScopedAStatus getVibrator(int32_t vibratorId,
@@ -33,9 +37,25 @@
     ndk::ScopedAStatus prepareSynced(const std::vector<int32_t>& vibratorIds) override;
     ndk::ScopedAStatus triggerSynced(const std::shared_ptr<IVibratorCallback>& callback) override;
     ndk::ScopedAStatus cancelSynced() override;
+    ndk::ScopedAStatus startSession(const std::vector<int32_t>& vibratorIds,
+                                    const VibrationSessionConfig& config,
+                                    const std::shared_ptr<IVibratorCallback>& callback,
+                                    std::shared_ptr<IVibrationSession>* _aidl_return) override;
+    ndk::ScopedAStatus clearSessions() override;
+
+    void abortSession();
+    void closeSession(int32_t delayMs);
 
   private:
-    std::shared_ptr<IVibrator> mDefaultVibrator;
+    std::shared_ptr<Vibrator> mDefaultVibrator;
+    mutable std::mutex mMutex;
+    int32_t mCapabilities GUARDED_BY(mMutex) = 0;
+    bool mIsPreparing GUARDED_BY(mMutex) = false;
+    bool mIsClosingSession GUARDED_BY(mMutex) = false;
+    std::shared_ptr<IVibrationSession> mSession GUARDED_BY(mMutex) = nullptr;
+    std::shared_ptr<IVibratorCallback> mSessionCallback GUARDED_BY(mMutex) = nullptr;
+
+    void clearSession(const std::shared_ptr<IVibrationSession>& session);
 };
 
 }  // namespace vibrator