Merge "Update to use nativehelper/JNIPlatformHelp.h"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9d3f4f9..a686dfb 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                cmds/idlcli/
                include/input/
+               include/powermanager/
                libs/binder/fuzzer/
                libs/binder/ndk/
                libs/binderthreadstate/
@@ -18,6 +19,7 @@
                opengl/libs/
                services/bufferhub/
                services/inputflinger/
+               services/powermanager/
                services/surfaceflinger/
                services/vibratorservice/
                services/vr/
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e6bfa14..581d3de 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2296,8 +2296,7 @@
 
     std::string final_path = ds.path_;
     if (ds.options_->OutputToCustomFile()) {
-        std::string bugreport_dir = dirname(ds.options_->use_outfile.c_str());
-        final_path = ds.GetPath(bugreport_dir, ".zip");
+        final_path = ds.GetPath(ds.options_->out_dir, ".zip");
         android::os::CopyFileToFile(ds.path_, final_path);
     }
 
@@ -2418,7 +2417,7 @@
             // clang-format off
             case 'd': do_add_date = true;            break;
             case 'z': do_zip_file = true;            break;
-            case 'o': use_outfile = optarg;          break;
+            case 'o': out_dir = optarg;              break;
             case 's': use_socket = true;             break;
             case 'S': use_control_socket = true;     break;
             case 'v': show_header_only = true;       break;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index a133f7e..0d25d30 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -386,12 +386,12 @@
         // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
         ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
             ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
-        // File descriptor to output zip file. Takes precedence over use_outfile..
+        // File descriptor to output zip file. Takes precedence over out_dir.
         android::base::unique_fd bugreport_fd;
         // File descriptor to screenshot file.
         android::base::unique_fd screenshot_fd;
-        // Partial path to output file.
-        std::string use_outfile;
+        // Custom output directory.
+        std::string out_dir;
         // Bugreport mode of the bugreport.
         std::string bugreport_mode;
         // Command-line arguments as string
@@ -421,7 +421,7 @@
         /* Returns if options specified require writing to custom file location */
         bool OutputToCustomFile() {
             // Custom location is only honored in limited mode.
-            return limited_only && !use_outfile.empty() && bugreport_fd.get() == -1;
+            return limited_only && !out_dir.empty() && bugreport_fd.get() == -1;
         }
     };
 
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index e167145..c7df1bb 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -172,7 +172,7 @@
 
     EXPECT_FALSE(options_.do_add_date);
     EXPECT_FALSE(options_.do_zip_file);
-    EXPECT_EQ("", options_.use_outfile);
+    EXPECT_EQ("", options_.out_dir);
     EXPECT_FALSE(options_.use_socket);
     EXPECT_FALSE(options_.use_control_socket);
     EXPECT_FALSE(options_.show_header_only);
@@ -366,7 +366,7 @@
     EXPECT_TRUE(options_.use_control_socket);
     EXPECT_FALSE(options_.do_vibrate);
     EXPECT_TRUE(options_.limited_only);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+    EXPECT_EQ(" abc", std::string(options_.out_dir));
 
     // Other options retain default values
     EXPECT_FALSE(options_.show_header_only);
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 59b1deb..c6d1c94 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -126,8 +126,8 @@
     ANDROID_RESOLV_NO_RETRY = 1 << 0,
 
     /**
-     * Do not cache the result of the lookup. The lookup may return a result that is already
-     * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+     * Don't lookup this request in the cache, and don't cache the result of the lookup.
+     * This flag implies {@link #ANDROID_RESOLV_NO_CACHE_LOOKUP}.
      */
     ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
 
diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h
index 44b8915..dd34c0a 100644
--- a/include/powermanager/PowerHalController.h
+++ b/include/powermanager/PowerHalController.h
@@ -21,58 +21,59 @@
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
-
 #include <powermanager/PowerHalWrapper.h>
 
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
-using android::hardware::power::V1_0::Feature;
-using android::hardware::power::V1_0::PowerHint;
-
 namespace android {
 
+namespace power {
+
 // -------------------------------------------------------------------------------------------------
 
 // Connects to underlying Power HAL handles.
-class PowerHalConnector {
+class HalConnector {
 public:
-    PowerHalConnector() = default;
-    virtual ~PowerHalConnector() = default;
+    HalConnector() = default;
+    virtual ~HalConnector() = default;
 
-    virtual std::unique_ptr<PowerHalWrapper> connect();
+    virtual std::unique_ptr<HalWrapper> connect();
     virtual void reset();
 };
 
 // -------------------------------------------------------------------------------------------------
 
 // Controller for Power HAL handle.
-// This relies on PowerHalConnector to connect to the underlying Power HAL service and reconnects to
-// it after each failed api call. This also ensures connecting to the service is thread-safe.
-class PowerHalController : public PowerHalWrapper {
+// This relies on HalConnector to connect to the underlying Power HAL
+// service and reconnects to it after each failed api call. This also ensures
+// connecting to the service is thread-safe.
+class PowerHalController : public HalWrapper {
 public:
-    PowerHalController() : PowerHalController(std::make_unique<PowerHalConnector>()) {}
-    explicit PowerHalController(std::unique_ptr<PowerHalConnector> connector)
-        : mHalConnector(std::move(connector)) {}
+    PowerHalController() : PowerHalController(std::make_unique<HalConnector>()) {}
+    explicit PowerHalController(std::unique_ptr<HalConnector> connector)
+          : mHalConnector(std::move(connector)) {}
+    virtual ~PowerHalController() = default;
 
     void init();
 
-    PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
-    PowerHalResult setMode(Mode mode, bool enabled) override;
+    virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+    virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
 
 private:
     std::mutex mConnectedHalMutex;
-    std::unique_ptr<PowerHalConnector> mHalConnector;
+    std::unique_ptr<HalConnector> mHalConnector;
 
-    // Shared pointers to keep global pointer and allow local copies to be used in different threads
-    std::shared_ptr<PowerHalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex) = nullptr;
-    const std::shared_ptr<PowerHalWrapper> mDefaultHal = std::make_shared<EmptyPowerHalWrapper>();
+    // Shared pointers to keep global pointer and allow local copies to be used in
+    // different threads
+    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex) = nullptr;
+    const std::shared_ptr<HalWrapper> mDefaultHal = std::make_shared<EmptyHalWrapper>();
 
-    std::shared_ptr<PowerHalWrapper> initHal();
-    PowerHalResult processHalResult(PowerHalResult result, const char* functionName);
+    std::shared_ptr<HalWrapper> initHal();
+    HalResult processHalResult(HalResult result, const char* functionName);
 };
 
 // -------------------------------------------------------------------------------------------------
 
+}; // namespace power
+
 }; // namespace android
 
 #endif // ANDROID_POWERHALCONTROLLER_H
diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h
index 487b95b..ed6f6f3 100644
--- a/include/powermanager/PowerHalLoader.h
+++ b/include/powermanager/PowerHalLoader.h
@@ -18,35 +18,36 @@
 #define ANDROID_POWERHALLOADER_H
 
 #include <android-base/thread_annotations.h>
-
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/IPower.h>
 
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
-using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerAidl = android::hardware::power::IPower;
-
 namespace android {
 
+namespace power {
+
 // Loads available Power HAL services.
 class PowerHalLoader {
 public:
     static void unloadAll();
-    static sp<IPowerAidl> loadAidl();
-    static sp<IPowerV1_0> loadHidlV1_0();
-    static sp<IPowerV1_1> loadHidlV1_1();
+    static sp<hardware::power::IPower> loadAidl();
+    static sp<hardware::power::V1_0::IPower> loadHidlV1_0();
+    static sp<hardware::power::V1_1::IPower> loadHidlV1_1();
 
 private:
     static std::mutex gHalMutex;
-    static sp<IPowerAidl> gHalAidl GUARDED_BY(gHalMutex);
-    static sp<IPowerV1_0> gHalHidlV1_0 GUARDED_BY(gHalMutex);
-    static sp<IPowerV1_1> gHalHidlV1_1 GUARDED_BY(gHalMutex);
+    static sp<hardware::power::IPower> gHalAidl GUARDED_BY(gHalMutex);
+    static sp<hardware::power::V1_0::IPower> gHalHidlV1_0 GUARDED_BY(gHalMutex);
+    static sp<hardware::power::V1_1::IPower> gHalHidlV1_1 GUARDED_BY(gHalMutex);
 
-    static sp<IPowerV1_0> loadHidlV1_0Locked() EXCLUSIVE_LOCKS_REQUIRED(gHalMutex);
+    static sp<hardware::power::V1_0::IPower> loadHidlV1_0Locked()
+            EXCLUSIVE_LOCKS_REQUIRED(gHalMutex);
 
-    PowerHalLoader() = default;
+    PowerHalLoader() = delete;
+    ~PowerHalLoader() = delete;
 };
 
+}; // namespace power
+
 } // namespace android
 
 #endif // ANDROID_POWERHALLOADER_H
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 6d8a6eb..c3e7601 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -18,111 +18,111 @@
 #define ANDROID_POWERHALWRAPPER_H
 
 #include <android-base/thread_annotations.h>
-
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
 
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
-using android::hardware::power::V1_0::Feature;
-using android::hardware::power::V1_0::PowerHint;
-using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
-using IPowerAidl = android::hardware::power::IPower;
-
 namespace android {
 
+namespace power {
+
 // State of Power HAL support for individual apis.
-enum class PowerHalSupport {
+enum class HalSupport {
     UNKNOWN = 0,
     ON = 1,
     OFF = 2,
 };
 
 // State of the Power HAL api call result.
-enum class PowerHalResult {
+enum class HalResult {
     SUCCESSFUL = 0,
     FAILED = 1,
     UNSUPPORTED = 2,
 };
 
 // Wrapper for Power HAL handlers.
-class PowerHalWrapper {
+class HalWrapper {
 public:
-    virtual ~PowerHalWrapper() = default;
+    virtual ~HalWrapper() = default;
 
-    virtual PowerHalResult setBoost(Boost boost, int32_t durationMs) = 0;
-    virtual PowerHalResult setMode(Mode mode, bool enabled) = 0;
+    virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) = 0;
+    virtual HalResult setMode(hardware::power::Mode mode, bool enabled) = 0;
 };
 
 // Empty Power HAL wrapper that ignores all api calls.
-class EmptyPowerHalWrapper : public PowerHalWrapper {
+class EmptyHalWrapper : public HalWrapper {
 public:
-    EmptyPowerHalWrapper() = default;
-    ~EmptyPowerHalWrapper() = default;
+    EmptyHalWrapper() = default;
+    ~EmptyHalWrapper() = default;
 
-    PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
-    PowerHalResult setMode(Mode mode, bool enabled) override;
+    virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+    virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
 };
 
 // Wrapper for the HIDL Power HAL v1.0.
-class HidlPowerHalWrapperV1_0 : public PowerHalWrapper {
+class HidlHalWrapperV1_0 : public HalWrapper {
 public:
-    explicit HidlPowerHalWrapperV1_0(sp<IPowerV1_0> powerHal) : handleV1_0(std::move(powerHal)) {}
-    virtual ~HidlPowerHalWrapperV1_0() = default;
+    explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> Hal)
+          : mHandleV1_0(std::move(Hal)) {}
+    virtual ~HidlHalWrapperV1_0() = default;
 
-    PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
-    PowerHalResult setMode(Mode mode, bool enabled) override;
+    virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+    virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
 
 protected:
-    virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data);
+    virtual HalResult sendPowerHint(hardware::power::V1_0::PowerHint hintId, uint32_t data);
 
 private:
-    sp<IPowerV1_0> handleV1_0;
-    PowerHalResult setInteractive(bool enabled);
-    PowerHalResult setFeature(Feature feature, bool enabled);
+    sp<hardware::power::V1_0::IPower> mHandleV1_0;
+    HalResult setInteractive(bool enabled);
+    HalResult setFeature(hardware::power::V1_0::Feature feature, bool enabled);
 };
 
 // Wrapper for the HIDL Power HAL v1.1.
-class HidlPowerHalWrapperV1_1 : public HidlPowerHalWrapperV1_0 {
+class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
 public:
-    HidlPowerHalWrapperV1_1(sp<IPowerV1_0> powerHalV1_0, sp<IPowerV1_1> powerHalV1_1)
-        : HidlPowerHalWrapperV1_0(powerHalV1_0), handleV1_1(std::move(powerHalV1_1)) {}
-    ~HidlPowerHalWrapperV1_1() = default;
+    HidlHalWrapperV1_1(sp<hardware::power::V1_0::IPower> handleV1_0,
+                       sp<hardware::power::V1_1::IPower> handleV1_1)
+          : HidlHalWrapperV1_0(std::move(handleV1_0)), mHandleV1_1(std::move(handleV1_1)) {}
+    virtual ~HidlHalWrapperV1_1() = default;
 
 protected:
-    virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data) override;
+    virtual HalResult sendPowerHint(hardware::power::V1_0::PowerHint hintId,
+                                    uint32_t data) override;
 
 private:
-    sp<IPowerV1_1> handleV1_1;
+    sp<hardware::power::V1_1::IPower> mHandleV1_1;
 };
 
 // Wrapper for the AIDL Power HAL.
-class AidlPowerHalWrapper : public PowerHalWrapper {
+class AidlHalWrapper : public HalWrapper {
 public:
-    explicit AidlPowerHalWrapper(sp<IPowerAidl> powerHal) : handle(std::move(powerHal)) {}
-    ~AidlPowerHalWrapper() = default;
+    explicit AidlHalWrapper(sp<hardware::power::IPower> handle) : mHandle(std::move(handle)) {}
+    virtual ~AidlHalWrapper() = default;
 
-    PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
-    PowerHalResult setMode(Mode mode, bool enabled) override;
+    virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+    virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
 
 private:
     // Control access to the boost and mode supported arrays.
     std::mutex mBoostMutex;
     std::mutex mModeMutex;
-    sp<IPowerAidl> handle;
+    sp<hardware::power::IPower> mHandle;
     // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT.
     // Need to increase the array size if more boost supported.
-    std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT)+1>
-        boostSupportedArray GUARDED_BY(mBoostMutex) = {PowerHalSupport::UNKNOWN};
+    std::array<std::atomic<HalSupport>,
+               static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1>
+            mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN};
     // Android framework only sends mode upto DISPLAY_INACTIVE.
     // Need to increase the array if more mode supported.
-    std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE)+1>
-        modeSupportedArray GUARDED_BY(mModeMutex) = {PowerHalSupport::UNKNOWN};
+    std::array<std::atomic<HalSupport>,
+               static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1>
+            mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN};
 };
 
+}; // namespace power
+
 }; // namespace android
 
 #endif // ANDROID_POWERHALWRAPPER_H
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 0b77ab3..50f6289 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -88,16 +88,6 @@
     return policyN1 - policyN2;
 }
 
-static int bpf_obj_get_wronly(const char *pathname) {
-    union bpf_attr attr;
-
-    memset(&attr, 0, sizeof(attr));
-    attr.pathname = ptr_to_u64((void *)pathname);
-    attr.file_flags = BPF_F_WRONLY;
-
-    return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
-}
-
 static bool initGlobals() {
     std::lock_guard<std::mutex> guard(gInitializedMutex);
     if (gInitialized) return true;
@@ -156,7 +146,7 @@
 static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
     std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
                                     eventType.c_str(), eventName.c_str());
-    int prog_fd = bpfFdGet(path.c_str(), BPF_F_RDONLY);
+    int prog_fd = retrieveProgram(path.c_str());
     if (prog_fd < 0) return false;
     return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
 }
@@ -183,7 +173,7 @@
     if (!initGlobals()) return false;
     if (gTracking) return true;
 
-    unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
     if (cpuPolicyFd < 0) return false;
 
     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
@@ -192,7 +182,7 @@
         }
     }
 
-    unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
     if (freqToIdxFd < 0) return false;
     freq_idx_key_t key;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
@@ -207,23 +197,23 @@
         }
     }
 
-    unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
     if (cpuLastUpdateFd < 0) return false;
     std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
     uint32_t zero = 0;
     if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
 
-    unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_nr_active_map"));
     if (nrActiveFd < 0) return false;
     if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
 
-    unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
     if (policyNrActiveFd < 0) return false;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
     }
 
-    unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
     if (policyFreqIdxFd < 0) return false;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         auto freqIdx = getPolicyFreqIdx(i);
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index cfc7e98..119b3e0 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -39,6 +39,13 @@
 #include <string>
 #include <thread>
 
+// TODO(b/159240322): Extend this to x86 ABI.
+#if defined(__LP64__)
+#define UPDATABLE_DRIVER_ABI "arm64-v8a"
+#else
+#define UPDATABLE_DRIVER_ABI "armeabi-v7a"
+#endif // defined(__LP64__)
+
 // TODO(ianelliott@): Get the following from an ANGLE header:
 #define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
 // Version-2 API:
@@ -582,7 +589,28 @@
     }
 
     if (mDriverPath.empty()) {
-        return nullptr;
+        // For an application process, driver path is empty means this application is not opted in
+        // to use updatable driver. Application process doesn't have the ability to set up
+        // environment variables and hence before `getenv` call will return.
+        // For a process that is not an application process, if it's run from an environment,
+        // for example shell, where environment variables can be set, then it can opt into using
+        // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
+        // driver will be used currently.
+        // TODO(b/159240322) Support the production updatable driver.
+        const char* id = getenv("UPDATABLE_GFX_DRIVER");
+        if (id == nullptr || std::strcmp(id, "1")) {
+            return nullptr;
+        }
+        const sp<IGpuService> gpuService = getGpuService();
+        if (!gpuService) {
+            return nullptr;
+        }
+        mDriverPath = gpuService->getUpdatableDriverPath();
+        if (mDriverPath.empty()) {
+            return nullptr;
+        }
+        mDriverPath.append(UPDATABLE_DRIVER_ABI);
+        ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
     }
 
     auto vndkNamespace = android_get_exported_namespace("vndk");
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index de3503b..fa25c55 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -27,11 +27,11 @@
 public:
     explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
 
-    virtual void setGpuStats(const std::string& driverPackageName,
-                             const std::string& driverVersionName, uint64_t driverVersionCode,
-                             int64_t driverBuildTime, const std::string& appPackageName,
-                             const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
-                             bool isDriverLoaded, int64_t driverLoadingTime) {
+    void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
+                     uint64_t driverVersionCode, int64_t driverBuildTime,
+                     const std::string& appPackageName, const int32_t vulkanVersion,
+                     GpuStatsInfo::Driver driver, bool isDriverLoaded,
+                     int64_t driverLoadingTime) override {
         Parcel data, reply;
         data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
 
@@ -48,8 +48,8 @@
         remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
-                                const GpuStatsInfo::Stats stats, const uint64_t value) {
+    void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
+                        const GpuStatsInfo::Stats stats, const uint64_t value) override {
         Parcel data, reply;
         data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
 
@@ -60,6 +60,27 @@
 
         remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    void setUpdatableDriverPath(const std::string& driverPath) override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+        data.writeUtf8AsUtf16(driverPath);
+
+        remote()->transact(BnGpuService::SET_UPDATABLE_DRIVER_PATH, data, &reply,
+                           IBinder::FLAG_ONEWAY);
+    }
+
+    std::string getUpdatableDriverPath() override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+
+        status_t error = remote()->transact(BnGpuService::GET_UPDATABLE_DRIVER_PATH, data, &reply);
+        std::string driverPath;
+        if (error == OK) {
+            error = reply.readUtf8FromUtf16(&driverPath);
+        }
+        return driverPath;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
@@ -126,6 +147,21 @@
 
             return OK;
         }
+        case SET_UPDATABLE_DRIVER_PATH: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::string driverPath;
+            if ((status = data.readUtf8FromUtf16(&driverPath)) != OK) return status;
+
+            setUpdatableDriverPath(driverPath);
+            return OK;
+        }
+        case GET_UPDATABLE_DRIVER_PATH: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::string driverPath = getUpdatableDriverPath();
+            return reply->writeUtf8AsUtf16(driverPath);
+        }
         case SHELL_COMMAND_TRANSACTION: {
             int in = data.readFileDescriptor();
             int out = data.readFileDescriptor();
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index c7c6d1e..2d59fa0 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -42,6 +42,10 @@
     // set target stats.
     virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
                                 const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0;
+
+    // setter and getter for updatable driver path.
+    virtual void setUpdatableDriverPath(const std::string& driverPath) = 0;
+    virtual std::string getUpdatableDriverPath() = 0;
 };
 
 class BnGpuService : public BnInterface<IGpuService> {
@@ -49,6 +53,8 @@
     enum IGpuServiceTag {
         SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
         SET_TARGET_STATS,
+        SET_UPDATABLE_DRIVER_PATH,
+        GET_UPDATABLE_DRIVER_PATH,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1efd98b..a86eafa 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -110,7 +110,7 @@
     mConnectedToCpu = false;
     mProducerControlledByApp = controlledByApp;
     mSwapIntervalZero = false;
-    mMaxBufferCount = 0;
+    mMaxBufferCount = NUM_BUFFER_SLOTS;
 }
 
 Surface::~Surface() {
@@ -1585,6 +1585,7 @@
         mStickyTransform = 0;
         mAutoPrerotation = false;
         mEnableFrameTimestamps = false;
+        mMaxBufferCount = NUM_BUFFER_SLOTS;
 
         if (api == NATIVE_WINDOW_API_CPU) {
             mConnectedToCpu = false;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 88232fa..16b46df 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -353,6 +353,8 @@
         mTransactionNestCount(other.mTransactionNestCount),
         mAnimation(other.mAnimation),
         mEarlyWakeup(other.mEarlyWakeup),
+        mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart),
+        mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd),
         mContainsBuffer(other.mContainsBuffer),
         mDesiredPresentTime(other.mDesiredPresentTime) {
     mDisplayStates = other.mDisplayStates;
@@ -375,6 +377,8 @@
     const uint32_t transactionNestCount = parcel->readUint32();
     const bool animation = parcel->readBool();
     const bool earlyWakeup = parcel->readBool();
+    const bool explicitEarlyWakeupStart = parcel->readBool();
+    const bool explicitEarlyWakeupEnd = parcel->readBool();
     const bool containsBuffer = parcel->readBool();
     const int64_t desiredPresentTime = parcel->readInt64();
 
@@ -443,6 +447,8 @@
     mTransactionNestCount = transactionNestCount;
     mAnimation = animation;
     mEarlyWakeup = earlyWakeup;
+    mExplicitEarlyWakeupStart = explicitEarlyWakeupStart;
+    mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd;
     mContainsBuffer = containsBuffer;
     mDesiredPresentTime = desiredPresentTime;
     mDisplayStates = displayStates;
@@ -470,6 +476,8 @@
     parcel->writeUint32(mTransactionNestCount);
     parcel->writeBool(mAnimation);
     parcel->writeBool(mEarlyWakeup);
+    parcel->writeBool(mExplicitEarlyWakeupStart);
+    parcel->writeBool(mExplicitEarlyWakeupEnd);
     parcel->writeBool(mContainsBuffer);
     parcel->writeInt64(mDesiredPresentTime);
     parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
@@ -545,6 +553,8 @@
 
     mContainsBuffer |= other.mContainsBuffer;
     mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
+    mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
+    mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
     other.clear();
     return *this;
 }
@@ -559,6 +569,8 @@
     mTransactionNestCount = 0;
     mAnimation = false;
     mEarlyWakeup = false;
+    mExplicitEarlyWakeupStart = false;
+    mExplicitEarlyWakeupEnd = false;
     mDesiredPresentTime = -1;
 }
 
@@ -682,9 +694,20 @@
         flags |= ISurfaceComposer::eEarlyWakeup;
     }
 
+    // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set
+    // it is equivalent for none
+    if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) {
+        flags |= ISurfaceComposer::eExplicitEarlyWakeupStart;
+    }
+    if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) {
+        flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
+    }
+
     mForceSynchronous = false;
     mAnimation = false;
     mEarlyWakeup = false;
+    mExplicitEarlyWakeupStart = false;
+    mExplicitEarlyWakeupEnd = false;
 
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
     sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
@@ -731,6 +754,14 @@
     mEarlyWakeup = true;
 }
 
+void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() {
+    mExplicitEarlyWakeupStart = true;
+}
+
+void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() {
+    mExplicitEarlyWakeupEnd = true;
+}
+
 layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
     if (mComposerStates.count(handle) == 0) {
         // we don't have it, add an initialized layer_state to our list
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a2fb849..645714a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -81,12 +81,20 @@
     // flags for setTransactionState()
     enum {
         eSynchronous = 0x01,
-        eAnimation   = 0x02,
+        eAnimation = 0x02,
 
-        // Indicates that this transaction will likely result in a lot of layers being composed, and
-        // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this
-        // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns)
-        eEarlyWakeup = 0x04
+        // DEPRECATED - use eExplicitEarlyWakeup[Start|End]
+        eEarlyWakeup = 0x04,
+
+        // Explicit indication that this transaction and others to follow will likely result in a
+        // lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid
+        // missing frame deadlines. In this case SurfaceFlinger will wake up at
+        // (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be
+        // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are
+        // expected to be used by WindowManager only and are guarded by
+        // android.permission.ACCESS_SURFACE_FLINGER
+        eExplicitEarlyWakeupStart = 0x08,
+        eExplicitEarlyWakeupEnd = 0x10,
     };
 
     enum VsyncSource {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 32c0bab..eb757ba 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -345,10 +345,12 @@
         std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
                 mListenerCallbacks;
 
-        uint32_t                    mForceSynchronous = 0;
-        uint32_t                    mTransactionNestCount = 0;
-        bool                        mAnimation = false;
-        bool                        mEarlyWakeup = false;
+        uint32_t mForceSynchronous = 0;
+        uint32_t mTransactionNestCount = 0;
+        bool mAnimation = false;
+        bool mEarlyWakeup = false;
+        bool mExplicitEarlyWakeupStart = false;
+        bool mExplicitEarlyWakeupEnd = false;
 
         // Indicates that the Transaction contains a buffer that should be cached
         bool mContainsBuffer = false;
@@ -547,6 +549,8 @@
         void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
         void setAnimationTransaction();
         void setEarlyWakeup();
+        void setExplicitEarlyWakeupStart();
+        void setExplicitEarlyWakeupEnd();
     };
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 5188a09..b1d3ecb 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -104,6 +104,15 @@
         return std::make_unique<InputSurface>(surfaceControl, width, height);
     }
 
+    static std::unique_ptr<InputSurface> makeCursorInputSurface(
+            const sp<SurfaceComposerClient> &scc, int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Cursor Surface"), 0 /* bufHeight */,
+                                   0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eCursorWindow);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
     InputEvent* consumeEvent() {
         waitForEventAvailable();
 
@@ -134,12 +143,14 @@
         EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
         EXPECT_EQ(x, mev->getX(0));
         EXPECT_EQ(y, mev->getY(0));
+        EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
 
         ev = consumeEvent();
         ASSERT_NE(ev, nullptr);
         ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
         mev = static_cast<MotionEvent*>(ev);
         EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+        EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
     }
 
     ~InputSurface() {
@@ -537,5 +548,18 @@
     injectTap(0, 0);
     surface->expectTap(1, 1);
 }
+
+TEST_F(InputSurfacesTest, input_ignores_cursor_layer) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> cursorSurface =
+            InputSurface::makeCursorInputSurface(mComposerClient, 10, 10);
+
+    surface->showAt(10, 10);
+    surface->assertFocusChange(true);
+    cursorSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+}
 }
 }
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 81f168c..6d92143 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -30,6 +30,7 @@
 #include <gui/SurfaceComposerClient.h>
 #include <inttypes.h>
 #include <private/gui/ComposerService.h>
+#include <ui/BufferQueueDefs.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
 
@@ -1974,4 +1975,29 @@
     ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
 }
 
+TEST_F(SurfaceTest, DefaultMaxBufferCountSetAndUpdated) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+
+    int count = -1;
+    ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count));
+    EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count);
+
+    consumer->setMaxBufferCount(10);
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU));
+    EXPECT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count));
+    EXPECT_EQ(10, count);
+
+    ASSERT_EQ(NO_ERROR, native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU));
+    ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count));
+    EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count);
+}
+
 } // namespace android
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index 20a03ea..3490775 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -16,4 +16,8 @@
         "libutils",
         "liblog",
     ],
+    fuzz_config: {
+        fuzz_on_haiku_host: false,
+        fuzz_on_haiku_device: false,
+    },
 }
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 85e2c15..1afc693 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -364,7 +364,7 @@
             f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
 
             /*
-             * GL_EXT_debug_label is special, we always report it as
+             * GL_EXT_debug_marker is special, we always report it as
              * supported, it's handled by GLES_trace. If GLES_trace is not
              * enabled, then these are no-ops.
              */
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index bf0d6a9..bad5637 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -65,6 +65,14 @@
     mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value);
 }
 
+void GpuService::setUpdatableDriverPath(const std::string& driverPath) {
+    developerDriverPath = driverPath;
+}
+
+std::string GpuService::getUpdatableDriverPath() {
+    return developerDriverPath;
+}
+
 status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
     ATRACE_CALL();
 
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index f4b8597..9a0460d 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -51,6 +51,8 @@
                      int64_t driverLoadingTime) override;
     void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
                         const GpuStatsInfo::Stats stats, const uint64_t value) override;
+    void setUpdatableDriverPath(const std::string& driverPath) override;
+    std::string getUpdatableDriverPath() override;
 
     /*
      * IBinder interface
@@ -75,6 +77,7 @@
      */
     std::unique_ptr<GpuMem> mGpuMem;
     std::unique_ptr<GpuStats> mGpuStats;
+    std::string developerDriverPath;
 };
 
 } // namespace android
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index aad79ae..6ba304c 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -57,11 +57,16 @@
     }
 
     void SetUp() override {
+        SKIP_IF_BPF_NOT_SUPPORTED;
+        ASSERT_EQ(0, bpf::setrlimitForTest());
+
         mGpuMem = std::make_unique<GpuMem>();
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
+        errno = 0;
         mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
                                                    BPF_F_NO_PREALLOC);
 
+        EXPECT_EQ(0, errno);
         EXPECT_LE(0, mTestMap.getMap().get());
         EXPECT_TRUE(mTestMap.isValid());
     }
@@ -79,6 +84,8 @@
 };
 
 TEST_F(GpuMemTest, validGpuMemTotalBpfPaths) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
     EXPECT_EQ(mTestableGpuMem.getGpuMemTraceGroup(), "gpu_mem");
     EXPECT_EQ(mTestableGpuMem.getGpuMemTotalTracepoint(), "gpu_mem_total");
     EXPECT_EQ(mTestableGpuMem.getGpuMemTotalProgPath(),
@@ -87,16 +94,20 @@
 }
 
 TEST_F(GpuMemTest, bpfInitializationFailed) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
     EXPECT_EQ(dumpsys(), "Failed to initialize GPU memory eBPF\n");
 }
 
 TEST_F(GpuMemTest, gpuMemTotalMapEmpty) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
     mTestableGpuMem.setGpuMemTotalMap(mTestMap);
 
     EXPECT_EQ(dumpsys(), "GPU memory total usage map is empty\n");
 }
 
 TEST_F(GpuMemTest, globalMemTotal) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
     mTestableGpuMem.setGpuMemTotalMap(mTestMap);
 
@@ -104,6 +115,7 @@
 }
 
 TEST_F(GpuMemTest, missingGlobalMemTotal) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
     mTestableGpuMem.setGpuMemTotalMap(mTestMap);
 
@@ -111,6 +123,7 @@
 }
 
 TEST_F(GpuMemTest, procMemTotal) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
     mTestableGpuMem.setGpuMemTotalMap(mTestMap);
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index d29d8df..390c6b8 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -68,5 +68,4 @@
     export_header_lib_headers: [
         "libinputdispatcher_headers",
     ],
-    logtags: ["EventLogTags.logtags"],
 }
diff --git a/services/inputflinger/dispatcher/EventLogTags.logtags b/services/inputflinger/dispatcher/EventLogTags.logtags
deleted file mode 100644
index 9c0f80e..0000000
--- a/services/inputflinger/dispatcher/EventLogTags.logtags
+++ /dev/null
@@ -1,42 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace.  Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-#    (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# Default value for data of type int/long is 2 (bytes).
-#
-# See system/core/logcat/event.logtags for the master copy of the tags.
-
-# 62000 - 62199 reserved for inputflinger
-
-62000 input_interaction (windows|4)
-62001 input_focus (window|3)
-
-# NOTE - the range 1000000-2000000 is reserved for partners and others who
-# want to define their own log tags without conflicting with the core platform.
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c139dc5..91803c8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -62,7 +62,6 @@
 #include <binder/Binder.h>
 #include <input/InputDevice.h>
 #include <log/log.h>
-#include <log/log_event_list.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
 #include <powermanager/PowerManager.h>
@@ -104,10 +103,6 @@
 // Number of recent events to keep for debugging purposes.
 constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
 
-// Event log tags. See EventLogTags.logtags for reference
-constexpr int LOGTAG_INPUT_INTERACTION = 62000;
-constexpr int LOGTAG_INPUT_FOCUS = 62001;
-
 static inline nsecs_t now() {
     return systemTime(SYSTEM_TIME_MONOTONIC);
 }
@@ -722,7 +717,7 @@
         for (TouchedMonitor& gestureMonitor : gestureMonitors) {
             sp<Connection> connection =
                     getConnectionLocked(gestureMonitor.monitor.inputChannel->getConnectionToken());
-            if (connection->responsive) {
+            if (connection != nullptr && connection->responsive) {
                 // This monitor could take more input. Drop all events preceding this
                 // event, so that gesture monitor could get a chance to receive the stream
                 ALOGW("Pruning the input queue because %s is unresponsive, but we have a "
@@ -1109,9 +1104,7 @@
     target.inputChannel = channel;
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
     entry->dispatchInProgress = true;
-    std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
-            channel->getName();
-    android_log_event_list(LOGTAG_INPUT_FOCUS) << message << LOG_ID_EVENTS;
+
     dispatchEventLocked(currentTime, entry, {target});
 }
 
@@ -1349,8 +1342,6 @@
     ALOGD("dispatchEventToCurrentInputTargets");
 #endif
 
-    updateInteractionTokensLocked(*eventEntry, inputTargets);
-
     ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
 
     pokeUserActivityLocked(*eventEntry);
@@ -2097,14 +2088,9 @@
     auto otherInfo = otherHandle->getInfo();
     if (!otherInfo->visible) {
         return false;
-    } else if (info->ownerPid == otherInfo->ownerPid && otherHandle->getToken() == nullptr) {
-      // In general, if ownerPid is the same we don't want to generate occlusion
-      // events. This line is now necessary since we are including all Surfaces
-      // in occlusion calculation, so if we didn't check PID like this SurfaceView
-      // would occlude their parents. On the other hand before we started including
-      // all surfaces in occlusion calculation and had this line, we would count
-      // windows with an input channel from the same PID as occluding, and so we
-      // preserve this behavior with the getToken() == null check.
+    } else if (info->ownerPid == otherInfo->ownerPid) {
+        // If ownerPid is the same we don't generate occlusion events as there
+        // is no in-process security boundary.
         return false;
     } else if (otherInfo->trustedOverlay) {
         return false;
@@ -2438,73 +2424,6 @@
     traceOutboundQueueLength(connection);
 }
 
-/**
- * This function is purely for debugging. It helps us understand where the user interaction
- * was taking place. For example, if user is touching launcher, we will see a log that user
- * started interacting with launcher. In that example, the event would go to the wallpaper as well.
- * We will see both launcher and wallpaper in that list.
- * Once the interaction with a particular set of connections starts, no new logs will be printed
- * until the set of interacted connections changes.
- *
- * The following items are skipped, to reduce the logspam:
- * ACTION_OUTSIDE: any windows that are receiving ACTION_OUTSIDE are not logged
- * ACTION_UP: any windows that receive ACTION_UP are not logged (for both keys and motions).
- * This includes situations like the soft BACK button key. When the user releases (lifts up the
- * finger) the back button, then navigation bar will inject KEYCODE_BACK with ACTION_UP.
- * Both of those ACTION_UP events would not be logged
- * Monitors (both gesture and global): any gesture monitors or global monitors receiving events
- * will not be logged. This is omitted to reduce the amount of data printed.
- * If you see <none>, it's likely that one of the gesture monitors pilfered the event, and therefore
- * gesture monitor is the only connection receiving the remainder of the gesture.
- */
-void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
-                                                    const std::vector<InputTarget>& targets) {
-    // Skip ACTION_UP events, and all events other than keys and motions
-    if (entry.type == EventEntry::Type::KEY) {
-        const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
-        if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
-            return;
-        }
-    } else if (entry.type == EventEntry::Type::MOTION) {
-        const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
-        if (motionEntry.action == AMOTION_EVENT_ACTION_UP) {
-            return;
-        }
-    } else {
-        return; // Not a key or a motion
-    }
-
-    std::unordered_set<sp<IBinder>, IBinderHash> newConnections;
-    for (const InputTarget& target : targets) {
-        if ((target.flags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) ==
-            InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
-            continue; // Skip windows that receive ACTION_OUTSIDE
-        }
-
-        sp<IBinder> token = target.inputChannel->getConnectionToken();
-        sp<Connection> connection = getConnectionLocked(token); // get connection
-        if (connection->monitor) {
-            continue; // We only need to keep track of the non-monitor connections.
-        }
-
-        newConnections.insert(std::move(token));
-    }
-    if (newConnections == mInteractionConnections) {
-        return; // no change
-    }
-    mInteractionConnections = newConnections;
-    std::string windowList;
-    for (const sp<IBinder>& token : newConnections) {
-        sp<Connection> connection = getConnectionLocked(token);
-        windowList += connection->getWindowName() + ", ";
-    }
-    std::string message = "Interaction with windows: " + windowList;
-    if (windowList.empty()) {
-        message += "<none>";
-    }
-    android_log_event_list(LOGTAG_INPUT_INTERACTION) << message << LOG_ID_EVENTS;
-}
-
 void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
                                                       const sp<IBinder>& newToken) {
     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7c2028a..e679c6b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -49,7 +49,6 @@
 #include <deque>
 #include <optional>
 #include <unordered_map>
-#include <unordered_set>
 
 #include <InputListener.h>
 #include <InputReporterInterface.h>
@@ -327,11 +326,6 @@
     // Dispatcher state at time of last ANR.
     std::string mLastAnrState GUARDED_BY(mLock);
 
-    // The connection token of the channel that was last interacted with.
-    std::unordered_set<sp<IBinder>, IBinderHash> mInteractionConnections GUARDED_BY(mLock);
-    void updateInteractionTokensLocked(const EventEntry& entry,
-                                       const std::vector<InputTarget>& targets) REQUIRES(mLock);
-
     // Dispatch inbound events.
     bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry)
             REQUIRES(mLock);
diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp
index d26d582..178f545 100644
--- a/services/powermanager/PowerHalController.cpp
+++ b/services/powermanager/PowerHalController.cpp
@@ -15,40 +15,39 @@
  */
 
 #define LOG_TAG "PowerHalController"
-#include <utils/Log.h>
-
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
-
 #include <powermanager/PowerHalController.h>
 #include <powermanager/PowerHalLoader.h>
+#include <utils/Log.h>
 
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
+using namespace android::hardware::power;
 
 namespace android {
 
+namespace power {
+
 // -------------------------------------------------------------------------------------------------
 
-std::unique_ptr<PowerHalWrapper> PowerHalConnector::connect() {
-    sp<IPowerAidl> halAidl = PowerHalLoader::loadAidl();
+std::unique_ptr<HalWrapper> HalConnector::connect() {
+    sp<IPower> halAidl = PowerHalLoader::loadAidl();
     if (halAidl) {
-        return std::make_unique<AidlPowerHalWrapper>(halAidl);
+        return std::make_unique<AidlHalWrapper>(halAidl);
     }
-    sp<IPowerV1_0> halHidlV1_0 = PowerHalLoader::loadHidlV1_0();
-    sp<IPowerV1_1> halHidlV1_1 = PowerHalLoader::loadHidlV1_1();
+    sp<V1_0::IPower> halHidlV1_0 = PowerHalLoader::loadHidlV1_0();
+    sp<V1_1::IPower> halHidlV1_1 = PowerHalLoader::loadHidlV1_1();
     if (halHidlV1_1) {
-        return std::make_unique<HidlPowerHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
+        return std::make_unique<HidlHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
     }
     if (halHidlV1_0) {
-        return std::make_unique<HidlPowerHalWrapperV1_0>(halHidlV1_0);
+        return std::make_unique<HidlHalWrapperV1_0>(halHidlV1_0);
     }
     return nullptr;
 }
 
-void PowerHalConnector::reset() {
+void HalConnector::reset() {
     PowerHalLoader::unloadAll();
 }
 
@@ -58,8 +57,9 @@
     initHal();
 }
 
-// Check validity of current handle to the power HAL service, and create a new one if necessary.
-std::shared_ptr<PowerHalWrapper> PowerHalController::initHal() {
+// Check validity of current handle to the power HAL service, and create a new
+// one if necessary.
+std::shared_ptr<HalWrapper> PowerHalController::initHal() {
     std::lock_guard<std::mutex> lock(mConnectedHalMutex);
     if (mConnectedHal == nullptr) {
         mConnectedHal = mHalConnector->connect();
@@ -71,10 +71,10 @@
     return mConnectedHal;
 }
 
-// Check if a call to Power HAL function failed; if so, log the failure and invalidate the
-// current Power HAL handle.
-PowerHalResult PowerHalController::processHalResult(PowerHalResult result, const char* fnName) {
-    if (result == PowerHalResult::FAILED) {
+// Check if a call to Power HAL function failed; if so, log the failure and
+// invalidate the current Power HAL handle.
+HalResult PowerHalController::processHalResult(HalResult result, const char* fnName) {
+    if (result == HalResult::FAILED) {
         ALOGE("%s() failed: power HAL service not available.", fnName);
         std::lock_guard<std::mutex> lock(mConnectedHalMutex);
         // Drop Power HAL handle. This will force future api calls to reconnect.
@@ -84,16 +84,18 @@
     return result;
 }
 
-PowerHalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) {
-    std::shared_ptr<PowerHalWrapper> handle = initHal();
+HalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) {
+    std::shared_ptr<HalWrapper> handle = initHal();
     auto result = handle->setBoost(boost, durationMs);
     return processHalResult(result, "setBoost");
 }
 
-PowerHalResult PowerHalController::setMode(Mode mode, bool enabled) {
-    std::shared_ptr<PowerHalWrapper> handle = initHal();
+HalResult PowerHalController::setMode(Mode mode, bool enabled) {
+    std::shared_ptr<HalWrapper> handle = initHal();
     auto result = handle->setMode(mode, enabled);
     return processHalResult(result, "setMode");
 }
 
-}; // namespace android
+} // namespace power
+
+} // namespace android
diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp
index 3ae5384..1f1b43a 100644
--- a/services/powermanager/PowerHalLoader.cpp
+++ b/services/powermanager/PowerHalLoader.cpp
@@ -21,15 +21,14 @@
 #include <binder/IServiceManager.h>
 #include <hardware/power.h>
 #include <hardware_legacy/power.h>
-
 #include <powermanager/PowerHalLoader.h>
 
-using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
-using IPowerAidl = android::hardware::power::IPower;
+using namespace android::hardware::power;
 
 namespace android {
 
+namespace power {
+
 // -------------------------------------------------------------------------------------------------
 
 template <typename T, typename F>
@@ -53,9 +52,9 @@
 // -------------------------------------------------------------------------------------------------
 
 std::mutex PowerHalLoader::gHalMutex;
-sp<IPowerAidl> PowerHalLoader::gHalAidl = nullptr;
-sp<IPowerV1_0> PowerHalLoader::gHalHidlV1_0 = nullptr;
-sp<IPowerV1_1> PowerHalLoader::gHalHidlV1_1 = nullptr;
+sp<IPower> PowerHalLoader::gHalAidl = nullptr;
+sp<V1_0::IPower> PowerHalLoader::gHalHidlV1_0 = nullptr;
+sp<V1_1::IPower> PowerHalLoader::gHalHidlV1_1 = nullptr;
 
 void PowerHalLoader::unloadAll() {
     std::lock_guard<std::mutex> lock(gHalMutex);
@@ -64,31 +63,33 @@
     gHalHidlV1_1 = nullptr;
 }
 
-sp<IPowerAidl> PowerHalLoader::loadAidl() {
+sp<IPower> PowerHalLoader::loadAidl() {
     std::lock_guard<std::mutex> lock(gHalMutex);
     static bool gHalExists = true;
-    static auto loadFn = []() { return waitForVintfService<IPowerAidl>(); };
-    return loadHal<IPowerAidl>(gHalExists, gHalAidl, loadFn, "AIDL");
+    static auto loadFn = []() { return waitForVintfService<IPower>(); };
+    return loadHal<IPower>(gHalExists, gHalAidl, loadFn, "AIDL");
 }
 
-sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0() {
+sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0() {
     std::lock_guard<std::mutex> lock(gHalMutex);
     return loadHidlV1_0Locked();
 }
 
-sp<IPowerV1_1> PowerHalLoader::loadHidlV1_1() {
+sp<V1_1::IPower> PowerHalLoader::loadHidlV1_1() {
     std::lock_guard<std::mutex> lock(gHalMutex);
     static bool gHalExists = true;
-    static auto loadFn = []() { return IPowerV1_1::castFrom(loadHidlV1_0Locked()); };
-    return loadHal<IPowerV1_1>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1");
+    static auto loadFn = []() { return V1_1::IPower::castFrom(loadHidlV1_0Locked()); };
+    return loadHal<V1_1::IPower>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1");
 }
 
-sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0Locked() {
+sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0Locked() {
     static bool gHalExists = true;
-    static auto loadFn = []() { return IPowerV1_0::getService(); };
-    return loadHal<IPowerV1_0>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0");
+    static auto loadFn = []() { return V1_0::IPower::getService(); };
+    return loadHal<V1_0::IPower>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0");
 }
 
 // -------------------------------------------------------------------------------------------------
 
+} // namespace power
+
 } // namespace android
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index d959a2c..5f4bfed 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -14,159 +14,162 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "PowerHalWrapper"
-#include <utils/Log.h>
-
+#define LOG_TAG "HalWrapper"
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/Mode.h>
-
 #include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
 
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
-using android::hardware::power::V1_0::Feature;
-using android::hardware::power::V1_0::PowerHint;
+using namespace android::hardware::power;
 
 namespace android {
 
+namespace power {
+
 // -------------------------------------------------------------------------------------------------
 
-PowerHalResult EmptyPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) {
+inline HalResult toHalResult(const binder::Status& result) {
+    return result.isOk() ? HalResult::SUCCESSFUL : HalResult::FAILED;
+}
+
+template <typename T>
+inline HalResult toHalResult(const hardware::Return<T>& result) {
+    return result.isOk() ? HalResult::SUCCESSFUL : HalResult::FAILED;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult EmptyHalWrapper::setBoost(Boost boost, int32_t durationMs) {
     ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available",
-        toString(boost).c_str(), durationMs);
-    return PowerHalResult::UNSUPPORTED;
+          toString(boost).c_str(), durationMs);
+    return HalResult::UNSUPPORTED;
 }
 
-PowerHalResult EmptyPowerHalWrapper::setMode(Mode mode, bool enabled) {
-    ALOGV("Skipped setMode %s to %s because Power HAL not available",
-        toString(mode).c_str(), enabled ? "true" : "false");
-    return PowerHalResult::UNSUPPORTED;
+HalResult EmptyHalWrapper::setMode(Mode mode, bool enabled) {
+    ALOGV("Skipped setMode %s to %s because Power HAL not available", toString(mode).c_str(),
+          enabled ? "true" : "false");
+    return HalResult::UNSUPPORTED;
 }
 
 // -------------------------------------------------------------------------------------------------
 
-PowerHalResult HidlPowerHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) {
+HalResult HidlHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) {
     if (boost == Boost::INTERACTION) {
-        return sendPowerHint(PowerHint::INTERACTION, durationMs);
+        return sendPowerHint(V1_0::PowerHint::INTERACTION, durationMs);
     } else {
-        ALOGV("Skipped setBoost %s because Power HAL AIDL not available",
-            toString(boost).c_str());
-        return PowerHalResult::UNSUPPORTED;
+        ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str());
+        return HalResult::UNSUPPORTED;
     }
 }
 
-PowerHalResult HidlPowerHalWrapperV1_0::setMode(Mode mode, bool enabled) {
+HalResult HidlHalWrapperV1_0::setMode(Mode mode, bool enabled) {
     uint32_t data = enabled ? 1 : 0;
     switch (mode) {
         case Mode::LAUNCH:
-            return sendPowerHint(PowerHint::LAUNCH, data);
+            return sendPowerHint(V1_0::PowerHint::LAUNCH, data);
         case Mode::LOW_POWER:
-            return sendPowerHint(PowerHint::LOW_POWER, data);
+            return sendPowerHint(V1_0::PowerHint::LOW_POWER, data);
         case Mode::SUSTAINED_PERFORMANCE:
-            return sendPowerHint(PowerHint::SUSTAINED_PERFORMANCE, data);
+            return sendPowerHint(V1_0::PowerHint::SUSTAINED_PERFORMANCE, data);
         case Mode::VR:
-            return sendPowerHint(PowerHint::VR_MODE, data);
+            return sendPowerHint(V1_0::PowerHint::VR_MODE, data);
         case Mode::INTERACTIVE:
             return setInteractive(enabled);
         case Mode::DOUBLE_TAP_TO_WAKE:
-            return setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled);
+            return setFeature(V1_0::Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled);
         default:
             ALOGV("Skipped setMode %s because Power HAL AIDL not available",
-                toString(mode).c_str());
-            return PowerHalResult::UNSUPPORTED;
+                  toString(mode).c_str());
+            return HalResult::UNSUPPORTED;
     }
 }
 
-PowerHalResult HidlPowerHalWrapperV1_0::sendPowerHint(PowerHint hintId, uint32_t data) {
-    auto ret = handleV1_0->powerHint(hintId, data);
-    return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_0::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
+    return toHalResult(mHandleV1_0->powerHint(hintId, data));
 }
 
-PowerHalResult HidlPowerHalWrapperV1_0::setInteractive(bool enabled) {
-    auto ret = handleV1_0->setInteractive(enabled);
-    return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_0::setInteractive(bool enabled) {
+    return toHalResult(mHandleV1_0->setInteractive(enabled));
 }
 
-PowerHalResult HidlPowerHalWrapperV1_0::setFeature(Feature feature, bool enabled) {
-    auto ret = handleV1_0->setFeature(feature, enabled);
-    return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_0::setFeature(V1_0::Feature feature, bool enabled) {
+    return toHalResult(mHandleV1_0->setFeature(feature, enabled));
 }
 
 // -------------------------------------------------------------------------------------------------
 
-PowerHalResult HidlPowerHalWrapperV1_1::sendPowerHint(PowerHint hintId, uint32_t data) {
-    auto ret = handleV1_1->powerHintAsync(hintId, data);
-    return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_1::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
+    return toHalResult(mHandleV1_1->powerHintAsync(hintId, data));
 }
 
 // -------------------------------------------------------------------------------------------------
 
-PowerHalResult AidlPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) {
+HalResult AidlHalWrapper::setBoost(Boost boost, int32_t durationMs) {
     std::unique_lock<std::mutex> lock(mBoostMutex);
     // Quick return if boost is not supported by HAL
     if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
-        boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::OFF) {
-        ALOGV("Skipped setBoost %s because Power HAL doesn't support it",
-            toString(boost).c_str());
-        return PowerHalResult::UNSUPPORTED;
+        mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
+        ALOGV("Skipped setBoost %s because Power HAL doesn't support it", toString(boost).c_str());
+        return HalResult::UNSUPPORTED;
     }
 
-    if (boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::UNKNOWN) {
+    if (mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
         bool isSupported = false;
-        auto isSupportedRet = handle->isBoostSupported(boost, &isSupported);
+        auto isSupportedRet = mHandle->isBoostSupported(boost, &isSupported);
         if (!isSupportedRet.isOk()) {
-            ALOGV("Skipped setBoost %s because Power HAL is not available to check support",
-                toString(boost).c_str());
-            return PowerHalResult::FAILED;
+            ALOGV("Skipped setBoost %s because Power HAL is not available to check "
+                  "support",
+                  toString(boost).c_str());
+            return HalResult::FAILED;
         }
 
-        boostSupportedArray[static_cast<int32_t>(boost)] =
-            isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF;
+        mBoostSupportedArray[static_cast<int32_t>(boost)] =
+                isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
             ALOGV("Skipped setBoost %s because Power HAL doesn't support it",
-                toString(boost).c_str());
-            return PowerHalResult::UNSUPPORTED;
+                  toString(boost).c_str());
+            return HalResult::UNSUPPORTED;
         }
     }
     lock.unlock();
 
-    auto ret = handle->setBoost(boost, durationMs);
-    return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+    return toHalResult(mHandle->setBoost(boost, durationMs));
 }
 
-PowerHalResult AidlPowerHalWrapper::setMode(Mode mode, bool enabled) {
+HalResult AidlHalWrapper::setMode(Mode mode, bool enabled) {
     std::unique_lock<std::mutex> lock(mModeMutex);
     // Quick return if mode is not supported by HAL
     if (mode > Mode::DISPLAY_INACTIVE ||
-        modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::OFF) {
-        ALOGV("Skipped setMode %s because Power HAL doesn't support it",
-            toString(mode).c_str());
-        return PowerHalResult::UNSUPPORTED;
+        mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
+        ALOGV("Skipped setMode %s because Power HAL doesn't support it", toString(mode).c_str());
+        return HalResult::UNSUPPORTED;
     }
 
-    if (modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::UNKNOWN) {
+    if (mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
         bool isSupported = false;
-        auto isSupportedRet = handle->isModeSupported(mode, &isSupported);
+        auto isSupportedRet = mHandle->isModeSupported(mode, &isSupported);
         if (!isSupportedRet.isOk()) {
-            ALOGV("Skipped setMode %s because Power HAL is not available to check support",
-                toString(mode).c_str());
-            return PowerHalResult::FAILED;
+            ALOGV("Skipped setMode %s because Power HAL is not available to check "
+                  "support",
+                  toString(mode).c_str());
+            return HalResult::FAILED;
         }
 
-        modeSupportedArray[static_cast<int32_t>(mode)] =
-            isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF;
+        mModeSupportedArray[static_cast<int32_t>(mode)] =
+                isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
-                ALOGV("Skipped setMode %s because Power HAL doesn't support it",
-                    toString(mode).c_str());
-                return PowerHalResult::UNSUPPORTED;
+            ALOGV("Skipped setMode %s because Power HAL doesn't support it",
+                  toString(mode).c_str());
+            return HalResult::UNSUPPORTED;
         }
     }
     lock.unlock();
 
-    auto ret = handle->setMode(mode, enabled);
-    return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+    return toHalResult(mHandle->setMode(mode, enabled));
 }
 
 // -------------------------------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace power
+
+} // namespace android
diff --git a/services/powermanager/TEST_MAPPING b/services/powermanager/TEST_MAPPING
index 9a67901..caaec55 100644
--- a/services/powermanager/TEST_MAPPING
+++ b/services/powermanager/TEST_MAPPING
@@ -1,10 +1,7 @@
 {
   "presubmit": [
     {
-      "name": "powermanager_test"
-    },
-    {
-      "name": "thermalmanager_test"
+      "name": "libpowermanager_test"
     }
   ]
 }
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 70837cf..49abc11 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -13,9 +13,10 @@
 // limitations under the License.
 
 cc_test {
-    name: "powermanager_test",
+    name: "libpowermanager_test",
     test_suites: ["device-tests"],
     srcs: [
+        "IThermalManagerTest.cpp",
         "PowerHalControllerTest.cpp",
         "PowerHalLoaderTest.cpp",
         "PowerHalWrapperAidlTest.cpp",
@@ -42,22 +43,3 @@
         "libgmock",
     ],
 }
-
-cc_test {
-    name: "thermalmanager_test",
-    test_suites: ["device-tests"],
-    srcs: ["IThermalManagerTest.cpp",],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "liblog",
-        "libpowermanager",
-        "libbinder",
-        "libutils",
-    ],
-}
diff --git a/services/powermanager/tests/PowerHalControllerTest.cpp b/services/powermanager/tests/PowerHalControllerTest.cpp
index ac1e19a..141b244 100644
--- a/services/powermanager/tests/PowerHalControllerTest.cpp
+++ b/services/powermanager/tests/PowerHalControllerTest.cpp
@@ -19,15 +19,12 @@
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
-#include <powermanager/PowerHalWrapper.h>
 #include <powermanager/PowerHalController.h>
+#include <utils/Log.h>
 
 #include <thread>
-#include <utils/Log.h>
 
 using android::hardware::power::Boost;
 using android::hardware::power::Mode;
@@ -36,6 +33,7 @@
 using android::hardware::power::V1_0::PowerHint;
 
 using namespace android;
+using namespace android::power;
 using namespace std::chrono_literals;
 using namespace testing;
 
@@ -45,23 +43,21 @@
 public:
     MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
     MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, getPlatformLowPowerStats,
-        (getPlatformLowPowerStats_cb _hidl_cb), (override));
+    MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+    MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+                (getPlatformLowPowerStats_cb _hidl_cb), (override));
 };
 
-class TestPowerHalConnector : public PowerHalConnector {
+class TestPowerHalConnector : public HalConnector {
 public:
     TestPowerHalConnector(sp<IPower> powerHal) : mHal(std::move(powerHal)) {}
     virtual ~TestPowerHalConnector() = default;
 
-    virtual std::unique_ptr<PowerHalWrapper> connect() override {
+    virtual std::unique_ptr<HalWrapper> connect() override {
         mCountMutex.lock();
         ++mConnectedCount;
         mCountMutex.unlock();
-        return std::make_unique<HidlPowerHalWrapperV1_0>(mHal);
+        return std::make_unique<HidlHalWrapperV1_0>(mHal);
     }
 
     void reset() override {
@@ -70,13 +66,9 @@
         mCountMutex.unlock();
     }
 
-    int getConnectCount() {
-        return mConnectedCount;
-    }
+    int getConnectCount() { return mConnectedCount; }
 
-    int getResetCount() {
-        return mResetCount;
-    }
+    int getResetCount() { return mResetCount; }
 
 private:
     sp<IPower> mHal = nullptr;
@@ -89,8 +81,8 @@
 public:
     AlwaysFailingTestPowerHalConnector() : TestPowerHalConnector(nullptr) {}
 
-    std::unique_ptr<PowerHalWrapper> connect() override {
-        // Call parent to update counter, but ignore connected PowerHalWrapper.
+    std::unique_ptr<HalWrapper> connect() override {
+        // Call parent to update counter, but ignore connected HalWrapper.
         TestPowerHalConnector::connect();
         return nullptr;
     }
@@ -103,7 +95,7 @@
     void SetUp() override {
         mMockHal = new StrictMock<MockIPowerV1_0>();
         std::unique_ptr<TestPowerHalConnector> halConnector =
-            std::make_unique<TestPowerHalConnector>(mMockHal);
+                std::make_unique<TestPowerHalConnector>(mMockHal);
         mHalConnector = halConnector.get();
         mHalController = std::make_unique<PowerHalController>(std::move(halConnector));
     }
@@ -132,20 +124,22 @@
 
 TEST_F(PowerHalControllerTest, TestUnableToConnectToPowerHalIgnoresAllApiCalls) {
     std::unique_ptr<AlwaysFailingTestPowerHalConnector> halConnector =
-        std::make_unique<AlwaysFailingTestPowerHalConnector>();
+            std::make_unique<AlwaysFailingTestPowerHalConnector>();
     AlwaysFailingTestPowerHalConnector* failingHalConnector = halConnector.get();
     PowerHalController halController(std::move(halConnector));
 
     int powerHalConnectCount = failingHalConnector->getConnectCount();
     EXPECT_EQ(powerHalConnectCount, 0);
 
-    // Still works with EmptyPowerHalWrapper as fallback ignoring every api call and logging.
+    // Still works with EmptyPowerHalWrapper as fallback ignoring every api call
+    // and logging.
     auto result = halController.setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
     result = halController.setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 
-    // PowerHalConnector was called every time to attempt to reconnect with underlying service.
+    // PowerHalConnector was called every time to attempt to reconnect with
+    // underlying service.
     powerHalConnectCount = failingHalConnector->getConnectCount();
     EXPECT_EQ(powerHalConnectCount, 2);
     // PowerHalConnector was never reset.
@@ -160,15 +154,14 @@
     {
         InSequence seg;
         EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(100)))
-            .Times(Exactly(1));
-        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
+        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))).Times(Exactly(1));
     }
 
     auto result = mHalController->setBoost(Boost::INTERACTION, 100);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mHalController->setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 
     // PowerHalConnector was called only once and never reset.
     powerHalConnectCount = mHalConnector->getConnectCount();
@@ -182,23 +175,23 @@
     EXPECT_EQ(powerHalConnectCount, 0);
 
     ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
-        .WillByDefault([](PowerHint, int32_t) {
-            return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
-        });
+            .WillByDefault([](PowerHint, int32_t) {
+                return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+            });
 
-    EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
-        .Times(Exactly(4));
+    EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(4));
 
     auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mHalController->setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
     result = mHalController->setMode(Mode::VR, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mHalController->setMode(Mode::LOW_POWER, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 
-    // PowerHalConnector was called only twice: on first api call and after failed call.
+    // PowerHalConnector was called only twice: on first api call and after failed
+    // call.
     powerHalConnectCount = mHalConnector->getConnectCount();
     EXPECT_EQ(powerHalConnectCount, 2);
     // PowerHalConnector was reset once after failed call.
@@ -211,9 +204,9 @@
     EXPECT_EQ(powerHalConnectCount, 0);
 
     auto result = mHalController->setBoost(Boost::CAMERA_LAUNCH, 1000);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
     result = mHalController->setMode(Mode::CAMERA_STREAMING_HIGH, true);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 
     // PowerHalConnector was called only once and never reset.
     powerHalConnectCount = mHalConnector->getConnectCount();
@@ -226,19 +219,19 @@
     int powerHalConnectCount = mHalConnector->getConnectCount();
     EXPECT_EQ(powerHalConnectCount, 0);
 
-    EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
-        .Times(Exactly(10));
+    EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(10));
 
     std::vector<std::thread> threads;
     for (int i = 0; i < 10; i++) {
         threads.push_back(std::thread([&]() {
             auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
-            ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+            ASSERT_EQ(HalResult::SUCCESSFUL, result);
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
 
-    // PowerHalConnector was called only by the first thread to use the api and never reset.
+    // PowerHalConnector was called only by the first thread to use the api and
+    // never reset.
     powerHalConnectCount = mHalConnector->getConnectCount();
     EXPECT_EQ(powerHalConnectCount, 1);
     int powerHalResetCount = mHalConnector->getResetCount();
@@ -250,36 +243,36 @@
     EXPECT_EQ(powerHalConnectCount, 0);
 
     ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
-        .WillByDefault([](PowerHint, int32_t) {
-            return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
-        });
+            .WillByDefault([](PowerHint, int32_t) {
+                return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+            });
 
-    EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
-        .Times(Exactly(40));
+    EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(40));
 
     std::vector<std::thread> threads;
     for (int i = 0; i < 10; i++) {
         threads.push_back(std::thread([&]() {
             auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
-            ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+            ASSERT_EQ(HalResult::SUCCESSFUL, result);
         }));
         threads.push_back(std::thread([&]() {
             auto result = mHalController->setMode(Mode::LAUNCH, true);
-            ASSERT_EQ(PowerHalResult::FAILED, result);
+            ASSERT_EQ(HalResult::FAILED, result);
         }));
         threads.push_back(std::thread([&]() {
             auto result = mHalController->setMode(Mode::LOW_POWER, false);
-            ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+            ASSERT_EQ(HalResult::SUCCESSFUL, result);
         }));
         threads.push_back(std::thread([&]() {
             auto result = mHalController->setMode(Mode::VR, true);
-            ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+            ASSERT_EQ(HalResult::SUCCESSFUL, result);
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
 
     // PowerHalConnector was called at least once by the first thread.
-    // Reset and reconnect calls were made at most 10 times, once after each failure.
+    // Reset and reconnect calls were made at most 10 times, once after each
+    // failure.
     powerHalConnectCount = mHalConnector->getConnectCount();
     EXPECT_THAT(powerHalConnectCount, AllOf(Ge(1), Le(11)));
     int powerHalResetCount = mHalConnector->getResetCount();
diff --git a/services/powermanager/tests/PowerHalLoaderTest.cpp b/services/powermanager/tests/PowerHalLoaderTest.cpp
index 2310a72..058e1b5 100644
--- a/services/powermanager/tests/PowerHalLoaderTest.cpp
+++ b/services/powermanager/tests/PowerHalLoaderTest.cpp
@@ -19,17 +19,18 @@
 #include <android-base/logging.h>
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/IPower.h>
+#include <gtest/gtest.h>
+#include <powermanager/PowerHalLoader.h>
 
 #include <future>
-#include <gtest/gtest.h>
-
-#include <powermanager/PowerHalLoader.h>
 
 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
 using IPowerV1_1 = android::hardware::power::V1_1::IPower;
 using IPowerAidl = android::hardware::power::IPower;
 
 using namespace android;
+using namespace android::power;
+using namespace testing;
 
 // -------------------------------------------------------------------------------------------------
 
@@ -54,14 +55,10 @@
 // -------------------------------------------------------------------------------------------------
 
 template <typename T>
-class PowerHalLoaderTest : public testing::Test {
+class PowerHalLoaderTest : public Test {
 public:
-    sp<T> load() {
-        return ::loadHal<T>();
-    }
-    void unload() {
-        PowerHalLoader::unloadAll();
-    }
+    sp<T> load() { return ::loadHal<T>(); }
+    void unload() { PowerHalLoader::unloadAll(); }
 };
 
 // -------------------------------------------------------------------------------------------------
@@ -95,7 +92,7 @@
     std::vector<std::future<sp<TypeParam>>> futures;
     for (int i = 0; i < 10; i++) {
         futures.push_back(
-            std::async(std::launch::async, &PowerHalLoaderTest<TypeParam>::load, this));
+                std::async(std::launch::async, &PowerHalLoaderTest<TypeParam>::load, this));
     }
 
     futures[0].wait();
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index 73b7466..a765659 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -19,14 +19,12 @@
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/Mode.h>
 #include <binder/IServiceManager.h>
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
 
 #include <thread>
-#include <utils/Log.h>
 
 using android::binder::Status;
 using android::hardware::power::Boost;
@@ -34,6 +32,7 @@
 using android::hardware::power::Mode;
 
 using namespace android;
+using namespace android::power;
 using namespace std::chrono_literals;
 using namespace testing;
 
@@ -57,7 +56,7 @@
     void SetUp() override;
 
 protected:
-    std::unique_ptr<PowerHalWrapper> mWrapper = nullptr;
+    std::unique_ptr<HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIPower>> mMockHal = nullptr;
 };
 
@@ -65,7 +64,7 @@
 
 void PowerHalWrapperAidlTest::SetUp() {
     mMockHal = new StrictMock<MockIPower>();
-    mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+    mWrapper = std::make_unique<AidlHalWrapper>(mMockHal);
     ASSERT_NE(mWrapper, nullptr);
 }
 
@@ -75,62 +74,61 @@
     {
         InSequence seq;
         EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
         EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::DISPLAY_UPDATE_IMMINENT), Eq(100)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
     }
 
     auto result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 100);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 }
 
 TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) {
     {
         InSequence seq;
         EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
         EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
-            .Times(Exactly(1))
-            .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
         EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
     }
 
     auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
     result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 1000);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
 }
 
 TEST_F(PowerHalWrapperAidlTest, TestSetBoostUnsupported) {
     EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
-        .Times(Exactly(1))
-        .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
 
     auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
     result = mWrapper->setBoost(Boost::CAMERA_SHOT, 10);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 }
 
 TEST_F(PowerHalWrapperAidlTest, TestSetBoostMultiThreadCheckSupportedOnlyOnce) {
     {
         InSequence seq;
         EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
-        EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
-            .Times(Exactly(10));
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+        EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))).Times(Exactly(10));
     }
 
     std::vector<std::thread> threads;
     for (int i = 0; i < 10; i++) {
         threads.push_back(std::thread([&]() {
             auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
-            ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+            ASSERT_EQ(HalResult::SUCCESSFUL, result);
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
@@ -140,62 +138,61 @@
     {
         InSequence seq;
         EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
         EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::DISPLAY_INACTIVE), Eq(false)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
     }
 
     auto result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 }
 
 TEST_F(PowerHalWrapperAidlTest, TestSetModeFailed) {
     {
         InSequence seq;
         EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
         EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(true)))
-            .Times(Exactly(1))
-            .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
         EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
     }
 
     auto result = mWrapper->setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
     result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
 }
 
 TEST_F(PowerHalWrapperAidlTest, TestSetModeUnsupported) {
     EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
-        .Times(Exactly(1))
-        .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
 
     auto result = mWrapper->setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
     result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 }
 
 TEST_F(PowerHalWrapperAidlTest, TestSetModeMultiThreadCheckSupportedOnlyOnce) {
     {
         InSequence seq;
         EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
-        EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false)))
-            .Times(Exactly(10));
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+        EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false))).Times(Exactly(10));
     }
 
     std::vector<std::thread> threads;
     for (int i = 0; i < 10; i++) {
         threads.push_back(std::thread([&]() {
             auto result = mWrapper->setMode(Mode::LAUNCH, false);
-            ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+            ASSERT_EQ(HalResult::SUCCESSFUL, result);
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
index 5379054..6693d0b 100644
--- a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
@@ -20,12 +20,9 @@
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
 #include <binder/IServiceManager.h>
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <powermanager/PowerHalWrapper.h>
-
 #include <utils/Log.h>
 
 using android::hardware::power::Boost;
@@ -35,6 +32,7 @@
 using android::hardware::power::V1_0::PowerHint;
 
 using namespace android;
+using namespace android::power;
 using namespace std::chrono_literals;
 using namespace testing;
 
@@ -44,11 +42,9 @@
 public:
     MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
     MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, getPlatformLowPowerStats,
-        (getPlatformLowPowerStats_cb _hidl_cb), (override));
+    MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+    MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+                (getPlatformLowPowerStats_cb _hidl_cb), (override));
 };
 
 // -------------------------------------------------------------------------------------------------
@@ -58,7 +54,7 @@
     void SetUp() override;
 
 protected:
-    std::unique_ptr<PowerHalWrapper> mWrapper = nullptr;
+    std::unique_ptr<HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr;
 };
 
@@ -66,80 +62,75 @@
 
 void PowerHalWrapperHidlV1_0Test::SetUp() {
     mMockHal = new StrictMock<MockIPowerV1_0>();
-    mWrapper = std::make_unique<HidlPowerHalWrapperV1_0>(mMockHal);
+    mWrapper = std::make_unique<HidlHalWrapperV1_0>(mMockHal);
     ASSERT_NE(mWrapper, nullptr);
 }
 
 // -------------------------------------------------------------------------------------------------
 
 TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostSuccessful) {
-    EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000)))
-        .Times(Exactly(1));
+    EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000))).Times(Exactly(1));
 
     auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostFailed) {
     EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000)))
-        .Times(Exactly(1))
-        .WillRepeatedly([](PowerHint, int32_t) {
-            return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
-        });
+            .Times(Exactly(1))
+            .WillRepeatedly([](PowerHint, int32_t) {
+                return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+            });
 
     auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostUnsupported) {
     auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeSuccessful) {
     {
         InSequence seq;
-        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
-            .Times(Exactly(1));
-        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(0)))
-            .Times(Exactly(1));
+        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))).Times(Exactly(1));
+        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(0))).Times(Exactly(1));
         EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
-            .Times(Exactly(1));
-        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(0)))
-            .Times(Exactly(1));
-        EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
+        EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(0))).Times(Exactly(1));
+        EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))).Times(Exactly(1));
         EXPECT_CALL(*mMockHal.get(),
                     setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
     }
 
     auto result = mWrapper->setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::LOW_POWER, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::VR, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::INTERACTIVE, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeFailed) {
     EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
-        .Times(Exactly(1))
-        .WillRepeatedly([](PowerHint, int32_t) {
-            return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
-        });
+            .Times(Exactly(1))
+            .WillRepeatedly([](PowerHint, int32_t) {
+                return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+            });
 
     auto result = mWrapper->setMode(Mode::LAUNCH, 1);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeIgnored) {
     auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 }
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
index 931c0d5..55bbd6d 100644
--- a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
@@ -21,12 +21,9 @@
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
 #include <binder/IServiceManager.h>
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <powermanager/PowerHalWrapper.h>
-
 #include <utils/Log.h>
 
 using android::hardware::power::Boost;
@@ -37,6 +34,7 @@
 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
 
 using namespace android;
+using namespace android::power;
 using namespace std::chrono_literals;
 using namespace testing;
 
@@ -46,27 +44,21 @@
 public:
     MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
     MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, getPlatformLowPowerStats,
-        (getPlatformLowPowerStats_cb _hidl_cb), (override));
+    MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+    MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+                (getPlatformLowPowerStats_cb _hidl_cb), (override));
 };
 
 class MockIPowerV1_1 : public IPowerV1_1 {
 public:
     MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
     MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, getPlatformLowPowerStats,
-        (getPlatformLowPowerStats_cb _hidl_cb), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, powerHintAsync, (PowerHint hint, int32_t data), (override));
-    MOCK_METHOD(
-        hardware::Return<void>, getSubsystemLowPowerStats,
-        (getSubsystemLowPowerStats_cb _hidl_cb), (override));
+    MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+    MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+                (getPlatformLowPowerStats_cb _hidl_cb), (override));
+    MOCK_METHOD(hardware::Return<void>, powerHintAsync, (PowerHint hint, int32_t data), (override));
+    MOCK_METHOD(hardware::Return<void>, getSubsystemLowPowerStats,
+                (getSubsystemLowPowerStats_cb _hidl_cb), (override));
 };
 
 // -------------------------------------------------------------------------------------------------
@@ -76,7 +68,7 @@
     void SetUp() override;
 
 protected:
-    std::unique_ptr<PowerHalWrapper> mWrapper = nullptr;
+    std::unique_ptr<HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIPowerV1_0>> mMockHalV1_0 = nullptr;
     sp<StrictMock<MockIPowerV1_1>> mMockHalV1_1 = nullptr;
 };
@@ -86,7 +78,7 @@
 void PowerHalWrapperHidlV1_1Test::SetUp() {
     mMockHalV1_0 = new StrictMock<MockIPowerV1_0>();
     mMockHalV1_1 = new StrictMock<MockIPowerV1_1>();
-    mWrapper = std::make_unique<HidlPowerHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1);
+    mWrapper = std::make_unique<HidlHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1);
     ASSERT_NE(mWrapper, nullptr);
 }
 
@@ -94,72 +86,72 @@
 
 TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostSuccessful) {
     EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
-        .Times(Exactly(1));
+            .Times(Exactly(1));
 
     auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostFailed) {
     EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
-        .Times(Exactly(1))
-        .WillRepeatedly([](PowerHint, int32_t) {
-            return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
-        });
+            .Times(Exactly(1))
+            .WillRepeatedly([](PowerHint, int32_t) {
+                return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+            });
 
     auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostUnsupported) {
     auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_1Test, TestSetMode) {
     {
         InSequence seq;
         EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
         EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LOW_POWER), Eq(0)))
-            .Times(Exactly(1));
-        EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
+        EXPECT_CALL(*mMockHalV1_1.get(),
+                    powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
+                .Times(Exactly(1));
         EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::VR_MODE), Eq(0)))
-            .Times(Exactly(1));
-        EXPECT_CALL(*mMockHalV1_0.get(), setInteractive(Eq(true)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
+        EXPECT_CALL(*mMockHalV1_0.get(), setInteractive(Eq(true))).Times(Exactly(1));
         EXPECT_CALL(*mMockHalV1_0.get(),
                     setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
-            .Times(Exactly(1));
+                .Times(Exactly(1));
     }
 
     auto result = mWrapper->setMode(Mode::LAUNCH, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::LOW_POWER, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::VR, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::INTERACTIVE, true);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
     result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
-    ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+    ASSERT_EQ(HalResult::SUCCESSFUL, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeFailed) {
     EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1)))
-        .Times(Exactly(1))
-        .WillRepeatedly([](PowerHint, int32_t) {
-            return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
-        });
+            .Times(Exactly(1))
+            .WillRepeatedly([](PowerHint, int32_t) {
+                return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+            });
 
     auto result = mWrapper->setMode(Mode::LAUNCH, 1);
-    ASSERT_EQ(PowerHalResult::FAILED, result);
+    ASSERT_EQ(HalResult::FAILED, result);
 }
 
 TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeIgnored) {
     auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
-    ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+    ASSERT_EQ(HalResult::UNSUPPORTED, result);
 }
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index ccf05d9..9b30dce 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -37,6 +37,7 @@
       mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
       mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false) {
     mChannel = new BitTube(mService->mSocketBufferSize);
+    mTargetSdk = SensorService::getTargetSdkVersion(opPackageName);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
     mTotalAcksNeeded = mTotalAcksReceived = 0;
@@ -439,8 +440,17 @@
     bool success = true;
     const auto iter = mHandleToAppOp.find(event.sensor);
     if (iter != mHandleToAppOp.end()) {
-        int32_t appOpMode = mService->sAppOpsManager.noteOp((*iter).second, mUid, mOpPackageName);
-        success = (appOpMode == AppOpsManager::MODE_ALLOWED);
+        // Special handling for step count/detect backwards compatibility: if the app's target SDK
+        // is pre-Q, still permit delivering events to the app even if permission isn't granted
+        // (since this permission was only introduced in Q)
+        if ((event.type == SENSOR_TYPE_STEP_COUNTER || event.type == SENSOR_TYPE_STEP_DETECTOR) &&
+                mTargetSdk > 0 && mTargetSdk <= __ANDROID_API_P__) {
+            success = true;
+        } else {
+            int32_t appOpMode = mService->sAppOpsManager.noteOp(iter->second, mUid,
+                                                                mOpPackageName);
+            success = (appOpMode == AppOpsManager::MODE_ALLOWED);
+        }
     }
     return success;
 }
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 13cee6f..8d5fcf7 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -175,6 +175,7 @@
     int mEventsDropped;
     String8 mPackageName;
     const String16 mOpPackageName;
+    int mTargetSdk;
 #if DEBUG_CONNECTIONS
     int mEventsReceived, mEventsSent, mEventsSentFromCache;
     int mTotalAcksNeeded, mTotalAcksReceived;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 2b4fd7f..3f88f77 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1805,36 +1805,28 @@
     const int32_t appOpMode = sAppOpsManager.checkOp(opCode,
             IPCThreadState::self()->getCallingUid(), opPackageName);
     bool appOpAllowed = appOpMode == AppOpsManager::MODE_ALLOWED;
+    int targetSdkVersion = getTargetSdkVersion(opPackageName);
 
     bool canAccess = false;
-    if (hasPermissionForSensor(sensor)) {
+    if (targetSdkVersion > 0 && targetSdkVersion <= __ANDROID_API_P__ &&
+            (sensor.getType() == SENSOR_TYPE_STEP_COUNTER ||
+             sensor.getType() == SENSOR_TYPE_STEP_DETECTOR)) {
+        // Allow access to step sensors if the application targets pre-Q, which is before the
+        // requirement to hold the AR permission to access Step Counter and Step Detector events
+        // was introduced.
+        canAccess = true;
+    } else if (hasPermissionForSensor(sensor)) {
         // Ensure that the AppOp is allowed, or that there is no necessary app op for the sensor
         if (opCode < 0 || appOpAllowed) {
             canAccess = true;
         }
-    } else if (sensor.getType() == SENSOR_TYPE_STEP_COUNTER ||
-            sensor.getType() == SENSOR_TYPE_STEP_DETECTOR) {
-        int targetSdkVersion = getTargetSdkVersion(opPackageName);
-        // Allow access to the sensor if the application targets pre-Q, which is before the
-        // requirement to hold the AR permission to access Step Counter and Step Detector events
-        // was introduced, and the user hasn't revoked the app op.
-        //
-        // Verifying the app op is required to ensure that the user hasn't revoked the necessary
-        // permissions to access the Step Detector and Step Counter when the application targets
-        // pre-Q. Without this check, if the user revokes the pre-Q install-time GMS Core AR
-        // permission, the app would still be able to receive Step Counter and Step Detector events.
-        if (appOpAllowed &&
-                targetSdkVersion > 0 &&
-                targetSdkVersion <= __ANDROID_API_P__) {
-            canAccess = true;
-        }
     }
 
     if (canAccess) {
         sAppOpsManager.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName);
     } else {
-        ALOGE("%s a sensor (%s) without holding its required permission: %s",
-                operation, sensor.getName().string(), sensor.getRequiredPermission().string());
+        ALOGE("%s %s a sensor (%s) without holding %s", String8(opPackageName).string(),
+              operation, sensor.getName().string(), sensor.getRequiredPermission().string());
     }
 
     return canAccess;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 0e69f60..26bfb49 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -148,10 +148,10 @@
     virtual status_t updateActiveBuffer() = 0;
     virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
 
-    // We generate InputWindowHandles for all buffered layers regardless of whether they
+    // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
     // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
     // detection.
-    bool needsInputInfo() const override { return true; }
+    bool needsInputInfo() const override { return !mPotentialCursor; }
 
 protected:
     struct BufferInfo {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4dabd2b..81b3ccf 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -59,12 +59,14 @@
 class DisplaySurface;
 } // namespace compositionengine
 
-class DisplayDevice : public LightRefBase<DisplayDevice> {
+class DisplayDevice : public RefBase {
 public:
     constexpr static float sDefaultMinLumiance = 0.0;
     constexpr static float sDefaultMaxLumiance = 500.0;
 
     explicit DisplayDevice(DisplayDeviceCreationArgs& args);
+
+    // Must be destroyed on the main thread because it may call into HWComposer.
     virtual ~DisplayDevice();
 
     std::shared_ptr<compositionengine::Display> getCompositionDisplay() const {
@@ -246,21 +248,18 @@
 
 class DisplayRenderArea : public RenderArea {
 public:
-    DisplayRenderArea(const sp<const DisplayDevice>& display,
-                      RotationFlags rotation = ui::Transform::ROT_0)
-          : DisplayRenderArea(display, display->getBounds(),
-                              static_cast<uint32_t>(display->getWidth()),
-                              static_cast<uint32_t>(display->getHeight()),
-                              display->getCompositionDataSpace(), rotation) {}
-
-    DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, uint32_t reqWidth,
-                      uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation,
-                      bool allowSecureLayers = true)
-          : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
-                       display->getViewport(), applyDeviceOrientation(rotation, display)),
-            mDisplay(std::move(display)),
-            mSourceCrop(sourceCrop),
-            mAllowSecureLayers(allowSecureLayers) {}
+    static std::unique_ptr<RenderArea> create(wp<const DisplayDevice> displayWeak,
+                                              const Rect& sourceCrop, ui::Size reqSize,
+                                              ui::Dataspace reqDataSpace, RotationFlags rotation,
+                                              bool allowSecureLayers = true) {
+        if (auto display = displayWeak.promote()) {
+            // Using new to access a private constructor.
+            return std::unique_ptr<DisplayRenderArea>(
+                    new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
+                                          rotation, allowSecureLayers));
+        }
+        return nullptr;
+    }
 
     const ui::Transform& getTransform() const override { return mTransform; }
     Rect getBounds() const override { return mDisplay->getBounds(); }
@@ -307,6 +306,14 @@
     }
 
 private:
+    DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, ui::Size reqSize,
+                      ui::Dataspace reqDataSpace, RotationFlags rotation, bool allowSecureLayers)
+          : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(),
+                       applyDeviceOrientation(rotation, display)),
+            mDisplay(std::move(display)),
+            mSourceCrop(sourceCrop),
+            mAllowSecureLayers(allowSecureLayers) {}
+
     static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag,
                                                 const sp<const DisplayDevice>& device) {
         uint32_t inverseRotate90 = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c355ebd..b800038 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -64,6 +64,8 @@
     const uint32_t id;
 };
 
+// See the comment for SurfaceFlinger::getHwComposer for the thread safety rules for accessing
+// this class.
 class HWComposer {
 public:
     struct DeviceRequestedChanges {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 1d8179c..4b4c050 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -85,6 +85,7 @@
 
     const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
     if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
+        std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper == nullptr) {
             return;
@@ -108,6 +109,7 @@
     }
 
     if (mSendUpdateImminent.load()) {
+        std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper == nullptr) {
             return;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 34e63e7..95eb0e2 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -19,6 +19,8 @@
 #include <atomic>
 #include <unordered_set>
 
+#include <utils/Mutex.h>
+
 #include "../Scheduler/OneShotTimer.h"
 #include "DisplayIdentification.h"
 
@@ -56,10 +58,11 @@
     void notifyDisplayUpdateImminent() override;
 
 private:
-    HalWrapper* getPowerHal();
+    HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
+    bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false;
+    std::mutex mPowerHalMutex;
 
     std::atomic_bool mBootFinished = false;
-    bool mReconnectPowerHal = false;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 49112dd..f36b67d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -866,13 +866,12 @@
     }
 
     // If we still have pending updates, we need to ensure SurfaceFlinger
-    // will keep calling doTransaction, and so we set the transaction flags.
+    // will keep calling doTransaction, and so we force a traversal.
     // However, our pending states won't clear until a frame is available,
-    // and so there is no need to specifically trigger a wakeup. Rather
-    // we set the flags and wait for something else to wake us up.
+    // and so there is no need to specifically trigger a wakeup.
     if (!mPendingStates.empty()) {
         setTransactionFlags(eTransactionNeeded);
-        mFlinger->setTransactionFlagsNoWake(eTraversalNeeded);
+        mFlinger->setTraversalNeeded();
     }
 
     mCurrentState.modified = false;
@@ -2409,7 +2408,15 @@
     // Position the touchable region relative to frame screen location and restrict it to frame
     // bounds.
     info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
-    info.visible = canReceiveInput();
+    // For compatibility reasons we let layers which can receive input
+    // receive input before they have actually submitted a buffer. Because
+    // of this we use canReceiveInput instead of isVisible to check the
+    // policy-visibility, ignoring the buffer state. However for layers with
+    // hasInputInfo()==false we can use the real visibility state.
+    // We are just using these layers for occlusion detection in
+    // InputDispatcher, and obviously if they aren't visible they can't occlude
+    // anything.
+    info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
 
     auto cropLayer = mDrawingState.touchableRegionCrop.promote();
     if (info.replaceTouchableRegionWithCrop) {
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 27353d8..398fd40 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -36,6 +36,7 @@
 
 #include "DisplayDevice.h"
 #include "Layer.h"
+#include "Promise.h"
 #include "Scheduler/DispSync.h"
 #include "SurfaceFlinger.h"
 
@@ -336,8 +337,20 @@
         return;
     }
 
-    const auto device = mFlinger.getDefaultDisplayDevice();
-    const auto orientation = ui::Transform::toRotationFlags(device->getOrientation());
+    wp<const DisplayDevice> displayWeak;
+
+    ui::LayerStack layerStack;
+    ui::Transform::RotationFlags orientation;
+    ui::Size displaySize;
+
+    {
+        // TODO(b/159112860): Don't keep sp<DisplayDevice> outside of SF main thread
+        const sp<const DisplayDevice> display = mFlinger.getDefaultDisplayDevice();
+        displayWeak = display;
+        layerStack = display->getLayerStack();
+        orientation = ui::Transform::toRotationFlags(display->getOrientation());
+        displaySize = display->getSize();
+    }
 
     std::vector<RegionSamplingThread::Descriptor> descriptors;
     Region sampleRegion;
@@ -346,20 +359,18 @@
         descriptors.emplace_back(descriptor);
     }
 
-    const Rect sampledArea = sampleRegion.bounds();
-
     auto dx = 0;
     auto dy = 0;
     switch (orientation) {
         case ui::Transform::ROT_90:
-            dx = device->getWidth();
+            dx = displaySize.getWidth();
             break;
         case ui::Transform::ROT_180:
-            dx = device->getWidth();
-            dy = device->getHeight();
+            dx = displaySize.getWidth();
+            dy = displaySize.getHeight();
             break;
         case ui::Transform::ROT_270:
-            dy = device->getHeight();
+            dy = displaySize.getHeight();
             break;
         default:
             break;
@@ -368,8 +379,13 @@
     ui::Transform t(orientation);
     auto screencapRegion = t.transform(sampleRegion);
     screencapRegion = screencapRegion.translate(dx, dy);
-    DisplayRenderArea renderArea(device, screencapRegion.bounds(), sampledArea.getWidth(),
-                                 sampledArea.getHeight(), ui::Dataspace::V0_SRGB, orientation);
+
+    const Rect sampledBounds = sampleRegion.bounds();
+
+    SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] {
+        return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
+                                         ui::Dataspace::V0_SRGB, orientation);
+    });
 
     std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
 
@@ -393,9 +409,9 @@
             constexpr bool roundOutwards = true;
             Rect transformed = transform.transform(bounds, roundOutwards);
 
-            // If this layer doesn't intersect with the larger sampledArea, skip capturing it
+            // If this layer doesn't intersect with the larger sampledBounds, skip capturing it
             Rect ignore;
-            if (!transformed.intersect(sampledArea, &ignore)) return;
+            if (!transformed.intersect(sampledBounds, &ignore)) return;
 
             // If the layer doesn't intersect a sampling area, skip capturing it
             bool intersectsAnyArea = false;
@@ -411,22 +427,22 @@
                   bounds.top, bounds.right, bounds.bottom);
             visitor(layer);
         };
-        mFlinger.traverseLayersInDisplay(device, filterVisitor);
+        mFlinger.traverseLayersInLayerStack(layerStack, filterVisitor);
     };
 
     sp<GraphicBuffer> buffer = nullptr;
-    if (mCachedBuffer && mCachedBuffer->getWidth() == sampledArea.getWidth() &&
-        mCachedBuffer->getHeight() == sampledArea.getHeight()) {
+    if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() &&
+        mCachedBuffer->getHeight() == sampledBounds.getHeight()) {
         buffer = mCachedBuffer;
     } else {
         const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
-        buffer = new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+        buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
                                    PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
     }
 
     bool ignored;
-    mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false /* identityTransform */,
-                                 true /* regionSampling */, ignored);
+    mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+                                 false /* identityTransform */, true /* regionSampling */, ignored);
 
     std::vector<Descriptor> activeDescriptors;
     for (const auto& descriptor : descriptors) {
@@ -437,7 +453,7 @@
 
     ALOGV("Sampling %zu descriptors", activeDescriptors.size());
     std::vector<float> lumas =
-            sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors, orientation);
+            sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation);
     if (lumas.size() != activeDescriptors.size()) {
         ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
               activeDescriptors.size());
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 6b0455a..a6246d9 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -23,11 +23,9 @@
 
     static float getCaptureFillValue(CaptureFill captureFill);
 
-    RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
-               ui::Dataspace reqDataSpace, const Rect& displayViewport,
-               RotationFlags rotation = ui::Transform::ROT_0)
-          : mReqWidth(reqWidth),
-            mReqHeight(reqHeight),
+    RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
+               const Rect& displayViewport, RotationFlags rotation = ui::Transform::ROT_0)
+          : mReqSize(reqSize),
             mReqDataSpace(reqDataSpace),
             mCaptureFill(captureFill),
             mRotationFlags(rotation),
@@ -70,8 +68,8 @@
     RotationFlags getRotationFlags() const { return mRotationFlags; }
 
     // Returns the size of the physical render area.
-    int getReqWidth() const { return static_cast<int>(mReqWidth); }
-    int getReqHeight() const { return static_cast<int>(mReqHeight); }
+    int getReqWidth() const { return mReqSize.width; }
+    int getReqHeight() const { return mReqSize.height; }
 
     // Returns the composition data space of the render area.
     ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
@@ -86,8 +84,7 @@
     const Rect& getDisplayViewport() const { return mDisplayViewport; }
 
 private:
-    const uint32_t mReqWidth;
-    const uint32_t mReqHeight;
+    const ui::Size mReqSize;
     const ui::Dataspace mReqDataSpace;
     const CaptureFill mCaptureFill;
     const RotationFlags mRotationFlags;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 6dbff14..a6036c6 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -595,4 +595,28 @@
     return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
 }
 
+RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
+    std::lock_guard lock(mLock);
+    const auto& deviceMin = getMinRefreshRate();
+    const auto& minByPolicy = getMinRefreshRateByPolicyLocked();
+    const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked();
+
+    // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
+    // the min allowed refresh rate is higher than the device min, we do not want to enable the
+    // timer.
+    if (deviceMin < minByPolicy) {
+        return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
+    }
+    if (minByPolicy == maxByPolicy) {
+        // Do not sent the call to toggle off kernel idle timer if the device min and policy min and
+        // max are all the same. This saves us extra unnecessary calls to sysprop.
+        if (deviceMin == minByPolicy) {
+            return RefreshRateConfigs::KernelIdleTimerAction::NoChange;
+        }
+        return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
+    }
+    // Turn on the timer in all other cases.
+    return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 584a5e7..8a51b85 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -82,6 +82,8 @@
             return configId != other.configId || hwcConfig != other.hwcConfig;
         }
 
+        bool operator<(const RefreshRate& other) const { return getFps() < other.getFps(); }
+
         bool operator==(const RefreshRate& other) const { return !(*this != other); }
 
     private:
@@ -271,6 +273,17 @@
     RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
                        HwcConfigIndexType currentConfigId);
 
+    // Class to enumerate options around toggling the kernel timer on and off. We have an option
+    // for no change to avoid extra calls to kernel.
+    enum class KernelIdleTimerAction {
+        NoChange, // Do not change the idle timer.
+        TurnOff,  // Turn off the idle timer.
+        TurnOn    // Turn on the idle timer.
+    };
+    // Checks whether kernel idle timer should be active depending the policy decisions around
+    // refresh rates.
+    KernelIdleTimerAction getIdleTimerAction() const;
+
 private:
     friend class RefreshRateConfigsTest;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9e24f909..730ea8f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -55,13 +55,24 @@
     virtual void kernelTimerChanged(bool expired) = 0;
 };
 
-class Scheduler {
+class IPhaseOffsetControl {
+public:
+    virtual ~IPhaseOffsetControl() = default;
+    virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0;
+};
+
+class Scheduler : public IPhaseOffsetControl {
 public:
     using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
     using ConfigEvent = scheduler::RefreshRateConfigEvent;
 
     // Indicates whether to start the transaction early, or at vsync time.
-    enum class TransactionStart { EARLY, NORMAL };
+    enum class TransactionStart {
+        Early,      // DEPRECATED. Start the transaction early. Times out on its own
+        EarlyStart, // Start the transaction early and keep this config until EarlyEnd
+        EarlyEnd,   // End the early config started at EarlyStart
+        Normal      // Start the transaction at the normal time
+    };
 
     Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
               const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
@@ -90,7 +101,7 @@
     void onScreenReleased(ConnectionHandle);
 
     // Modifies phase offset in the event thread.
-    void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset);
+    void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override;
 
     void getDisplayStatInfo(DisplayStatInfo* stats);
 
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index abeacfe..a596bce 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -338,10 +338,14 @@
     }
     auto& callback = it->second;
 
-    if (callback->wakeupTime()) {
+    auto const wakeupTime = callback->wakeupTime();
+    if (wakeupTime) {
         callback->disarm();
-        mIntendedWakeupTime = kInvalidTime;
-        rearmTimer(mTimeKeeper->now());
+
+        if (*wakeupTime == mIntendedWakeupTime) {
+            mIntendedWakeupTime = kInvalidTime;
+            rearmTimer(mTimeKeeper->now());
+        }
         return CancelResult::Cancelled;
     }
     return CancelResult::TooLate;
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 510dc2d..2567c04 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -31,11 +31,11 @@
 
 namespace android::scheduler {
 
-VSyncModulator::VSyncModulator(Scheduler& scheduler,
+VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl,
                                Scheduler::ConnectionHandle appConnectionHandle,
                                Scheduler::ConnectionHandle sfConnectionHandle,
                                const OffsetsConfig& config)
-      : mScheduler(scheduler),
+      : mPhaseOffsetControl(phaseOffsetControl),
         mAppConnectionHandle(appConnectionHandle),
         mSfConnectionHandle(sfConnectionHandle),
         mOffsetsConfig(config) {
@@ -51,14 +51,35 @@
 }
 
 void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
-    if (transactionStart == Scheduler::TransactionStart::EARLY) {
+    switch (transactionStart) {
+        case Scheduler::TransactionStart::EarlyStart:
+            ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart");
+            mExplicitEarlyWakeup = true;
+            break;
+        case Scheduler::TransactionStart::EarlyEnd:
+            ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart");
+            mExplicitEarlyWakeup = false;
+            break;
+        case Scheduler::TransactionStart::Normal:
+        case Scheduler::TransactionStart::Early:
+            // Non explicit don't change the explicit early wakeup state
+            break;
+    }
+
+    if (mTraceDetailedInfo) {
+        ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup);
+    }
+
+    if (!mExplicitEarlyWakeup &&
+        (transactionStart == Scheduler::TransactionStart::Early ||
+         transactionStart == Scheduler::TransactionStart::EarlyEnd)) {
         mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
         mEarlyTxnStartTime = std::chrono::steady_clock::now();
     }
 
     // An early transaction stays an early transaction.
     if (transactionStart == mTransactionStart ||
-        mTransactionStart == Scheduler::TransactionStart::EARLY) {
+        mTransactionStart == Scheduler::TransactionStart::EarlyEnd) {
         return;
     }
     mTransactionStart = transactionStart;
@@ -67,8 +88,8 @@
 
 void VSyncModulator::onTransactionHandled() {
     mTxnAppliedTime = std::chrono::steady_clock::now();
-    if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
-    mTransactionStart = Scheduler::TransactionStart::NORMAL;
+    if (mTransactionStart == Scheduler::TransactionStart::Normal) return;
+    mTransactionStart = Scheduler::TransactionStart::Normal;
     updateOffsets();
 }
 
@@ -91,11 +112,10 @@
 void VSyncModulator::onRefreshed(bool usedRenderEngine) {
     bool updateOffsetsNeeded = false;
 
-    // Apply a 1ms margin to account for potential data races
+    // Apply a margin to account for potential data races
     // This might make us stay in early offsets for one
     // additional frame but it's better to be conservative here.
-    static const constexpr std::chrono::nanoseconds kMargin = 1ms;
-    if ((mEarlyTxnStartTime.load() + kMargin) < mTxnAppliedTime.load()) {
+    if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) {
         if (mRemainingEarlyFrameCount > 0) {
             mRemainingEarlyFrameCount--;
             updateOffsetsNeeded = true;
@@ -121,8 +141,8 @@
 const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
     // Early offsets are used if we're in the middle of a refresh rate
     // change, or if we recently begin a transaction.
-    if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
-        mRefreshRateChangePending) {
+    if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd ||
+        mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
         return mOffsetsConfig.early;
     } else if (mRemainingRenderEngineUsageCount > 0) {
         return mOffsetsConfig.earlyGl;
@@ -139,8 +159,8 @@
 void VSyncModulator::updateOffsetsLocked() {
     const Offsets& offsets = getNextOffsets();
 
-    mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf);
-    mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app);
+    mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf);
+    mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app);
 
     mOffsets = offsets;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index d777ef9..ab678c9 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -38,6 +38,9 @@
     // switch in and out of gl composition.
     static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
 
+    // Margin used to account for potential data races
+    static const constexpr std::chrono::nanoseconds MARGIN_FOR_TX_APPLY = 1ms;
+
 public:
     // Wrapper for a collection of surfaceflinger/app offsets for a particular
     // configuration.
@@ -62,7 +65,7 @@
         bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
     };
 
-    VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle,
+    VSyncModulator(IPhaseOffsetControl&, ConnectionHandle appConnectionHandle,
                    ConnectionHandle sfConnectionHandle, const OffsetsConfig&);
 
     void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
@@ -91,13 +94,14 @@
     Offsets getOffsets() const EXCLUDES(mMutex);
 
 private:
+    friend class VSyncModulatorTest;
     // Returns the next offsets that we should be using
     const Offsets& getNextOffsets() const REQUIRES(mMutex);
     // Updates offsets and persists them into the scheduler framework.
     void updateOffsets() EXCLUDES(mMutex);
     void updateOffsetsLocked() REQUIRES(mMutex);
 
-    Scheduler& mScheduler;
+    IPhaseOffsetControl& mPhaseOffsetControl;
     const ConnectionHandle mAppConnectionHandle;
     const ConnectionHandle mSfConnectionHandle;
 
@@ -107,8 +111,9 @@
     Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
 
     std::atomic<Scheduler::TransactionStart> mTransactionStart =
-            Scheduler::TransactionStart::NORMAL;
+            Scheduler::TransactionStart::Normal;
     std::atomic<bool> mRefreshRateChangePending = false;
+    std::atomic<bool> mExplicitEarlyWakeup = false;
     std::atomic<int> mRemainingEarlyFrameCount = 0;
     std::atomic<int> mRemainingRenderEngineUsageCount = 0;
     std::atomic<std::chrono::steady_clock::time_point> mEarlyTxnStartTime = {};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4492f94..e68c484 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -23,6 +23,7 @@
 
 #include "SurfaceFlinger.h"
 
+#include <android-base/properties.h>
 #include <android/configuration.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -448,6 +449,9 @@
     }
 
     useFrameRateApi = use_frame_rate_api(true);
+
+    mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false);
+    base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false");
 }
 
 SurfaceFlinger::~SurfaceFlinger() = default;
@@ -1670,7 +1674,7 @@
     if (const auto displayId = getInternalDisplayIdLocked()) {
         sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
         if (display && display->isPoweredOn()) {
-            setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+            getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
         }
     }
 }
@@ -2748,7 +2752,8 @@
      * (perform the transaction for each of them if needed)
      */
 
-    if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
+    if ((transactionFlags & eTraversalNeeded) || mForceTraversal) {
+        mForceTraversal = false;
         mCurrentState.traverse([&](Layer* layer) {
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
             if (!trFlags) return;
@@ -2761,7 +2766,6 @@
                 mInputInfoChanged = true;
             }
         });
-        mTraversalNeededMainThread = false;
     }
 
     /*
@@ -3224,7 +3228,7 @@
 }
 
 uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
-    return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
+    return setTransactionFlags(flags, Scheduler::TransactionStart::Normal);
 }
 
 uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
@@ -3237,8 +3241,8 @@
     return old;
 }
 
-uint32_t SurfaceFlinger::setTransactionFlagsNoWake(uint32_t flags) {
-    return mTransactionFlags.fetch_or(flags);
+void SurfaceFlinger::setTraversalNeeded() {
+    mForceTraversal = true;
 }
 
 bool SurfaceFlinger::flushTransactionQueues() {
@@ -3438,18 +3442,39 @@
     // so we don't have to wake up again next frame to preform an uneeded traversal.
     if (isMainThread && (transactionFlags & eTraversalNeeded)) {
         transactionFlags = transactionFlags & (~eTraversalNeeded);
-        mTraversalNeededMainThread = true;
+        mForceTraversal = true;
     }
 
+    const auto transactionStart = [](uint32_t flags) {
+        if (flags & eEarlyWakeup) {
+            return Scheduler::TransactionStart::Early;
+        }
+        if (flags & eExplicitEarlyWakeupEnd) {
+            return Scheduler::TransactionStart::EarlyEnd;
+        }
+        if (flags & eExplicitEarlyWakeupStart) {
+            return Scheduler::TransactionStart::EarlyStart;
+        }
+        return Scheduler::TransactionStart::Normal;
+    }(flags);
+
     if (transactionFlags) {
         if (mInterceptor->isEnabled()) {
             mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
         }
 
+        // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
+        if (flags & eEarlyWakeup) {
+            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
+        }
+
+        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
+            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
+            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
+        }
+
         // this triggers the transaction
-        const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY
-                                                  : Scheduler::TransactionStart::NORMAL;
-        setTransactionFlags(transactionFlags, start);
+        setTransactionFlags(transactionFlags, transactionStart);
 
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
@@ -3486,6 +3511,13 @@
                 break;
             }
         }
+    } else {
+        // even if a transaction is not needed, we need to update VsyncModulator
+        // about explicit early indications
+        if (transactionStart == Scheduler::TransactionStart::EarlyStart ||
+            transactionStart == Scheduler::TransactionStart::EarlyEnd) {
+            mVSyncModulator->setTransactionStart(transactionStart);
+        }
     }
 }
 
@@ -4161,13 +4193,6 @@
     static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
 }
 
-void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled) {
-    if (mHWCVsyncState != enabled) {
-        getHwComposer().setVsyncEnabled(displayId, enabled);
-        mHWCVsyncState = enabled;
-    }
-}
-
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
     if (display->isVirtual()) {
         ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4196,7 +4221,7 @@
         }
         getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
-            setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+            getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
         }
@@ -4215,7 +4240,7 @@
         }
 
         // Make sure HWVsync is disabled before turning off the display
-        setVsyncEnabledInHWC(*displayId, hal::Vsync::DISABLE);
+        getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE);
 
         getHwComposer().setPowerMode(*displayId, mode);
         mVisibleRegionsDirty = true;
@@ -5322,8 +5347,7 @@
         const auto& min = mRefreshRateConfigs->getMinRefreshRate();
 
         if (current != min) {
-            const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
-            const bool timerExpired = kernelTimerEnabled && expired;
+            const bool timerExpired = mKernelIdleTimerEnabled && expired;
 
             if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
                 mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current);
@@ -5333,6 +5357,35 @@
     }));
 }
 
+void SurfaceFlinger::toggleKernelIdleTimer() {
+    using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
+
+    // If the support for kernel idle timer is disabled in SF code, don't do anything.
+    if (!mSupportKernelIdleTimer) {
+        return;
+    }
+    const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction();
+
+    switch (action) {
+        case KernelIdleTimerAction::TurnOff:
+            if (mKernelIdleTimerEnabled) {
+                ATRACE_INT("KernelIdleTimer", 0);
+                base::SetProperty(KERNEL_IDLE_TIMER_PROP, "false");
+                mKernelIdleTimerEnabled = false;
+            }
+            break;
+        case KernelIdleTimerAction::TurnOn:
+            if (!mKernelIdleTimerEnabled) {
+                ATRACE_INT("KernelIdleTimer", 1);
+                base::SetProperty(KERNEL_IDLE_TIMER_PROP, "true");
+                mKernelIdleTimerEnabled = true;
+            }
+            break;
+        case KernelIdleTimerAction::NoChange:
+            break;
+    }
+}
+
 // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
 class WindowDisconnector {
 public:
@@ -5362,27 +5415,33 @@
         renderAreaRotation = ui::Transform::ROT_0;
     }
 
-    sp<DisplayDevice> display;
+    wp<DisplayDevice> displayWeak;
+    ui::LayerStack layerStack;
+    ui::Size reqSize(reqWidth, reqHeight);
     {
         Mutex::Autolock lock(mStateLock);
-
-        display = getDisplayDeviceLocked(displayToken);
+        sp<DisplayDevice> display = getDisplayDeviceLocked(displayToken);
         if (!display) return NAME_NOT_FOUND;
+        displayWeak = display;
+        layerStack = display->getLayerStack();
 
         // set the requested width/height to the logical display viewport size
         // by default
         if (reqWidth == 0 || reqHeight == 0) {
-            reqWidth = uint32_t(display->getViewport().width());
-            reqHeight = uint32_t(display->getViewport().height());
+            reqSize = display->getViewport().getSize();
         }
     }
 
-    DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
-                                 renderAreaRotation, captureSecureLayers);
-    auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
-                                    std::placeholders::_1);
-    return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
-                               useIdentityTransform, outCapturedSecureLayers);
+    RenderAreaFuture renderAreaFuture = promise::defer([=] {
+        return DisplayRenderArea::create(displayWeak, sourceCrop, reqSize, reqDataspace,
+                                         renderAreaRotation, captureSecureLayers);
+    });
+
+    auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
+        traverseLayersInLayerStack(layerStack, visitor);
+    };
+    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, outBuffer,
+                               reqPixelFormat, useIdentityTransform, outCapturedSecureLayers);
 }
 
 static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) {
@@ -5438,19 +5497,20 @@
 
 status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* outDataspace,
                                        sp<GraphicBuffer>* outBuffer) {
-    sp<DisplayDevice> display;
-    uint32_t width;
-    uint32_t height;
+    ui::LayerStack layerStack;
+    wp<DisplayDevice> displayWeak;
+    ui::Size size;
     ui::Transform::RotationFlags captureOrientation;
     {
         Mutex::Autolock lock(mStateLock);
-        display = getDisplayByIdOrLayerStack(displayOrLayerStack);
+        sp<DisplayDevice> display = getDisplayByIdOrLayerStack(displayOrLayerStack);
         if (!display) {
             return NAME_NOT_FOUND;
         }
+        layerStack = display->getLayerStack();
+        displayWeak = display;
 
-        width = uint32_t(display->getViewport().width());
-        height = uint32_t(display->getViewport().height());
+        size = display->getViewport().getSize();
 
         const auto orientation = display->getOrientation();
         captureOrientation = ui::Transform::toRotationFlags(orientation);
@@ -5476,14 +5536,19 @@
                 pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
     }
 
-    DisplayRenderArea renderArea(display, Rect(), width, height, *outDataspace, captureOrientation,
-                                 false /* captureSecureLayers */);
+    RenderAreaFuture renderAreaFuture = promise::defer([=] {
+        return DisplayRenderArea::create(displayWeak, Rect(), size, *outDataspace,
+                                         captureOrientation, false /* captureSecureLayers */);
+    });
 
-    auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
-                                    std::placeholders::_1);
+    auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
+        traverseLayersInLayerStack(layerStack, visitor);
+    };
+
     bool ignored = false;
-    return captureScreenCommon(renderArea, traverseLayers, outBuffer, ui::PixelFormat::RGBA_8888,
-                               false /* useIdentityTransform */,
+
+    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, outBuffer,
+                               ui::PixelFormat::RGBA_8888, false /* useIdentityTransform */,
                                ignored /* outCapturedSecureLayers */);
 }
 
@@ -5497,9 +5562,9 @@
     class LayerRenderArea : public RenderArea {
     public:
         LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
-                        int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace,
-                        bool childrenOnly, const Rect& displayViewport)
-              : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace, displayViewport),
+                        ui::Size reqSize, Dataspace reqDataSpace, bool childrenOnly,
+                        const Rect& displayViewport)
+              : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport),
                 mLayer(layer),
                 mCrop(crop),
                 mNeedsFiltering(false),
@@ -5574,8 +5639,7 @@
         const bool mChildrenOnly;
     };
 
-    int reqWidth = 0;
-    int reqHeight = 0;
+    ui::Size reqSize;
     sp<Layer> parent;
     Rect crop(sourceCrop);
     std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
@@ -5612,8 +5676,7 @@
             // crop was not specified, or an invalid frame scale was provided.
             return BAD_VALUE;
         }
-        reqWidth = crop.width() * frameScale;
-        reqHeight = crop.height() * frameScale;
+        reqSize = ui::Size(crop.width() * frameScale, crop.height() * frameScale);
 
         for (const auto& handle : excludeHandles) {
             sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
@@ -5634,15 +5697,18 @@
     } // mStateLock
 
     // really small crop or frameScale
-    if (reqWidth <= 0) {
-        reqWidth = 1;
+    if (reqSize.width <= 0) {
+        reqSize.width = 1;
     }
-    if (reqHeight <= 0) {
-        reqHeight = 1;
+    if (reqSize.height <= 0) {
+        reqSize.height = 1;
     }
 
-    LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly,
-                               displayViewport);
+    RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr<RenderArea> {
+        return std::make_unique<LayerRenderArea>(this, parent, crop, reqSize, reqDataspace,
+                                                 childrenOnly, displayViewport);
+    });
+
     auto traverseLayers = [parent, childrenOnly,
                            &excludeLayers](const LayerVector::Visitor& visitor) {
         parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
@@ -5665,14 +5731,14 @@
     };
 
     bool outCapturedSecureLayers = false;
-    return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false,
-                               outCapturedSecureLayers);
+    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, outBuffer,
+                               reqPixelFormat, false, outCapturedSecureLayers);
 }
 
-status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
-                                             sp<GraphicBuffer>* outBuffer,
-                                             const ui::PixelFormat reqPixelFormat,
+                                             ui::Size bufferSize, sp<GraphicBuffer>* outBuffer,
+                                             ui::PixelFormat reqPixelFormat,
                                              bool useIdentityTransform,
                                              bool& outCapturedSecureLayers) {
     ATRACE_CALL();
@@ -5680,16 +5746,16 @@
     // TODO(b/116112787) Make buffer usage a parameter.
     const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
             GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-    *outBuffer =
-            getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
-                                             static_cast<android_pixel_format>(reqPixelFormat), 1,
-                                             usage, "screenshot");
+    *outBuffer = getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
+                                                  static_cast<android_pixel_format>(reqPixelFormat),
+                                                  1, usage, "screenshot");
 
-    return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform,
-                               false /* regionSampling */, outCapturedSecureLayers);
+    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, *outBuffer,
+                               useIdentityTransform, false /* regionSampling */,
+                               outCapturedSecureLayers);
 }
 
-status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
                                              const sp<GraphicBuffer>& buffer,
                                              bool useIdentityTransform, bool regionSampling,
@@ -5702,23 +5768,28 @@
 
     do {
         std::tie(result, syncFd) =
-                schedule([&] {
+                schedule([&]() -> std::pair<status_t, int> {
                     if (mRefreshPending) {
-                        ATRACE_NAME("Skipping screenshot for now");
-                        return std::make_pair(EAGAIN, -1);
+                        ALOGW("Skipping screenshot for now");
+                        return {EAGAIN, -1};
+                    }
+                    std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
+                    if (!renderArea) {
+                        ALOGW("Skipping screen capture because of invalid render area.");
+                        return {NO_MEMORY, -1};
                     }
 
                     status_t result = NO_ERROR;
                     int fd = -1;
 
                     Mutex::Autolock lock(mStateLock);
-                    renderArea.render([&] {
-                        result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
+                    renderArea->render([&] {
+                        result = captureScreenImplLocked(*renderArea, traverseLayers, buffer.get(),
                                                          useIdentityTransform, forSystem, &fd,
                                                          regionSampling, outCapturedSecureLayers);
                     });
 
-                    return std::make_pair(result, fd);
+                    return {result, fd};
                 }).get();
     } while (result == EAGAIN);
 
@@ -5877,17 +5948,17 @@
     layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
 }
 
-void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& display,
-                                             const LayerVector::Visitor& visitor) {
+void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack,
+                                                const LayerVector::Visitor& visitor) {
     // We loop through the first level of layers without traversing,
     // as we need to determine which layers belong to the requested display.
     for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
+        if (!layer->belongsToDisplay(layerStack, false)) {
             continue;
         }
         // relative layers are traversed in Layer::traverseInZOrder
         layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
+            if (!layer->belongsToDisplay(layerStack, false)) {
                 return;
             }
             if (!layer->isVisible()) {
@@ -5960,14 +6031,14 @@
           currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
           currentPolicy.appRequestRange.max);
 
-    // TODO(b/140204874): This hack triggers a notification that something has changed, so
-    // that listeners that care about a change in allowed configs can get the notification.
-    // Giving current ActiveConfig so that most other listeners would just drop the event
+    // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
+    // be depending in this callback.
     const nsecs_t vsyncPeriod =
             mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig())
                     .getVsyncPeriod();
     mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value,
                                               display->getActiveConfig(), vsyncPeriod);
+    toggleKernelIdleTimer();
 
     auto configId = mScheduler->getPreferredConfigId();
     auto& preferredRefreshRate = configId
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5c81a54..6a3937f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -302,7 +302,6 @@
 
     // main thread function to enable/disable h/w composer event
     void setPrimaryVsyncEnabledInternal(bool enabled) REQUIRES(mStateLock);
-    void setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled);
 
     // called on the main thread by MessageQueue when an internal message
     // is received
@@ -536,6 +535,13 @@
     void repaintEverythingForHWC() override;
     // Called when kernel idle timer has expired. Used to update the refresh rate overlay.
     void kernelTimerChanged(bool expired) override;
+    // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
+    void toggleKernelIdleTimer();
+    // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
+    // make calls to sys prop each time.
+    bool mKernelIdleTimerEnabled = false;
+    // Keeps track of whether the kernel timer is supported on the SF side.
+    bool mSupportKernelIdleTimer = false;
     /* ------------------------------------------------------------------------
      * Message handling
      */
@@ -628,12 +634,12 @@
     uint32_t peekTransactionFlags();
     // Can only be called from the main thread or with mStateLock held
     uint32_t setTransactionFlags(uint32_t flags);
-    // Set the transaction flags, but don't trigger a wakeup! We use this cases where
-    // there are still pending transactions but we know they won't be ready until a frame
+    // Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases
+    // where there are still pending transactions but we know they won't be ready until a frame
     // arrives from a different layer. So we need to ensure we performTransaction from invalidate
     // but there is no need to try and wake up immediately to do it. Rather we rely on
-    // onFrameAvailable to wake us up.
-    uint32_t setTransactionFlagsNoWake(uint32_t flags);
+    // onFrameAvailable or another layer update to wake us up.
+    void setTraversalNeeded();
     uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
     void commitTransaction() REQUIRES(mStateLock);
     void commitOffscreenLayers();
@@ -712,16 +718,17 @@
     void startBootAnim();
 
     using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
+    using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
 
     void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                 const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
                                 bool regionSampling, int* outSyncFd);
-    status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
-                                 sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
+    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
+                                 sp<GraphicBuffer>* outBuffer, ui::PixelFormat,
                                  bool useIdentityTransform, bool& outCapturedSecureLayers);
-    status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
-                                 const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
-                                 bool regionSampling, bool& outCapturedSecureLayers);
+    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp<GraphicBuffer>&,
+                                 bool useIdentityTransform, bool regionSampling,
+                                 bool& outCapturedSecureLayers);
     sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
     sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
     status_t captureScreenImplLocked(const RenderArea& renderArea,
@@ -729,8 +736,7 @@
                                      const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
                                      bool forSystem, int* outSyncFd, bool regionSampling,
                                      bool& outCapturedSecureLayers);
-    void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
-                                 const LayerVector::Visitor& visitor);
+    void traverseLayersInLayerStack(ui::LayerStack, const LayerVector::Visitor&);
 
     sp<StartPropertySetThread> mStartPropertySetThread;
 
@@ -999,7 +1005,7 @@
     bool mTransactionPending = false;
     bool mAnimTransactionPending = false;
     SortedVector<sp<Layer>> mLayersPendingRemoval;
-    bool mTraversalNeededMainThread = false;
+    bool mForceTraversal = false;
 
     // global color transform states
     Daltonizer mDaltonizer;
@@ -1211,6 +1217,7 @@
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
+    hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
 
     /* ------------------------------------------------------------------------
      * Generic Layer Metadata
@@ -1281,10 +1288,6 @@
     // be any issues with a raw pointer referencing an invalid object.
     std::unordered_set<Layer*> mOffscreenLayers;
 
-    // Flags to capture the state of Vsync in HWC
-    hal::Vsync mHWCVsyncState = hal::Vsync::DISABLE;
-    hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
-
     // Fields tracking the current jank event: when it started and how many
     // janky frames there are.
     nsecs_t mMissedFrameJankStart = 0;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 0cdff8f..ca24493 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -154,6 +154,9 @@
 
 status_t TransactionCompletedThread::finalizePendingCallbackHandles(
         const std::deque<sp<CallbackHandle>>& handles) {
+    if (handles.empty()) {
+        return NO_ERROR;
+    }
     std::lock_guard lock(mMutex);
     if (!mRunning) {
         ALOGE("cannot add presented callback handle because the callback thread isn't running");
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7574ff1..3c4a791 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -62,6 +62,7 @@
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
         "VSyncDispatchRealtimeTest.cpp",
+        "VSyncModulatorTest.cpp",
         "VSyncPredictorTest.cpp",
         "VSyncReactorTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 95e2ef5..456891e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -233,23 +233,22 @@
     constexpr bool forSystem = true;
     constexpr bool regionSampling = false;
 
-    DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
-                                 DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
-                                 ui::Transform::ROT_0);
+    auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
+                                                ui::Dataspace::V0_SRGB, ui::Transform::ROT_0);
 
     auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
-        return mFlinger.traverseLayersInDisplay(mDisplay, visitor);
+        return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), visitor);
     };
 
     // TODO: Eliminate expensive/real allocation if possible.
     const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
             GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-    mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+    mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(),
                                              HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
 
     int fd = -1;
     status_t result =
-            mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+            mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(),
                                              useIdentityTransform, forSystem, &fd, regionSampling);
     if (fd >= 0) {
         close(fd);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index f24575e..fed591c 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1420,6 +1420,34 @@
     }
 }
 
+TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
+    EXPECT_TRUE(mExpected60Config < mExpected90Config);
+    EXPECT_FALSE(mExpected60Config < mExpected60Config);
+    EXPECT_FALSE(mExpected90Config < mExpected90Config);
+}
+
+TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
+    using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
+
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+    // SetPolicy(60, 90), current 90Hz => TurnOn.
+    EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+    // SetPolicy(60, 90), current 60Hz => TurnOn.
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 90}}), 0);
+    EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+    // SetPolicy(60, 60), current 60Hz => NoChange, avoid extra calls.
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+    EXPECT_EQ(KernelIdleTimerAction::NoChange, refreshRateConfigs->getIdleTimerAction());
+
+    // SetPolicy(90, 90), current 90Hz => TurnOff.
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+    EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
+}
+
 } // namespace
 } // namespace scheduler
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4652da0..f630103 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -341,9 +341,9 @@
                                                  regionSampling, ignored);
     }
 
-    auto traverseLayersInDisplay(const sp<const DisplayDevice>& display,
-                                 const LayerVector::Visitor& visitor) {
-        return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, visitor);
+    auto traverseLayersInLayerStack(ui::LayerStack layerStack,
+                                    const LayerVector::Visitor& visitor) {
+        return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, visitor);
     }
 
     auto getDisplayNativePrimaries(const sp<IBinder>& displayToken,
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 793cb8b..d940dc5 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -701,6 +701,52 @@
     EXPECT_THAT(cb.mCalls.size(), Eq(1));
 }
 
+// b/154303580.
+TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+    CountingCallback cb1(mDispatch);
+    CountingCallback cb2(mDispatch);
+
+    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+    mMockClock.setLag(100);
+    mMockClock.advanceBy(620);
+
+    EXPECT_EQ(mDispatch.cancel(cb2), CancelResult::Cancelled);
+
+    mMockClock.advanceBy(80);
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+    CountingCallback cb1(mDispatch);
+    CountingCallback cb2(mDispatch);
+
+    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+    mMockClock.setLag(100);
+    mMockClock.advanceBy(620);
+
+    EXPECT_EQ(mDispatch.cancel(cb1), CancelResult::Cancelled);
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+    mMockClock.advanceToNextCallback();
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(1));
+}
+
 class VSyncDispatchTimerQueueEntryTest : public testing::Test {
 protected:
     nsecs_t const mPeriod = 1000;
diff --git a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
new file mode 100644
index 0000000..9c1ec07
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/VSyncModulator.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+
+namespace android::scheduler {
+
+class MockScheduler : public IPhaseOffsetControl {
+public:
+    void setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+        mPhaseOffset[handle] = phaseOffset;
+    }
+
+    nsecs_t getOffset(ConnectionHandle handle) { return mPhaseOffset[handle]; }
+
+private:
+    std::unordered_map<ConnectionHandle, nsecs_t> mPhaseOffset;
+};
+
+class VSyncModulatorTest : public testing::Test {
+protected:
+    static constexpr auto MIN_EARLY_FRAME_COUNT_TRANSACTION =
+            VSyncModulator::MIN_EARLY_FRAME_COUNT_TRANSACTION;
+    // Add a 1ms slack to avoid strange timer race conditions.
+    static constexpr auto MARGIN_FOR_TX_APPLY = VSyncModulator::MARGIN_FOR_TX_APPLY + 1ms;
+
+    // Used to enumerate the different offsets we have
+    enum {
+        SF_LATE,
+        APP_LATE,
+        SF_EARLY,
+        APP_EARLY,
+        SF_EARLY_GL,
+        APP_EARLY_GL,
+    };
+
+    std::unique_ptr<VSyncModulator> mVSyncModulator;
+    MockScheduler mMockScheduler;
+    ConnectionHandle mAppConnection{1};
+    ConnectionHandle mSfConnection{2};
+    VSyncModulator::OffsetsConfig mOffsets = {{SF_EARLY, APP_EARLY},
+                                              {SF_EARLY_GL, APP_EARLY_GL},
+                                              {SF_LATE, APP_LATE}};
+
+    void SetUp() override {
+        mVSyncModulator = std::make_unique<VSyncModulator>(mMockScheduler, mAppConnection,
+                                                           mSfConnection, mOffsets);
+        mVSyncModulator->setPhaseOffsets(mOffsets);
+
+        EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+    };
+
+    void TearDown() override { mVSyncModulator.reset(); }
+};
+
+TEST_F(VSyncModulatorTest, Normal) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+    }
+}
+
+TEST_F(VSyncModulatorTest, EarlyEnd) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStart) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithEarly) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Early);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithMoreTransactions) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+        std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEnd) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+        std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+} // namespace android::scheduler
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index b4342bd..e3c254d 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -16,6 +16,7 @@
     name: "libvibratorservice",
 
     srcs: [
+        "VibratorCallbackScheduler.cpp",
         "VibratorHalWrapper.cpp",
     ],
 
diff --git a/services/vibratorservice/VibratorCallbackScheduler.cpp b/services/vibratorservice/VibratorCallbackScheduler.cpp
new file mode 100644
index 0000000..3f8cd67
--- /dev/null
+++ b/services/vibratorservice/VibratorCallbackScheduler.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <chrono>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+bool DelayedCallback::isExpired() const {
+    return mExpiration <= std::chrono::steady_clock::now();
+}
+
+DelayedCallback::Timestamp DelayedCallback::getExpiration() const {
+    return mExpiration;
+}
+
+void DelayedCallback::run() const {
+    mCallback();
+}
+
+bool DelayedCallback::operator<(const DelayedCallback& other) const {
+    return mExpiration < other.mExpiration;
+}
+
+bool DelayedCallback::operator>(const DelayedCallback& other) const {
+    return mExpiration > other.mExpiration;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+CallbackScheduler::~CallbackScheduler() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mFinished = true;
+    }
+    mCondition.notify_all();
+    if (mCallbackThread && mCallbackThread->joinable()) {
+        mCallbackThread->join();
+    }
+}
+
+void CallbackScheduler::schedule(std::function<void()> callback, std::chrono::milliseconds delay) {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (mCallbackThread == nullptr) {
+            mCallbackThread = std::make_unique<std::thread>(&CallbackScheduler::loop, this);
+        }
+        mQueue.emplace(DelayedCallback(callback, delay));
+    }
+    mCondition.notify_all();
+}
+
+void CallbackScheduler::loop() {
+    while (true) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (mFinished) {
+            // Destructor was called, so let the callback thread die.
+            break;
+        }
+        while (!mQueue.empty() && mQueue.top().isExpired()) {
+            mQueue.top().run();
+            mQueue.pop();
+        }
+        if (mQueue.empty()) {
+            // Wait until a new callback is scheduled.
+            mCondition.wait(mMutex);
+        } else {
+            // Wait until next callback expires, or a new one is scheduled.
+            mCondition.wait_until(mMutex, mQueue.top().getExpiration());
+        }
+    }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index db27bd9..1420bf5 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -23,6 +23,7 @@
 
 #include <utils/Log.h>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 using android::hardware::vibrator::CompositeEffect;
@@ -46,10 +47,12 @@
 template <class T>
 HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
     if (cache.has_value()) {
-        return HalResult<T>::ok(cache.value());
+        // Return copy of cached value.
+        return HalResult<T>::ok(*cache);
     }
     HalResult<T> ret = loadFn();
     if (ret.isOk()) {
+        // Cache copy of returned value.
         cache.emplace(ret.value());
     }
     return ret;
@@ -62,27 +65,6 @@
     return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end());
 }
 
-template <class I, class T>
-using perform_fn = hardware::Return<void> (I::*)(T, V1_0::EffectStrength,
-                                                 V1_0::IVibrator::perform_cb);
-
-template <class I, class T>
-HalResult<milliseconds> perform(perform_fn<I, T> performFn, sp<I> handle, T effect,
-                                EffectStrength strength) {
-    V1_0::Status status;
-    int32_t lengthMs;
-    V1_0::IVibrator::perform_cb effectCallback = [&status, &lengthMs](V1_0::Status retStatus,
-                                                                      uint32_t retLengthMs) {
-        status = retStatus;
-        lengthMs = retLengthMs;
-    };
-
-    V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
-    auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
-
-    return HalResult<milliseconds>::fromReturn(result, status, milliseconds(lengthMs));
-}
-
 // -------------------------------------------------------------------------------------------------
 
 template <typename T>
@@ -179,7 +161,7 @@
 
 class HalCallbackWrapper : public Aidl::BnVibratorCallback {
 public:
-    HalCallbackWrapper(const std::function<void()>& completionCallback)
+    HalCallbackWrapper(std::function<void()> completionCallback)
           : mCompletionCallback(completionCallback) {}
 
     binder::Status onComplete() override {
@@ -200,8 +182,17 @@
 
 HalResult<void> AidlHalWrapper::on(milliseconds timeout,
                                    const std::function<void()>& completionCallback) {
-    auto cb = new HalCallbackWrapper(completionCallback);
-    return HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+    HalResult<Capabilities> capabilities = getCapabilities();
+    bool supportsCallback = capabilities.isOk() &&
+            static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK);
+    auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
+    auto ret = HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+    if (!supportsCallback && ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, timeout);
+    }
+
+    return ret;
 }
 
 HalResult<void> AidlHalWrapper::off() {
@@ -227,39 +218,56 @@
 
 HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
     std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
-    static auto loadFn = [this]() {
-        int32_t capabilities = 0;
-        auto result = mHandle->getCapabilities(&capabilities);
-        return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
-    };
-    return loadCached<Capabilities>(loadFn, mCapabilities);
+    return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
+                                    mCapabilities);
 }
 
 HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
     std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
-    static auto loadFn = [this]() {
-        std::vector<Effect> supportedEffects;
-        auto result = mHandle->getSupportedEffects(&supportedEffects);
-        return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
-    };
-    return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects);
+    return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
+                                                     this),
+                                           mSupportedEffects);
 }
 
 HalResult<milliseconds> AidlHalWrapper::performEffect(
         Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    HalResult<Capabilities> capabilities = getCapabilities();
+    bool supportsCallback = capabilities.isOk() &&
+            static_cast<int32_t>(capabilities.value() & Capabilities::PERFORM_CALLBACK);
+    auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
     int32_t lengthMs;
-    auto cb = new HalCallbackWrapper(completionCallback);
     auto result = mHandle->perform(effect, strength, cb, &lengthMs);
-    return HalResult<milliseconds>::fromStatus(result, milliseconds(lengthMs));
+    milliseconds length = milliseconds(lengthMs);
+
+    auto ret = HalResult<milliseconds>::fromStatus(result, length);
+    if (!supportsCallback && ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, length);
+    }
+
+    return ret;
 }
 
 HalResult<void> AidlHalWrapper::performComposedEffect(
         const std::vector<CompositeEffect>& primitiveEffects,
         const std::function<void()>& completionCallback) {
+    // This method should always support callbacks, so no need to double check.
     auto cb = new HalCallbackWrapper(completionCallback);
     return HalResult<void>::fromStatus(mHandle->compose(primitiveEffects, cb));
 }
 
+HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
+    int32_t capabilities = 0;
+    auto result = mHandle->getCapabilities(&capabilities);
+    return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
+}
+
+HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() {
+    std::vector<Effect> supportedEffects;
+    auto result = mHandle->getSupportedEffects(&supportedEffects);
+    return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
+}
+
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> HidlHalWrapperV1_0::ping() {
@@ -267,10 +275,14 @@
     return HalResult<void>::fromReturn(result);
 }
 
-HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>&) {
+HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout,
+                                       const std::function<void()>& completionCallback) {
     auto result = mHandleV1_0->on(timeout.count());
-    auto status = result.withDefault(V1_0::Status::UNKNOWN_ERROR);
-    return HalResult<void>::fromStatus(status);
+    auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+    if (ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, timeout);
+    }
+    return ret;
 }
 
 HalResult<void> HidlHalWrapperV1_0::off() {
@@ -309,11 +321,10 @@
     return HalResult<std::vector<Effect>>::unsupported();
 }
 
-HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -334,17 +345,44 @@
     return HalResult<Capabilities>::fromReturn(result, capabilities);
 }
 
+template <class I, class T>
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternal(
+        perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength,
+        const std::function<void()>& completionCallback) {
+    V1_0::Status status;
+    int32_t lengthMs;
+    auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
+        status = retStatus;
+        lengthMs = retLengthMs;
+    };
+
+    V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
+    auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
+    milliseconds length = milliseconds(lengthMs);
+
+    auto ret = HalResult<milliseconds>::fromReturn(result, status, length);
+    if (ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, length);
+    }
+
+    return ret;
+}
+
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternalV1_0(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_0::Effect e = static_cast<V1_0::Effect>(effect);
+    return performInternal(&V1_0::IVibrator::perform, mHandleV1_0, e, strength, completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
-HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
-        V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
-        return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+        return performInternalV1_1(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -352,21 +390,25 @@
     return HalResult<milliseconds>::unsupported();
 }
 
+HalResult<milliseconds> HidlHalWrapperV1_1::performInternalV1_1(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
+    return performInternal(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength,
+                           completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
-HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
-        V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
-        return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+        return performInternalV1_1(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_2::Effect>(effect)) {
-        V1_2::Effect e = static_cast<V1_2::Effect>(effect);
-        return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+        return performInternalV1_2(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -374,6 +416,13 @@
     return HalResult<milliseconds>::unsupported();
 }
 
+HalResult<milliseconds> HidlHalWrapperV1_2::performInternalV1_2(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_2::Effect e = static_cast<V1_2::Effect>(effect);
+    return performInternal(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength,
+                           completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
@@ -381,23 +430,19 @@
     return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
 }
 
-HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
-        V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
-        return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+        return performInternalV1_1(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_2::Effect>(effect)) {
-        V1_2::Effect e = static_cast<V1_2::Effect>(effect);
-        return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+        return performInternalV1_2(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_3::Effect>(effect)) {
-        V1_3::Effect e = static_cast<V1_3::Effect>(effect);
-        return perform(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength);
+        return performInternalV1_3(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -418,6 +463,13 @@
     return HalResult<Capabilities>::fromReturn(result, capabilities);
 }
 
+HalResult<milliseconds> HidlHalWrapperV1_3::performInternalV1_3(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_3::Effect e = static_cast<V1_3::Effect>(effect);
+    return performInternal(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength,
+                           completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
 }; // namespace vibrator
diff --git a/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h
new file mode 100644
index 0000000..2c194b5
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
+#define ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
+
+#include <android-base/thread_annotations.h>
+#include <chrono>
+#include <condition_variable>
+#include <queue>
+#include <thread>
+
+namespace android {
+
+namespace vibrator {
+
+// Wrapper for a callback to be executed after a delay.
+class DelayedCallback {
+public:
+    using Timestamp = std::chrono::time_point<std::chrono::steady_clock>;
+
+    DelayedCallback(std::function<void()> callback, std::chrono::milliseconds delay)
+          : mCallback(callback), mExpiration(std::chrono::steady_clock::now() + delay) {}
+    ~DelayedCallback() = default;
+
+    void run() const;
+    bool isExpired() const;
+    Timestamp getExpiration() const;
+
+    // Compare by expiration time, where A < B when A expires first.
+    bool operator<(const DelayedCallback& other) const;
+    bool operator>(const DelayedCallback& other) const;
+
+private:
+    std::function<void()> mCallback;
+    Timestamp mExpiration;
+};
+
+// Schedules callbacks to be executed after a delay.
+class CallbackScheduler {
+public:
+    CallbackScheduler() : mCallbackThread(nullptr), mFinished(false) {}
+    virtual ~CallbackScheduler();
+
+    virtual void schedule(std::function<void()> callback, std::chrono::milliseconds delay);
+
+private:
+    std::condition_variable_any mCondition;
+    std::mutex mMutex;
+
+    // Lazily instantiated only at the first time this scheduler is used.
+    std::unique_ptr<std::thread> mCallbackThread;
+
+    // Used to quit the callback thread when this instance is being destroyed.
+    bool mFinished GUARDED_BY(mMutex);
+
+    // Priority queue with reverse comparator, so tasks that expire first will be on top.
+    std::priority_queue<DelayedCallback, std::vector<DelayedCallback>,
+                        std::greater<DelayedCallback>>
+            mQueue GUARDED_BY(mMutex);
+
+    void loop();
+};
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 1a1f64b..0f9aacb 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -21,6 +21,8 @@
 #include <android/hardware/vibrator/1.3/IVibrator.h>
 #include <android/hardware/vibrator/IVibrator.h>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
 namespace android {
 
 namespace vibrator {
@@ -46,7 +48,7 @@
                                    hardware::vibrator::V1_0::Status status, T data);
 
     // This will throw std::bad_optional_access if this result is not ok.
-    T value() const { return mValue.value(); }
+    const T& value() const { return mValue.value(); }
     bool isOk() const { return !mUnsupported && mValue.has_value(); }
     bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
     bool isUnsupported() const { return mUnsupported; }
@@ -122,6 +124,8 @@
 // Wrapper for Vibrator HAL handlers.
 class HalWrapper {
 public:
+    explicit HalWrapper(std::shared_ptr<CallbackScheduler> scheduler)
+          : mCallbackScheduler(std::move(scheduler)) {}
     virtual ~HalWrapper() = default;
 
     virtual HalResult<void> ping() = 0;
@@ -147,13 +151,19 @@
     virtual HalResult<void> performComposedEffect(
             const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
             const std::function<void()>& completionCallback) = 0;
+
+protected:
+    // Shared pointer to allow CallbackScheduler to outlive this wrapper.
+    const std::shared_ptr<CallbackScheduler> mCallbackScheduler;
 };
 
 // Wrapper for the AIDL Vibrator HAL.
 class AidlHalWrapper : public HalWrapper {
 public:
-    explicit AidlHalWrapper(sp<hardware::vibrator::IVibrator> handle)
-          : mHandle(std::move(handle)) {}
+    AidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler,
+                   sp<hardware::vibrator::IVibrator> handle)
+          : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {}
+    virtual ~AidlHalWrapper() = default;
 
     virtual HalResult<void> ping() override;
 
@@ -186,13 +196,19 @@
     std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
     std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
             GUARDED_BY(mSupportedEffectsMutex);
+
+    // Loads directly from IVibrator handle, skipping caches.
+    HalResult<Capabilities> getCapabilitiesInternal();
+    HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
 };
 
 // Wrapper for the HDIL Vibrator HAL v1.0.
 class HidlHalWrapperV1_0 : public HalWrapper {
 public:
-    explicit HidlHalWrapperV1_0(sp<hardware::vibrator::V1_0::IVibrator> handle)
-          : mHandleV1_0(std::move(handle)) {}
+    HidlHalWrapperV1_0(std::shared_ptr<CallbackScheduler> scheduler,
+                       sp<hardware::vibrator::V1_0::IVibrator> handle)
+          : HalWrapper(std::move(scheduler)), mHandleV1_0(std::move(handle)) {}
+    virtual ~HidlHalWrapperV1_0() = default;
 
     virtual HalResult<void> ping() override;
 
@@ -225,14 +241,31 @@
 
     // Loads directly from IVibrator handle, skipping the mCapabilities cache.
     virtual HalResult<Capabilities> getCapabilitiesInternal();
+
+    template <class I, class T>
+    using perform_fn =
+            hardware::Return<void> (I::*)(T, hardware::vibrator::V1_0::EffectStrength,
+                                          hardware::vibrator::V1_0::IVibrator::perform_cb);
+
+    template <class I, class T>
+    HalResult<std::chrono::milliseconds> performInternal(
+            perform_fn<I, T> performFn, sp<I> handle, T effect,
+            hardware::vibrator::EffectStrength strength,
+            const std::function<void()>& completionCallback);
+
+    HalResult<std::chrono::milliseconds> performInternalV1_0(
+            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+            const std::function<void()>& completionCallback);
 };
 
 // Wrapper for the HDIL Vibrator HAL v1.1.
 class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
 public:
-    explicit HidlHalWrapperV1_1(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
-          : HidlHalWrapperV1_0(handleV1_0),
+    HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
+                       sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+          : HidlHalWrapperV1_0(std::move(scheduler), handleV1_0),
             mHandleV1_1(hardware::vibrator::V1_1::IVibrator::castFrom(handleV1_0)) {}
+    virtual ~HidlHalWrapperV1_1() = default;
 
     virtual HalResult<std::chrono::milliseconds> performEffect(
             hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -240,14 +273,20 @@
 
 protected:
     const sp<hardware::vibrator::V1_1::IVibrator> mHandleV1_1;
+
+    HalResult<std::chrono::milliseconds> performInternalV1_1(
+            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+            const std::function<void()>& completionCallback);
 };
 
 // Wrapper for the HDIL Vibrator HAL v1.2.
 class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 {
 public:
-    explicit HidlHalWrapperV1_2(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
-          : HidlHalWrapperV1_1(handleV1_0),
+    HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
+                       sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+          : HidlHalWrapperV1_1(std::move(scheduler), handleV1_0),
             mHandleV1_2(hardware::vibrator::V1_2::IVibrator::castFrom(handleV1_0)) {}
+    virtual ~HidlHalWrapperV1_2() = default;
 
     virtual HalResult<std::chrono::milliseconds> performEffect(
             hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -255,14 +294,20 @@
 
 protected:
     const sp<hardware::vibrator::V1_2::IVibrator> mHandleV1_2;
+
+    HalResult<std::chrono::milliseconds> performInternalV1_2(
+            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+            const std::function<void()>& completionCallback);
 };
 
 // Wrapper for the HDIL Vibrator HAL v1.3.
 class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 {
 public:
-    explicit HidlHalWrapperV1_3(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
-          : HidlHalWrapperV1_2(handleV1_0),
+    HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
+                       sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+          : HidlHalWrapperV1_2(std::move(scheduler), handleV1_0),
             mHandleV1_3(hardware::vibrator::V1_3::IVibrator::castFrom(handleV1_0)) {}
+    virtual ~HidlHalWrapperV1_3() = default;
 
     virtual HalResult<void> setExternalControl(bool enabled) override;
 
@@ -274,6 +319,9 @@
     const sp<hardware::vibrator::V1_3::IVibrator> mHandleV1_3;
 
     virtual HalResult<Capabilities> getCapabilitiesInternal() override;
+    HalResult<std::chrono::milliseconds> performInternalV1_3(
+            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+            const std::function<void()>& completionCallback);
 };
 
 // -------------------------------------------------------------------------------------------------
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 7c038e9..fa399ad 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -16,6 +16,7 @@
     name: "libvibratorservice_test",
     test_suites: ["device-tests"],
     srcs: [
+        "VibratorCallbackSchedulerTest.cpp",
         "VibratorHalWrapperAidlTest.cpp",
         "VibratorHalWrapperHidlV1_0Test.cpp",
         "VibratorHalWrapperHidlV1_1Test.cpp",
diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
new file mode 100644
index 0000000..aaeb8f9
--- /dev/null
+++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "VibratorHalWrapperAidlTest"
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <condition_variable>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::chrono::time_point;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorCallbackSchedulerTest : public Test {
+public:
+    void SetUp() override {
+        mScheduler = std::make_unique<vibrator::CallbackScheduler>();
+        std::lock_guard<std::mutex> lock(mMutex);
+        mExpiredCallbacks.clear();
+    }
+
+protected:
+    std::mutex mMutex;
+    std::condition_variable_any mCondition;
+    std::unique_ptr<vibrator::CallbackScheduler> mScheduler = nullptr;
+    std::vector<int32_t> mExpiredCallbacks GUARDED_BY(mMutex);
+
+    std::function<void()> createCallback(int32_t id) {
+        return [=]() {
+            {
+                std::lock_guard<std::mutex> lock(mMutex);
+                mExpiredCallbacks.push_back(id);
+            }
+            mCondition.notify_all();
+        };
+    }
+
+    std::vector<int32_t> getExpiredCallbacks() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return std::vector<int32_t>(mExpiredCallbacks);
+    }
+
+    bool waitForCallbacks(uint32_t callbackCount, milliseconds timeout) {
+        time_point<steady_clock> expiration = steady_clock::now() + timeout;
+        while (steady_clock::now() < expiration) {
+            std::lock_guard<std::mutex> lock(mMutex);
+            if (callbackCount <= mExpiredCallbacks.size()) {
+                return true;
+            }
+            mCondition.wait_until(mMutex, expiration);
+        }
+        return false;
+    }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleRunsOnlyAfterDelay) {
+    mScheduler->schedule(createCallback(1), 15ms);
+
+    // Not triggered before delay.
+    ASSERT_FALSE(waitForCallbacks(1, 10ms));
+    ASSERT_TRUE(getExpiredCallbacks().empty());
+
+    ASSERT_TRUE(waitForCallbacks(1, 10ms));
+    ASSERT_THAT(getExpiredCallbacks(), ElementsAre(1));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOrder) {
+    mScheduler->schedule(createCallback(1), 10ms);
+    mScheduler->schedule(createCallback(2), 5ms);
+    mScheduler->schedule(createCallback(3), 1ms);
+
+    ASSERT_TRUE(waitForCallbacks(3, 15ms));
+    ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleInParallelRunsInDelayOrder) {
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 5; i++) {
+        threads.push_back(std::thread(
+                [=]() { mScheduler->schedule(createCallback(i), milliseconds(10 + 2 * i)); }));
+    }
+    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    ASSERT_TRUE(waitForCallbacks(5, 25ms));
+    ASSERT_THAT(getExpiredCallbacks(), ElementsAre(0, 1, 2, 3, 4));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) {
+    mScheduler->schedule(createCallback(1), 5ms);
+    mScheduler.reset(nullptr);
+
+    // Should time out waiting for callback to run.
+    ASSERT_FALSE(waitForCallbacks(1, 10ms));
+    ASSERT_TRUE(getExpiredCallbacks().empty());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 6db449a..0f2d7bc 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -24,6 +24,7 @@
 #include <utils/Log.h>
 #include <thread>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 #include "test_utils.h"
@@ -88,11 +89,13 @@
     void SetUp() override {
         mMockBinder = new StrictMock<MockBinder>();
         mMockHal = new StrictMock<MockIVibrator>();
-        mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockHal);
+        mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+        mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockScheduler, mMockHal);
         ASSERT_NE(mWrapper, nullptr);
     }
 
 protected:
+    std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
     std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIVibrator>> mMockHal = nullptr;
     sp<StrictMock<MockBinder>> mMockBinder = nullptr;
@@ -124,9 +127,13 @@
     ASSERT_TRUE(mWrapper->ping().isFailed());
 }
 
-TEST_F(VibratorHalWrapperAidlTest, TestOn) {
+TEST_F(VibratorHalWrapperAidlTest, TestOnWithCallbackSupport) {
     {
         InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
         EXPECT_CALL(*mMockHal.get(), on(Eq(10), _))
                 .Times(Exactly(1))
                 .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
@@ -146,11 +153,46 @@
     ASSERT_EQ(1, *callbackCounter.get());
 
     ASSERT_TRUE(mWrapper->on(100ms, callback).isUnsupported());
-    // Callback not triggered
+    // Callback not triggered for unsupported
     ASSERT_EQ(1, *callbackCounter.get());
 
     ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
-    // Callback not triggered
+    // Callback not triggered on failure
+    ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestOnWithoutCallbackSupport) {
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        DoAll(SetArgPointee<0>(IVibrator::CAP_COMPOSE_EFFECTS), Return(Status())));
+        EXPECT_CALL(*mMockHal.get(), on(Eq(10), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status()));
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+        EXPECT_CALL(*mMockHal.get(), on(Eq(11), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(
+                        Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+        EXPECT_CALL(*mMockHal.get(), on(Eq(12), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+    }
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    ASSERT_TRUE(mWrapper->on(10ms, callback).isOk());
+    ASSERT_EQ(1, *callbackCounter.get());
+
+    ASSERT_TRUE(mWrapper->on(11ms, callback).isUnsupported());
+    ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
+
+    // Callback not triggered for unsupported and on failure
     ASSERT_EQ(1, *callbackCounter.get());
 }
 
@@ -274,6 +316,10 @@
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getCapabilities();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
 }
 
 TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsDoesNotCacheFailedResult) {
@@ -314,11 +360,19 @@
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getSupportedEffects();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(supportedEffects, result.value());
 }
 
-TEST_F(VibratorHalWrapperAidlTest, TestPerformEffect) {
+TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
     {
         InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        DoAll(SetArgPointee<0>(IVibrator::CAP_PERFORM_CALLBACK), Return(Status())));
         EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _))
                 .Times(Exactly(1))
                 .WillRepeatedly(
@@ -342,12 +396,52 @@
 
     result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
     ASSERT_TRUE(result.isUnsupported());
-    // Callback not triggered
+    // Callback not triggered for unsupported
     ASSERT_EQ(1, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
+    // Callback not triggered on failure
+    ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithoutCallbackSupport) {
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+        EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _))
+                .Times(Exactly(1))
+                .WillRepeatedly(DoAll(SetArgPointee<3>(10), Return(Status())));
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+        EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::POP), Eq(EffectStrength::MEDIUM), _, _))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(
+                        Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+        EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::THUD), Eq(EffectStrength::STRONG), _, _))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+    }
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
+
+    result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
+    ASSERT_TRUE(result.isUnsupported());
+
+    result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
+    ASSERT_TRUE(result.isFailed());
+
+    // Callback not triggered for unsupported and on failure
     ASSERT_EQ(1, *callbackCounter.get());
 }
 
@@ -383,11 +477,11 @@
 
     result = mWrapper->performComposedEffect(singleEffect, callback);
     ASSERT_TRUE(result.isUnsupported());
-    // Callback not triggered
+    // Callback not triggered for unsupported
     ASSERT_EQ(1, *callbackCounter.get());
 
     result = mWrapper->performComposedEffect(multipleEffects, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
+    // Callback not triggered on failure
     ASSERT_EQ(1, *callbackCounter.get());
 }
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 7f1016f..7eb4059 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -24,6 +24,7 @@
 #include <utils/Log.h>
 #include <thread>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 #include "test_utils.h"
@@ -59,11 +60,13 @@
 public:
     void SetUp() override {
         mMockHal = new StrictMock<MockIVibratorV1_0>();
-        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockHal);
+        mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockScheduler, mMockHal);
         ASSERT_NE(mWrapper, nullptr);
     }
 
 protected:
+    std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
     std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIVibratorV1_0>> mMockHal = nullptr;
 };
@@ -89,17 +92,20 @@
                 .Times(Exactly(1))
                 .WillRepeatedly(
                         [](uint32_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(1ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
         EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(10))))
                 .Times(Exactly(1))
                 .WillRepeatedly([](uint32_t) {
                     return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
                 });
-        EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(100))))
+        EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(11))))
                 .Times(Exactly(1))
                 .WillRepeatedly([](uint32_t) {
                     return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE);
                 });
-        EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(1000))))
+        EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(12))))
                 .Times(Exactly(1))
                 .WillRepeatedly([](uint32_t) {
                     return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
@@ -110,20 +116,14 @@
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
 
     ASSERT_TRUE(mWrapper->on(1ms, callback).isOk());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(1, *callbackCounter.get());
 
     ASSERT_TRUE(mWrapper->on(10ms, callback).isUnsupported());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_TRUE(mWrapper->on(11ms, callback).isFailed());
+    ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
 
-    ASSERT_TRUE(mWrapper->on(100ms, callback).isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
-
-    ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
+    // Callback not triggered for unsupported and on failure
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_0Test, TestOff) {
@@ -226,6 +226,10 @@
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getCapabilities();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedEffectsUnsupported) {
@@ -240,9 +244,12 @@
                 .Times(Exactly(1))
                 .WillRepeatedly(
                         [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
-                            cb(V1_0::Status::OK, 100);
+                            cb(V1_0::Status::OK, 10);
                             return hardware::Return<void>();
                         });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
         EXPECT_CALL(*mMockHal.get(),
                     perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::MEDIUM), _))
                 .Times(Exactly(1))
@@ -269,24 +276,20 @@
 
     auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::CLICK, EffectStrength::MEDIUM, callback);
     ASSERT_TRUE(result.isUnsupported());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
+
+    // Callback not triggered for unsupported and on failure
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffectUnsupported) {
@@ -295,6 +298,7 @@
     // Using TICK that is only available in v1.1
     auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isUnsupported());
+    // No callback is triggered.
     ASSERT_EQ(0, *callbackCounter.get());
 }
 
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
index d0531e6..d887efc 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
@@ -23,6 +23,7 @@
 
 #include <utils/Log.h>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 #include "test_utils.h"
@@ -58,11 +59,13 @@
 public:
     void SetUp() override {
         mMockHal = new StrictMock<MockIVibratorV1_1>();
-        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockHal);
+        mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockScheduler, mMockHal);
         ASSERT_NE(mWrapper, nullptr);
     }
 
 protected:
+    std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
     std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIVibratorV1_1>> mMockHal = nullptr;
 };
@@ -70,23 +73,28 @@
 // -------------------------------------------------------------------------------------------------
 
 TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_0) {
-    EXPECT_CALL(*mMockHal.get(),
-                perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(
-                    [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
-                        cb(V1_0::Status::OK, 100);
-                        return hardware::Return<void>();
-                    });
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(),
+                    perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
+                            cb(V1_0::Status::OK, 10);
+                            return hardware::Return<void>();
+                        });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+    }
 
     std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
     auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
 
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_1) {
@@ -100,6 +108,9 @@
                     cb(V1_0::Status::OK, 10);
                     return hardware::Return<void>();
                 });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
         EXPECT_CALL(*mMockHal.get(),
                     perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::MEDIUM), _))
                 .Times(Exactly(1))
@@ -128,23 +139,19 @@
     auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isOk());
     ASSERT_EQ(10ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(1, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::TICK, EffectStrength::MEDIUM, callback);
     ASSERT_TRUE(result.isUnsupported());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
+
+    // Callback not triggered for unsupported and on failure
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectUnsupported) {
@@ -153,5 +160,6 @@
     // Using THUD that is only available in v1.2
     auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isUnsupported());
+    // No callback is triggered.
     ASSERT_EQ(0, *callbackCounter.get());
 }
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
index 5d2c269..26d9350 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
@@ -23,6 +23,7 @@
 
 #include <utils/Log.h>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 #include "test_utils.h"
@@ -61,11 +62,13 @@
 public:
     void SetUp() override {
         mMockHal = new StrictMock<MockIVibratorV1_2>();
-        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockHal);
+        mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockScheduler, mMockHal);
         ASSERT_NE(mWrapper, nullptr);
     }
 
 protected:
+    std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
     std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIVibratorV1_2>> mMockHal = nullptr;
 };
@@ -73,43 +76,53 @@
 // -------------------------------------------------------------------------------------------------
 
 TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_0) {
-    EXPECT_CALL(*mMockHal.get(),
-                perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(
-                    [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
-                        cb(V1_0::Status::OK, 100);
-                        return hardware::Return<void>();
-                    });
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(),
+                    perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
+                            cb(V1_0::Status::OK, 10);
+                            return hardware::Return<void>();
+                        });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+    }
 
     std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
     auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
 
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_1) {
-    EXPECT_CALL(*mMockHal.get(),
-                perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(
-                    [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
-                        cb(V1_0::Status::OK, 100);
-                        return hardware::Return<void>();
-                    });
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(),
+                    perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+                .Times(Exactly(1))
+                .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+                                   MockIVibratorV1_2::perform_cb cb) {
+                    cb(V1_0::Status::OK, 10);
+                    return hardware::Return<void>();
+                });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+    }
 
     std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
     auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
 
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_2) {
@@ -120,9 +133,12 @@
                 .Times(Exactly(1))
                 .WillRepeatedly(
                         [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
-                            cb(V1_0::Status::OK, 100);
+                            cb(V1_0::Status::OK, 10);
                             return hardware::Return<void>();
                         });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
         EXPECT_CALL(*mMockHal.get(),
                     perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::MEDIUM), _))
                 .Times(Exactly(1))
@@ -149,24 +165,20 @@
 
     auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::THUD, EffectStrength::MEDIUM, callback);
     ASSERT_TRUE(result.isUnsupported());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
+
+    // Callback not triggered for unsupported and on failure
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectUnsupported) {
@@ -175,5 +187,6 @@
     // Using TEXTURE_TICK that is only available in v1.3
     auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isUnsupported());
+    // No callback is triggered.
     ASSERT_EQ(0, *callbackCounter.get());
 }
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
index a799257..5de6257 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
@@ -24,6 +24,7 @@
 #include <utils/Log.h>
 #include <thread>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 #include "test_utils.h"
@@ -68,11 +69,13 @@
 public:
     void SetUp() override {
         mMockHal = new StrictMock<MockIVibratorV1_3>();
-        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockHal);
+        mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+        mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockScheduler, mMockHal);
         ASSERT_NE(mWrapper, nullptr);
     }
 
 protected:
+    std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
     std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
     sp<StrictMock<MockIVibratorV1_3>> mMockHal = nullptr;
 };
@@ -210,6 +213,10 @@
         }));
     }
     std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+    auto result = mWrapper->getCapabilities();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
@@ -258,63 +265,78 @@
 }
 
 TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_0) {
-    EXPECT_CALL(*mMockHal.get(),
-                perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(
-                    [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
-                        cb(V1_0::Status::OK, 100);
-                        return hardware::Return<void>();
-                    });
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(),
+                    perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+                            cb(V1_0::Status::OK, 10);
+                            return hardware::Return<void>();
+                        });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+    }
 
     std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
     auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
 
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_1) {
-    EXPECT_CALL(*mMockHal.get(),
-                perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(
-                    [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
-                        cb(V1_0::Status::OK, 100);
-                        return hardware::Return<void>();
-                    });
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(),
+                    perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+                .Times(Exactly(1))
+                .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+                                   MockIVibratorV1_3::perform_cb cb) {
+                    cb(V1_0::Status::OK, 10);
+                    return hardware::Return<void>();
+                });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+    }
 
     std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
     auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
 
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_2) {
-    EXPECT_CALL(*mMockHal.get(),
-                perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
-            .Times(Exactly(1))
-            .WillRepeatedly(
-                    [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
-                        cb(V1_0::Status::OK, 100);
-                        return hardware::Return<void>();
-                    });
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(),
+                    perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(
+                        [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+                            cb(V1_0::Status::OK, 10);
+                            return hardware::Return<void>();
+                        });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+    }
 
     std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
     auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
     auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
 
     ASSERT_TRUE(result.isOk());
-    ASSERT_EQ(100ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(10ms, result.value());
+    ASSERT_EQ(1, *callbackCounter.get());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_3) {
@@ -328,6 +350,9 @@
                             cb(V1_0::Status::OK, 10);
                             return hardware::Return<void>();
                         });
+        EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+                .Times(Exactly(1))
+                .WillRepeatedly(vibrator::TriggerSchedulerCallback());
         EXPECT_CALL(*mMockHal.get(),
                     perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::MEDIUM),
                                 _))
@@ -357,21 +382,17 @@
     auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
     ASSERT_TRUE(result.isOk());
     ASSERT_EQ(10ms, result.value());
-    // TODO(b/153418251): check callback will be triggered once implemented
-    ASSERT_EQ(0, *callbackCounter.get());
+    ASSERT_EQ(1, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::MEDIUM, callback);
     ASSERT_TRUE(result.isUnsupported());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
 
     result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
     ASSERT_TRUE(result.isFailed());
-    // Callback not triggered
-    ASSERT_EQ(0, *callbackCounter.get());
+
+    // Callback not triggered for unsupported and on failure
+    ASSERT_EQ(1, *callbackCounter.get());
 }
diff --git a/services/vibratorservice/test/test_utils.h b/services/vibratorservice/test/test_utils.h
index fc9b364..8d0b22e 100644
--- a/services/vibratorservice/test/test_utils.h
+++ b/services/vibratorservice/test/test_utils.h
@@ -28,6 +28,20 @@
 using ::android::hardware::vibrator::CompositeEffect;
 using ::android::hardware::vibrator::CompositePrimitive;
 
+// -------------------------------------------------------------------------------------------------
+
+class MockCallbackScheduler : public vibrator::CallbackScheduler {
+public:
+    MOCK_METHOD(void, schedule, (std::function<void()> callback, std::chrono::milliseconds delay),
+                (override));
+};
+
+ACTION(TriggerSchedulerCallback) {
+    arg0();
+}
+
+// -------------------------------------------------------------------------------------------------
+
 class TestFactory {
 public:
     static CompositeEffect createCompositeEffect(CompositePrimitive primitive,
@@ -48,6 +62,8 @@
     ~TestFactory() = delete;
 };
 
+// -------------------------------------------------------------------------------------------------
+
 } // namespace vibrator
 
 } // namespace android