Merge "Execute DelayedCallback outside CallbackScheduler lock"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 08f44c8..2519ffa 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -124,6 +124,7 @@
     { "aidl",       "AIDL calls",               ATRACE_TAG_AIDL, { } },
     { "nnapi",      "NNAPI",                    ATRACE_TAG_NNAPI, { } },
     { "rro",        "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
+    { "sysprop",    "System Property",          ATRACE_TAG_SYSPROP, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 17015a4..eb6870e 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -25,9 +25,6 @@
         "view_compiler.cpp",
         ":installd_aidl",
     ],
-    header_libs: [
-        "dex2oat_headers",
-    ],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -240,10 +237,7 @@
         "view_compiler.cpp",
     ],
 
-    header_libs: ["dex2oat_headers"],
-
     static_libs: [
-        "libartimagevalues",
         "libdiskusage",
         "libotapreoptparameters",
     ],
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 2b36067..82ea746 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -39,7 +39,6 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
-#include <dex2oat_return_codes.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
diff --git a/cmds/installd/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
index bbecfa4..e5198ad 100644
--- a/cmds/installd/dexopt_return_codes.h
+++ b/cmds/installd/dexopt_return_codes.h
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <dex2oat_return_codes.h>
-
 namespace android {
 namespace installd {
 
@@ -70,48 +68,21 @@
     return nullptr;
 }
 
-inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
-    switch (code) {
-        case art::dex2oat::ReturnCode::kNoFailure:
-            return "dex2oat success";
-        case art::dex2oat::ReturnCode::kOther:
-            return "unspecified dex2oat error";
-        case art::dex2oat::ReturnCode::kCreateRuntime:
-            return "dex2oat failed to create a runtime";
+inline const char* get_dex2oat_return_code_name(int code) {
+    if (code == 0) {
+        return "dex2oat success";
+    } else {
+        return "dex2oat error";
     }
-    return nullptr;
 }
 
-// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
-// exit codes) as well as art::dex2oat::ReturnCode.
+// Get some slightly descriptive string for the return code.
 inline const char* get_return_code_name(int code) {
-    // Try to enforce non-overlap (see comment on DexoptReturnCodes)
-    // TODO: How could switch-case checks be used to enforce completeness?
-    switch (code) {
-        case kSetGid:
-        case kSetUid:
-        case kCapSet:
-        case kFlock:
-        case kProfmanExec:
-        case kSetSchedPolicy:
-        case kSetPriority:
-        case kDex2oatExec:
-        case kInstructionSetLength:
-        case kHashValidatePath:
-        case kHashOpenPath:
-        case kHashReadDex:
-        case kHashWrite:
-            break;
-        case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
-        case static_cast<int>(art::dex2oat::ReturnCode::kOther):
-        case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
-            break;
-    }
     const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
     if (value != nullptr) {
         return value;
     }
-    value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+    value = get_dex2oat_return_code_name(code);
     return value;
 }
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 9c75781..443821c 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -31,10 +31,8 @@
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <art_image_values.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
-#include <dex2oat_return_codes.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index 8cac58f..1572e3b 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -86,241 +86,22 @@
                             int dex_metadata_fd,
                             bool use_jitzygote_image,
                             const char* compilation_reason) {
-    // Get the relative path to the input file.
-    std::string input_basename = Basename(input_file_name);
+    PrepareBootImageAndBootClasspathFlags(use_jitzygote_image);
 
-    std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
-    std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+    PrepareInputFileFlags(zip_fd, oat_fd, input_vdex_fd, output_vdex_fd, image_fd, input_file_name,
+                          output_file_name, profile_fd, dex_metadata_fd, swap_fd,
+                          class_loader_context, class_loader_context_fds);
 
-    std::string threads_format = "-j%s";
-    std::string dex2oat_threads_arg = post_bootcomplete
-            ? (for_restore
-                ? MapPropertyToArgWithBackup(
-                        "dalvik.vm.restore-dex2oat-threads",
-                        "dalvik.vm.dex2oat-threads",
-                        threads_format)
-                : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
-            : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
-    std::string cpu_set_format = "--cpu-set=%s";
-    std::string dex2oat_cpu_set_arg = post_bootcomplete
-            ? (for_restore
-                ? MapPropertyToArgWithBackup(
-                        "dalvik.vm.restore-dex2oat-cpu-set",
-                        "dalvik.vm.dex2oat-cpu-set",
-                        cpu_set_format)
-                : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
-            : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
+    PrepareCompilerConfigFlags(input_vdex_fd, output_vdex_fd, instruction_set, compiler_filter,
+                               debuggable, target_sdk_version, enable_hidden_api_checks,
+                               generate_compact_dex, compilation_reason);
 
-    std::string bootclasspath;
-    char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
-    if (dex2oat_bootclasspath != nullptr) {
-        bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
-    }
-    // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
-    // BOOTCLASSPATH.
-
-    const std::string dex2oat_isa_features_key =
-            StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
-    std::string instruction_set_features_arg =
-        MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
-
-    const std::string dex2oat_isa_variant_key =
-            StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
-    std::string instruction_set_variant_arg =
-        MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
-
-    const char* dex2oat_norelocation = "-Xnorelocate";
+    PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore);
 
     const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
     std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
     ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
 
-    // If we are booting without the real /data, don't spend time compiling.
-    std::string vold_decrypt = GetProperty("vold.decrypt", "");
-    bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
-                            vold_decrypt == "1";
-
-    std::string updatable_bcp_packages =
-        MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
-                         "--updatable-bcp-packages-file=%s");
-    if (updatable_bcp_packages.empty()) {
-      // Make dex2oat fail by providing non-existent file name.
-      updatable_bcp_packages = "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
-    }
-
-    std::string resolve_startup_string_arg =
-            MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
-                             "--resolve-startup-const-strings=%s");
-    if (resolve_startup_string_arg.empty()) {
-      // If empty, fall back to system property.
-      resolve_startup_string_arg =
-            MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
-                             "--resolve-startup-const-strings=%s");
-    }
-
-    const std::string image_block_size_arg =
-            MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
-                             "--max-image-block-size=%s");
-
-    const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
-
-    std::string image_format_arg;
-    if (image_fd >= 0) {
-        image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
-    }
-
-    std::string dex2oat_large_app_threshold_arg =
-        MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
-
-    bool generate_minidebug_info = kEnableMinidebugInfo &&
-            GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
-
-    std::string boot_image;
-    if (use_jitzygote_image) {
-      boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
-    } else {
-      boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
-    }
-
-    // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
-    // use arraysize instead.
-    std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
-    std::string zip_location_arg = StringPrintf("--zip-location=%s", input_basename.c_str());
-    std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
-    std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
-    std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
-    std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
-    std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
-    std::string dex2oat_compiler_filter_arg;
-    std::string dex2oat_swap_fd;
-    std::string dex2oat_image_fd;
-    std::string target_sdk_version_arg;
-    if (target_sdk_version != 0) {
-        target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
-    }
-    std::string class_loader_context_arg;
-    std::string class_loader_context_fds_arg;
-    if (class_loader_context != nullptr) {
-        class_loader_context_arg = StringPrintf("--class-loader-context=%s",
-                                                class_loader_context);
-        if (!class_loader_context_fds.empty()) {
-            class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
-                                                        class_loader_context_fds.c_str());
-        }
-    }
-
-    if (swap_fd >= 0) {
-        dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
-    }
-    if (image_fd >= 0) {
-        dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
-    }
-
-    // Compute compiler filter.
-    bool have_dex2oat_relocation_skip_flag = false;
-    if (skip_compilation) {
-        dex2oat_compiler_filter_arg = "--compiler-filter=extract";
-        have_dex2oat_relocation_skip_flag = true;
-    } else if (compiler_filter != nullptr) {
-        dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
-    }
-
-    if (dex2oat_compiler_filter_arg.empty()) {
-        dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
-                                                       "--compiler-filter=%s");
-    }
-
-    // Check whether all apps should be compiled debuggable.
-    if (!debuggable) {
-        debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
-    }
-    std::string profile_arg;
-    if (profile_fd != -1) {
-        profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
-    }
-
-    // Get the directory of the apk to pass as a base classpath directory.
-    std::string base_dir;
-    std::string apk_dir(input_file_name);
-    unsigned long dir_index = apk_dir.rfind('/');
-    bool has_base_dir = dir_index != std::string::npos;
-    if (has_base_dir) {
-        apk_dir = apk_dir.substr(0, dir_index);
-        base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
-    }
-
-    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
-    std::string compilation_reason_arg = compilation_reason == nullptr
-            ? ""
-            : std::string("--compilation-reason=") + compilation_reason;
-
-    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin_.c_str(), input_basename.c_str(),
-          output_file_name);
-
-    // Disable cdex if update input vdex is true since this combination of options is not
-    // supported.
-    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
-    AddArg(zip_fd_arg);
-    AddArg(zip_location_arg);
-    AddArg(input_vdex_fd_arg);
-    AddArg(output_vdex_fd_arg);
-    AddArg(oat_fd_arg);
-    AddArg(oat_location_arg);
-    AddArg(instruction_set_arg);
-
-    AddArg(instruction_set_variant_arg);
-    AddArg(instruction_set_features_arg);
-
-    AddArg(boot_image);
-
-    AddRuntimeArg(bootclasspath);
-    AddRuntimeArg(dex2oat_Xms_arg);
-    AddRuntimeArg(dex2oat_Xmx_arg);
-
-    AddArg(updatable_bcp_packages);
-    AddArg(resolve_startup_string_arg);
-    AddArg(image_block_size_arg);
-    AddArg(dex2oat_compiler_filter_arg);
-    AddArg(dex2oat_threads_arg);
-    AddArg(dex2oat_cpu_set_arg);
-    AddArg(dex2oat_swap_fd);
-    AddArg(dex2oat_image_fd);
-
-    if (generate_debug_info) {
-        AddArg("--generate-debug-info");
-    }
-    if (debuggable) {
-        AddArg("--debuggable");
-    }
-    AddArg(image_format_arg);
-    AddArg(dex2oat_large_app_threshold_arg);
-
-    if (have_dex2oat_relocation_skip_flag) {
-        AddRuntimeArg(dex2oat_norelocation);
-    }
-    AddArg(profile_arg);
-    AddArg(base_dir);
-    AddArg(class_loader_context_arg);
-    AddArg(class_loader_context_fds_arg);
-    if (generate_minidebug_info) {
-        AddArg(kMinidebugDex2oatFlag);
-    }
-    if (disable_cdex) {
-        AddArg(kDisableCompactDexFlag);
-    }
-    AddRuntimeArg(target_sdk_version_arg);
-    if (enable_hidden_api_checks) {
-        AddRuntimeArg("-Xhidden-api-policy:enabled");
-    }
-
-    if (dex_metadata_fd > -1) {
-        AddArg(dex_metadata_fd_arg);
-    }
-
-    AddArg(compilation_reason_arg);
-
     // Do not add args after dex2oat_flags, they should override others for debugging.
     for (auto it = dex2oat_flags_args.begin(); it != dex2oat_flags_args.end(); ++it) {
         AddArg(*it);
@@ -331,8 +112,240 @@
 
 RunDex2Oat::~RunDex2Oat() {}
 
+void RunDex2Oat::PrepareBootImageAndBootClasspathFlags(bool use_jitzygote_image) {
+    std::string boot_image;
+    if (use_jitzygote_image) {
+        boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
+    } else {
+        boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
+    }
+    AddArg(boot_image);
+
+    // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+    // BOOTCLASSPATH.
+    char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+    if (dex2oat_bootclasspath != nullptr) {
+        AddRuntimeArg(StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath));
+    }
+
+    std::string updatable_bcp_packages =
+            MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
+                             "--updatable-bcp-packages-file=%s");
+    if (updatable_bcp_packages.empty()) {
+        // Make dex2oat fail by providing non-existent file name.
+        updatable_bcp_packages =
+                "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
+    }
+    AddArg(updatable_bcp_packages);
+}
+
+void RunDex2Oat::PrepareInputFileFlags(int zip_fd,
+                                       int oat_fd,
+                                       int input_vdex_fd,
+                                       int output_vdex_fd,
+                                       int image_fd,
+                                       const char* input_file_name,
+                                       const char* output_file_name,
+                                       int profile_fd,
+                                       int dex_metadata_fd,
+                                       int swap_fd,
+                                       const char* class_loader_context,
+                                       const std::string& class_loader_context_fds) {
+    std::string input_basename = Basename(input_file_name);
+    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin_.c_str(), input_basename.c_str(),
+          output_file_name);
+
+    AddArg(StringPrintf("--zip-fd=%d", zip_fd));
+    AddArg(StringPrintf("--zip-location=%s", input_basename.c_str()));
+    AddArg(StringPrintf("--oat-fd=%d", oat_fd));
+    AddArg(StringPrintf("--oat-location=%s", output_file_name));
+    AddArg(StringPrintf("--input-vdex-fd=%d", input_vdex_fd));
+    AddArg(StringPrintf("--output-vdex-fd=%d", output_vdex_fd));
+
+    if (image_fd >= 0) {
+        AddArg(StringPrintf("--app-image-fd=%d", image_fd));
+        AddArg(MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s"));
+    }
+    if (dex_metadata_fd > -1) {
+        AddArg("--dm-fd=" + std::to_string(dex_metadata_fd));
+    }
+    if (profile_fd != -1) {
+        AddArg(StringPrintf("--profile-file-fd=%d", profile_fd));
+    }
+    if (swap_fd >= 0) {
+        AddArg(StringPrintf("--swap-fd=%d", swap_fd));
+    }
+
+    // Get the directory of the apk to pass as a base classpath directory.
+    {
+        std::string apk_dir(input_file_name);
+        size_t dir_index = apk_dir.rfind('/');
+        if (dir_index != std::string::npos) {
+            apk_dir = apk_dir.substr(0, dir_index);
+            AddArg(StringPrintf("--classpath-dir=%s", apk_dir.c_str()));
+        }
+    }
+
+    if (class_loader_context != nullptr) {
+        AddArg(StringPrintf("--class-loader-context=%s", class_loader_context));
+        if (!class_loader_context_fds.empty()) {
+            AddArg(StringPrintf("--class-loader-context-fds=%s",
+                                class_loader_context_fds.c_str()));
+        }
+    }
+}
+
+void RunDex2Oat::PrepareCompilerConfigFlags(int input_vdex_fd,
+                                            int output_vdex_fd,
+                                            const char* instruction_set,
+                                            const char* compiler_filter,
+                                            bool debuggable,
+                                            int target_sdk_version,
+                                            bool enable_hidden_api_checks,
+                                            bool generate_compact_dex,
+                                            const char* compilation_reason) {
+    // Disable cdex if update input vdex is true since this combination of options is not
+    // supported.
+    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+    if (disable_cdex) {
+        AddArg(kDisableCompactDexFlag);
+    }
+    
+    // ISA related
+    {
+        AddArg(StringPrintf("--instruction-set=%s", instruction_set));
+
+        const std::string dex2oat_isa_features_key =
+                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+        std::string instruction_set_features_arg =
+                MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+        AddArg(instruction_set_features_arg);
+
+        const std::string dex2oat_isa_variant_key =
+                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+        std::string instruction_set_variant_arg =
+                MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+        AddArg(instruction_set_variant_arg);
+    }
+
+    // Compute compiler filter.
+    {
+        std::string dex2oat_compiler_filter_arg;
+        {
+            // If we are booting without the real /data, don't spend time compiling.
+            std::string vold_decrypt = GetProperty("vold.decrypt", "");
+            bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                    vold_decrypt == "1";
+
+            bool have_dex2oat_relocation_skip_flag = false;
+            if (skip_compilation) {
+                dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+                have_dex2oat_relocation_skip_flag = true;
+            } else if (compiler_filter != nullptr) {
+                dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s",
+                                                           compiler_filter);
+            }
+            if (have_dex2oat_relocation_skip_flag) {
+                AddRuntimeArg("-Xnorelocate");
+            }
+        }
+
+        if (dex2oat_compiler_filter_arg.empty()) {
+            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+                                                           "--compiler-filter=%s");
+        }
+        AddArg(dex2oat_compiler_filter_arg);
+
+        if (compilation_reason != nullptr) {
+            AddArg(std::string("--compilation-reason=") + compilation_reason);
+        }
+    }
+
+    AddArg(MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
+                            "--max-image-block-size=%s"));
+
+    AddArg(MapPropertyToArg("dalvik.vm.dex2oat-very-large",
+                            "--very-large-app-threshold=%s"));
+
+    std::string resolve_startup_string_arg = MapPropertyToArg(
+        "persist.device_config.runtime.dex2oat_resolve_startup_strings",
+        "--resolve-startup-const-strings=%s");
+    if (resolve_startup_string_arg.empty()) {
+        // If empty, fall back to system property.
+        resolve_startup_string_arg =
+                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+                                 "--resolve-startup-const-strings=%s");
+    }
+    AddArg(resolve_startup_string_arg);
+
+    // Debug related
+    {
+        // Check whether all apps should be compiled debuggable.
+        if (!debuggable) {
+            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+        }
+        if (debuggable) {
+            AddArg("--debuggable");
+        }
+
+        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+        if (generate_debug_info) {
+            AddArg("--generate-debug-info");
+        }
+        {
+            bool generate_minidebug_info = kEnableMinidebugInfo &&
+                    GetBoolProperty(kMinidebugInfoSystemProperty,
+                                    kMinidebugInfoSystemPropertyDefault);
+            if (generate_minidebug_info) {
+                AddArg(kMinidebugDex2oatFlag);
+            }
+        }
+    }
+
+    if (target_sdk_version != 0) {
+        AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
+    }
+
+    if (enable_hidden_api_checks) {
+        AddRuntimeArg("-Xhidden-api-policy:enabled");
+    }
+}
+
+void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
+                                                          bool for_restore) {
+    // CPU set
+    {
+        std::string cpu_set_format = "--cpu-set=%s";
+        std::string dex2oat_cpu_set_arg = post_bootcomplete
+                ? (for_restore
+                   ? MapPropertyToArgWithBackup(
+                           "dalvik.vm.restore-dex2oat-cpu-set",
+                           "dalvik.vm.dex2oat-cpu-set",
+                           cpu_set_format)
+                   : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
+                : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
+        AddArg(dex2oat_cpu_set_arg);
+    }
+
+    // Number of threads
+    {
+        std::string threads_format = "-j%s";
+        std::string dex2oat_threads_arg = post_bootcomplete
+                ? (for_restore
+                   ? MapPropertyToArgWithBackup(
+                           "dalvik.vm.restore-dex2oat-threads",
+                           "dalvik.vm.dex2oat-threads",
+                           threads_format)
+                   : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
+                : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
+        AddArg(dex2oat_threads_arg);
+    }
+
+    AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s"));
+    AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s"));
+}
+
 void RunDex2Oat::Exec(int exit_code) {
-    LOG(ERROR) << "RunDex2Oat::Exec";
     execv_helper_->Exec(exit_code);
 }
 
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index e4450b0..5453272 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -56,6 +56,30 @@
     void Exec(int exit_code);
 
   protected:
+    void PrepareBootImageAndBootClasspathFlags(bool use_jitzygote_image);
+    void PrepareInputFileFlags(int zip_fd,
+                               int oat_fd,
+                               int input_vdex_fd,
+                               int output_vdex_fd,
+                               int image_fd,
+                               const char* input_file_name,
+                               const char* output_file_name,
+                               int profile_fd,
+                               int dex_metadata_fd,
+                               int swap_fd,
+                               const char* class_loader_context,
+                               const std::string& class_loader_context_fds);
+    void PrepareCompilerConfigFlags(int input_vdex_fd,
+                                    int output_vdex_fd,
+                                    const char* instruction_set,
+                                    const char* compiler_filter,
+                                    bool debuggable,
+                                    int target_sdk_version,
+                                    bool enable_hidden_api_checks,
+                                    bool generate_compact_dex,
+                                    const char* compilation_reason);
+    void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, bool for_restore);
+
     virtual std::string GetProperty(const std::string& key, const std::string& default_value);
     virtual bool GetBoolProperty(const std::string& key, bool default_value);
 
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 96f5e44..fbf1e0c 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -663,7 +663,7 @@
                           &status);
     EXPECT_STREQ(status.toString8().c_str(),
                  "Status(-8, EX_SERVICE_SPECIFIC): \'256: Dex2oat invocation for "
-                 "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
+                 "/data/app/com.installd.test.dexopt/base.jar failed: dex2oat error'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
diff --git a/include/android/input.h b/include/android/input.h
index 7c39234..b04775b 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -988,11 +988,9 @@
 int64_t AKeyEvent_getEventTime(const AInputEvent* key_event);
 
 /**
- * Creates a native AInputEvent* object associated with the specified Java android.view.KeyEvent.
- * The result may be used with generic and KeyEvent-specific AInputEvent_* functions.
- * The object returned by this function must be disposed using {@link AInputEvent_release()}.
- * User must guarantee that lifetime for object referenced by keyEvent is prolongated
- * up to release of returned AInputEvent*.
+ * Creates a native AInputEvent* object that is a copy of the specified Java android.view.KeyEvent.
+ * The result may be used with generic and KeyEvent-specific AInputEvent_* functions. The object
+ * returned by this function must be disposed using {@link AInputEvent_release()}.
  */
 const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent);
 
@@ -1312,11 +1310,10 @@
         int32_t axis, size_t pointer_index, size_t history_index);
 
 /**
- * Creates a native AInputEvent* object associated with the specified Java android.view.MotionEvent.
- * The result may be used with generic and MotionEvent-specific AInputEvent_* functions.
- * The object returned by this function must be disposed using {@link AInputEvent_release()}.
- * User must guarantee that object referenced by motionEvent won't be recycled and
- * its lifetime is prolongated up to release of returned AInputEvent*.
+ * Creates a native AInputEvent* object that is a copy of the specified Java
+ * android.view.MotionEvent. The result may be used with generic and MotionEvent-specific
+ * AInputEvent_* functions. The object returned by this function must be disposed using
+ * {@link AInputEvent_release()}.
  */
 const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent);
 
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index ec2de61..2a742f9 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -21,11 +21,6 @@
 #include <android/keycodes.h>
 #include <unordered_map>
 
-#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
-#define DEFINE_AXIS(axis) { #axis, AMOTION_EVENT_AXIS_##axis }
-#define DEFINE_LED(led) { #led, ALED_##led }
-#define DEFINE_FLAG(flag) { #flag, POLICY_FLAG_##flag }
-
 namespace android {
 
 template<typename T, size_t N>
@@ -36,437 +31,41 @@
     int value;
 };
 
-// NOTE: If you add a new keycode here you must also add it to several other files.
-//       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
-#define KEYCODES_SEQUENCE \
-    DEFINE_KEYCODE(UNKNOWN), \
-    DEFINE_KEYCODE(SOFT_LEFT), \
-    DEFINE_KEYCODE(SOFT_RIGHT), \
-    DEFINE_KEYCODE(HOME), \
-    DEFINE_KEYCODE(BACK), \
-    DEFINE_KEYCODE(CALL), \
-    DEFINE_KEYCODE(ENDCALL), \
-    DEFINE_KEYCODE(0), \
-    DEFINE_KEYCODE(1), \
-    DEFINE_KEYCODE(2), \
-    DEFINE_KEYCODE(3), \
-    DEFINE_KEYCODE(4), \
-    DEFINE_KEYCODE(5), \
-    DEFINE_KEYCODE(6), \
-    DEFINE_KEYCODE(7), \
-    DEFINE_KEYCODE(8), \
-    DEFINE_KEYCODE(9), \
-    DEFINE_KEYCODE(STAR), \
-    DEFINE_KEYCODE(POUND), \
-    DEFINE_KEYCODE(DPAD_UP), \
-    DEFINE_KEYCODE(DPAD_DOWN), \
-    DEFINE_KEYCODE(DPAD_LEFT), \
-    DEFINE_KEYCODE(DPAD_RIGHT), \
-    DEFINE_KEYCODE(DPAD_CENTER), \
-    DEFINE_KEYCODE(VOLUME_UP), \
-    DEFINE_KEYCODE(VOLUME_DOWN), \
-    DEFINE_KEYCODE(POWER), \
-    DEFINE_KEYCODE(CAMERA), \
-    DEFINE_KEYCODE(CLEAR), \
-    DEFINE_KEYCODE(A), \
-    DEFINE_KEYCODE(B), \
-    DEFINE_KEYCODE(C), \
-    DEFINE_KEYCODE(D), \
-    DEFINE_KEYCODE(E), \
-    DEFINE_KEYCODE(F), \
-    DEFINE_KEYCODE(G), \
-    DEFINE_KEYCODE(H), \
-    DEFINE_KEYCODE(I), \
-    DEFINE_KEYCODE(J), \
-    DEFINE_KEYCODE(K), \
-    DEFINE_KEYCODE(L), \
-    DEFINE_KEYCODE(M), \
-    DEFINE_KEYCODE(N), \
-    DEFINE_KEYCODE(O), \
-    DEFINE_KEYCODE(P), \
-    DEFINE_KEYCODE(Q), \
-    DEFINE_KEYCODE(R), \
-    DEFINE_KEYCODE(S), \
-    DEFINE_KEYCODE(T), \
-    DEFINE_KEYCODE(U), \
-    DEFINE_KEYCODE(V), \
-    DEFINE_KEYCODE(W), \
-    DEFINE_KEYCODE(X), \
-    DEFINE_KEYCODE(Y), \
-    DEFINE_KEYCODE(Z), \
-    DEFINE_KEYCODE(COMMA), \
-    DEFINE_KEYCODE(PERIOD), \
-    DEFINE_KEYCODE(ALT_LEFT), \
-    DEFINE_KEYCODE(ALT_RIGHT), \
-    DEFINE_KEYCODE(SHIFT_LEFT), \
-    DEFINE_KEYCODE(SHIFT_RIGHT), \
-    DEFINE_KEYCODE(TAB), \
-    DEFINE_KEYCODE(SPACE), \
-    DEFINE_KEYCODE(SYM), \
-    DEFINE_KEYCODE(EXPLORER), \
-    DEFINE_KEYCODE(ENVELOPE), \
-    DEFINE_KEYCODE(ENTER), \
-    DEFINE_KEYCODE(DEL), \
-    DEFINE_KEYCODE(GRAVE), \
-    DEFINE_KEYCODE(MINUS), \
-    DEFINE_KEYCODE(EQUALS), \
-    DEFINE_KEYCODE(LEFT_BRACKET), \
-    DEFINE_KEYCODE(RIGHT_BRACKET), \
-    DEFINE_KEYCODE(BACKSLASH), \
-    DEFINE_KEYCODE(SEMICOLON), \
-    DEFINE_KEYCODE(APOSTROPHE), \
-    DEFINE_KEYCODE(SLASH), \
-    DEFINE_KEYCODE(AT), \
-    DEFINE_KEYCODE(NUM), \
-    DEFINE_KEYCODE(HEADSETHOOK), \
-    DEFINE_KEYCODE(FOCUS), \
-    DEFINE_KEYCODE(PLUS), \
-    DEFINE_KEYCODE(MENU), \
-    DEFINE_KEYCODE(NOTIFICATION), \
-    DEFINE_KEYCODE(SEARCH), \
-    DEFINE_KEYCODE(MEDIA_PLAY_PAUSE), \
-    DEFINE_KEYCODE(MEDIA_STOP), \
-    DEFINE_KEYCODE(MEDIA_NEXT), \
-    DEFINE_KEYCODE(MEDIA_PREVIOUS), \
-    DEFINE_KEYCODE(MEDIA_REWIND), \
-    DEFINE_KEYCODE(MEDIA_FAST_FORWARD), \
-    DEFINE_KEYCODE(MUTE), \
-    DEFINE_KEYCODE(PAGE_UP), \
-    DEFINE_KEYCODE(PAGE_DOWN), \
-    DEFINE_KEYCODE(PICTSYMBOLS), \
-    DEFINE_KEYCODE(SWITCH_CHARSET), \
-    DEFINE_KEYCODE(BUTTON_A), \
-    DEFINE_KEYCODE(BUTTON_B), \
-    DEFINE_KEYCODE(BUTTON_C), \
-    DEFINE_KEYCODE(BUTTON_X), \
-    DEFINE_KEYCODE(BUTTON_Y), \
-    DEFINE_KEYCODE(BUTTON_Z), \
-    DEFINE_KEYCODE(BUTTON_L1), \
-    DEFINE_KEYCODE(BUTTON_R1), \
-    DEFINE_KEYCODE(BUTTON_L2), \
-    DEFINE_KEYCODE(BUTTON_R2), \
-    DEFINE_KEYCODE(BUTTON_THUMBL), \
-    DEFINE_KEYCODE(BUTTON_THUMBR), \
-    DEFINE_KEYCODE(BUTTON_START), \
-    DEFINE_KEYCODE(BUTTON_SELECT), \
-    DEFINE_KEYCODE(BUTTON_MODE), \
-    DEFINE_KEYCODE(ESCAPE), \
-    DEFINE_KEYCODE(FORWARD_DEL), \
-    DEFINE_KEYCODE(CTRL_LEFT), \
-    DEFINE_KEYCODE(CTRL_RIGHT), \
-    DEFINE_KEYCODE(CAPS_LOCK), \
-    DEFINE_KEYCODE(SCROLL_LOCK), \
-    DEFINE_KEYCODE(META_LEFT), \
-    DEFINE_KEYCODE(META_RIGHT), \
-    DEFINE_KEYCODE(FUNCTION), \
-    DEFINE_KEYCODE(SYSRQ), \
-    DEFINE_KEYCODE(BREAK), \
-    DEFINE_KEYCODE(MOVE_HOME), \
-    DEFINE_KEYCODE(MOVE_END), \
-    DEFINE_KEYCODE(INSERT), \
-    DEFINE_KEYCODE(FORWARD), \
-    DEFINE_KEYCODE(MEDIA_PLAY), \
-    DEFINE_KEYCODE(MEDIA_PAUSE), \
-    DEFINE_KEYCODE(MEDIA_CLOSE), \
-    DEFINE_KEYCODE(MEDIA_EJECT), \
-    DEFINE_KEYCODE(MEDIA_RECORD), \
-    DEFINE_KEYCODE(F1), \
-    DEFINE_KEYCODE(F2), \
-    DEFINE_KEYCODE(F3), \
-    DEFINE_KEYCODE(F4), \
-    DEFINE_KEYCODE(F5), \
-    DEFINE_KEYCODE(F6), \
-    DEFINE_KEYCODE(F7), \
-    DEFINE_KEYCODE(F8), \
-    DEFINE_KEYCODE(F9), \
-    DEFINE_KEYCODE(F10), \
-    DEFINE_KEYCODE(F11), \
-    DEFINE_KEYCODE(F12), \
-    DEFINE_KEYCODE(NUM_LOCK), \
-    DEFINE_KEYCODE(NUMPAD_0), \
-    DEFINE_KEYCODE(NUMPAD_1), \
-    DEFINE_KEYCODE(NUMPAD_2), \
-    DEFINE_KEYCODE(NUMPAD_3), \
-    DEFINE_KEYCODE(NUMPAD_4), \
-    DEFINE_KEYCODE(NUMPAD_5), \
-    DEFINE_KEYCODE(NUMPAD_6), \
-    DEFINE_KEYCODE(NUMPAD_7), \
-    DEFINE_KEYCODE(NUMPAD_8), \
-    DEFINE_KEYCODE(NUMPAD_9), \
-    DEFINE_KEYCODE(NUMPAD_DIVIDE), \
-    DEFINE_KEYCODE(NUMPAD_MULTIPLY), \
-    DEFINE_KEYCODE(NUMPAD_SUBTRACT), \
-    DEFINE_KEYCODE(NUMPAD_ADD), \
-    DEFINE_KEYCODE(NUMPAD_DOT), \
-    DEFINE_KEYCODE(NUMPAD_COMMA), \
-    DEFINE_KEYCODE(NUMPAD_ENTER), \
-    DEFINE_KEYCODE(NUMPAD_EQUALS), \
-    DEFINE_KEYCODE(NUMPAD_LEFT_PAREN), \
-    DEFINE_KEYCODE(NUMPAD_RIGHT_PAREN), \
-    DEFINE_KEYCODE(VOLUME_MUTE), \
-    DEFINE_KEYCODE(INFO), \
-    DEFINE_KEYCODE(CHANNEL_UP), \
-    DEFINE_KEYCODE(CHANNEL_DOWN), \
-    DEFINE_KEYCODE(ZOOM_IN), \
-    DEFINE_KEYCODE(ZOOM_OUT), \
-    DEFINE_KEYCODE(TV), \
-    DEFINE_KEYCODE(WINDOW), \
-    DEFINE_KEYCODE(GUIDE), \
-    DEFINE_KEYCODE(DVR), \
-    DEFINE_KEYCODE(BOOKMARK), \
-    DEFINE_KEYCODE(CAPTIONS), \
-    DEFINE_KEYCODE(SETTINGS), \
-    DEFINE_KEYCODE(TV_POWER), \
-    DEFINE_KEYCODE(TV_INPUT), \
-    DEFINE_KEYCODE(STB_POWER), \
-    DEFINE_KEYCODE(STB_INPUT), \
-    DEFINE_KEYCODE(AVR_POWER), \
-    DEFINE_KEYCODE(AVR_INPUT), \
-    DEFINE_KEYCODE(PROG_RED), \
-    DEFINE_KEYCODE(PROG_GREEN), \
-    DEFINE_KEYCODE(PROG_YELLOW), \
-    DEFINE_KEYCODE(PROG_BLUE), \
-    DEFINE_KEYCODE(APP_SWITCH), \
-    DEFINE_KEYCODE(BUTTON_1), \
-    DEFINE_KEYCODE(BUTTON_2), \
-    DEFINE_KEYCODE(BUTTON_3), \
-    DEFINE_KEYCODE(BUTTON_4), \
-    DEFINE_KEYCODE(BUTTON_5), \
-    DEFINE_KEYCODE(BUTTON_6), \
-    DEFINE_KEYCODE(BUTTON_7), \
-    DEFINE_KEYCODE(BUTTON_8), \
-    DEFINE_KEYCODE(BUTTON_9), \
-    DEFINE_KEYCODE(BUTTON_10), \
-    DEFINE_KEYCODE(BUTTON_11), \
-    DEFINE_KEYCODE(BUTTON_12), \
-    DEFINE_KEYCODE(BUTTON_13), \
-    DEFINE_KEYCODE(BUTTON_14), \
-    DEFINE_KEYCODE(BUTTON_15), \
-    DEFINE_KEYCODE(BUTTON_16), \
-    DEFINE_KEYCODE(LANGUAGE_SWITCH), \
-    DEFINE_KEYCODE(MANNER_MODE), \
-    DEFINE_KEYCODE(3D_MODE), \
-    DEFINE_KEYCODE(CONTACTS), \
-    DEFINE_KEYCODE(CALENDAR), \
-    DEFINE_KEYCODE(MUSIC), \
-    DEFINE_KEYCODE(CALCULATOR), \
-    DEFINE_KEYCODE(ZENKAKU_HANKAKU), \
-    DEFINE_KEYCODE(EISU), \
-    DEFINE_KEYCODE(MUHENKAN), \
-    DEFINE_KEYCODE(HENKAN), \
-    DEFINE_KEYCODE(KATAKANA_HIRAGANA), \
-    DEFINE_KEYCODE(YEN), \
-    DEFINE_KEYCODE(RO), \
-    DEFINE_KEYCODE(KANA), \
-    DEFINE_KEYCODE(ASSIST), \
-    DEFINE_KEYCODE(BRIGHTNESS_DOWN), \
-    DEFINE_KEYCODE(BRIGHTNESS_UP), \
-    DEFINE_KEYCODE(MEDIA_AUDIO_TRACK), \
-    DEFINE_KEYCODE(SLEEP), \
-    DEFINE_KEYCODE(WAKEUP), \
-    DEFINE_KEYCODE(PAIRING), \
-    DEFINE_KEYCODE(MEDIA_TOP_MENU), \
-    DEFINE_KEYCODE(11), \
-    DEFINE_KEYCODE(12), \
-    DEFINE_KEYCODE(LAST_CHANNEL), \
-    DEFINE_KEYCODE(TV_DATA_SERVICE), \
-    DEFINE_KEYCODE(VOICE_ASSIST), \
-    DEFINE_KEYCODE(TV_RADIO_SERVICE), \
-    DEFINE_KEYCODE(TV_TELETEXT), \
-    DEFINE_KEYCODE(TV_NUMBER_ENTRY), \
-    DEFINE_KEYCODE(TV_TERRESTRIAL_ANALOG), \
-    DEFINE_KEYCODE(TV_TERRESTRIAL_DIGITAL), \
-    DEFINE_KEYCODE(TV_SATELLITE), \
-    DEFINE_KEYCODE(TV_SATELLITE_BS), \
-    DEFINE_KEYCODE(TV_SATELLITE_CS), \
-    DEFINE_KEYCODE(TV_SATELLITE_SERVICE), \
-    DEFINE_KEYCODE(TV_NETWORK), \
-    DEFINE_KEYCODE(TV_ANTENNA_CABLE), \
-    DEFINE_KEYCODE(TV_INPUT_HDMI_1), \
-    DEFINE_KEYCODE(TV_INPUT_HDMI_2), \
-    DEFINE_KEYCODE(TV_INPUT_HDMI_3), \
-    DEFINE_KEYCODE(TV_INPUT_HDMI_4), \
-    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_1), \
-    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_2), \
-    DEFINE_KEYCODE(TV_INPUT_COMPONENT_1), \
-    DEFINE_KEYCODE(TV_INPUT_COMPONENT_2), \
-    DEFINE_KEYCODE(TV_INPUT_VGA_1), \
-    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION), \
-    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_UP), \
-    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_DOWN), \
-    DEFINE_KEYCODE(TV_ZOOM_MODE), \
-    DEFINE_KEYCODE(TV_CONTENTS_MENU), \
-    DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU), \
-    DEFINE_KEYCODE(TV_TIMER_PROGRAMMING), \
-    DEFINE_KEYCODE(HELP), \
-    DEFINE_KEYCODE(NAVIGATE_PREVIOUS), \
-    DEFINE_KEYCODE(NAVIGATE_NEXT), \
-    DEFINE_KEYCODE(NAVIGATE_IN), \
-    DEFINE_KEYCODE(NAVIGATE_OUT), \
-    DEFINE_KEYCODE(STEM_PRIMARY), \
-    DEFINE_KEYCODE(STEM_1), \
-    DEFINE_KEYCODE(STEM_2), \
-    DEFINE_KEYCODE(STEM_3), \
-    DEFINE_KEYCODE(DPAD_UP_LEFT), \
-    DEFINE_KEYCODE(DPAD_DOWN_LEFT), \
-    DEFINE_KEYCODE(DPAD_UP_RIGHT), \
-    DEFINE_KEYCODE(DPAD_DOWN_RIGHT), \
-    DEFINE_KEYCODE(MEDIA_SKIP_FORWARD), \
-    DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD), \
-    DEFINE_KEYCODE(MEDIA_STEP_FORWARD), \
-    DEFINE_KEYCODE(MEDIA_STEP_BACKWARD), \
-    DEFINE_KEYCODE(SOFT_SLEEP), \
-    DEFINE_KEYCODE(CUT), \
-    DEFINE_KEYCODE(COPY), \
-    DEFINE_KEYCODE(PASTE), \
-    DEFINE_KEYCODE(SYSTEM_NAVIGATION_UP), \
-    DEFINE_KEYCODE(SYSTEM_NAVIGATION_DOWN), \
-    DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT), \
-    DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT), \
-    DEFINE_KEYCODE(ALL_APPS), \
-    DEFINE_KEYCODE(REFRESH), \
-    DEFINE_KEYCODE(THUMBS_UP), \
-    DEFINE_KEYCODE(THUMBS_DOWN), \
-    DEFINE_KEYCODE(PROFILE_SWITCH)
+//   NOTE: If you want a new key code, axis code, led code or flag code in keylayout file,
+//   then you must add it to InputEventLabels.cpp.
 
-static const std::unordered_map<std::string, int> KEYCODES = {
-    KEYCODES_SEQUENCE
+class InputEventLookup {
+public:
+    static int lookupValueByLabel(const std::unordered_map<std::string, int>& map,
+                                  const char* literal);
+
+    static const char* lookupLabelByValue(const std::vector<InputEventLabel>& vec, int value);
+
+    static int32_t getKeyCodeByLabel(const char* label);
+
+    static const char* getLabelByKeyCode(int32_t keyCode);
+
+    static uint32_t getKeyFlagByLabel(const char* label);
+
+    static int32_t getAxisByLabel(const char* label);
+
+    static const char* getAxisLabel(int32_t axisId);
+
+    static int32_t getLedByLabel(const char* label);
+
+private:
+    static const std::unordered_map<std::string, int> KEYCODES;
+
+    static const std::vector<InputEventLabel> KEY_NAMES;
+
+    static const std::unordered_map<std::string, int> AXES;
+
+    static const std::vector<InputEventLabel> AXES_NAMES;
+
+    static const std::unordered_map<std::string, int> LEDS;
+
+    static const std::unordered_map<std::string, int> FLAGS;
 };
 
-static const std::vector<InputEventLabel> KEY_NAMES = {
-    KEYCODES_SEQUENCE
-};
-
-// NOTE: If you add a new axis here you must also add it to several other files.
-//       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
-#define AXES_SEQUENCE \
-    DEFINE_AXIS(X), \
-    DEFINE_AXIS(Y), \
-    DEFINE_AXIS(PRESSURE), \
-    DEFINE_AXIS(SIZE), \
-    DEFINE_AXIS(TOUCH_MAJOR), \
-    DEFINE_AXIS(TOUCH_MINOR), \
-    DEFINE_AXIS(TOOL_MAJOR), \
-    DEFINE_AXIS(TOOL_MINOR), \
-    DEFINE_AXIS(ORIENTATION), \
-    DEFINE_AXIS(VSCROLL), \
-    DEFINE_AXIS(HSCROLL), \
-    DEFINE_AXIS(Z), \
-    DEFINE_AXIS(RX), \
-    DEFINE_AXIS(RY), \
-    DEFINE_AXIS(RZ), \
-    DEFINE_AXIS(HAT_X), \
-    DEFINE_AXIS(HAT_Y), \
-    DEFINE_AXIS(LTRIGGER), \
-    DEFINE_AXIS(RTRIGGER), \
-    DEFINE_AXIS(THROTTLE), \
-    DEFINE_AXIS(RUDDER), \
-    DEFINE_AXIS(WHEEL), \
-    DEFINE_AXIS(GAS), \
-    DEFINE_AXIS(BRAKE), \
-    DEFINE_AXIS(DISTANCE), \
-    DEFINE_AXIS(TILT), \
-    DEFINE_AXIS(SCROLL), \
-    DEFINE_AXIS(RELATIVE_X), \
-    DEFINE_AXIS(RELATIVE_Y), \
-    DEFINE_AXIS(GENERIC_1), \
-    DEFINE_AXIS(GENERIC_2), \
-    DEFINE_AXIS(GENERIC_3), \
-    DEFINE_AXIS(GENERIC_4), \
-    DEFINE_AXIS(GENERIC_5), \
-    DEFINE_AXIS(GENERIC_6), \
-    DEFINE_AXIS(GENERIC_7), \
-    DEFINE_AXIS(GENERIC_8), \
-    DEFINE_AXIS(GENERIC_9), \
-    DEFINE_AXIS(GENERIC_10), \
-    DEFINE_AXIS(GENERIC_11), \
-    DEFINE_AXIS(GENERIC_12), \
-    DEFINE_AXIS(GENERIC_13), \
-    DEFINE_AXIS(GENERIC_14), \
-    DEFINE_AXIS(GENERIC_15), \
-    DEFINE_AXIS(GENERIC_16)
-
-static const std::unordered_map<std::string, int> AXES = {
-    AXES_SEQUENCE
-};
-
-static const std::vector<InputEventLabel> AXES_NAMES = {
-    AXES_SEQUENCE
-};
-
-// NOTE: If you add new LEDs here, you must also add them to Input.h
-#define LEDS_SEQUENCE \
-    DEFINE_LED(NUM_LOCK), \
-    DEFINE_LED(CAPS_LOCK), \
-    DEFINE_LED(SCROLL_LOCK), \
-    DEFINE_LED(COMPOSE), \
-    DEFINE_LED(KANA), \
-    DEFINE_LED(SLEEP), \
-    DEFINE_LED(SUSPEND), \
-    DEFINE_LED(MUTE), \
-    DEFINE_LED(MISC), \
-    DEFINE_LED(MAIL), \
-    DEFINE_LED(CHARGING), \
-    DEFINE_LED(CONTROLLER_1), \
-    DEFINE_LED(CONTROLLER_2), \
-    DEFINE_LED(CONTROLLER_3), \
-    DEFINE_LED(CONTROLLER_4)
-
-static const std::unordered_map<std::string, int> LEDS = {
-    LEDS_SEQUENCE
-};
-
-#define FLAGS_SEQUENCE \
-    DEFINE_FLAG(VIRTUAL), \
-    DEFINE_FLAG(FUNCTION), \
-    DEFINE_FLAG(GESTURE), \
-    DEFINE_FLAG(WAKE)
-
-static const std::unordered_map<std::string, int> FLAGS = {
-    FLAGS_SEQUENCE
-};
-
-static int lookupValueByLabel(const std::unordered_map<std::string, int> &map,
-        const char* literal) {
-    std::string str(literal);
-    auto it = map.find(str);
-    return it != map.end() ? it->second : 0;
-}
-
-static const char* lookupLabelByValue(const std::vector<InputEventLabel> &vec, int value) {
-    if (static_cast<size_t>(value) < vec.size()) {
-        return vec[value].literal;
-    }
-    return nullptr;
-}
-
-static inline int32_t getKeyCodeByLabel(const char* label) {
-    return int32_t(lookupValueByLabel(KEYCODES, label));
-}
-
-static inline const char* getLabelByKeyCode(int32_t keyCode) {
-    if (keyCode >= 0 && static_cast<size_t>(keyCode) < KEYCODES.size()) {
-        return lookupLabelByValue(KEY_NAMES, keyCode);
-    }
-    return nullptr;
-}
-
-static inline uint32_t getKeyFlagByLabel(const char* label) {
-    return uint32_t(lookupValueByLabel(FLAGS, label));
-}
-
-static inline int32_t getAxisByLabel(const char* label) {
-    return int32_t(lookupValueByLabel(AXES, label));
-}
-
-static inline const char* getAxisLabel(int32_t axisId) {
-    return lookupLabelByValue(AXES_NAMES, axisId);
-}
-
-static inline int32_t getLedByLabel(const char* label) {
-    return int32_t(lookupValueByLabel(LEDS, label));
-}
-
-
 } // namespace android
 #endif // _LIBINPUT_INPUT_EVENT_LABELS_H
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 8a752c1..7372022 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -167,8 +167,7 @@
      */
     Region touchableRegion;
     bool visible = false;
-    bool canReceiveKeys = false;
-    bool hasFocus = false;
+    bool focusable = false;
     bool hasWallpaper = false;
     bool paused = false;
     /* This flag is set when the window is of a trusted type that is allowed to silently
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 258a4e3..80aa891 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -22,6 +22,8 @@
 
 cc_library_headers {
     name: "libarect_headers",
+    // TODO(b/153609531): remove when no longer needed.
+    native_bridge_supported: true,
     export_include_dirs: ["include"],
 }
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 8fd59ba..14ab60f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -41,7 +41,6 @@
 #include <binder/TextOutput.h>
 
 #include <cutils/ashmem.h>
-#include <utils/Debug.h>
 #include <utils/Flattenable.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
@@ -1526,7 +1525,7 @@
 
 template<class T>
 status_t Parcel::readAligned(T *pArg) const {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
         if (mObjectsSize > 0) {
@@ -1559,7 +1558,7 @@
 
 template<class T>
 status_t Parcel::writeAligned(T val) {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(val)) <= mDataCapacity) {
 restart_write:
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 6d04f13..233f12a 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -133,7 +133,11 @@
         OP_DEPRECATED_1 = 96,
         OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97,
         OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98,
-        _NUM_OP = 99
+        OP_NO_ISOLATED_STORAGE = 99,
+        OP_PHONE_CALL_MICROPHONE = 100,
+        OP_PHONE_CALL_CAMERA = 101,
+        OP_RECORD_AUDIO_HOTWORD = 102,
+        _NUM_OP = 103
     };
 
     AppOpsManager();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 33ee680..468cc16 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -234,6 +234,7 @@
   "android.gui.IGraphicBufferConsumer",
   "android.gui.IRegionSamplingListener",
   "android.gui.ITransactionComposerListener",
+  "android.gui.IScreenCaptureListener",
   "android.gui.SensorEventConnection",
   "android.gui.SensorServer",
   "android.hardware.ICamera",
@@ -255,8 +256,6 @@
   "android.media.IAudioTrack",
   "android.media.IDataSource",
   "android.media.IDrmClient",
-  "android.media.IEffect",
-  "android.media.IEffectClient",
   "android.media.IMediaCodecList",
   "android.media.IMediaDrmService",
   "android.media.IMediaExtractor",
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 16811ee..0234820 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -3,12 +3,24 @@
     crate_name: "binder",
     srcs: ["src/lib.rs"],
     shared_libs: [
-        "libbinder_ndk",
         "libutils",
     ],
     rustlibs: [
         "liblibc",
-        "libbinder_ndk_bindgen",
+        "libbinder_ndk_sys",
+    ],
+    host_supported: true,
+}
+
+rust_library {
+    name: "libbinder_ndk_sys",
+    crate_name: "binder_ndk_sys",
+    srcs: [
+        "sys/lib.rs",
+        ":libbinder_ndk_bindgen",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
     ],
     host_supported: true,
 }
@@ -16,8 +28,8 @@
 rust_bindgen {
     name: "libbinder_ndk_bindgen",
     crate_name: "binder_ndk_bindgen",
-    wrapper_src: "BinderBindings.h",
-    source_stem: "ndk_bindings",
+    wrapper_src: "sys/BinderBindings.h",
+    source_stem: "bindings",
     cflags: [
         "-x c++",
     ],
@@ -69,6 +81,6 @@
     ],
     rustlibs: [
         "liblibc",
-        "libbinder_ndk_bindgen",
+        "libbinder_ndk_sys",
     ],
 }
diff --git a/libs/binder/rust/TEST_MAPPING b/libs/binder/rust/TEST_MAPPING
index 4470e17..50c474c 100644
--- a/libs/binder/rust/TEST_MAPPING
+++ b/libs/binder/rust/TEST_MAPPING
@@ -2,7 +2,9 @@
   "presubmit": [
     {
       "name": "libbinder_rs-internal_test"
-    },
+    }
+  ],
+  "postsubmit": [
     {
       "name": "rustBinderTest"
     }
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index f5e7509..d55eafe 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -61,7 +61,7 @@
 /// the AIDL backend, users need only implement the high-level AIDL-defined
 /// interface. The AIDL compiler then generates a container struct that wraps
 /// the user-defined service and implements `Remotable`.
-pub trait Remotable: Sync {
+pub trait Remotable: Send + Sync {
     /// The Binder interface descriptor string.
     ///
     /// This string is a unique identifier for a Binder interface, and should be
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index 289b157..4492cf7 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -43,14 +43,6 @@
     }
 }
 
-// impl Display for StatusCode {
-//     fn fmt(&self, f: &mut Formatter) -> FmtResult {
-//         write!(f, "StatusCode::{:?}", self)
-//     }
-// }
-
-// impl error::Error for StatusCode {}
-
 fn parse_status_code(code: i32) -> StatusCode {
     match code {
         e if e == StatusCode::OK as i32 => StatusCode::OK,
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 4b9cccf..8ee6a62 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -102,7 +102,7 @@
 mod native;
 mod state;
 
-use binder_ndk_bindgen as sys;
+use binder_ndk_sys as sys;
 
 pub mod parcel;
 
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 798fed8..185645e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -36,6 +36,18 @@
     rust_object: *mut T,
 }
 
+/// # Safety
+///
+/// A `Binder<T>` is a pair of unique owning pointers to two values:
+///   * a C++ ABBinder which the C++ API guarantees can be passed between threads
+///   * a Rust object which implements `Remotable`; this trait requires `Send + Sync`
+///
+/// Both pointers are unique (never escape the `Binder<T>` object and are not copied)
+/// so we can essentially treat `Binder<T>` as a box-like containing the two objects;
+/// the box-like object inherits `Send` from the two inner values, similarly
+/// to how `Box<T>` is `Send` if `T` is `Send`.
+unsafe impl<T: Remotable> Send for Binder<T> {}
+
 impl<T: Remotable> Binder<T> {
     /// Create a new Binder remotable object.
     ///
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 43850fe..a248f5c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -21,6 +21,7 @@
 use crate::proxy::SpIBinder;
 use crate::sys;
 
+use std::cell::RefCell;
 use std::convert::TryInto;
 use std::mem::ManuallyDrop;
 use std::ptr;
@@ -117,6 +118,55 @@
         }
     }
 
+    /// Perform a series of writes to the `Parcel`, prepended with the length
+    /// (in bytes) of the written data.
+    ///
+    /// The length `0i32` will be written to the parcel first, followed by the
+    /// writes performed by the callback. The initial length will then be
+    /// updated to the length of all data written by the callback, plus the
+    /// size of the length elemement itself (4 bytes).
+    ///
+    /// # Examples
+    ///
+    /// After the following call:
+    ///
+    /// ```
+    /// # use binder::{Binder, Interface, Parcel};
+    /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+    /// parcel.sized_write(|subparcel| {
+    ///     subparcel.write(&1u32)?;
+    ///     subparcel.write(&2u32)?;
+    ///     subparcel.write(&3u32)
+    /// });
+    /// ```
+    ///
+    /// `parcel` will contain the following:
+    ///
+    /// ```ignore
+    /// [16i32, 1u32, 2u32, 3u32]
+    /// ```
+    pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+    where for<'a>
+        F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+    {
+        let start = self.get_data_position();
+        self.write(&0i32)?;
+        {
+            let subparcel = WritableSubParcel(RefCell::new(self));
+            f(&subparcel)?;
+        }
+        let end = self.get_data_position();
+        unsafe {
+            self.set_data_position(start)?;
+        }
+        assert!(end >= start);
+        self.write(&(end - start))?;
+        unsafe {
+            self.set_data_position(end)?;
+        }
+        Ok(())
+    }
+
     /// Returns the current position in the parcel data.
     pub fn get_data_position(&self) -> i32 {
         unsafe {
@@ -143,6 +193,16 @@
     }
 }
 
+/// A segment of a writable parcel, used for [`Parcel::sized_write`].
+pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+
+impl<'a> WritableSubParcel<'a> {
+    /// Write a type that implements [`Serialize`] to the sub-parcel.
+    pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
+        parcelable.serialize(&mut *self.0.borrow_mut())
+    }
+}
+
 // Data deserialization methods
 impl Parcel {
     /// Attempt to read a type that implements [`Deserialize`] from this
@@ -445,3 +505,38 @@
     );
     assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
 }
+
+#[test]
+fn test_sized_write() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+
+    let mut service = Binder::new(()).as_binder();
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    let arr = [1i32, 2i32, 3i32];
+
+    parcel.sized_write(|subparcel| {
+        subparcel.write(&arr[..])
+    }).expect("Could not perform sized write");
+
+    // i32 sub-parcel length + i32 array length + 3 i32 elements
+    let expected_len = 20i32;
+
+    assert_eq!(parcel.get_data_position(), start + expected_len);
+
+    unsafe {
+        parcel.set_data_position(start).unwrap();
+    }
+
+    assert_eq!(
+        expected_len,
+        parcel.read().unwrap(),
+    );
+
+    assert_eq!(
+        parcel.read::<Vec<i32>>().unwrap(),
+        &arr,
+    );
+}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index f9519b4..13e5619 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -122,6 +122,14 @@
     }
 }
 
+impl PartialEq for SpIBinder {
+    fn eq(&self, other: &Self) -> bool {
+        ptr::eq(self.0, other.0)
+    }
+}
+
+impl Eq for SpIBinder {}
+
 impl Clone for SpIBinder {
     fn clone(&self) -> Self {
         unsafe {
@@ -363,6 +371,18 @@
         assert!(!ptr.is_null());
         Self(ptr)
     }
+
+    /// Promote this weak reference to a strong reference to the binder object.
+    pub fn promote(&self) -> Option<SpIBinder> {
+        unsafe {
+            // Safety: `WpIBinder` always contains a valid weak reference, so we
+            // can pass this pointer to `AIBinder_Weak_promote`. Returns either
+            // null or an AIBinder owned by the caller, both of which are valid
+            // to pass to `SpIBinder::from_raw`.
+            let ptr = sys::AIBinder_Weak_promote(self.0);
+            SpIBinder::from_raw(ptr)
+        }
+    }
 }
 
 /// Rust wrapper around DeathRecipient objects.
diff --git a/libs/binder/rust/BinderBindings.h b/libs/binder/rust/sys/BinderBindings.h
similarity index 100%
rename from libs/binder/rust/BinderBindings.h
rename to libs/binder/rust/sys/BinderBindings.h
diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs
new file mode 100644
index 0000000..9095af2
--- /dev/null
+++ b/libs/binder/rust/sys/lib.rs
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+//! Generated Rust bindings to libbinder_ndk
+
+#![allow(
+    non_camel_case_types,
+    non_snake_case,
+    non_upper_case_globals,
+    unused,
+    improper_ctypes,
+    missing_docs
+)]
+use std::error::Error;
+use std::fmt;
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+
+impl Error for android_c_interface_StatusCode {}
+
+impl fmt::Display for android_c_interface_StatusCode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "StatusCode::{:?}", self)
+    }
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 3ec4b3a..8f092f6 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -56,6 +56,7 @@
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
+        "android.hardware.audio@7.0::IDevicesFactory",
         "android.hardware.automotive.audiocontrol@1.0::IAudioControl",
         "android.hardware.automotive.audiocontrol@2.0::IAudioControl",
         "android.hardware.automotive.evs@1.0::IEvsCamera",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 686e274..9285b23 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -62,6 +62,7 @@
         "IGraphicBufferProducer.cpp",
         "IProducerListener.cpp",
         "IRegionSamplingListener.cpp",
+        "IScreenCaptureListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
         "ITransactionCompletedListener.cpp",
diff --git a/libs/gui/IScreenCaptureListener.cpp b/libs/gui/IScreenCaptureListener.cpp
new file mode 100644
index 0000000..0635e9c
--- /dev/null
+++ b/libs/gui/IScreenCaptureListener.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 <gui/IScreenCaptureListener.h>
+#include <gui/LayerState.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_SCREEN_CAPTURE_COMPLETE = IBinder::FIRST_CALL_TRANSACTION,
+    LAST = ON_SCREEN_CAPTURE_COMPLETE,
+};
+
+} // Anonymous namespace
+
+class BpScreenCaptureListener : public SafeBpInterface<IScreenCaptureListener> {
+public:
+    explicit BpScreenCaptureListener(const sp<IBinder>& impl)
+          : SafeBpInterface<IScreenCaptureListener>(impl, "BpScreenCaptureListener") {}
+
+    ~BpScreenCaptureListener() override;
+
+    status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IScreenCaptureListener::getInterfaceDescriptor());
+
+        SAFE_PARCEL(captureResults.write, data);
+        return remote()->transact(static_cast<uint32_t>(Tag::ON_SCREEN_CAPTURE_COMPLETE), data,
+                                  &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpScreenCaptureListener::~BpScreenCaptureListener() = default;
+
+IMPLEMENT_META_INTERFACE(ScreenCaptureListener, "android.gui.IScreenCaptureListener");
+
+status_t BnScreenCaptureListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                             uint32_t flags) {
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_SCREEN_CAPTURE_COMPLETE: {
+            CHECK_INTERFACE(IScreenCaptureListener, data, reply);
+            ScreenCaptureResults captureResults;
+            SAFE_PARCEL(captureResults.read, data);
+            return onScreenCaptureComplete(captureResults);
+        }
+        default: {
+            return BBinder::onTransact(code, data, reply, flags);
+        }
+    }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4a12035..0ac493d 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -66,42 +66,39 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual void setTransactionState(const Vector<ComposerState>& state,
-                                     const Vector<DisplayState>& displays, uint32_t flags,
-                                     const sp<IBinder>& applyToken,
-                                     const InputWindowCommands& commands,
-                                     int64_t desiredPresentTime,
-                                     const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
-                                     const std::vector<ListenerCallbacks>& listenerCallbacks) {
+    virtual status_t setTransactionState(
+            const Vector<ComposerState>& state, const Vector<DisplayState>& displays,
+            uint32_t flags, const sp<IBinder>& applyToken, const InputWindowCommands& commands,
+            int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+            bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
-        data.writeUint32(static_cast<uint32_t>(state.size()));
+        SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size()));
         for (const auto& s : state) {
-            s.write(data);
+            SAFE_PARCEL(s.write, data);
         }
 
-        data.writeUint32(static_cast<uint32_t>(displays.size()));
+        SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(displays.size()));
         for (const auto& d : displays) {
-            d.write(data);
+            SAFE_PARCEL(d.write, data);
         }
 
-        data.writeUint32(flags);
-        data.writeStrongBinder(applyToken);
-        commands.write(data);
-        data.writeInt64(desiredPresentTime);
-        data.writeStrongBinder(uncacheBuffer.token.promote());
-        data.writeUint64(uncacheBuffer.id);
-        data.writeBool(hasListenerCallbacks);
+        SAFE_PARCEL(data.writeUint32, flags);
+        SAFE_PARCEL(data.writeStrongBinder, applyToken);
+        SAFE_PARCEL(commands.write, data);
+        SAFE_PARCEL(data.writeInt64, desiredPresentTime);
+        SAFE_PARCEL(data.writeStrongBinder, uncacheBuffer.token.promote());
+        SAFE_PARCEL(data.writeUint64, uncacheBuffer.id);
+        SAFE_PARCEL(data.writeBool, hasListenerCallbacks);
 
-        if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) {
-            for (const auto& [listener, callbackIds] : listenerCallbacks) {
-                data.writeStrongBinder(listener);
-                data.writeInt64Vector(callbackIds);
-            }
+        SAFE_PARCEL(data.writeVectorSize, listenerCallbacks);
+        for (const auto& [listener, callbackIds] : listenerCallbacks) {
+            SAFE_PARCEL(data.writeStrongBinder, listener);
+            SAFE_PARCEL(data.writeInt64Vector, callbackIds);
         }
 
-        remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
+        return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
     virtual void bootFinished()
@@ -112,75 +109,33 @@
     }
 
     virtual status_t captureDisplay(const DisplayCaptureArgs& args,
-                                    ScreenCaptureResults& captureResults) {
+                                    const sp<IScreenCaptureListener>& captureListener) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        SAFE_PARCEL(args.write, data);
+        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
 
-        status_t result = args.write(data);
-        if (result != NO_ERROR) {
-            ALOGE("captureDisplay failed to parcel args: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("captureDisplay failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result != NO_ERROR) {
-            ALOGE("captureDisplay failed to readInt32: %d", result);
-            return result;
-        }
-
-        captureResults.read(reply);
-        return result;
+        return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
     }
 
     virtual status_t captureDisplay(uint64_t displayOrLayerStack,
-                                    ScreenCaptureResults& captureResults) {
+                                    const sp<IScreenCaptureListener>& captureListener) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeUint64(displayOrLayerStack);
-        status_t result =
-                remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("captureDisplay failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result != NO_ERROR) {
-            ALOGE("captureDisplay failed to readInt32: %d", result);
-            return result;
-        }
+        SAFE_PARCEL(data.writeUint64, displayOrLayerStack);
+        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
 
-        captureResults.read(reply);
-        return result;
+        return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
     }
 
     virtual status_t captureLayers(const LayerCaptureArgs& args,
-                                   ScreenCaptureResults& captureResults) {
+                                   const sp<IScreenCaptureListener>& captureListener) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        SAFE_PARCEL(args.write, data);
+        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
 
-        status_t result = args.write(data);
-        if (result != NO_ERROR) {
-            ALOGE("captureLayers failed to parcel args: %d", result);
-            return result;
-        }
-
-        result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("captureLayers failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result != NO_ERROR) {
-            ALOGE("captureLayers failed to readInt32: %d", result);
-            return result;
-        }
-
-        captureResults.read(reply);
-        return result;
+        return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
     }
 
     virtual bool authenticateSurfaceTexture(
@@ -1218,59 +1173,56 @@
         case SET_TRANSACTION_STATE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
-            size_t count = data.readUint32();
-            if (count > data.dataSize()) {
-                return BAD_VALUE;
-            }
+            uint32_t count = 0;
+            SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
             Vector<ComposerState> state;
             state.setCapacity(count);
             for (size_t i = 0; i < count; i++) {
                 ComposerState s;
-                if (s.read(data) == BAD_VALUE) {
-                    return BAD_VALUE;
-                }
+                SAFE_PARCEL(s.read, data);
                 state.add(s);
             }
 
-            count = data.readUint32();
-            if (count > data.dataSize()) {
-                return BAD_VALUE;
-            }
+            SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
             DisplayState d;
             Vector<DisplayState> displays;
             displays.setCapacity(count);
             for (size_t i = 0; i < count; i++) {
-                if (d.read(data) == BAD_VALUE) {
-                    return BAD_VALUE;
-                }
+                SAFE_PARCEL(d.read, data);
                 displays.add(d);
             }
 
-            uint32_t stateFlags = data.readUint32();
-            sp<IBinder> applyToken = data.readStrongBinder();
+            uint32_t stateFlags = 0;
+            SAFE_PARCEL(data.readUint32, &stateFlags);
+            sp<IBinder> applyToken;
+            SAFE_PARCEL(data.readStrongBinder, &applyToken);
             InputWindowCommands inputWindowCommands;
-            inputWindowCommands.read(data);
+            SAFE_PARCEL(inputWindowCommands.read, data);
 
-            int64_t desiredPresentTime = data.readInt64();
+            int64_t desiredPresentTime = 0;
+            SAFE_PARCEL(data.readInt64, &desiredPresentTime);
 
             client_cache_t uncachedBuffer;
-            uncachedBuffer.token = data.readStrongBinder();
-            uncachedBuffer.id = data.readUint64();
+            sp<IBinder> tmpBinder;
+            SAFE_PARCEL(data.readNullableStrongBinder, &tmpBinder);
+            uncachedBuffer.token = tmpBinder;
+            SAFE_PARCEL(data.readUint64, &uncachedBuffer.id);
 
-            bool hasListenerCallbacks = data.readBool();
+            bool hasListenerCallbacks = false;
+            SAFE_PARCEL(data.readBool, &hasListenerCallbacks);
 
             std::vector<ListenerCallbacks> listenerCallbacks;
-            int32_t listenersSize = data.readInt32();
+            int32_t listenersSize = 0;
+            SAFE_PARCEL_READ_SIZE(data.readInt32, &listenersSize, data.dataSize());
             for (int32_t i = 0; i < listenersSize; i++) {
-                auto listener = data.readStrongBinder();
+                SAFE_PARCEL(data.readStrongBinder, &tmpBinder);
                 std::vector<CallbackId> callbackIds;
-                data.readInt64Vector(&callbackIds);
-                listenerCallbacks.emplace_back(listener, callbackIds);
+                SAFE_PARCEL(data.readInt64Vector, &callbackIds);
+                listenerCallbacks.emplace_back(tmpBinder, callbackIds);
             }
-            setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
-                                desiredPresentTime, uncachedBuffer, hasListenerCallbacks,
-                                listenerCallbacks);
-            return NO_ERROR;
+            return setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
+                                       desiredPresentTime, uncachedBuffer, hasListenerCallbacks,
+                                       listenerCallbacks);
         }
         case BOOT_FINISHED: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1280,50 +1232,29 @@
         case CAPTURE_DISPLAY: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             DisplayCaptureArgs args;
-            ScreenCaptureResults captureResults;
+            sp<IScreenCaptureListener> captureListener;
+            SAFE_PARCEL(args.read, data);
+            SAFE_PARCEL(data.readStrongBinder, &captureListener);
 
-            status_t res = args.read(data);
-            if (res != NO_ERROR) {
-                reply->writeInt32(res);
-                return NO_ERROR;
-            }
-
-            res = captureDisplay(args, captureResults);
-
-            reply->writeInt32(res);
-            if (res == NO_ERROR) {
-                captureResults.write(*reply);
-            }
-            return NO_ERROR;
+            return captureDisplay(args, captureListener);
         }
         case CAPTURE_DISPLAY_BY_ID: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            uint64_t displayOrLayerStack = data.readUint64();
-            ScreenCaptureResults captureResults;
-            status_t res = captureDisplay(displayOrLayerStack, captureResults);
-            reply->writeInt32(res);
-            if (res == NO_ERROR) {
-                captureResults.write(*reply);
-            }
-            return NO_ERROR;
+            uint64_t displayOrLayerStack = 0;
+            sp<IScreenCaptureListener> captureListener;
+            SAFE_PARCEL(data.readUint64, &displayOrLayerStack);
+            SAFE_PARCEL(data.readStrongBinder, &captureListener);
+
+            return captureDisplay(displayOrLayerStack, captureListener);
         }
         case CAPTURE_LAYERS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             LayerCaptureArgs args;
-            ScreenCaptureResults captureResults;
+            sp<IScreenCaptureListener> captureListener;
+            SAFE_PARCEL(args.read, data);
+            SAFE_PARCEL(data.readStrongBinder, &captureListener);
 
-            status_t res = args.read(data);
-            if (res != NO_ERROR) {
-                reply->writeInt32(res);
-                return NO_ERROR;
-            }
-
-            res = captureLayers(args, captureResults);
-            reply->writeInt32(res);
-            if (res == NO_ERROR) {
-                captureResults.write(*reply);
-            }
-            return NO_ERROR;
+            return captureLayers(args, captureListener);
         }
         case AUTHENTICATE_SURFACE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 725d3cd..3b0b392 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -30,181 +30,189 @@
 
 status_t layer_state_t::write(Parcel& output) const
 {
-    output.writeStrongBinder(surface);
-    output.writeUint64(what);
-    output.writeFloat(x);
-    output.writeFloat(y);
-    output.writeInt32(z);
-    output.writeUint32(w);
-    output.writeUint32(h);
-    output.writeUint32(layerStack);
-    output.writeFloat(alpha);
-    output.writeUint32(flags);
-    output.writeUint32(mask);
-    *reinterpret_cast<layer_state_t::matrix22_t *>(
-            output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
-    output.write(crop_legacy);
-    output.writeStrongBinder(barrierHandle_legacy);
-    output.writeStrongBinder(reparentHandle);
-    output.writeUint64(frameNumber_legacy);
-    output.writeInt32(overrideScalingMode);
-    output.writeStrongBinder(IInterface::asBinder(barrierGbp_legacy));
-    output.writeStrongBinder(relativeLayerHandle);
-    output.writeStrongBinder(parentHandleForChild);
-    output.writeFloat(color.r);
-    output.writeFloat(color.g);
-    output.writeFloat(color.b);
+    SAFE_PARCEL(output.writeStrongBinder, surface);
+    SAFE_PARCEL(output.writeUint64, what);
+    SAFE_PARCEL(output.writeFloat, x);
+    SAFE_PARCEL(output.writeFloat, y);
+    SAFE_PARCEL(output.writeInt32, z);
+    SAFE_PARCEL(output.writeUint32, w);
+    SAFE_PARCEL(output.writeUint32, h);
+    SAFE_PARCEL(output.writeUint32, layerStack);
+    SAFE_PARCEL(output.writeFloat, alpha);
+    SAFE_PARCEL(output.writeUint32, flags);
+    SAFE_PARCEL(output.writeUint32, mask);
+    SAFE_PARCEL(matrix.write, output);
+    SAFE_PARCEL(output.write, crop_legacy);
+    SAFE_PARCEL(output.writeStrongBinder, barrierHandle_legacy);
+    SAFE_PARCEL(output.writeStrongBinder, reparentHandle);
+    SAFE_PARCEL(output.writeUint64, frameNumber_legacy);
+    SAFE_PARCEL(output.writeInt32, overrideScalingMode);
+    SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(barrierGbp_legacy));
+    SAFE_PARCEL(output.writeStrongBinder, relativeLayerHandle);
+    SAFE_PARCEL(output.writeStrongBinder, parentHandleForChild);
+    SAFE_PARCEL(output.writeFloat, color.r);
+    SAFE_PARCEL(output.writeFloat, color.g);
+    SAFE_PARCEL(output.writeFloat, color.b);
 #ifndef NO_INPUT
-    inputHandle->writeToParcel(&output);
+    SAFE_PARCEL(inputHandle->writeToParcel, &output);
 #endif
-    output.write(transparentRegion);
-    output.writeUint32(transform);
-    output.writeBool(transformToDisplayInverse);
-    output.write(crop);
-    output.write(orientedDisplaySpaceRect);
+    SAFE_PARCEL(output.write, transparentRegion);
+    SAFE_PARCEL(output.writeUint32, transform);
+    SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
+    SAFE_PARCEL(output.write, crop);
+    SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
+
     if (buffer) {
-        output.writeBool(true);
-        output.write(*buffer);
+        SAFE_PARCEL(output.writeBool, true);
+        SAFE_PARCEL(output.write, *buffer);
     } else {
-        output.writeBool(false);
+        SAFE_PARCEL(output.writeBool, false);
     }
+
     if (acquireFence) {
-        output.writeBool(true);
-        output.write(*acquireFence);
+        SAFE_PARCEL(output.writeBool, true);
+        SAFE_PARCEL(output.write, *acquireFence);
     } else {
-        output.writeBool(false);
+        SAFE_PARCEL(output.writeBool, false);
     }
-    output.writeUint32(static_cast<uint32_t>(dataspace));
-    output.write(hdrMetadata);
-    output.write(surfaceDamageRegion);
-    output.writeInt32(api);
+
+    SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace));
+    SAFE_PARCEL(output.write, hdrMetadata);
+    SAFE_PARCEL(output.write, surfaceDamageRegion);
+    SAFE_PARCEL(output.writeInt32, api);
+
     if (sidebandStream) {
-        output.writeBool(true);
-        output.writeNativeHandle(sidebandStream->handle());
+        SAFE_PARCEL(output.writeBool, true);
+        SAFE_PARCEL(output.writeNativeHandle, sidebandStream->handle());
     } else {
-        output.writeBool(false);
+        SAFE_PARCEL(output.writeBool, false);
     }
 
-    memcpy(output.writeInplace(16 * sizeof(float)),
-           colorTransform.asArray(), 16 * sizeof(float));
-    output.writeFloat(cornerRadius);
-    output.writeUint32(backgroundBlurRadius);
-    output.writeStrongBinder(cachedBuffer.token.promote());
-    output.writeUint64(cachedBuffer.id);
-    output.writeParcelable(metadata);
-
-    output.writeFloat(bgColorAlpha);
-    output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
-    output.writeBool(colorSpaceAgnostic);
-
-    auto err = output.writeVectorSize(listeners);
-    if (err) {
-        return err;
-    }
+    SAFE_PARCEL(output.write, colorTransform.asArray(), 16 * sizeof(float));
+    SAFE_PARCEL(output.writeFloat, cornerRadius);
+    SAFE_PARCEL(output.writeUint32, backgroundBlurRadius);
+    SAFE_PARCEL(output.writeStrongBinder, cachedBuffer.token.promote());
+    SAFE_PARCEL(output.writeUint64, cachedBuffer.id);
+    SAFE_PARCEL(output.writeParcelable, metadata);
+    SAFE_PARCEL(output.writeFloat, bgColorAlpha);
+    SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(bgColorDataspace));
+    SAFE_PARCEL(output.writeBool, colorSpaceAgnostic);
+    SAFE_PARCEL(output.writeVectorSize, listeners);
 
     for (auto listener : listeners) {
-        err = output.writeStrongBinder(listener.transactionCompletedListener);
-        if (err) {
-            return err;
-        }
-        err = output.writeInt64Vector(listener.callbackIds);
-        if (err) {
-            return err;
-        }
+        SAFE_PARCEL(output.writeStrongBinder, listener.transactionCompletedListener);
+        SAFE_PARCEL(output.writeInt64Vector, listener.callbackIds);
     }
-    output.writeFloat(shadowRadius);
-    output.writeInt32(frameRateSelectionPriority);
-    output.writeFloat(frameRate);
-    output.writeByte(frameRateCompatibility);
-    output.writeUint32(fixedTransformHint);
+    SAFE_PARCEL(output.writeFloat, shadowRadius);
+    SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority);
+    SAFE_PARCEL(output.writeFloat, frameRate);
+    SAFE_PARCEL(output.writeByte, frameRateCompatibility);
+    SAFE_PARCEL(output.writeUint32, fixedTransformHint);
     return NO_ERROR;
 }
 
 status_t layer_state_t::read(const Parcel& input)
 {
-    surface = input.readStrongBinder();
-    what = input.readUint64();
-    x = input.readFloat();
-    y = input.readFloat();
-    z = input.readInt32();
-    w = input.readUint32();
-    h = input.readUint32();
-    layerStack = input.readUint32();
-    alpha = input.readFloat();
-    flags = static_cast<uint8_t>(input.readUint32());
-    mask = static_cast<uint8_t>(input.readUint32());
-    const void* matrix_data = input.readInplace(sizeof(layer_state_t::matrix22_t));
-    if (matrix_data) {
-        matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>(matrix_data);
-    } else {
-        return BAD_VALUE;
-    }
-    input.read(crop_legacy);
-    barrierHandle_legacy = input.readStrongBinder();
-    reparentHandle = input.readStrongBinder();
-    frameNumber_legacy = input.readUint64();
-    overrideScalingMode = input.readInt32();
-    barrierGbp_legacy = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
-    relativeLayerHandle = input.readStrongBinder();
-    parentHandleForChild = input.readStrongBinder();
-    color.r = input.readFloat();
-    color.g = input.readFloat();
-    color.b = input.readFloat();
+    SAFE_PARCEL(input.readNullableStrongBinder, &surface);
+    SAFE_PARCEL(input.readUint64, &what);
+    SAFE_PARCEL(input.readFloat, &x);
+    SAFE_PARCEL(input.readFloat, &y);
+    SAFE_PARCEL(input.readInt32, &z);
+    SAFE_PARCEL(input.readUint32, &w);
+    SAFE_PARCEL(input.readUint32, &h);
+    SAFE_PARCEL(input.readUint32, &layerStack);
+    SAFE_PARCEL(input.readFloat, &alpha);
 
+    uint32_t tmpUint32 = 0;
+    SAFE_PARCEL(input.readUint32, &tmpUint32);
+    flags = static_cast<uint8_t>(tmpUint32);
+
+    SAFE_PARCEL(input.readUint32, &tmpUint32);
+    mask = static_cast<uint8_t>(tmpUint32);
+
+    SAFE_PARCEL(matrix.read, input);
+    SAFE_PARCEL(input.read, crop_legacy);
+    SAFE_PARCEL(input.readNullableStrongBinder, &barrierHandle_legacy);
+    SAFE_PARCEL(input.readNullableStrongBinder, &reparentHandle);
+    SAFE_PARCEL(input.readUint64, &frameNumber_legacy);
+    SAFE_PARCEL(input.readInt32, &overrideScalingMode);
+
+    sp<IBinder> tmpBinder;
+    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+    barrierGbp_legacy = interface_cast<IGraphicBufferProducer>(tmpBinder);
+
+    float tmpFloat = 0;
+    SAFE_PARCEL(input.readNullableStrongBinder, &relativeLayerHandle);
+    SAFE_PARCEL(input.readNullableStrongBinder, &parentHandleForChild);
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    color.r = tmpFloat;
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    color.g = tmpFloat;
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    color.b = tmpFloat;
 #ifndef NO_INPUT
-    inputHandle->readFromParcel(&input);
+    SAFE_PARCEL(inputHandle->readFromParcel, &input);
 #endif
 
-    input.read(transparentRegion);
-    transform = input.readUint32();
-    transformToDisplayInverse = input.readBool();
-    input.read(crop);
-    input.read(orientedDisplaySpaceRect);
-    buffer = new GraphicBuffer();
-    if (input.readBool()) {
-        input.read(*buffer);
+    SAFE_PARCEL(input.read, transparentRegion);
+    SAFE_PARCEL(input.readUint32, &transform);
+    SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
+    SAFE_PARCEL(input.read, crop);
+    SAFE_PARCEL(input.read, orientedDisplaySpaceRect);
+
+    bool tmpBool = false;
+    SAFE_PARCEL(input.readBool, &tmpBool);
+    if (tmpBool) {
+        buffer = new GraphicBuffer();
+        SAFE_PARCEL(input.read, *buffer);
     }
-    acquireFence = new Fence();
-    if (input.readBool()) {
-        input.read(*acquireFence);
+
+    SAFE_PARCEL(input.readBool, &tmpBool);
+    if (tmpBool) {
+        acquireFence = new Fence();
+        SAFE_PARCEL(input.read, *acquireFence);
     }
-    dataspace = static_cast<ui::Dataspace>(input.readUint32());
-    input.read(hdrMetadata);
-    input.read(surfaceDamageRegion);
-    api = input.readInt32();
-    if (input.readBool()) {
+
+    SAFE_PARCEL(input.readUint32, &tmpUint32);
+    dataspace = static_cast<ui::Dataspace>(tmpUint32);
+
+    SAFE_PARCEL(input.read, hdrMetadata);
+    SAFE_PARCEL(input.read, surfaceDamageRegion);
+    SAFE_PARCEL(input.readInt32, &api);
+    SAFE_PARCEL(input.readBool, &tmpBool);
+    if (tmpBool) {
         sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
     }
 
-    const void* color_transform_data = input.readInplace(16 * sizeof(float));
-    if (color_transform_data) {
-        colorTransform = mat4(static_cast<const float*>(color_transform_data));
-    } else {
-        return BAD_VALUE;
-    }
-    cornerRadius = input.readFloat();
-    backgroundBlurRadius = input.readUint32();
-    cachedBuffer.token = input.readStrongBinder();
-    cachedBuffer.id = input.readUint64();
-    input.readParcelable(&metadata);
+    SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float));
+    SAFE_PARCEL(input.readFloat, &cornerRadius);
+    SAFE_PARCEL(input.readUint32, &backgroundBlurRadius);
+    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+    cachedBuffer.token = tmpBinder;
+    SAFE_PARCEL(input.readUint64, &cachedBuffer.id);
+    SAFE_PARCEL(input.readParcelable, &metadata);
 
-    bgColorAlpha = input.readFloat();
-    bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
-    colorSpaceAgnostic = input.readBool();
+    SAFE_PARCEL(input.readFloat, &bgColorAlpha);
+    SAFE_PARCEL(input.readUint32, &tmpUint32);
+    bgColorDataspace = static_cast<ui::Dataspace>(tmpUint32);
+    SAFE_PARCEL(input.readBool, &colorSpaceAgnostic);
 
-    int32_t numListeners = input.readInt32();
+    int32_t numListeners = 0;
+    SAFE_PARCEL_READ_SIZE(input.readInt32, &numListeners, input.dataSize());
     listeners.clear();
     for (int i = 0; i < numListeners; i++) {
-        auto listener = input.readStrongBinder();
+        sp<IBinder> listener;
         std::vector<CallbackId> callbackIds;
-        input.readInt64Vector(&callbackIds);
+        SAFE_PARCEL(input.readNullableStrongBinder, &listener);
+        SAFE_PARCEL(input.readInt64Vector, &callbackIds);
         listeners.emplace_back(listener, callbackIds);
     }
-    shadowRadius = input.readFloat();
-    frameRateSelectionPriority = input.readInt32();
-    frameRate = input.readFloat();
-    frameRateCompatibility = input.readByte();
-    fixedTransformHint = static_cast<ui::Transform::RotationFlags>(input.readUint32());
+    SAFE_PARCEL(input.readFloat, &shadowRadius);
+    SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority);
+    SAFE_PARCEL(input.readFloat, &frameRate);
+    SAFE_PARCEL(input.readByte, &frameRateCompatibility);
+    SAFE_PARCEL(input.readUint32, &tmpUint32);
+    fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
     return NO_ERROR;
 }
 
@@ -225,28 +233,34 @@
         height(0) {}
 
 status_t DisplayState::write(Parcel& output) const {
-    output.writeStrongBinder(token);
-    output.writeStrongBinder(IInterface::asBinder(surface));
-    output.writeUint32(what);
-    output.writeUint32(layerStack);
-    output.writeUint32(toRotationInt(orientation));
-    output.write(layerStackSpaceRect);
-    output.write(orientedDisplaySpaceRect);
-    output.writeUint32(width);
-    output.writeUint32(height);
+    SAFE_PARCEL(output.writeStrongBinder, token);
+    SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface));
+    SAFE_PARCEL(output.writeUint32, what);
+    SAFE_PARCEL(output.writeUint32, layerStack);
+    SAFE_PARCEL(output.writeUint32, toRotationInt(orientation));
+    SAFE_PARCEL(output.write, layerStackSpaceRect);
+    SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
+    SAFE_PARCEL(output.writeUint32, width);
+    SAFE_PARCEL(output.writeUint32, height);
     return NO_ERROR;
 }
 
 status_t DisplayState::read(const Parcel& input) {
-    token = input.readStrongBinder();
-    surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
-    what = input.readUint32();
-    layerStack = input.readUint32();
-    orientation = ui::toRotation(input.readUint32());
-    input.read(layerStackSpaceRect);
-    input.read(orientedDisplaySpaceRect);
-    width = input.readUint32();
-    height = input.readUint32();
+    SAFE_PARCEL(input.readStrongBinder, &token);
+    sp<IBinder> tmpBinder;
+    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+    surface = interface_cast<IGraphicBufferProducer>(tmpBinder);
+
+    SAFE_PARCEL(input.readUint32, &what);
+    SAFE_PARCEL(input.readUint32, &layerStack);
+    uint32_t tmpUint = 0;
+    SAFE_PARCEL(input.readUint32, &tmpUint);
+    orientation = ui::toRotation(tmpUint);
+
+    SAFE_PARCEL(input.read, layerStackSpaceRect);
+    SAFE_PARCEL(input.read, orientedDisplaySpaceRect);
+    SAFE_PARCEL(input.readUint32, &width);
+    SAFE_PARCEL(input.readUint32, &height);
     return NO_ERROR;
 }
 
@@ -449,6 +463,22 @@
     }
 }
 
+status_t layer_state_t::matrix22_t::write(Parcel& output) const {
+    SAFE_PARCEL(output.writeFloat, dsdx);
+    SAFE_PARCEL(output.writeFloat, dtdx);
+    SAFE_PARCEL(output.writeFloat, dtdy);
+    SAFE_PARCEL(output.writeFloat, dsdy);
+    return NO_ERROR;
+}
+
+status_t layer_state_t::matrix22_t::read(const Parcel& input) {
+    SAFE_PARCEL(input.readFloat, &dsdx);
+    SAFE_PARCEL(input.readFloat, &dtdx);
+    SAFE_PARCEL(input.readFloat, &dtdy);
+    SAFE_PARCEL(input.readFloat, &dsdy);
+    return NO_ERROR;
+}
+
 // ------------------------------- InputWindowCommands ----------------------------------------
 
 bool InputWindowCommands::merge(const InputWindowCommands& other) {
@@ -470,18 +500,20 @@
     syncInputWindows = false;
 }
 
-void InputWindowCommands::write(Parcel& output) const {
+status_t InputWindowCommands::write(Parcel& output) const {
 #ifndef NO_INPUT
-    output.writeParcelableVector(focusRequests);
+    SAFE_PARCEL(output.writeParcelableVector, focusRequests);
 #endif
-    output.writeBool(syncInputWindows);
+    SAFE_PARCEL(output.writeBool, syncInputWindows);
+    return NO_ERROR;
 }
 
-void InputWindowCommands::read(const Parcel& input) {
+status_t InputWindowCommands::read(const Parcel& input) {
 #ifndef NO_INPUT
-    input.readParcelableVector(&focusRequests);
+    SAFE_PARCEL(input.readParcelableVector, &focusRequests);
 #endif
-    syncInputWindows = input.readBool();
+    SAFE_PARCEL(input.readBool, &syncInputWindows);
+    return NO_ERROR;
 }
 
 bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) {
@@ -504,93 +536,103 @@
 // ----------------------------------------------------------------------------
 
 status_t CaptureArgs::write(Parcel& output) const {
-    status_t status = output.writeInt32(static_cast<int32_t>(pixelFormat)) ?:
-        output.write(sourceCrop) ?:
-        output.writeFloat(frameScale) ?:
-        output.writeBool(captureSecureLayers) ?:
-        output.writeInt32(uid);
-    return status;
+    SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(pixelFormat));
+    SAFE_PARCEL(output.write, sourceCrop);
+    SAFE_PARCEL(output.writeFloat, frameScale);
+    SAFE_PARCEL(output.writeBool, captureSecureLayers);
+    SAFE_PARCEL(output.writeInt32, uid);
+    return NO_ERROR;
 }
 
 status_t CaptureArgs::read(const Parcel& input) {
     int32_t format = 0;
-    status_t status = input.readInt32(&format) ?:
-        input.read(sourceCrop) ?:
-        input.readFloat(&frameScale) ?:
-        input.readBool(&captureSecureLayers) ?:
-        input.readInt32(&uid);
-
+    SAFE_PARCEL(input.readInt32, &format);
     pixelFormat = static_cast<ui::PixelFormat>(format);
-    return status;
+    SAFE_PARCEL(input.read, sourceCrop);
+    SAFE_PARCEL(input.readFloat, &frameScale);
+    SAFE_PARCEL(input.readBool, &captureSecureLayers);
+    SAFE_PARCEL(input.readInt32, &uid);
+
+    return NO_ERROR;
 }
 
 status_t DisplayCaptureArgs::write(Parcel& output) const {
-    status_t status = CaptureArgs::write(output);
+    SAFE_PARCEL(CaptureArgs::write, output);
 
-    status |= output.writeStrongBinder(displayToken) ?:
-        output.writeUint32(width) ?:
-        output.writeUint32(height) ?:
-        output.writeBool(useIdentityTransform);
-    return status;
+    SAFE_PARCEL(output.writeStrongBinder, displayToken);
+    SAFE_PARCEL(output.writeUint32, width);
+    SAFE_PARCEL(output.writeUint32, height);
+    SAFE_PARCEL(output.writeBool, useIdentityTransform);
+    return NO_ERROR;
 }
 
 status_t DisplayCaptureArgs::read(const Parcel& input) {
-    status_t status = CaptureArgs::read(input);
+    SAFE_PARCEL(CaptureArgs::read, input);
 
-    status |= input.readStrongBinder(&displayToken) ?:
-        input.readUint32(&width) ?:
-        input.readUint32(&height) ?:
-        input.readBool(&useIdentityTransform);
-    return status;
+    SAFE_PARCEL(input.readStrongBinder, &displayToken);
+    SAFE_PARCEL(input.readUint32, &width);
+    SAFE_PARCEL(input.readUint32, &height);
+    SAFE_PARCEL(input.readBool, &useIdentityTransform);
+    return NO_ERROR;
 }
 
 status_t LayerCaptureArgs::write(Parcel& output) const {
-    status_t status = CaptureArgs::write(output);
+    SAFE_PARCEL(CaptureArgs::write, output);
 
-    status |= output.writeStrongBinder(layerHandle);
-    status |= output.writeInt32(excludeHandles.size());
+    SAFE_PARCEL(output.writeStrongBinder, layerHandle);
+    SAFE_PARCEL(output.writeInt32, excludeHandles.size());
     for (auto el : excludeHandles) {
-        status |= output.writeStrongBinder(el);
+        SAFE_PARCEL(output.writeStrongBinder, el);
     }
-    status |= output.writeBool(childrenOnly);
-    return status;
+    SAFE_PARCEL(output.writeBool, childrenOnly);
+    return NO_ERROR;
 }
 
 status_t LayerCaptureArgs::read(const Parcel& input) {
-    status_t status = CaptureArgs::read(input);
+    SAFE_PARCEL(CaptureArgs::read, input);
 
-    status |= input.readStrongBinder(&layerHandle);
+    SAFE_PARCEL(input.readStrongBinder, &layerHandle);
 
     int32_t numExcludeHandles = 0;
-    status |= input.readInt32(&numExcludeHandles);
+    SAFE_PARCEL_READ_SIZE(input.readInt32, &numExcludeHandles, input.dataSize());
     excludeHandles.reserve(numExcludeHandles);
     for (int i = 0; i < numExcludeHandles; i++) {
         sp<IBinder> binder;
-        status |= input.readStrongBinder(&binder);
+        SAFE_PARCEL(input.readStrongBinder, &binder);
         excludeHandles.emplace(binder);
     }
 
-    status |= input.readBool(&childrenOnly);
-    return status;
+    SAFE_PARCEL(input.readBool, &childrenOnly);
+    return NO_ERROR;
 }
 
 status_t ScreenCaptureResults::write(Parcel& output) const {
-    status_t status = output.write(*buffer) ?:
-        output.writeBool(capturedSecureLayers) ?:
-        output.writeUint32(static_cast<uint32_t>(capturedDataspace));
-    return status;
+    if (buffer != nullptr) {
+        SAFE_PARCEL(output.writeBool, true);
+        SAFE_PARCEL(output.write, *buffer);
+    } else {
+        SAFE_PARCEL(output.writeBool, false);
+    }
+    SAFE_PARCEL(output.writeBool, capturedSecureLayers);
+    SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(capturedDataspace));
+    SAFE_PARCEL(output.writeInt32, result);
+    return NO_ERROR;
 }
 
 status_t ScreenCaptureResults::read(const Parcel& input) {
-    buffer = new GraphicBuffer();
+    bool hasGraphicBuffer;
+    SAFE_PARCEL(input.readBool, &hasGraphicBuffer);
+    if (hasGraphicBuffer) {
+        buffer = new GraphicBuffer();
+        SAFE_PARCEL(input.read, *buffer);
+    }
+
+    SAFE_PARCEL(input.readBool, &capturedSecureLayers);
     uint32_t dataspace = 0;
-    status_t status = input.read(*buffer) ?:
-        input.readBool(&capturedSecureLayers) ?:
-        input.readUint32(&dataspace);
-
+    SAFE_PARCEL(input.readUint32, &dataspace);
     capturedDataspace = static_cast<ui::Dataspace>(dataspace);
-
-    return status;
+    SAFE_PARCEL(input.readInt32, &result);
+    return NO_ERROR;
 }
 
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 62a3c45..65a1a01 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1921,26 +1921,57 @@
 }
 
 // ----------------------------------------------------------------------------
+status_t SyncScreenCaptureListener::onScreenCaptureComplete(
+        const ScreenCaptureResults& captureResults) {
+    resultsPromise.set_value(captureResults);
+    return NO_ERROR;
+}
+
+ScreenCaptureResults SyncScreenCaptureListener::waitForResults() {
+    std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
+    return resultsFuture.get();
+}
 
 status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
                                           ScreenCaptureResults& captureResults) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    return s->captureDisplay(captureArgs, captureResults);
+
+    sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+    status_t status = s->captureDisplay(captureArgs, captureListener);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    captureResults = captureListener->waitForResults();
+    return captureResults.result;
 }
 
 status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack,
                                           ScreenCaptureResults& captureResults) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    return s->captureDisplay(displayOrLayerStack, captureResults);
+
+    sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+    status_t status = s->captureDisplay(displayOrLayerStack, captureListener);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    captureResults = captureListener->waitForResults();
+    return captureResults.result;
 }
 
 status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
                                          ScreenCaptureResults& captureResults) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    return s->captureLayers(captureArgs, captureResults);
+
+    sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+    status_t status = s->captureLayers(captureArgs, captureListener);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    captureResults = captureListener->waitForResults();
+    return captureResults.result;
 }
 
 } // namespace android
diff --git a/libs/gui/include/gui/IScreenCaptureListener.h b/libs/gui/include/gui/IScreenCaptureListener.h
new file mode 100644
index 0000000..a2ddc9f
--- /dev/null
+++ b/libs/gui/include/gui/IScreenCaptureListener.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <binder/Binder.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/SafeInterface.h>
+
+namespace android {
+
+struct ScreenCaptureResults;
+
+// TODO(b/166271443): Convert to AIDL
+class IScreenCaptureListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(ScreenCaptureListener)
+
+    virtual status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) = 0;
+};
+
+class BnScreenCaptureListener : public SafeBnInterface<IScreenCaptureListener> {
+public:
+    BnScreenCaptureListener()
+          : SafeBnInterface<IScreenCaptureListener>("BnScreenCaptureListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 926a66f..e057b68 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -22,6 +22,7 @@
 #include <binder/IBinder.h>
 #include <binder/IInterface.h>
 
+#include <gui/IScreenCaptureListener.h>
 #include <gui/ITransactionCompletedListener.h>
 
 #include <math/vec4.h>
@@ -150,13 +151,12 @@
     }
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
-    virtual void setTransactionState(const Vector<ComposerState>& state,
-                                     const Vector<DisplayState>& displays, uint32_t flags,
-                                     const sp<IBinder>& applyToken,
-                                     const InputWindowCommands& inputWindowCommands,
-                                     int64_t desiredPresentTime,
-                                     const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
-                                     const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
+    virtual status_t setTransactionState(
+            const Vector<ComposerState>& state, const Vector<DisplayState>& displays,
+            uint32_t flags, const sp<IBinder>& applyToken,
+            const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+            const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+            const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -256,10 +256,10 @@
      * match the size of the output buffer.
      */
     virtual status_t captureDisplay(const DisplayCaptureArgs& args,
-                                    ScreenCaptureResults& captureResults) = 0;
+                                    const sp<IScreenCaptureListener>& captureListener) = 0;
 
     virtual status_t captureDisplay(uint64_t displayOrLayerStack,
-                                    ScreenCaptureResults& captureResults) = 0;
+                                    const sp<IScreenCaptureListener>& captureListener) = 0;
 
     template <class AA>
     struct SpHash {
@@ -272,7 +272,7 @@
      * is a secure window on screen
      */
     virtual status_t captureLayers(const LayerCaptureArgs& args,
-                                   ScreenCaptureResults& captureResults) = 0;
+                                   const sp<IScreenCaptureListener>& captureListener) = 0;
 
     /* Clears the frame statistics for animations.
      *
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 187e478..47d62fe 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -16,6 +16,23 @@
 
 #ifndef ANDROID_SF_LAYER_STATE_H
 #define ANDROID_SF_LAYER_STATE_H
+#define SAFE_PARCEL(FUNC, ...)                                                            \
+    {                                                                                     \
+        status_t error = FUNC(__VA_ARGS__);                                               \
+        if (error) {                                                                      \
+            ALOGE("ERROR(%d). Failed to call parcel %s(%s)", error, #FUNC, #__VA_ARGS__); \
+            return error;                                                                 \
+        }                                                                                 \
+    }
+
+#define SAFE_PARCEL_READ_SIZE(FUNC, COUNT, SIZE)                             \
+    {                                                                        \
+        SAFE_PARCEL(FUNC, COUNT);                                            \
+        if (static_cast<unsigned int>(*COUNT) > SIZE) {                      \
+            ALOGE("ERROR(BAD_VALUE). %s was greater than dataSize", #COUNT); \
+            return BAD_VALUE;                                                \
+        }                                                                    \
+    }
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -156,6 +173,8 @@
         float dtdx{0};
         float dtdy{0};
         float dsdy{0};
+        status_t write(Parcel& output) const;
+        status_t read(const Parcel& input);
     };
     sp<IBinder> surface;
     uint64_t what;
@@ -293,8 +312,8 @@
     // Merges the passed in commands and returns true if there were any changes.
     bool merge(const InputWindowCommands& other);
     void clear();
-    void write(Parcel& output) const;
-    void read(const Parcel& input);
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
 };
 
 static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
@@ -350,6 +369,7 @@
     sp<GraphicBuffer> buffer;
     bool capturedSecureLayers{false};
     ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
+    status_t result = NO_ERROR;
 
     status_t write(Parcel& output) const;
     status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 1a9710a..05151ba 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -18,6 +18,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <future>
 #include <set>
 #include <unordered_map>
 #include <unordered_set>
@@ -593,10 +594,17 @@
 
 // ---------------------------------------------------------------------------
 
+class SyncScreenCaptureListener : public BnScreenCaptureListener {
+public:
+    status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override;
+    ScreenCaptureResults waitForResults();
+
+private:
+    std::promise<ScreenCaptureResults> resultsPromise;
+};
+
 class ScreenshotClient {
 public:
-    // if cropping isn't required, callers may pass in a default Rect, e.g.:
-    //   capture(display, producer, Rect(), reqWidth, ...);
     static status_t captureDisplay(const DisplayCaptureArgs& captureArgs,
                                    ScreenCaptureResults& captureResults);
     static status_t captureDisplay(uint64_t displayOrLayerStack,
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index d88c477..4a186b1 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -203,6 +203,20 @@
         ASSERT_EQ(false, ::testing::Test::HasFailure());
     }
 
+    static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
+                                   ScreenCaptureResults& captureResults) {
+        const auto sf = ComposerService::getComposerService();
+        SurfaceComposerClient::Transaction().apply(true);
+
+        const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+        status_t status = sf->captureDisplay(captureArgs, captureListener);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        captureResults = captureListener->waitForResults();
+        return captureResults.result;
+    }
+
     sp<SurfaceComposerClient> mClient;
     sp<ISurfaceComposer> mComposer;
 
@@ -306,7 +320,7 @@
     adapter.waitForCallbacks();
 
     // capture screen and verify that it is red
-    ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
     ASSERT_NO_FATAL_FAILURE(
             checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
 }
@@ -383,7 +397,7 @@
 
     adapter.waitForCallbacks();
     // capture screen and verify that it is red
-    ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
 
     ASSERT_NO_FATAL_FAILURE(
             checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -440,7 +454,7 @@
 
     adapter.waitForCallbacks();
     // capture screen and verify that it is red
-    ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
 
     ASSERT_NO_FATAL_FAILURE(
             checkScreenCapture(r, g, b,
@@ -481,7 +495,7 @@
         ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
 
         adapter.waitForCallbacks();
-        ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+        ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
 
         switch (tr) {
             case ui::Transform::ROT_0:
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index a68ec29..287a6f4 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -192,8 +192,7 @@
         mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION;
         mInputInfo.dispatchingTimeout = 5s;
         mInputInfo.globalScaleFactor = 1.0;
-        mInputInfo.canReceiveKeys = true;
-        mInputInfo.hasFocus = true;
+        mInputInfo.focusable = true;
         mInputInfo.hasWallpaper = false;
         mInputInfo.paused = false;
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2f8e412..aedba2a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -197,6 +197,20 @@
         ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU));
     }
 
+    static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
+                                   ScreenCaptureResults& captureResults) {
+        const auto sf = ComposerService::getComposerService();
+        SurfaceComposerClient::Transaction().apply(true);
+
+        const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+        status_t status = sf->captureDisplay(captureArgs, captureListener);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        captureResults = captureListener->waitForResults();
+        return captureResults.result;
+    }
+
     sp<Surface> mSurface;
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mSurfaceControl;
@@ -250,7 +264,7 @@
     captureArgs.height = 64;
 
     ScreenCaptureResults captureResults;
-    ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
+    ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
             NATIVE_WINDOW_API_CPU));
@@ -280,7 +294,7 @@
                 &buf));
         ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
     }
-    ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
+    ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
 }
 
 TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
@@ -681,13 +695,13 @@
     void destroyDisplay(const sp<IBinder>& /*display */) override {}
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
-    void setTransactionState(const Vector<ComposerState>& /*state*/,
-                             const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
-                             const sp<IBinder>& /*applyToken*/,
-                             const InputWindowCommands& /*inputWindowCommands*/,
-                             int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/,
-                             bool /*hasListenerCallbacks*/,
-                             const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
+    status_t setTransactionState(
+            const Vector<ComposerState>& /*state*/, const Vector<DisplayState>& /*displays*/,
+            uint32_t /*flags*/, const sp<IBinder>& /*applyToken*/,
+            const InputWindowCommands& /*inputWindowCommands*/, int64_t /*desiredPresentTime*/,
+            const client_cache_t& /*cachedBuffer*/, bool /*hasListenerCallbacks*/,
+            const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
+        return NO_ERROR;
     }
 
     void bootFinished() override {}
@@ -743,7 +757,7 @@
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */,
-                            ScreenCaptureResults& /* captureResults */) override {
+                            const sp<IScreenCaptureListener>& /* captureListener */) override {
         return NO_ERROR;
     }
     status_t getAutoLowLatencyModeSupport(const sp<IBinder>& /*display*/,
@@ -757,11 +771,12 @@
     }
     void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
     status_t captureDisplay(uint64_t /*displayOrLayerStack*/,
-                            ScreenCaptureResults& /* captureResults */) override {
+                            const sp<IScreenCaptureListener>& /* captureListener */) override {
         return NO_ERROR;
     }
-    virtual status_t captureLayers(const LayerCaptureArgs& /* captureArgs */,
-                                   ScreenCaptureResults& /* captureResults */) override {
+    virtual status_t captureLayers(
+            const LayerCaptureArgs& /* captureArgs */,
+            const sp<IScreenCaptureListener>& /* captureListener */) override {
         return NO_ERROR;
     }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 0c3c1f0..392d478 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -32,6 +32,7 @@
     srcs: [
         "Input.cpp",
         "InputDevice.cpp",
+        "InputEventLabels.cpp",
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index fc73de3..51910fe 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -135,11 +135,11 @@
 // --- KeyEvent ---
 
 const char* KeyEvent::getLabel(int32_t keyCode) {
-    return getLabelByKeyCode(keyCode);
+    return InputEventLookup::getLabelByKeyCode(keyCode);
 }
 
 int32_t KeyEvent::getKeyCodeFromLabel(const char* label) {
-    return getKeyCodeByLabel(label);
+    return InputEventLookup::getKeyCodeByLabel(label);
 }
 
 void KeyEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
@@ -692,11 +692,11 @@
 }
 
 const char* MotionEvent::getLabel(int32_t axis) {
-    return getAxisLabel(axis);
+    return InputEventLookup::getAxisLabel(axis);
 }
 
 int32_t MotionEvent::getAxisFromLabel(const char* label) {
-    return getAxisByLabel(label);
+    return InputEventLookup::getAxisByLabel(label);
 }
 
 const char* MotionEvent::actionToString(int32_t action) {
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
new file mode 100644
index 0000000..dee240c
--- /dev/null
+++ b/libs/input/InputEventLabels.cpp
@@ -0,0 +1,448 @@
+/*
+ * 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 <input/InputEventLabels.h>
+
+#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
+#define DEFINE_AXIS(axis) { #axis, AMOTION_EVENT_AXIS_##axis }
+#define DEFINE_LED(led) { #led, ALED_##led }
+#define DEFINE_FLAG(flag) { #flag, POLICY_FLAG_##flag }
+
+namespace android {
+
+// NOTE: If you add a new keycode here you must also add it to several other files.
+//       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
+#define KEYCODES_SEQUENCE \
+    DEFINE_KEYCODE(UNKNOWN), \
+    DEFINE_KEYCODE(SOFT_LEFT), \
+    DEFINE_KEYCODE(SOFT_RIGHT), \
+    DEFINE_KEYCODE(HOME), \
+    DEFINE_KEYCODE(BACK), \
+    DEFINE_KEYCODE(CALL), \
+    DEFINE_KEYCODE(ENDCALL), \
+    DEFINE_KEYCODE(0), \
+    DEFINE_KEYCODE(1), \
+    DEFINE_KEYCODE(2), \
+    DEFINE_KEYCODE(3), \
+    DEFINE_KEYCODE(4), \
+    DEFINE_KEYCODE(5), \
+    DEFINE_KEYCODE(6), \
+    DEFINE_KEYCODE(7), \
+    DEFINE_KEYCODE(8), \
+    DEFINE_KEYCODE(9), \
+    DEFINE_KEYCODE(STAR), \
+    DEFINE_KEYCODE(POUND), \
+    DEFINE_KEYCODE(DPAD_UP), \
+    DEFINE_KEYCODE(DPAD_DOWN), \
+    DEFINE_KEYCODE(DPAD_LEFT), \
+    DEFINE_KEYCODE(DPAD_RIGHT), \
+    DEFINE_KEYCODE(DPAD_CENTER), \
+    DEFINE_KEYCODE(VOLUME_UP), \
+    DEFINE_KEYCODE(VOLUME_DOWN), \
+    DEFINE_KEYCODE(POWER), \
+    DEFINE_KEYCODE(CAMERA), \
+    DEFINE_KEYCODE(CLEAR), \
+    DEFINE_KEYCODE(A), \
+    DEFINE_KEYCODE(B), \
+    DEFINE_KEYCODE(C), \
+    DEFINE_KEYCODE(D), \
+    DEFINE_KEYCODE(E), \
+    DEFINE_KEYCODE(F), \
+    DEFINE_KEYCODE(G), \
+    DEFINE_KEYCODE(H), \
+    DEFINE_KEYCODE(I), \
+    DEFINE_KEYCODE(J), \
+    DEFINE_KEYCODE(K), \
+    DEFINE_KEYCODE(L), \
+    DEFINE_KEYCODE(M), \
+    DEFINE_KEYCODE(N), \
+    DEFINE_KEYCODE(O), \
+    DEFINE_KEYCODE(P), \
+    DEFINE_KEYCODE(Q), \
+    DEFINE_KEYCODE(R), \
+    DEFINE_KEYCODE(S), \
+    DEFINE_KEYCODE(T), \
+    DEFINE_KEYCODE(U), \
+    DEFINE_KEYCODE(V), \
+    DEFINE_KEYCODE(W), \
+    DEFINE_KEYCODE(X), \
+    DEFINE_KEYCODE(Y), \
+    DEFINE_KEYCODE(Z), \
+    DEFINE_KEYCODE(COMMA), \
+    DEFINE_KEYCODE(PERIOD), \
+    DEFINE_KEYCODE(ALT_LEFT), \
+    DEFINE_KEYCODE(ALT_RIGHT), \
+    DEFINE_KEYCODE(SHIFT_LEFT), \
+    DEFINE_KEYCODE(SHIFT_RIGHT), \
+    DEFINE_KEYCODE(TAB), \
+    DEFINE_KEYCODE(SPACE), \
+    DEFINE_KEYCODE(SYM), \
+    DEFINE_KEYCODE(EXPLORER), \
+    DEFINE_KEYCODE(ENVELOPE), \
+    DEFINE_KEYCODE(ENTER), \
+    DEFINE_KEYCODE(DEL), \
+    DEFINE_KEYCODE(GRAVE), \
+    DEFINE_KEYCODE(MINUS), \
+    DEFINE_KEYCODE(EQUALS), \
+    DEFINE_KEYCODE(LEFT_BRACKET), \
+    DEFINE_KEYCODE(RIGHT_BRACKET), \
+    DEFINE_KEYCODE(BACKSLASH), \
+    DEFINE_KEYCODE(SEMICOLON), \
+    DEFINE_KEYCODE(APOSTROPHE), \
+    DEFINE_KEYCODE(SLASH), \
+    DEFINE_KEYCODE(AT), \
+    DEFINE_KEYCODE(NUM), \
+    DEFINE_KEYCODE(HEADSETHOOK), \
+    DEFINE_KEYCODE(FOCUS), \
+    DEFINE_KEYCODE(PLUS), \
+    DEFINE_KEYCODE(MENU), \
+    DEFINE_KEYCODE(NOTIFICATION), \
+    DEFINE_KEYCODE(SEARCH), \
+    DEFINE_KEYCODE(MEDIA_PLAY_PAUSE), \
+    DEFINE_KEYCODE(MEDIA_STOP), \
+    DEFINE_KEYCODE(MEDIA_NEXT), \
+    DEFINE_KEYCODE(MEDIA_PREVIOUS), \
+    DEFINE_KEYCODE(MEDIA_REWIND), \
+    DEFINE_KEYCODE(MEDIA_FAST_FORWARD), \
+    DEFINE_KEYCODE(MUTE), \
+    DEFINE_KEYCODE(PAGE_UP), \
+    DEFINE_KEYCODE(PAGE_DOWN), \
+    DEFINE_KEYCODE(PICTSYMBOLS), \
+    DEFINE_KEYCODE(SWITCH_CHARSET), \
+    DEFINE_KEYCODE(BUTTON_A), \
+    DEFINE_KEYCODE(BUTTON_B), \
+    DEFINE_KEYCODE(BUTTON_C), \
+    DEFINE_KEYCODE(BUTTON_X), \
+    DEFINE_KEYCODE(BUTTON_Y), \
+    DEFINE_KEYCODE(BUTTON_Z), \
+    DEFINE_KEYCODE(BUTTON_L1), \
+    DEFINE_KEYCODE(BUTTON_R1), \
+    DEFINE_KEYCODE(BUTTON_L2), \
+    DEFINE_KEYCODE(BUTTON_R2), \
+    DEFINE_KEYCODE(BUTTON_THUMBL), \
+    DEFINE_KEYCODE(BUTTON_THUMBR), \
+    DEFINE_KEYCODE(BUTTON_START), \
+    DEFINE_KEYCODE(BUTTON_SELECT), \
+    DEFINE_KEYCODE(BUTTON_MODE), \
+    DEFINE_KEYCODE(ESCAPE), \
+    DEFINE_KEYCODE(FORWARD_DEL), \
+    DEFINE_KEYCODE(CTRL_LEFT), \
+    DEFINE_KEYCODE(CTRL_RIGHT), \
+    DEFINE_KEYCODE(CAPS_LOCK), \
+    DEFINE_KEYCODE(SCROLL_LOCK), \
+    DEFINE_KEYCODE(META_LEFT), \
+    DEFINE_KEYCODE(META_RIGHT), \
+    DEFINE_KEYCODE(FUNCTION), \
+    DEFINE_KEYCODE(SYSRQ), \
+    DEFINE_KEYCODE(BREAK), \
+    DEFINE_KEYCODE(MOVE_HOME), \
+    DEFINE_KEYCODE(MOVE_END), \
+    DEFINE_KEYCODE(INSERT), \
+    DEFINE_KEYCODE(FORWARD), \
+    DEFINE_KEYCODE(MEDIA_PLAY), \
+    DEFINE_KEYCODE(MEDIA_PAUSE), \
+    DEFINE_KEYCODE(MEDIA_CLOSE), \
+    DEFINE_KEYCODE(MEDIA_EJECT), \
+    DEFINE_KEYCODE(MEDIA_RECORD), \
+    DEFINE_KEYCODE(F1), \
+    DEFINE_KEYCODE(F2), \
+    DEFINE_KEYCODE(F3), \
+    DEFINE_KEYCODE(F4), \
+    DEFINE_KEYCODE(F5), \
+    DEFINE_KEYCODE(F6), \
+    DEFINE_KEYCODE(F7), \
+    DEFINE_KEYCODE(F8), \
+    DEFINE_KEYCODE(F9), \
+    DEFINE_KEYCODE(F10), \
+    DEFINE_KEYCODE(F11), \
+    DEFINE_KEYCODE(F12), \
+    DEFINE_KEYCODE(NUM_LOCK), \
+    DEFINE_KEYCODE(NUMPAD_0), \
+    DEFINE_KEYCODE(NUMPAD_1), \
+    DEFINE_KEYCODE(NUMPAD_2), \
+    DEFINE_KEYCODE(NUMPAD_3), \
+    DEFINE_KEYCODE(NUMPAD_4), \
+    DEFINE_KEYCODE(NUMPAD_5), \
+    DEFINE_KEYCODE(NUMPAD_6), \
+    DEFINE_KEYCODE(NUMPAD_7), \
+    DEFINE_KEYCODE(NUMPAD_8), \
+    DEFINE_KEYCODE(NUMPAD_9), \
+    DEFINE_KEYCODE(NUMPAD_DIVIDE), \
+    DEFINE_KEYCODE(NUMPAD_MULTIPLY), \
+    DEFINE_KEYCODE(NUMPAD_SUBTRACT), \
+    DEFINE_KEYCODE(NUMPAD_ADD), \
+    DEFINE_KEYCODE(NUMPAD_DOT), \
+    DEFINE_KEYCODE(NUMPAD_COMMA), \
+    DEFINE_KEYCODE(NUMPAD_ENTER), \
+    DEFINE_KEYCODE(NUMPAD_EQUALS), \
+    DEFINE_KEYCODE(NUMPAD_LEFT_PAREN), \
+    DEFINE_KEYCODE(NUMPAD_RIGHT_PAREN), \
+    DEFINE_KEYCODE(VOLUME_MUTE), \
+    DEFINE_KEYCODE(INFO), \
+    DEFINE_KEYCODE(CHANNEL_UP), \
+    DEFINE_KEYCODE(CHANNEL_DOWN), \
+    DEFINE_KEYCODE(ZOOM_IN), \
+    DEFINE_KEYCODE(ZOOM_OUT), \
+    DEFINE_KEYCODE(TV), \
+    DEFINE_KEYCODE(WINDOW), \
+    DEFINE_KEYCODE(GUIDE), \
+    DEFINE_KEYCODE(DVR), \
+    DEFINE_KEYCODE(BOOKMARK), \
+    DEFINE_KEYCODE(CAPTIONS), \
+    DEFINE_KEYCODE(SETTINGS), \
+    DEFINE_KEYCODE(TV_POWER), \
+    DEFINE_KEYCODE(TV_INPUT), \
+    DEFINE_KEYCODE(STB_POWER), \
+    DEFINE_KEYCODE(STB_INPUT), \
+    DEFINE_KEYCODE(AVR_POWER), \
+    DEFINE_KEYCODE(AVR_INPUT), \
+    DEFINE_KEYCODE(PROG_RED), \
+    DEFINE_KEYCODE(PROG_GREEN), \
+    DEFINE_KEYCODE(PROG_YELLOW), \
+    DEFINE_KEYCODE(PROG_BLUE), \
+    DEFINE_KEYCODE(APP_SWITCH), \
+    DEFINE_KEYCODE(BUTTON_1), \
+    DEFINE_KEYCODE(BUTTON_2), \
+    DEFINE_KEYCODE(BUTTON_3), \
+    DEFINE_KEYCODE(BUTTON_4), \
+    DEFINE_KEYCODE(BUTTON_5), \
+    DEFINE_KEYCODE(BUTTON_6), \
+    DEFINE_KEYCODE(BUTTON_7), \
+    DEFINE_KEYCODE(BUTTON_8), \
+    DEFINE_KEYCODE(BUTTON_9), \
+    DEFINE_KEYCODE(BUTTON_10), \
+    DEFINE_KEYCODE(BUTTON_11), \
+    DEFINE_KEYCODE(BUTTON_12), \
+    DEFINE_KEYCODE(BUTTON_13), \
+    DEFINE_KEYCODE(BUTTON_14), \
+    DEFINE_KEYCODE(BUTTON_15), \
+    DEFINE_KEYCODE(BUTTON_16), \
+    DEFINE_KEYCODE(LANGUAGE_SWITCH), \
+    DEFINE_KEYCODE(MANNER_MODE), \
+    DEFINE_KEYCODE(3D_MODE), \
+    DEFINE_KEYCODE(CONTACTS), \
+    DEFINE_KEYCODE(CALENDAR), \
+    DEFINE_KEYCODE(MUSIC), \
+    DEFINE_KEYCODE(CALCULATOR), \
+    DEFINE_KEYCODE(ZENKAKU_HANKAKU), \
+    DEFINE_KEYCODE(EISU), \
+    DEFINE_KEYCODE(MUHENKAN), \
+    DEFINE_KEYCODE(HENKAN), \
+    DEFINE_KEYCODE(KATAKANA_HIRAGANA), \
+    DEFINE_KEYCODE(YEN), \
+    DEFINE_KEYCODE(RO), \
+    DEFINE_KEYCODE(KANA), \
+    DEFINE_KEYCODE(ASSIST), \
+    DEFINE_KEYCODE(BRIGHTNESS_DOWN), \
+    DEFINE_KEYCODE(BRIGHTNESS_UP), \
+    DEFINE_KEYCODE(MEDIA_AUDIO_TRACK), \
+    DEFINE_KEYCODE(SLEEP), \
+    DEFINE_KEYCODE(WAKEUP), \
+    DEFINE_KEYCODE(PAIRING), \
+    DEFINE_KEYCODE(MEDIA_TOP_MENU), \
+    DEFINE_KEYCODE(11), \
+    DEFINE_KEYCODE(12), \
+    DEFINE_KEYCODE(LAST_CHANNEL), \
+    DEFINE_KEYCODE(TV_DATA_SERVICE), \
+    DEFINE_KEYCODE(VOICE_ASSIST), \
+    DEFINE_KEYCODE(TV_RADIO_SERVICE), \
+    DEFINE_KEYCODE(TV_TELETEXT), \
+    DEFINE_KEYCODE(TV_NUMBER_ENTRY), \
+    DEFINE_KEYCODE(TV_TERRESTRIAL_ANALOG), \
+    DEFINE_KEYCODE(TV_TERRESTRIAL_DIGITAL), \
+    DEFINE_KEYCODE(TV_SATELLITE), \
+    DEFINE_KEYCODE(TV_SATELLITE_BS), \
+    DEFINE_KEYCODE(TV_SATELLITE_CS), \
+    DEFINE_KEYCODE(TV_SATELLITE_SERVICE), \
+    DEFINE_KEYCODE(TV_NETWORK), \
+    DEFINE_KEYCODE(TV_ANTENNA_CABLE), \
+    DEFINE_KEYCODE(TV_INPUT_HDMI_1), \
+    DEFINE_KEYCODE(TV_INPUT_HDMI_2), \
+    DEFINE_KEYCODE(TV_INPUT_HDMI_3), \
+    DEFINE_KEYCODE(TV_INPUT_HDMI_4), \
+    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_1), \
+    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_2), \
+    DEFINE_KEYCODE(TV_INPUT_COMPONENT_1), \
+    DEFINE_KEYCODE(TV_INPUT_COMPONENT_2), \
+    DEFINE_KEYCODE(TV_INPUT_VGA_1), \
+    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION), \
+    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_UP), \
+    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_DOWN), \
+    DEFINE_KEYCODE(TV_ZOOM_MODE), \
+    DEFINE_KEYCODE(TV_CONTENTS_MENU), \
+    DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU), \
+    DEFINE_KEYCODE(TV_TIMER_PROGRAMMING), \
+    DEFINE_KEYCODE(HELP), \
+    DEFINE_KEYCODE(NAVIGATE_PREVIOUS), \
+    DEFINE_KEYCODE(NAVIGATE_NEXT), \
+    DEFINE_KEYCODE(NAVIGATE_IN), \
+    DEFINE_KEYCODE(NAVIGATE_OUT), \
+    DEFINE_KEYCODE(STEM_PRIMARY), \
+    DEFINE_KEYCODE(STEM_1), \
+    DEFINE_KEYCODE(STEM_2), \
+    DEFINE_KEYCODE(STEM_3), \
+    DEFINE_KEYCODE(DPAD_UP_LEFT), \
+    DEFINE_KEYCODE(DPAD_DOWN_LEFT), \
+    DEFINE_KEYCODE(DPAD_UP_RIGHT), \
+    DEFINE_KEYCODE(DPAD_DOWN_RIGHT), \
+    DEFINE_KEYCODE(MEDIA_SKIP_FORWARD), \
+    DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD), \
+    DEFINE_KEYCODE(MEDIA_STEP_FORWARD), \
+    DEFINE_KEYCODE(MEDIA_STEP_BACKWARD), \
+    DEFINE_KEYCODE(SOFT_SLEEP), \
+    DEFINE_KEYCODE(CUT), \
+    DEFINE_KEYCODE(COPY), \
+    DEFINE_KEYCODE(PASTE), \
+    DEFINE_KEYCODE(SYSTEM_NAVIGATION_UP), \
+    DEFINE_KEYCODE(SYSTEM_NAVIGATION_DOWN), \
+    DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT), \
+    DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT), \
+    DEFINE_KEYCODE(ALL_APPS), \
+    DEFINE_KEYCODE(REFRESH), \
+    DEFINE_KEYCODE(THUMBS_UP), \
+    DEFINE_KEYCODE(THUMBS_DOWN), \
+    DEFINE_KEYCODE(PROFILE_SWITCH)
+
+// NOTE: If you add a new axis here you must also add it to several other files.
+//       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
+#define AXES_SEQUENCE \
+    DEFINE_AXIS(X), \
+    DEFINE_AXIS(Y), \
+    DEFINE_AXIS(PRESSURE), \
+    DEFINE_AXIS(SIZE), \
+    DEFINE_AXIS(TOUCH_MAJOR), \
+    DEFINE_AXIS(TOUCH_MINOR), \
+    DEFINE_AXIS(TOOL_MAJOR), \
+    DEFINE_AXIS(TOOL_MINOR), \
+    DEFINE_AXIS(ORIENTATION), \
+    DEFINE_AXIS(VSCROLL), \
+    DEFINE_AXIS(HSCROLL), \
+    DEFINE_AXIS(Z), \
+    DEFINE_AXIS(RX), \
+    DEFINE_AXIS(RY), \
+    DEFINE_AXIS(RZ), \
+    DEFINE_AXIS(HAT_X), \
+    DEFINE_AXIS(HAT_Y), \
+    DEFINE_AXIS(LTRIGGER), \
+    DEFINE_AXIS(RTRIGGER), \
+    DEFINE_AXIS(THROTTLE), \
+    DEFINE_AXIS(RUDDER), \
+    DEFINE_AXIS(WHEEL), \
+    DEFINE_AXIS(GAS), \
+    DEFINE_AXIS(BRAKE), \
+    DEFINE_AXIS(DISTANCE), \
+    DEFINE_AXIS(TILT), \
+    DEFINE_AXIS(SCROLL), \
+    DEFINE_AXIS(RELATIVE_X), \
+    DEFINE_AXIS(RELATIVE_Y), \
+    DEFINE_AXIS(GENERIC_1), \
+    DEFINE_AXIS(GENERIC_2), \
+    DEFINE_AXIS(GENERIC_3), \
+    DEFINE_AXIS(GENERIC_4), \
+    DEFINE_AXIS(GENERIC_5), \
+    DEFINE_AXIS(GENERIC_6), \
+    DEFINE_AXIS(GENERIC_7), \
+    DEFINE_AXIS(GENERIC_8), \
+    DEFINE_AXIS(GENERIC_9), \
+    DEFINE_AXIS(GENERIC_10), \
+    DEFINE_AXIS(GENERIC_11), \
+    DEFINE_AXIS(GENERIC_12), \
+    DEFINE_AXIS(GENERIC_13), \
+    DEFINE_AXIS(GENERIC_14), \
+    DEFINE_AXIS(GENERIC_15), \
+    DEFINE_AXIS(GENERIC_16)
+
+
+// NOTE: If you add new LEDs here, you must also add them to Input.h
+#define LEDS_SEQUENCE \
+    DEFINE_LED(NUM_LOCK), \
+    DEFINE_LED(CAPS_LOCK), \
+    DEFINE_LED(SCROLL_LOCK), \
+    DEFINE_LED(COMPOSE), \
+    DEFINE_LED(KANA), \
+    DEFINE_LED(SLEEP), \
+    DEFINE_LED(SUSPEND), \
+    DEFINE_LED(MUTE), \
+    DEFINE_LED(MISC), \
+    DEFINE_LED(MAIL), \
+    DEFINE_LED(CHARGING), \
+    DEFINE_LED(CONTROLLER_1), \
+    DEFINE_LED(CONTROLLER_2), \
+    DEFINE_LED(CONTROLLER_3), \
+    DEFINE_LED(CONTROLLER_4)
+
+#define FLAGS_SEQUENCE \
+    DEFINE_FLAG(VIRTUAL), \
+    DEFINE_FLAG(FUNCTION), \
+    DEFINE_FLAG(GESTURE), \
+    DEFINE_FLAG(WAKE)
+
+// --- InputEventLookup ---
+const std::unordered_map<std::string, int> InputEventLookup::KEYCODES = {KEYCODES_SEQUENCE};
+
+const std::vector<InputEventLabel> InputEventLookup::KEY_NAMES = {KEYCODES_SEQUENCE};
+
+const std::unordered_map<std::string, int> InputEventLookup::AXES = {AXES_SEQUENCE};
+
+const std::vector<InputEventLabel> InputEventLookup::AXES_NAMES = {AXES_SEQUENCE};
+
+const std::unordered_map<std::string, int> InputEventLookup::LEDS = {LEDS_SEQUENCE};
+
+const std::unordered_map<std::string, int> InputEventLookup::FLAGS = {FLAGS_SEQUENCE};
+
+int InputEventLookup::lookupValueByLabel(const std::unordered_map<std::string, int>& map,
+                                         const char* literal) {
+    std::string str(literal);
+    auto it = map.find(str);
+    return it != map.end() ? it->second : 0;
+}
+
+const char* InputEventLookup::lookupLabelByValue(const std::vector<InputEventLabel>& vec,
+                                                 int value) {
+    if (static_cast<size_t>(value) < vec.size()) {
+        return vec[value].literal;
+    }
+    return nullptr;
+}
+
+int32_t InputEventLookup::getKeyCodeByLabel(const char* label) {
+    return int32_t(lookupValueByLabel(KEYCODES, label));
+}
+
+const char* InputEventLookup::getLabelByKeyCode(int32_t keyCode) {
+    if (keyCode >= 0 && static_cast<size_t>(keyCode) < KEYCODES.size()) {
+        return lookupLabelByValue(KEY_NAMES, keyCode);
+    }
+    return nullptr;
+}
+
+uint32_t InputEventLookup::getKeyFlagByLabel(const char* label) {
+    return uint32_t(lookupValueByLabel(FLAGS, label));
+}
+
+int32_t InputEventLookup::getAxisByLabel(const char* label) {
+    return int32_t(lookupValueByLabel(AXES, label));
+}
+
+const char* InputEventLookup::getAxisLabel(int32_t axisId) {
+    return lookupLabelByValue(AXES_NAMES, axisId);
+}
+
+int32_t InputEventLookup::getLedByLabel(const char* label) {
+    return int32_t(lookupValueByLabel(LEDS, label));
+}
+
+} // namespace android
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 6db9ed5..885dc9b 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -58,10 +58,9 @@
             info.frameRight == frameRight && info.frameBottom == frameBottom &&
             info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
             info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) &&
-            info.visible == visible && info.canReceiveKeys == canReceiveKeys &&
-            info.trustedOverlay == trustedOverlay && info.hasFocus == hasFocus &&
-            info.hasWallpaper == hasWallpaper && info.paused == paused &&
-            info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
+            info.visible == visible && info.trustedOverlay == trustedOverlay &&
+            info.focusable == focusable && info.hasWallpaper == hasWallpaper &&
+            info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
             info.inputFeatures == inputFeatures && info.displayId == displayId &&
             info.portalToDisplayId == portalToDisplayId &&
             info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
@@ -79,6 +78,7 @@
     }
     parcel->writeInt32(1);
 
+    // clang-format off
     status_t status = parcel->writeStrongBinder(token) ?:
         parcel->writeInt64(dispatchingTimeout.count()) ?:
         parcel->writeInt32(id) ?:
@@ -98,8 +98,7 @@
         parcel->writeFloat(transform.dsdy()) ?:
         parcel->writeFloat(transform.ty()) ?:
         parcel->writeBool(visible) ?:
-        parcel->writeBool(canReceiveKeys) ?:
-        parcel->writeBool(hasFocus) ?:
+        parcel->writeBool(focusable) ?:
         parcel->writeBool(hasWallpaper) ?:
         parcel->writeBool(paused) ?:
         parcel->writeBool(trustedOverlay) ?:
@@ -112,7 +111,7 @@
         parcel->write(touchableRegion) ?:
         parcel->writeBool(replaceTouchableRegionWithCrop) ?:
         parcel->writeStrongBinder(touchableRegionCropHandle.promote());
-
+    // clang-format on
     return status;
 }
 
@@ -135,6 +134,7 @@
     flags = Flags<Flag>(parcel->readInt32());
     type = static_cast<Type>(parcel->readInt32());
     float dsdx, dtdx, tx, dtdy, dsdy, ty;
+    // clang-format off
     status = parcel->readInt32(&frameLeft) ?:
         parcel->readInt32(&frameTop) ?:
         parcel->readInt32(&frameRight) ?:
@@ -148,13 +148,13 @@
         parcel->readFloat(&dsdy) ?:
         parcel->readFloat(&ty) ?:
         parcel->readBool(&visible) ?:
-        parcel->readBool(&canReceiveKeys) ?:
-        parcel->readBool(&hasFocus) ?:
+        parcel->readBool(&focusable) ?:
         parcel->readBool(&hasWallpaper) ?:
         parcel->readBool(&paused) ?:
         parcel->readBool(&trustedOverlay) ?:
         parcel->readInt32(&ownerPid) ?:
         parcel->readInt32(&ownerUid);
+    // clang-format on
 
     if (status != OK) {
         return status;
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index cb68165..5c03d50 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -880,7 +880,7 @@
 
     mTokenizer->skipDelimiters(WHITESPACE);
     String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+    int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
     if (!keyCode) {
         ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
                 keyCodeToken.string());
@@ -897,7 +897,7 @@
 
 status_t KeyCharacterMap::Parser::parseKey() {
     String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+    int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
     if (!keyCode) {
         ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
                 keyCodeToken.string());
@@ -1017,7 +1017,7 @@
             } else if (token == "fallback") {
                 mTokenizer->skipDelimiters(WHITESPACE);
                 token = mTokenizer->nextToken(WHITESPACE);
-                int32_t keyCode = getKeyCodeByLabel(token.string());
+                int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
                 if (!keyCode) {
                     ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
                             mTokenizer->getLocation().string(),
@@ -1034,7 +1034,7 @@
             } else if (token == "replace") {
                 mTokenizer->skipDelimiters(WHITESPACE);
                 token = mTokenizer->nextToken(WHITESPACE);
-                int32_t keyCode = getKeyCodeByLabel(token.string());
+                int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
                 if (!keyCode) {
                     ALOGE("%s: Invalid key code label for replace, got '%s'.",
                             mTokenizer->getLocation().string(),
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index efca68d..9c399b3 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -264,7 +264,7 @@
 
     mTokenizer->skipDelimiters(WHITESPACE);
     String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+    int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
     if (!keyCode) {
         ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
                 keyCodeToken.string());
@@ -277,7 +277,7 @@
         if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
 
         String8 flagToken = mTokenizer->nextToken(WHITESPACE);
-        uint32_t flag = getKeyFlagByLabel(flagToken.string());
+        uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
         if (!flag) {
             ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
                     flagToken.string());
@@ -326,7 +326,7 @@
 
         mTokenizer->skipDelimiters(WHITESPACE);
         String8 axisToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.axis = getAxisByLabel(axisToken.string());
+        axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string());
         if (axisInfo.axis < 0) {
             ALOGE("%s: Expected inverted axis label, got '%s'.",
                     mTokenizer->getLocation().string(), axisToken.string());
@@ -346,7 +346,7 @@
 
         mTokenizer->skipDelimiters(WHITESPACE);
         String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.axis = getAxisByLabel(lowAxisToken.string());
+        axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string());
         if (axisInfo.axis < 0) {
             ALOGE("%s: Expected low axis label, got '%s'.",
                     mTokenizer->getLocation().string(), lowAxisToken.string());
@@ -355,14 +355,14 @@
 
         mTokenizer->skipDelimiters(WHITESPACE);
         String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
-        axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
+        axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string());
         if (axisInfo.highAxis < 0) {
             ALOGE("%s: Expected high axis label, got '%s'.",
                     mTokenizer->getLocation().string(), highAxisToken.string());
             return BAD_VALUE;
         }
     } else {
-        axisInfo.axis = getAxisByLabel(token.string());
+        axisInfo.axis = InputEventLookup::getAxisByLabel(token.string());
         if (axisInfo.axis < 0) {
             ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
                     mTokenizer->getLocation().string(), token.string());
@@ -428,7 +428,7 @@
 
     mTokenizer->skipDelimiters(WHITESPACE);
     String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t ledCode = getLedByLabel(ledCodeToken.string());
+    int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string());
     if (ledCode < 0) {
         ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
                 ledCodeToken.string());
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 7e3a40d..65a7761 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -55,8 +55,7 @@
     i.globalScaleFactor = 0.3;
     i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
     i.visible = false;
-    i.canReceiveKeys = false;
-    i.hasFocus = false;
+    i.focusable = false;
     i.hasWallpaper = false;
     i.paused = false;
     i.ownerPid = 19;
@@ -89,8 +88,7 @@
     ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
     ASSERT_EQ(i.transform, i2.transform);
     ASSERT_EQ(i.visible, i2.visible);
-    ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
-    ASSERT_EQ(i.hasFocus, i2.hasFocus);
+    ASSERT_EQ(i.focusable, i2.focusable);
     ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
     ASSERT_EQ(i.paused, i2.paused);
     ASSERT_EQ(i.ownerPid, i2.ownerPid);
diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp
index 6366e1d..000cf27 100644
--- a/services/gpuservice/tracing/GpuMemTracer.cpp
+++ b/services/gpuservice/tracing/GpuMemTracer.cpp
@@ -80,6 +80,7 @@
     mGpuMem->traverseGpuMemTotals([](int64_t ts, uint32_t gpuId, uint32_t pid, uint64_t size) {
         GpuMemDataSource::Trace([&](GpuMemDataSource::TraceContext ctx) {
             auto packet = ctx.NewTracePacket();
+            packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
             packet->set_timestamp(ts);
             auto* event = packet->set_gpu_mem_total_event();
             event->set_gpu_id(gpuId);
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index f99fffe..b645d69 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -171,8 +171,7 @@
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(mFrame);
         mInfo.visible = true;
-        mInfo.canReceiveKeys = true;
-        mInfo.hasFocus = true;
+        mInfo.focusable = true;
         mInfo.hasWallpaper = false;
         mInfo.paused = false;
         mInfo.ownerPid = INJECTOR_PID;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5d71666..078448f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3818,7 +3818,7 @@
     bool foundHoveredWindow = false;
     for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
         // Set newFocusedWindowHandle to the top most focused window instead of the last one
-        if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus &&
+        if (!newFocusedWindowHandle && windowHandle->getInfo()->focusable &&
             windowHandle->getInfo()->visible) {
             newFocusedWindowHandle = windowHandle;
         }
@@ -4221,18 +4221,17 @@
                     const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
                     dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
-                                                 "portalToDisplayId=%d, paused=%s, hasFocus=%s, "
-                                                 "hasWallpaper=%s, visible=%s, canReceiveKeys=%s, "
+                                                 "portalToDisplayId=%d, paused=%s, focusable=%s, "
+                                                 "hasWallpaper=%s, visible=%s, "
                                                  "flags=%s, type=0x%08x, "
                                                  "frame=[%d,%d][%d,%d], globalScale=%f, "
                                                  "touchableRegion=",
                                          i, windowInfo->name.c_str(), windowInfo->displayId,
                                          windowInfo->portalToDisplayId,
                                          toString(windowInfo->paused),
-                                         toString(windowInfo->hasFocus),
+                                         toString(windowInfo->focusable),
                                          toString(windowInfo->hasWallpaper),
                                          toString(windowInfo->visible),
-                                         toString(windowInfo->canReceiveKeys),
                                          windowInfo->flags.string().c_str(),
                                          static_cast<int32_t>(windowInfo->type),
                                          windowInfo->frameLeft, windowInfo->frameTop,
diff --git a/services/inputflinger/docs/anr.md b/services/inputflinger/docs/anr.md
new file mode 100644
index 0000000..ce64fe9
--- /dev/null
+++ b/services/inputflinger/docs/anr.md
@@ -0,0 +1,73 @@
+# ANR detection in InputDispatcher #
+
+'ANR' means 'application not responding'. This is an event that gets triggered when the system thinks that an application is too slow to respond. A dialog may pop up because of an ANR event. ANRs can be triggered by multiple systems within Android.
+
+In InputDispatcher, ANRs are raised in 2 cases:
+
+1. An event was sent to a connection, and the response was not received within a certain timeout.
+2. The application did not have a focused window, and an input event that requires focus was generated by the user.
+
+Let's consider each of these cases.
+
+## 1. Application does not respond to an input event that was sent to it. ##
+
+The most common case is when an application does not respond to input that dispatcher sent to it. Typically, it means an application is performing a long operation on its UI thread.
+
+When the event is being dispatched to an application, the normal flow is: `mPendingEvent` → `connection.outboundQueue` → `connection.waitQueue`.
+
+Every dispatch cycle, InputDispatcher will check all connections to see if any are unresponsive. To determine whether an app is not responding, we look at the oldest entry in the `waitQueue`. If the entry sits in the `waitQueue` past `entry.timeoutTime`, we trigger an ANR.
+
+
+### Checking if a connection is unresponsive ###
+
+When a dispatch entry is sent to the app, its `deliveryTime` and `timeoutTime` fields are populated. The `deliveryTime` is the time that the event is delivered to the app. This is simply the current time inside `publishMotionEvent`. The `timeoutTime` is the time when this entry would be considered overdue. At that time, the ANR process would start for this connection.
+
+Most connections are associated with a window, and each window may have a custom timeout time. To calculate the timeout time of a specific event, simply add the `window.dispatchingTimeout` to the current time. In case where there is no associated window, such as gesture monitors, use the default dispatching timeout which is defined in `IInputConstants::DEFAULT_DISPATCHING_TIMEOUT_MILLIS`.
+
+The `timeoutTime` field of the `DispatchEntry` is needed because the window associated with a specific connection may change its timeout time. Therefore, entries sent prior to the timeout change would need to follow the previous timeout value. If a window timeout changes, it only affects new events being dispatched, and does not alter the timeout times of events already sent to the app.
+
+For example, if an application is being debugged, the ActivityManager may want to increase the timeout time for a window to prevent the ANR dialog from appearing or the app from getting killed.
+
+Looping through `waitQueue`s of all connections on every dispatch cycle could be costly. To improve this, we introduced the `AnrTracker` class.
+
+`AnrTracker` uses a multiset (a set that allows duplicate entries) to keep track of the next time a dispatch entry would become out of date. Duplicate entries are allowed because there may be two events with an identical timeout time. This is unlikely to happen in practice today, but is possible if the window timeouts are different or if the device has a high input report rate or a low clock resolution.
+
+On each dispatch cycle, InputDispatcher checks `AnrTracker` for the nearest timeout value. If the nearest timeout value is in the past, InputDispatcher will trigger the ANR for the corresponding connection.
+
+When an application sends a response for a particular dispatch entry, that entry is removed from the connection's `waitQueue`, and it is also removed from the `AnrTracker`. During normal operation, the entries are removed from `AnrTracker` quickly.
+
+
+### How to test ###
+
+In order to test this behaviour, you can create an application that calls `SystemClock.sleep` while handling a click event.
+
+When this happens, the expectation is that the ANR dialog will come up within a short period of sending an input event (typically 5 seconds). While the app is not responding, it is expected that touches on other applications and gesture monitors still continue to work.
+
+
+## 2. Application does not have a focused window, and a focused event comes in ##
+
+This is a legacy behaviour that we are maintaining inside InputDispatcher. When an application is launched, WindowManager calls `setFocusedApplication` to tell InputDispatcher that there is a focused application. This is used by InputDispatcher purely for ANR and debugging purposes.
+
+After launching, an application may not add a focused window. This could be either due to a bug in WindowManager or in the app.
+
+The legacy behaviour in this situation is as follows: touches will continue to function normally, without causing an ANR. If there is a focused event, however, it would require a focused window to be dispatched. InputDispatcher will keep this focused event inside mPendingEvent until:
+
+* A focused window is added
+* Timeout occurs
+* User touches another application
+
+To keep track of this timeout, when this situation is detected initially, `mInputTargetWaitTimeoutTime` and `mAwaitedFocusedApplication` are set. When the `mInputTargetWaitTimeoutTime` expires, an ANR will be raised.
+
+
+### How to test ###
+
+Create an empty application that sets `FLAG_NOT_FOCUSABLE` on its window in `onCreate`. Touching the application's window should not cause an ANR. Sending a key event to the application, however, should cause ANR. One easy way to do this is by pressing or gesturing the BACK key. In this scenario, `adb shell dumpsys input` will reveal that there's no focused window in the current display.
+
+
+## Extending the timeout based on the response from policy ##
+
+When the policy processes the ANR notification and responds with a positive timeout, InputDispatcher marks the connection as "responsive" by setting `inputPublisherBlocked = false`. All of the entries for this connection inside AnrTracker will be modified to expire at `time = (current time) + (timeout extension returned by policy)`.
+
+If the policy wants to abort dispatch, it returns a timeout value of 0. In this case, InputDispatcher will synthesize cancel events for the connection.
+
+When an app is unresponsive, new touches do not go to the app. They get dropped with a warning log. This is done to prevent overwhelming the app with events in case it later becomes responsive.
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 14f922f..c63c179 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -108,7 +108,7 @@
         dump += INDENT2 "Motion Ranges:\n";
         for (size_t i = 0; i < ranges.size(); i++) {
             const InputDeviceInfo::MotionRange& range = ranges[i];
-            const char* label = getAxisLabel(range.axis);
+            const char* label = InputEventLookup::getAxisLabel(range.axis);
             char name[32];
             if (label) {
                 strncpy(name, label, sizeof(name));
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 57acba5..abd8aa9 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -73,14 +73,14 @@
 
     dump += INDENT3 "Axes:\n";
     for (const auto& [rawAxis, axis] : mAxes) {
-        const char* label = getAxisLabel(axis.axisInfo.axis);
+        const char* label = InputEventLookup::getAxisLabel(axis.axisInfo.axis);
         if (label) {
             dump += StringPrintf(INDENT4 "%s", label);
         } else {
             dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis);
         }
         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
-            label = getAxisLabel(axis.axisInfo.highAxis);
+            label = InputEventLookup::getAxisLabel(axis.axisInfo.highAxis);
             if (label) {
                 dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue);
             } else {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c7bb2ac..da50af5 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -777,8 +777,7 @@
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
         mInfo.visible = true;
-        mInfo.canReceiveKeys = true;
-        mInfo.hasFocus = false;
+        mInfo.focusable = false;
         mInfo.hasWallpaper = false;
         mInfo.paused = false;
         mInfo.ownerPid = INJECTOR_PID;
@@ -788,7 +787,7 @@
 
     virtual bool updateInfo() { return true; }
 
-    void setFocus(bool hasFocus) { mInfo.hasFocus = hasFocus; }
+    void setFocusable(bool focusable) { mInfo.focusable = focusable; }
 
     void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
         mInfo.dispatchingTimeout = timeout;
@@ -1237,7 +1236,7 @@
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // Display should have only one focused window
-    windowSecond->setFocus(true);
+    windowSecond->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
 
     windowSecond->consumeFocusEvent(true);
@@ -1260,8 +1259,8 @@
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
-    windowTop->setFocus(true);
-    windowSecond->setFocus(true);
+    windowTop->setFocusable(true);
+    windowSecond->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
     windowTop->consumeFocusEvent(true);
@@ -1284,8 +1283,8 @@
     // Set focused application.
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
-    windowTop->setFocus(true);
-    windowSecond->setFocus(true);
+    windowTop->setFocusable(true);
+    windowSecond->setFocusable(true);
     // Release channel for window is no longer valid.
     windowTop->releaseChannel();
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
@@ -1521,7 +1520,7 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
-    window->setFocus(true);
+    window->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(true);
@@ -1723,7 +1722,7 @@
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
 
-    window->setFocus(true);
+    window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
     window->consumeFocusEvent(true);
@@ -1831,7 +1830,7 @@
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-    window->setFocus(true);
+    window->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(true);
@@ -1923,31 +1922,31 @@
 
     // Set focused application.
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-    window->setFocus(true);
+    window->setFocusable(true);
 
     SCOPED_TRACE("Check default value of touch mode");
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
 
     SCOPED_TRACE("Remove the window to trigger focus loss");
-    window->setFocus(false);
+    window->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(false /*hasFocus*/, true /*inTouchMode*/);
 
     SCOPED_TRACE("Disable touch mode");
     mDispatcher->setInTouchMode(false);
-    window->setFocus(true);
+    window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(true /*hasFocus*/, false /*inTouchMode*/);
 
     SCOPED_TRACE("Remove the window to trigger focus loss");
-    window->setFocus(false);
+    window->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(false /*hasFocus*/, false /*inTouchMode*/);
 
     SCOPED_TRACE("Enable touch mode again");
     mDispatcher->setInTouchMode(true);
-    window->setFocus(true);
+    window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
 
@@ -1960,7 +1959,7 @@
             new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-    window->setFocus(true);
+    window->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
@@ -2050,7 +2049,7 @@
         mApp = std::make_shared<FakeApplicationHandle>();
         mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
 
-        mWindow->setFocus(true);
+        mWindow->setFocusable(true);
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
 
         mWindow->consumeFocusEvent(true);
@@ -2140,7 +2139,7 @@
 
         // Set focus window for primary display, but focused display would be second one.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
-        windowInPrimary->setFocus(true);
+        windowInPrimary->setFocusable(true);
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary}}});
         windowInPrimary->consumeFocusEvent(true);
 
@@ -2152,7 +2151,7 @@
         mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
         // Set focus window for second display.
         mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
-        windowInSecondary->setFocus(true);
+        windowInSecondary->setFocusable(true);
         mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
         windowInSecondary->consumeFocusEvent(true);
     }
@@ -2364,7 +2363,7 @@
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-        mFocusedWindow->setFocus(true);
+        mFocusedWindow->setFocusable(true);
 
         // Expect one focus window exist in display.
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}});
@@ -2652,7 +2651,7 @@
                 new FakeWindowHandle(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFrame(Rect(0, 0, 30, 30));
         mWindow->setDispatchingTimeout(30ms);
-        mWindow->setFocus(true);
+        mWindow->setFocusable(true);
         // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
         // window.
         mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
@@ -2734,7 +2733,7 @@
 
 // We have a focused application, but no focused window
 TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
-    mWindow->setFocus(false);
+    mWindow->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
     mWindow->consumeFocusEvent(false);
 
@@ -2762,7 +2761,7 @@
 // If the policy wants to keep waiting on the focused window to be added, make sure
 // that this timeout extension is honored and ANR is raised again.
 TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_ExtendsAnr) {
-    mWindow->setFocus(false);
+    mWindow->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
     mWindow->consumeFocusEvent(false);
     const std::chrono::duration timeout = 5ms;
@@ -2790,7 +2789,7 @@
 
 // We have a focused application, but no focused window
 TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
-    mWindow->setFocus(false);
+    mWindow->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
     mWindow->consumeFocusEvent(false);
 
@@ -3050,7 +3049,7 @@
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
-        mFocusedWindow->setFocus(true);
+        mFocusedWindow->setFocusable(true);
 
         // Expect one focus window exist in display.
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}});
@@ -3247,8 +3246,8 @@
     ASSERT_FALSE(keySequenceNum);
 
     // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
-    mFocusedWindow->setFocus(false);
-    mUnfocusedWindow->setFocus(true);
+    mFocusedWindow->setFocusable(false);
+    mUnfocusedWindow->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
 
     // Focus events should precede the key events
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index a4922fa..99b96e9 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -73,9 +73,8 @@
                                                  450 /* bottom */};
 static const Region TestInfoTouchableRegion(TestInfoTouchableRegionRect);
 static constexpr bool TestInfoVisible = false;
-static constexpr bool TestInfoCanReceiveKeys = false;
 static constexpr bool TestInfoTrustedOverlay = true;
-static constexpr bool TestInfoHasFocus = false;
+static constexpr bool TestInfoFocusable = false;
 static constexpr bool TestInfoHasWallpaper = false;
 static constexpr bool TestInfoPaused = false;
 static constexpr int32_t TestInfoOwnerPid = 19;
@@ -295,9 +294,9 @@
                          TestInfoFrameTop, 0, 0, 1});
     mInfo.touchableRegion = TestInfoTouchableRegion;
     mInfo.visible = TestInfoVisible;
-    mInfo.canReceiveKeys = TestInfoCanReceiveKeys;
     mInfo.trustedOverlay = TestInfoTrustedOverlay;
-    mInfo.hasFocus = TestInfoHasFocus;
+    mInfo.focusable = TestInfoFocusable;
+
     mInfo.hasWallpaper = TestInfoHasWallpaper;
     mInfo.paused = TestInfoPaused;
     mInfo.ownerPid = TestInfoOwnerPid;
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index ec3dfc8..b5e6ae9 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -4,6 +4,7 @@
     srcs: [
         "BatterySaverPolicyConfig.cpp",
         "CoolingDevice.cpp",
+        "ParcelDuration.cpp",
         "PowerHalController.cpp",
         "PowerHalLoader.cpp",
         "PowerHalWrapper.cpp",
diff --git a/services/powermanager/ParcelDuration.cpp b/services/powermanager/ParcelDuration.cpp
new file mode 100644
index 0000000..c0ab380
--- /dev/null
+++ b/services/powermanager/ParcelDuration.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "ParcelDuration"
+
+#include <android/ParcelDuration.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android::os {
+
+status_t ParcelDuration::readFromParcel(const android::Parcel *parcel) {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+
+    return parcel->readInt64(&mSeconds) ?: parcel->readInt32(&mNanos);
+}
+
+status_t ParcelDuration::writeToParcel(android::Parcel *parcel) const {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+
+    return parcel->writeInt64(mSeconds) ?: parcel->writeInt32(mNanos);
+}
+
+} // namespace android::os
diff --git a/services/powermanager/include/android/ParcelDuration.h b/services/powermanager/include/android/ParcelDuration.h
new file mode 100644
index 0000000..117d173
--- /dev/null
+++ b/services/powermanager/include/android/ParcelDuration.h
@@ -0,0 +1,47 @@
+/*
+ * 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_OS_PARCELDURATION_H
+#define ANDROID_OS_PARCELDURATION_H
+
+#include <binder/Parcelable.h>
+#include <math.h>
+#include <utils/RefBase.h>
+
+namespace android::os {
+
+/**
+ * Parcelable version of {@link java.time.Duration} that can be used in binder calls.
+ * This file needs to be kept in sync with
+ * frameworks/base/core/java/android/os/ParcelDuration.java
+ */
+struct ParcelDuration : public android::Parcelable {
+    ParcelDuration(int64_t seconds = 0, int32_t nanos = 0) : mSeconds(seconds), mNanos(nanos) {}
+
+    status_t readFromParcel(const android::Parcel* parcel) override;
+    status_t writeToParcel(android::Parcel* parcel) const override;
+    bool operator==(const ParcelDuration& pd) const {
+        return mSeconds == pd.mSeconds && mNanos == pd.mNanos;
+    }
+
+private:
+    int64_t mSeconds;
+    int32_t mNanos;
+};
+
+} // namespace android::os
+
+#endif /* ANDROID_OS_PARCELDURATION_H */
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index e341af1..b039f6e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -160,7 +160,6 @@
         "RefreshRateOverlay.cpp",
         "RegionSamplingThread.cpp",
         "RenderArea.cpp",
-        "Scheduler/DispSync.cpp",
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventThread.cpp",
         "Scheduler/OneShotTimer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 2483abb..54c060b 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -50,10 +50,7 @@
     explicit BufferLayer(const LayerCreationArgs& args);
     virtual ~BufferLayer() override;
 
-    // -----------------------------------------------------------------------
-    // Overriden from Layer
-    // -----------------------------------------------------------------------
-public:
+    // Implements Layer.
     sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
     compositionengine::LayerFECompositionState* editCompositionState() override;
 
@@ -118,41 +115,6 @@
 
     ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
 
-    // -----------------------------------------------------------------------
-    // Functions that must be implemented by derived classes
-    // -----------------------------------------------------------------------
-private:
-    virtual bool fenceHasSignaled() const = 0;
-    virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
-
-    PixelFormat getPixelFormat() const;
-
-    // Computes the transform matrix using the setFilteringEnabled to determine whether the
-    // transform matrix should be computed for use with bilinear filtering.
-    void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]);
-
-    virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
-
-    virtual bool getAutoRefresh() const = 0;
-    virtual bool getSidebandStreamChanged() const = 0;
-
-    // Latch sideband stream and returns true if the dirty region should be updated.
-    virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
-
-    virtual bool hasFrameUpdate() const = 0;
-
-    virtual status_t bindTextureImage() = 0;
-    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                    nsecs_t expectedPresentTime) = 0;
-
-    virtual status_t updateActiveBuffer() = 0;
-    virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
-
-    // 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 !mPotentialCursor; }
-
 protected:
     struct BufferInfo {
         nsecs_t mDesiredPresentTime;
@@ -213,6 +175,30 @@
     ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
 
 private:
+    virtual bool fenceHasSignaled() const = 0;
+    virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
+    virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
+
+    virtual bool getAutoRefresh() const = 0;
+    virtual bool getSidebandStreamChanged() const = 0;
+
+    // Latch sideband stream and returns true if the dirty region should be updated.
+    virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
+
+    virtual bool hasFrameUpdate() const = 0;
+
+    virtual status_t bindTextureImage() = 0;
+    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                                    nsecs_t expectedPresentTime) = 0;
+
+    virtual status_t updateActiveBuffer() = 0;
+    virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
+
+    // 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 !mPotentialCursor; }
+
     // Returns true if this layer requires filtering
     bool needsFiltering(const DisplayDevice*) const override;
     bool needsFilteringForScreenshots(const DisplayDevice*,
@@ -222,6 +208,12 @@
     // and its parent layer is not bounded
     Rect getBufferSize(const State& s) const override;
 
+    PixelFormat getPixelFormat() const;
+
+    // Computes the transform matrix using the setFilteringEnabled to determine whether the
+    // transform matrix should be computed for use with bilinear filtering.
+    void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]);
+
     std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
 
     FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 5ebc22d..1ac0453 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -35,10 +35,7 @@
     explicit BufferQueueLayer(const LayerCreationArgs&);
     ~BufferQueueLayer() override;
 
-    // -----------------------------------------------------------------------
-    // Interface implementation for Layer
-    // -----------------------------------------------------------------------
-public:
+    // Implements Layer.
     const char* getType() const override { return "BufferQueueLayer"; }
 
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
@@ -54,41 +51,12 @@
 
     bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
 
-    // -----------------------------------------------------------------------
-
-    // -----------------------------------------------------------------------
-    // Interface implementation for BufferLayer
-    // -----------------------------------------------------------------------
-public:
+    // Implements BufferLayer.
     bool fenceHasSignaled() const override;
     bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
 
-private:
-    uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
-
-    bool getAutoRefresh() const override;
-    bool getSidebandStreamChanged() const override;
-
-    bool latchSidebandStream(bool& recomputeVisibleRegions) override;
-    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
-
-    bool hasFrameUpdate() const override;
-
-    status_t bindTextureImage() override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            nsecs_t expectedPresentTime) override;
-
-    status_t updateActiveBuffer() override;
-    status_t updateFrameNumber(nsecs_t latchTime) override;
-
-    sp<Layer> createClone() override;
-
-    void onFrameAvailable(const BufferItem& item);
-    void onFrameReplaced(const BufferItem& item);
-    void onSidebandStreamChanged();
-    void onFrameDequeued(const uint64_t bufferId);
-    void onFrameDetached(const uint64_t bufferId);
-    void onFrameCancelled(const uint64_t bufferId);
+    status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format);
+    sp<IGraphicBufferProducer> getProducer() const;
 
 protected:
     void gatherBufferInfo() override;
@@ -114,19 +82,39 @@
         BufferQueueLayer* mBufferQueueLayer = nullptr;
         Mutex mMutex;
     };
-    // -----------------------------------------------------------------------
-
-public:
-    status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format);
-
-    sp<IGraphicBufferProducer> getProducer() const;
 
 private:
-    // Temporary - Used only for LEGACY camera mode.
-    uint32_t getProducerStickyTransform() const;
+    uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
+
+    bool getAutoRefresh() const override;
+    bool getSidebandStreamChanged() const override;
+
+    bool latchSidebandStream(bool& recomputeVisibleRegions) override;
+    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
+
+    bool hasFrameUpdate() const override;
+
+    status_t bindTextureImage() override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                            nsecs_t expectedPresentTime) override;
+
+    status_t updateActiveBuffer() override;
+    status_t updateFrameNumber(nsecs_t latchTime) override;
+
+    sp<Layer> createClone() override;
 
     void onFirstRef() override;
 
+    void onFrameAvailable(const BufferItem& item);
+    void onFrameReplaced(const BufferItem& item);
+    void onSidebandStreamChanged();
+    void onFrameDequeued(const uint64_t bufferId);
+    void onFrameDetached(const uint64_t bufferId);
+    void onFrameCancelled(const uint64_t bufferId);
+
+    // Temporary - Used only for LEGACY camera mode.
+    uint32_t getProducerStickyTransform() const;
+
     sp<BufferLayerConsumer> mConsumer;
     sp<IGraphicBufferProducer> mProducer;
 
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 00fa7f7..89d9a00 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -36,9 +36,7 @@
 
     ~BufferStateLayer() override;
 
-    // -----------------------------------------------------------------------
-    // Interface implementation for Layer
-    // -----------------------------------------------------------------------
+    // Implements Layer.
     const char* getType() const override { return "BufferStateLayer"; }
 
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
@@ -117,6 +115,8 @@
     uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
 
 private:
+    friend class SlotGenerationTest;
+
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
                                  nsecs_t requestedPresentTime);
 
@@ -141,8 +141,6 @@
     // Crop that applies to the buffer
     Rect computeCrop(const State& s);
 
-private:
-    friend class SlotGenerationTest;
     bool willPresentCurrentTransaction() const;
 
     static const std::array<float, 16> IDENTITY_MATRIX;
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index e9063e5..f64be3a 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -28,13 +28,9 @@
 
 namespace android {
 
-// ---------------------------------------------------------------------------
-
 class Layer;
 class SurfaceFlinger;
 
-// ---------------------------------------------------------------------------
-
 class Client : public BnSurfaceComposerClient
 {
 public:
@@ -80,7 +76,6 @@
     mutable Mutex mLock;
 };
 
-// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SF_CLIENT_H
diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h
index b7d61ce..b0cc030 100644
--- a/services/surfaceflinger/Colorizer.h
+++ b/services/surfaceflinger/Colorizer.h
@@ -21,8 +21,6 @@
 
 namespace android {
 
-// ---------------------------------------------------------------------------
-
 class Colorizer {
     bool mEnabled;
 public:
@@ -59,9 +57,6 @@
     }
 };
 
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
+} // namespace android
 
 #endif /* ANDROID_SURFACE_FLINGER_COLORIZER_H */
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b3b9fe5..b37ca33 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -121,13 +121,6 @@
         //
         // You can either "make dist tests" before flashing, or set this
         // option to false temporarily.
-
-
-        // FIXME: ASAN build is broken for a while, but was not discovered
-        // since new PM silently suppressed ASAN. Temporarily turn off ASAN
-        // to unblock the compiler upgrade process.
-        // address: true,
-        // http://b/139747256
-        address: false,
+        address: true,
     },
 }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 8a9763b..b4ed92f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -116,7 +116,7 @@
     FloatRect geomLayerBounds;
 
     // length of the shadow in screen space
-    float shadowRadius;
+    float shadowRadius{0.f};
 
     /*
      * Geometry state
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 75394fa..d2b38d1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -110,7 +110,7 @@
     void dump(std::string& result) const;
 
     // Timestamp for when the layer is queued for client composition
-    nsecs_t clientCompositionTimestamp;
+    nsecs_t clientCompositionTimestamp{0};
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 016b6ca..ea59692 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -167,12 +167,6 @@
     const int displayWidth = displayBounds.width();
     const int displayHeight = displayBounds.height();
 
-    ui::Transform rotation;
-    if (const auto flags = ui::Transform::toRotationFlags(orientation);
-        flags != ui::Transform::ROT_INVALID) {
-        rotation.set(flags, displayWidth, displayHeight);
-    }
-
     if (!orientedDisplaySpaceRect.isValid()) {
         // the destination frame can be invalid if it has never been set,
         // in that case we assume the whole display frame.
@@ -185,7 +179,7 @@
         // It's also invalid to have an empty layerStackSpaceRect, so we handle that
         // case in the same way.
         layerStackSpaceRect = Rect(displayWidth, displayHeight);
-        if (rotation.getOrientation() & ui::Transform::ROT_90) {
+        if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
             std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom);
         }
     }
@@ -208,13 +202,13 @@
     logicalTranslation.set(-sourceX, -sourceY);
     physicalTranslation.set(destX, destY);
 
-    // need to take care of primary display rotation for globalTransform
-    // for case if the panel is not installed aligned with device orientation
-    if (isPrimary()) {
-        if (const auto flags = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
-            flags != ui::Transform::ROT_INVALID) {
-            rotation.set(flags, displayWidth, displayHeight);
-        }
+    // We need to take care of display rotation for globalTransform for case if the panel is not
+    // installed aligned with device orientation.
+    const auto transformOrientation = orientation + mPhysicalOrientation;
+    const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(transformOrientation);
+    ui::Transform rotation;
+    if (transformOrientationFlags != ui::Transform::ROT_INVALID) {
+        rotation.set(transformOrientationFlags, displayWidth, displayHeight);
     }
 
     // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation.
@@ -233,16 +227,11 @@
     // Make sure the displaySpaceRect is contained in the display bounds
     displaySpaceRect.intersect(displayBounds, &displaySpaceRect);
 
-    uint32_t transformOrientation;
-
     if (isPrimary()) {
         sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
-        transformOrientation = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
-    } else {
-        transformOrientation = ui::Transform::toRotationFlags(orientation);
     }
 
-    getCompositionDisplay()->setProjection(globalTransform, transformOrientation,
+    getCompositionDisplay()->setProjection(globalTransform, transformOrientationFlags,
                                            orientedDisplaySpaceRect, layerStackSpaceRect,
                                            displaySpaceRect, needsFiltering);
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 521659d..913f13a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -55,8 +55,6 @@
 
 namespace android {
 
-// ---------------------------------------------------------------------------
-
 class Client;
 class Colorizer;
 class DisplayDevice;
@@ -73,8 +71,6 @@
 class SurfaceInterceptor;
 }
 
-// ---------------------------------------------------------------------------
-
 struct LayerCreationArgs {
     LayerCreationArgs(SurfaceFlinger*, sp<Client>, std::string name, uint32_t w, uint32_t h,
                       uint32_t flags, LayerMetadata);
@@ -106,14 +102,6 @@
     static constexpr int32_t PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
 
 public:
-    mutable bool contentDirty{false};
-    Region surfaceDamageRegion;
-
-    // Layer serial number.  This gives layers an explicit ordering, so we
-    // have a stable sort order when their layer stack and Z-order are
-    // the same.
-    int32_t sequence{sSequence++};
-
     enum { // flags for doTransaction()
         eDontUpdateGeometryState = 0x00000001,
         eVisibleRegion = 0x00000002,
@@ -281,17 +269,56 @@
         ui::Transform::RotationFlags fixedTransformHint;
     };
 
+    /*
+     * Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
+     * is called.
+     */
+    class LayerCleaner {
+        sp<SurfaceFlinger> mFlinger;
+        sp<Layer> mLayer;
+
+    protected:
+        ~LayerCleaner() {
+            // destroy client resources
+            mFlinger->onHandleDestroyed(mLayer);
+        }
+
+    public:
+        LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+              : mFlinger(flinger), mLayer(layer) {}
+    };
+
+    /*
+     * The layer handle is just a BBinder object passed to the client
+     * (remote process) -- we don't keep any reference on our side such that
+     * the dtor is called when the remote side let go of its reference.
+     *
+     * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+     * this layer when the handle is destroyed.
+     */
+    class Handle : public BBinder, public LayerCleaner {
+    public:
+        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+              : LayerCleaner(flinger, layer), owner(layer) {}
+
+        wp<Layer> owner;
+    };
+
     explicit Layer(const LayerCreationArgs& args);
     virtual ~Layer();
 
-    void onFirstRef() override;
+    static bool isLayerFocusedBasedOnPriority(int32_t priority);
+    static void miniDumpHeader(std::string& result);
+    static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility);
 
-    InputWindowInfo::Type getWindowType() const { return mWindowType; }
+    // Provide unique string for each class type in the Layer hierarchy
+    virtual const char* getType() const = 0;
 
-    void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
-    bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
+    // true if this layer is visible, false otherwise
+    virtual bool isVisible() const = 0;
 
-    // ------------------------------------------------------------------------
+    virtual sp<Layer> createClone() = 0;
+
     // Geometry setting functions.
     //
     // The following group of functions are used to specify the layers
@@ -364,13 +391,9 @@
     virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
     virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
     virtual bool setMetadata(const LayerMetadata& data);
-    bool reparentChildren(const sp<IBinder>& newParentHandle);
-    void reparentChildren(const sp<Layer>& newParent);
     virtual void setChildrenDrawingParent(const sp<Layer>&);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
     virtual bool detachChildren();
-    bool attachChildren();
-    bool isLayerDetached() const { return mLayerDetached; }
     virtual bool setColorTransform(const mat4& matrix);
     virtual mat4 getColorTransform() const;
     virtual bool hasColorTransform() const;
@@ -403,23 +426,13 @@
     }
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
     virtual bool setColorSpaceAgnostic(const bool agnostic);
-    bool setShadowRadius(float shadowRadius);
     virtual bool setFrameRateSelectionPriority(int32_t priority);
     virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
     //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
     //  rate priority from its parent.
     virtual int32_t getFrameRateSelectionPriority() const;
-    static bool isLayerFocusedBasedOnPriority(int32_t priority);
-
     virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
 
-    // Before color management is introduced, contents on Android have to be
-    // desaturated in order to match what they appears like visually.
-    // With color management, these contents will appear desaturated, thus
-    // needed to be saturated so that they match what they are designed for
-    // visually.
-    bool isLegacyDataSpace() const;
-
     virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const;
     virtual compositionengine::LayerFECompositionState* editCompositionState();
 
@@ -429,6 +442,194 @@
     virtual void useSurfaceDamage() {}
     virtual void useEmptyDamage() {}
 
+    /*
+     * isOpaque - true if this surface is opaque
+     *
+     * This takes into account the buffer format (i.e. whether or not the
+     * pixel format includes an alpha channel) and the "opaque" flag set
+     * on the layer.  It does not examine the current plane alpha value.
+     */
+    virtual bool isOpaque(const Layer::State&) const { return false; }
+
+    /*
+     * Returns whether this layer can receive input.
+     */
+    virtual bool canReceiveInput() const;
+
+    /*
+     * isProtected - true if the layer may contain protected content in the
+     * GRALLOC_USAGE_PROTECTED sense.
+     */
+    virtual bool isProtected() const { return false; }
+
+    /*
+     * isFixedSize - true if content has a fixed size
+     */
+    virtual bool isFixedSize() const { return true; }
+
+    /*
+     * usesSourceCrop - true if content should use a source crop
+     */
+    virtual bool usesSourceCrop() const { return false; }
+
+    // Most layers aren't created from the main thread, and therefore need to
+    // grab the SF state lock to access HWC, but ContainerLayer does, so we need
+    // to avoid grabbing the lock again to avoid deadlock
+    virtual bool isCreatedFromMainThread() const { return false; }
+
+    virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
+    virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
+    virtual uint32_t getActiveHeight(const Layer::State& s) const { return s.active_legacy.h; }
+    virtual ui::Transform getActiveTransform(const Layer::State& s) const {
+        return s.active_legacy.transform;
+    }
+    virtual Region getActiveTransparentRegion(const Layer::State& s) const {
+        return s.activeTransparentRegion_legacy;
+    }
+    virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
+    virtual bool needsFiltering(const DisplayDevice*) const { return false; }
+
+    // True if this layer requires filtering
+    // This method is distinct from needsFiltering() in how the filter
+    // requirement is computed. needsFiltering() compares displayFrame and crop,
+    // where as this method transforms the displayFrame to layer-stack space
+    // first. This method should be used if there is no physical display to
+    // project onto when taking screenshots, as the filtering requirements are
+    // different.
+    // If the parent transform needs to be undone when capturing the layer, then
+    // the inverse parent transform is also required.
+    virtual bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const {
+        return false;
+    }
+
+    virtual void updateCloneBufferInfo(){};
+
+    virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
+
+    virtual bool isHdrY410() const { return false; }
+
+    virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
+
+    /*
+     * called after composition.
+     * returns true if the layer latched a new buffer this frame.
+     */
+    virtual bool onPostComposition(const DisplayDevice*,
+                                   const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+                                   const std::shared_ptr<FenceTime>& /*presentFence*/,
+                                   const CompositorTiming&) {
+        return false;
+    }
+
+    // If a buffer was replaced this frame, release the former buffer
+    virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+
+    virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+                                           const CompositorTiming& /*compositorTiming*/) {}
+
+    /*
+     * latchBuffer - called each time the screen is redrawn and returns whether
+     * the visible regions need to be recomputed (this is a fairly heavy
+     * operation, so this should be set only if needed). Typically this is used
+     * to figure out if the content or size of a surface has changed.
+     */
+    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+                             nsecs_t /*expectedPresentTime*/) {
+        return false;
+    }
+
+    virtual bool isBufferLatched() const { return false; }
+
+    virtual void latchAndReleaseBuffer() {}
+
+    /*
+     * returns the rectangle that crops the content of the layer and scales it
+     * to the layer's size.
+     */
+    virtual Rect getBufferCrop() const { return Rect(); }
+
+    /*
+     * Returns the transform applied to the buffer.
+     */
+    virtual uint32_t getBufferTransform() const { return 0; }
+
+    virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
+
+    virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; }
+
+    /*
+     * Returns if a frame is ready
+     */
+    virtual bool hasReadyFrame() const { return false; }
+
+    virtual int32_t getQueuedFrameCount() const { return 0; }
+
+    virtual void pushPendingState();
+
+    /**
+     * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
+     * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
+     */
+    virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
+
+    /**
+     * Returns the source bounds. If the bounds are not defined, it is inferred from the
+     * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
+     * For the root layer, this is the display viewport size.
+     */
+    virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const {
+        return parentBounds;
+    }
+    virtual FrameRate getFrameRateForLayerTree() const;
+
+    virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
+        return {};
+    }
+
+    virtual bool getTransformToDisplayInverse() const { return false; }
+
+    // Returns how rounded corners should be drawn for this layer.
+    // This will traverse the hierarchy until it reaches its root, finding topmost rounded
+    // corner definition and converting it into current layer's coordinates.
+    // As of now, only 1 corner radius per display list is supported. Subsequent ones will be
+    // ignored.
+    virtual RoundedCornerState getRoundedCornerState() const;
+
+    virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
+    virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
+    /**
+     * Return whether this layer needs an input info. For most layer types
+     * this is only true if they explicitly set an input-info but BufferLayer
+     * overrides this so we can generate input-info for Buffered layers that don't
+     * have them (for input occlusion detection checks).
+     */
+    virtual bool needsInputInfo() const { return hasInputInfo(); }
+
+    // Implements RefBase.
+    void onFirstRef() override;
+
+    // implements compositionengine::LayerFE
+    const compositionengine::LayerFECompositionState* getCompositionState() const override;
+    bool onPreComposition(nsecs_t) override;
+    void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
+    std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    const char* getDebugName() const override;
+
+    bool reparentChildren(const sp<IBinder>& newParentHandle);
+    void reparentChildren(const sp<Layer>& newParent);
+    bool attachChildren();
+    bool isLayerDetached() const { return mLayerDetached; }
+    bool setShadowRadius(float shadowRadius);
+
+    // Before color management is introduced, contents on Android have to be
+    // desaturated in order to match what they appears like visually.
+    // With color management, these contents will appear desaturated, thus
+    // needed to be saturated so that they match what they are designed for
+    // visually.
+    bool isLegacyDataSpace() const;
+
     uint32_t getTransactionFlags() const { return mTransactionFlags; }
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
@@ -464,21 +665,6 @@
     // only used within a single layer.
     uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; }
 
-    // -----------------------------------------------------------------------
-    // Virtuals
-
-    // Provide unique string for each class type in the Layer hierarchy
-    virtual const char* getType() const = 0;
-
-    /*
-     * isOpaque - true if this surface is opaque
-     *
-     * This takes into account the buffer format (i.e. whether or not the
-     * pixel format includes an alpha channel) and the "opaque" flag set
-     * on the layer.  It does not examine the current plane alpha value.
-     */
-    virtual bool isOpaque(const Layer::State&) const { return false; }
-
     /*
      * isSecure - true if this surface is secure, that is if it prevents
      * screenshots or VNC servers.
@@ -486,11 +672,6 @@
     bool isSecure() const;
 
     /*
-     * isVisible - true if this layer is visible, false otherwise
-     */
-    virtual bool isVisible() const = 0;
-
-    /*
      * isHiddenByPolicy - true if this layer has been forced invisible.
      * just because this is false, doesn't mean isVisible() is true.
      * For example if this layer has no active buffer, it may not be hidden by
@@ -498,32 +679,6 @@
      */
     bool isHiddenByPolicy() const;
 
-    /*
-     * Returns whether this layer can receive input.
-     */
-    virtual bool canReceiveInput() const;
-
-    /*
-     * isProtected - true if the layer may contain protected content in the
-     * GRALLOC_USAGE_PROTECTED sense.
-     */
-    virtual bool isProtected() const { return false; }
-
-    /*
-     * isFixedSize - true if content has a fixed size
-     */
-    virtual bool isFixedSize() const { return true; }
-
-    /*
-     * usesSourceCrop - true if content should use a source crop
-     */
-    virtual bool usesSourceCrop() const { return false; }
-
-    // Most layers aren't created from the main thread, and therefore need to
-    // grab the SF state lock to access HWC, but ContainerLayer does, so we need
-    // to avoid grabbing the lock again to avoid deadlock
-    virtual bool isCreatedFromMainThread() const { return false; }
-
     bool isRemovedFromCurrentState() const;
 
     LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*);
@@ -538,105 +693,13 @@
     void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet,
                                  uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
 
-    virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
-    virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
-    virtual uint32_t getActiveHeight(const Layer::State& s) const { return s.active_legacy.h; }
-    virtual ui::Transform getActiveTransform(const Layer::State& s) const {
-        return s.active_legacy.transform;
-    }
-    virtual Region getActiveTransparentRegion(const Layer::State& s) const {
-        return s.activeTransparentRegion_legacy;
-    }
-    virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
-    virtual bool needsFiltering(const DisplayDevice*) const { return false; }
-    // True if this layer requires filtering
-    // This method is distinct from needsFiltering() in how the filter
-    // requirement is computed. needsFiltering() compares displayFrame and crop,
-    // where as this method transforms the displayFrame to layer-stack space
-    // first. This method should be used if there is no physical display to
-    // project onto when taking screenshots, as the filtering requirements are
-    // different.
-    // If the parent transform needs to be undone when capturing the layer, then
-    // the inverse parent transform is also required.
-    virtual bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const {
-        return false;
-    }
+    InputWindowInfo::Type getWindowType() const { return mWindowType; }
 
-    // This layer is not a clone, but it's the parent to the cloned hierarchy. The
-    // variable mClonedChild represents the top layer that will be cloned so this
-    // layer will be the parent of mClonedChild.
-    // The layers in the cloned hierarchy will match the lifetime of the real layers. That is
-    // if the real layer is destroyed, then the clone layer will also be destroyed.
-    sp<Layer> mClonedChild;
+    void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
+    bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
 
-    virtual sp<Layer> createClone() = 0;
     void updateMirrorInfo();
-    virtual void updateCloneBufferInfo(){};
 
-protected:
-    sp<compositionengine::LayerFE> asLayerFE() const;
-    sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
-    bool isClone() { return mClonedFrom != nullptr; }
-    bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
-
-    virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
-
-    void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-    void updateClonedChildren(const sp<Layer>& mirrorRoot,
-                              std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-    void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-    void addChildToDrawing(const sp<Layer>&);
-    void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-    virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&);
-    virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareShadowClientComposition(
-            const LayerFE::LayerSettings&, const Rect& layerStackRect,
-            ui::Dataspace outputDataspace);
-    // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
-    // the settings clears the content with a solid black fill.
-    void prepareClearClientComposition(LayerFE::LayerSettings&, bool blackout) const;
-
-public:
-    /*
-     * compositionengine::LayerFE overrides
-     */
-    const compositionengine::LayerFECompositionState* getCompositionState() const override;
-    bool onPreComposition(nsecs_t) override;
-    void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
-    std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
-    const char* getDebugName() const override;
-
-protected:
-    void prepareBasicGeometryCompositionState();
-    void prepareGeometryCompositionState();
-    virtual void preparePerFrameCompositionState();
-    void prepareCursorCompositionState();
-
-public:
-    virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
-
-    virtual bool isHdrY410() const { return false; }
-
-    virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
-
-    /*
-     * called after composition.
-     * returns true if the layer latched a new buffer this frame.
-     */
-    virtual bool onPostComposition(const DisplayDevice*,
-                                   const std::shared_ptr<FenceTime>& /*glDoneFence*/,
-                                   const std::shared_ptr<FenceTime>& /*presentFence*/,
-                                   const CompositorTiming&) {
-        return false;
-    }
-
-    // If a buffer was replaced this frame, release the former buffer
-    virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
-
-    virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
-                                           const CompositorTiming& /*compositorTiming*/) {}
     /*
      * doTransaction - process the transaction. This is a good place to figure
      * out which attributes of the surface have changed.
@@ -644,21 +707,6 @@
     uint32_t doTransaction(uint32_t transactionFlags);
 
     /*
-     * latchBuffer - called each time the screen is redrawn and returns whether
-     * the visible regions need to be recomputed (this is a fairly heavy
-     * operation, so this should be set only if needed). Typically this is used
-     * to figure out if the content or size of a surface has changed.
-     */
-    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
-                             nsecs_t /*expectedPresentTime*/) {
-        return false;
-    }
-
-    virtual bool isBufferLatched() const { return false; }
-
-    virtual void latchAndReleaseBuffer() {}
-
-    /*
      * Remove relative z for the layer if its relative parent is not part of the
      * provided layer tree.
      */
@@ -685,36 +733,12 @@
      */
     void updateTransformHint(ui::Transform::RotationFlags);
 
-    /*
-     * returns the rectangle that crops the content of the layer and scales it
-     * to the layer's size.
-     */
-    virtual Rect getBufferCrop() const { return Rect(); }
-
-    /*
-     * Returns the transform applied to the buffer.
-     */
-    virtual uint32_t getBufferTransform() const { return 0; }
-
-    virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
-
-    virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; }
-
-    /*
-     * Returns if a frame is ready
-     */
-    virtual bool hasReadyFrame() const { return false; }
-
-    virtual int32_t getQueuedFrameCount() const { return 0; }
-
-    // -----------------------------------------------------------------------
     inline const State& getDrawingState() const { return mDrawingState; }
     inline const State& getCurrentState() const { return mCurrentState; }
     inline State& getCurrentState() { return mCurrentState; }
 
     LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const;
 
-    static void miniDumpHeader(std::string& result);
     void miniDump(std::string& result, const DisplayDevice&) const;
     void dumpFrameStats(std::string& result) const;
     void dumpFrameEvents(std::string& result);
@@ -722,17 +746,10 @@
     void clearFrameStats();
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
-
-    virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
-        return {};
-    }
-
     void onDisconnect();
     void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
                                   FrameEventHistoryDelta* outDelta);
 
-    virtual bool getTransformToDisplayInverse() const { return false; }
-
     ui::Transform getTransform() const;
 
     // Returns the Alpha of the Surface, accounting for the Alpha
@@ -749,13 +766,6 @@
     // is ready to acquire a buffer.
     ui::Transform::RotationFlags getFixedTransformHint() const;
 
-    // Returns how rounded corners should be drawn for this layer.
-    // This will traverse the hierarchy until it reaches its root, finding topmost rounded
-    // corner definition and converting it into current layer's coordinates.
-    // As of now, only 1 corner radius per display list is supported. Subsequent ones will be
-    // ignored.
-    virtual RoundedCornerState getRoundedCornerState() const;
-
     renderengine::ShadowSettings getShadowSettings(const Rect& layerStackRect) const;
 
     /**
@@ -801,22 +811,6 @@
     // SurfaceFlinger to complete a transaction.
     void commitChildList();
     int32_t getZ(LayerVector::StateSet) const;
-    virtual void pushPendingState();
-
-    /**
-     * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
-     * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
-     */
-    virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
-
-    /**
-     * Returns the source bounds. If the bounds are not defined, it is inferred from the
-     * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
-     * For the root layer, this is the display viewport size.
-     */
-    virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const {
-        return parentBounds;
-    }
 
     /**
      * Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
@@ -827,52 +821,40 @@
     Rect getCroppedBufferSize(const Layer::State& s) const;
 
     bool setFrameRate(FrameRate);
-    virtual FrameRate getFrameRateForLayerTree() const;
-    static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility);
+
+    // Creates a new handle each time, so we only expect
+    // this to be called once.
+    sp<IBinder> getHandle();
+    const std::string& getName() const { return mName; }
+    bool getPremultipledAlpha() const;
+    void setInputInfo(const InputWindowInfo& info);
+
+    InputWindowInfo fillInputInfo();
+    /**
+     * Returns whether this layer has an explicitly set input-info.
+     */
+    bool hasInputInfo() const;
+
+    uid_t getOwnerUid() { return mOwnerUid; }
+
+    // This layer is not a clone, but it's the parent to the cloned hierarchy. The
+    // variable mClonedChild represents the top layer that will be cloned so this
+    // layer will be the parent of mClonedChild.
+    // The layers in the cloned hierarchy will match the lifetime of the real layers. That is
+    // if the real layer is destroyed, then the clone layer will also be destroyed.
+    sp<Layer> mClonedChild;
+
+    mutable bool contentDirty{false};
+    Region surfaceDamageRegion;
+
+    // Layer serial number.  This gives layers an explicit ordering, so we
+    // have a stable sort order when their layer stack and Z-order are
+    // the same.
+    int32_t sequence{sSequence++};
+
+    bool mPendingHWCDestroy{false};
 
 protected:
-    // constant
-    sp<SurfaceFlinger> mFlinger;
-    /*
-     * Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
-     * is called.
-     */
-    class LayerCleaner {
-        sp<SurfaceFlinger> mFlinger;
-        sp<Layer> mLayer;
-
-    protected:
-        ~LayerCleaner() {
-            // destroy client resources
-            mFlinger->onHandleDestroyed(mLayer);
-        }
-
-    public:
-        LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
-              : mFlinger(flinger), mLayer(layer) {}
-    };
-
-    friend class impl::SurfaceInterceptor;
-
-    // For unit tests
-    friend class TestableSurfaceFlinger;
-    friend class RefreshRateSelectionTest;
-    friend class SetFrameRateTest;
-
-    virtual void commitTransaction(const State& stateToCommit);
-
-    uint32_t getEffectiveUsage(uint32_t usage) const;
-
-    /**
-     * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
-     * crop coordinates, transforming them into layer space.
-     */
-    void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
-    void setParent(const sp<Layer>&);
-    LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers);
-    void addZOrderRelative(const wp<Layer>& relative);
-    void removeZOrderRelative(const wp<Layer>& relative);
-
     class SyncPoint {
     public:
         explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer)
@@ -900,6 +882,63 @@
         wp<Layer> mRequestedSyncLayer;
     };
 
+    friend class impl::SurfaceInterceptor;
+
+    // For unit tests
+    friend class TestableSurfaceFlinger;
+    friend class RefreshRateSelectionTest;
+    friend class SetFrameRateTest;
+
+    virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+    virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&);
+    virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareShadowClientComposition(
+            const LayerFE::LayerSettings&, const Rect& layerStackRect,
+            ui::Dataspace outputDataspace);
+    virtual void preparePerFrameCompositionState();
+    virtual void commitTransaction(const State& stateToCommit);
+    virtual bool applyPendingStates(State* stateToCommit);
+    virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
+
+    // Returns mCurrentScaling mode (originating from the
+    // Client) or mOverrideScalingMode mode (originating from
+    // the Surface Controller) if set.
+    virtual uint32_t getEffectiveScalingMode() const { return 0; }
+
+    sp<compositionengine::LayerFE> asLayerFE() const;
+    sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
+    bool isClone() { return mClonedFrom != nullptr; }
+    bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
+
+    void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+    void updateClonedChildren(const sp<Layer>& mirrorRoot,
+                              std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+    void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+    void addChildToDrawing(const sp<Layer>&);
+    void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+
+    // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
+    // the settings clears the content with a solid black fill.
+    void prepareClearClientComposition(LayerFE::LayerSettings&, bool blackout) const;
+
+    void prepareBasicGeometryCompositionState();
+    void prepareGeometryCompositionState();
+    void prepareCursorCompositionState();
+
+    uint32_t getEffectiveUsage(uint32_t usage) const;
+
+    /**
+     * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
+     * crop coordinates, transforming them into layer space.
+     */
+    void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
+    void setParent(const sp<Layer>&);
+    LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers);
+    void addZOrderRelative(const wp<Layer>& relative);
+    void removeZOrderRelative(const wp<Layer>& relative);
+    compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
+    bool usingRelativeZ(LayerVector::StateSet) const;
+
     // SyncPoints which will be signaled when the correct frame is at the head
     // of the queue and dropped after the frame has been latched. Protected by
     // mLocalSyncPointMutex.
@@ -914,61 +953,9 @@
     bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
 
     void popPendingState(State* stateToCommit);
-    virtual bool applyPendingStates(State* stateToCommit);
-    virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
 
-    // Returns mCurrentScaling mode (originating from the
-    // Client) or mOverrideScalingMode mode (originating from
-    // the Surface Controller) if set.
-    virtual uint32_t getEffectiveScalingMode() const { return 0; }
-
-public:
-    /*
-     * The layer handle is just a BBinder object passed to the client
-     * (remote process) -- we don't keep any reference on our side such that
-     * the dtor is called when the remote side let go of its reference.
-     *
-     * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
-     * this layer when the handle is destroyed.
-     */
-    class Handle : public BBinder, public LayerCleaner {
-    public:
-        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
-              : LayerCleaner(flinger, layer), owner(layer) {}
-
-        wp<Layer> owner;
-    };
-
-    // Creates a new handle each time, so we only expect
-    // this to be called once.
-    sp<IBinder> getHandle();
-    const std::string& getName() const { return mName; }
-    virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
-    virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
-    bool getPremultipledAlpha() const;
-
-    bool mPendingHWCDestroy{false};
-    void setInputInfo(const InputWindowInfo& info);
-
-    InputWindowInfo fillInputInfo();
-    /**
-     * Returns whether this layer has an explicitly set input-info.
-     */
-    bool hasInputInfo() const;
-    /**
-     * Return whether this layer needs an input info. For most layer types
-     * this is only true if they explicitly set an input-info but BufferLayer
-     * overrides this so we can generate input-info for Buffered layers that don't
-     * have them (for input occlusion detection checks).
-     */
-    virtual bool needsInputInfo() const { return hasInputInfo(); }
-
-    uid_t getOwnerUid() { return mOwnerUid; }
-
-protected:
-    compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
-
-    bool usingRelativeZ(LayerVector::StateSet) const;
+    // constant
+    sp<SurfaceFlinger> mFlinger;
 
     bool mPremultipliedAlpha{true};
     const std::string mName;
@@ -1041,6 +1028,9 @@
 private:
     virtual void setTransformHint(ui::Transform::RotationFlags) {}
 
+    // Returns true if the layer can draw shadows on its border.
+    virtual bool canDrawShadows() const { return true; }
+
     Hwc2::IComposerClient::Composition getCompositionType(const DisplayDevice&) const;
     Region getVisibleRegion(const DisplayDevice*) const;
 
@@ -1059,6 +1049,16 @@
                                           const std::vector<Layer*>& layersInTree);
 
     void updateTreeHasFrameRateVote();
+    void setZOrderRelativeOf(const wp<Layer>& relativeOf);
+    void removeRemoteSyncPoints();
+
+    // Find the root of the cloned hierarchy, this means the first non cloned parent.
+    // This will return null if first non cloned parent is not found.
+    sp<Layer> getClonedRoot();
+
+    // Finds the top most layer in the hierarchy. This will find the root Layer where the parent is
+    // null.
+    sp<Layer> getRootLayer();
 
     // Cached properties computed from drawing state
     // Effective transform taking into account parent transforms and any parent scaling.
@@ -1075,12 +1075,8 @@
     // Layer bounds in screen space.
     FloatRect mScreenBounds;
 
-    void setZOrderRelativeOf(const wp<Layer>& relativeOf);
-
     bool mGetHandleCalled = false;
 
-    void removeRemoteSyncPoints();
-
     // Tracks the process and user id of the caller when creating this layer
     // to help debugging.
     pid_t mCallingPid;
@@ -1100,17 +1096,6 @@
     // final shadow radius for this layer. If a shadow is specified for a layer, then effective
     // shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
     float mEffectiveShadowRadius = 0.f;
-
-    // Returns true if the layer can draw shadows on its border.
-    virtual bool canDrawShadows() const { return true; }
-
-    // Find the root of the cloned hierarchy, this means the first non cloned parent.
-    // This will return null if first non cloned parent is not found.
-    sp<Layer> getClonedRoot();
-
-    // Finds the top most layer in the hierarchy. This will find the root Layer where the parent is
-    // null.
-    sp<Layer> getRootLayer();
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 5d99908..59fad9b 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -146,8 +146,7 @@
 
     proto->set_surface_inset(inputInfo.surfaceInset);
     proto->set_visible(inputInfo.visible);
-    proto->set_can_receive_keys(inputInfo.canReceiveKeys);
-    proto->set_has_focus(inputInfo.hasFocus);
+    proto->set_focusable(inputInfo.focusable);
     proto->set_has_wallpaper(inputInfo.hasWallpaper);
 
     proto->set_global_scale_factor(inputInfo.globalScaleFactor);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 0157a7f..b24855d 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -61,7 +61,7 @@
 
 constexpr auto timeForRegionSampling = 5000000ns;
 constexpr auto maxRegionSamplingSkips = 10;
-constexpr auto defaultRegionSamplingOffset = -3ms;
+constexpr auto defaultRegionSamplingWorkDuration = 3ms;
 constexpr auto defaultRegionSamplingPeriod = 100ms;
 constexpr auto defaultRegionSamplingTimerTimeout = 100ms;
 // TODO: (b/127403193) duration to string conversion could probably be constexpr
@@ -73,9 +73,9 @@
 RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() {
     char value[PROPERTY_VALUE_MAX] = {};
 
-    property_get("debug.sf.region_sampling_offset_ns", value,
-                 toNsString(defaultRegionSamplingOffset).c_str());
-    int const samplingOffsetNsRaw = atoi(value);
+    property_get("debug.sf.region_sampling_duration_ns", value,
+                 toNsString(defaultRegionSamplingWorkDuration).c_str());
+    int const samplingDurationNsRaw = atoi(value);
 
     property_get("debug.sf.region_sampling_period_ns", value,
                  toNsString(defaultRegionSamplingPeriod).c_str());
@@ -87,22 +87,26 @@
 
     if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) {
         ALOGW("User-specified sampling tuning options nonsensical. Using defaults");
-        mSamplingOffset = defaultRegionSamplingOffset;
+        mSamplingDuration = defaultRegionSamplingWorkDuration;
         mSamplingPeriod = defaultRegionSamplingPeriod;
         mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout;
     } else {
-        mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw);
+        mSamplingDuration = std::chrono::nanoseconds(samplingDurationNsRaw);
         mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw);
         mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw);
     }
 }
 
-struct SamplingOffsetCallback : DispSync::Callback {
+struct SamplingOffsetCallback : VSyncSource::Callback {
     SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler,
-                           std::chrono::nanoseconds targetSamplingOffset)
+                           std::chrono::nanoseconds targetSamplingWorkDuration)
           : mRegionSamplingThread(samplingThread),
-            mScheduler(scheduler),
-            mTargetSamplingOffset(targetSamplingOffset) {}
+            mTargetSamplingWorkDuration(targetSamplingWorkDuration),
+            mVSyncSource(scheduler.makePrimaryDispSyncSource("SamplingThreadDispSyncListener", 0ns,
+                                                             0ns,
+                                                             /*traceVsync=*/false)) {
+        mVSyncSource->setCallback(this);
+    }
 
     ~SamplingOffsetCallback() { stopVsyncListener(); }
 
@@ -114,8 +118,7 @@
         if (mVsyncListening) return;
 
         mPhaseIntervalSetting = Phase::ZERO;
-        mScheduler.getPrimaryDispSync().addEventListener("SamplingThreadDispSyncListener", 0, this,
-                                                         mLastCallbackTime);
+        mVSyncSource->setVSyncEnabled(true);
         mVsyncListening = true;
     }
 
@@ -128,23 +131,24 @@
     void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ {
         if (!mVsyncListening) return;
 
-        mScheduler.getPrimaryDispSync().removeEventListener(this, &mLastCallbackTime);
+        mVSyncSource->setVSyncEnabled(false);
         mVsyncListening = false;
     }
 
-    void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) final {
+    void onVSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/,
+                      nsecs_t /*deadlineTimestamp*/) final {
         std::unique_lock<decltype(mMutex)> lock(mMutex);
 
         if (mPhaseIntervalSetting == Phase::ZERO) {
             ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
             mPhaseIntervalSetting = Phase::SAMPLING;
-            mScheduler.getPrimaryDispSync().changePhaseOffset(this, mTargetSamplingOffset.count());
+            mVSyncSource->setDuration(mTargetSamplingWorkDuration, 0ns);
             return;
         }
 
         if (mPhaseIntervalSetting == Phase::SAMPLING) {
             mPhaseIntervalSetting = Phase::ZERO;
-            mScheduler.getPrimaryDispSync().changePhaseOffset(this, 0);
+            mVSyncSource->setDuration(0ns, 0ns);
             stopVsyncListenerLocked();
             lock.unlock();
             mRegionSamplingThread.notifySamplingOffset();
@@ -153,16 +157,15 @@
     }
 
     RegionSamplingThread& mRegionSamplingThread;
-    Scheduler& mScheduler;
-    const std::chrono::nanoseconds mTargetSamplingOffset;
+    const std::chrono::nanoseconds mTargetSamplingWorkDuration;
     mutable std::mutex mMutex;
-    nsecs_t mLastCallbackTime = 0;
     enum class Phase {
         ZERO,
         SAMPLING
     } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/
             = Phase::ZERO;
     bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false;
+    std::unique_ptr<VSyncSource> mVSyncSource;
 };
 
 RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler,
@@ -170,11 +173,12 @@
       : mFlinger(flinger),
         mScheduler(scheduler),
         mTunables(tunables),
-        mIdleTimer(std::chrono::duration_cast<std::chrono::milliseconds>(
-                           mTunables.mSamplingTimerTimeout),
-                   [] {}, [this] { checkForStaleLuma(); }),
+        mIdleTimer(
+                std::chrono::duration_cast<std::chrono::milliseconds>(
+                        mTunables.mSamplingTimerTimeout),
+                [] {}, [this] { checkForStaleLuma(); }),
         mPhaseCallback(std::make_unique<SamplingOffsetCallback>(*this, mScheduler,
-                                                                tunables.mSamplingOffset)),
+                                                                tunables.mSamplingDuration)),
         lastSampleTime(0ns) {
     mThread = std::thread([this]() { threadMain(); });
     pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
@@ -183,7 +187,7 @@
 
 RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler)
       : RegionSamplingThread(flinger, scheduler,
-                             TimingTunables{defaultRegionSamplingOffset,
+                             TimingTunables{defaultRegionSamplingWorkDuration,
                                             defaultRegionSamplingPeriod,
                                             defaultRegionSamplingTimerTimeout}) {}
 
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index b9b7a3c..0defdb3 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -43,10 +43,10 @@
 class RegionSamplingThread : public IBinder::DeathRecipient {
 public:
     struct TimingTunables {
-        // debug.sf.sampling_offset_ns
-        // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline
-        // at which the sampling should start.
-        std::chrono::nanoseconds mSamplingOffset;
+        // debug.sf.sampling_duration_ns
+        // When asynchronously collecting sample, the duration, at which the sampling should start
+        // before a vsync
+        std::chrono::nanoseconds mSamplingDuration;
         // debug.sf.sampling_period_ns
         // This is the maximum amount of time the luma recieving client
         // should have to wait for a new luma value after a frame is updated. The inverse of this is
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
deleted file mode 100644
index 46112f5..0000000
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
-
-// This is needed for stdint.h to define INT64_MAX in C++
-#define __STDC_LIMIT_MACROS
-
-#include <math.h>
-
-#include <algorithm>
-
-#include <android-base/stringprintf.h>
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <utils/Thread.h>
-#include <utils/Trace.h>
-
-#include <ui/FenceTime.h>
-
-#include "DispSync.h"
-#include "EventLog/EventLog.h"
-#include "SurfaceFlinger.h"
-
-using android::base::StringAppendF;
-using std::max;
-using std::min;
-
-namespace android {
-
-DispSync::~DispSync() = default;
-DispSync::Callback::~Callback() = default;
-
-namespace impl {
-
-// Setting this to true adds a zero-phase tracer for correlating with hardware
-// vsync events
-static const bool kEnableZeroPhaseTracer = false;
-
-// This is the threshold used to determine when hardware vsync events are
-// needed to re-synchronize the software vsync model with the hardware.  The
-// error metric used is the mean of the squared difference between each
-// present time and the nearest software-predicted vsync.
-static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
-
-#undef LOG_TAG
-#define LOG_TAG "DispSyncThread"
-class DispSyncThread : public Thread {
-public:
-    DispSyncThread(const char* name, bool showTraceDetailedInfo)
-          : mName(name),
-            mStop(false),
-            mModelLocked("DispSync:ModelLocked", false),
-            mPeriod(0),
-            mPhase(0),
-            mReferenceTime(0),
-            mWakeupLatency(0),
-            mFrameNumber(0),
-            mTraceDetailedInfo(showTraceDetailedInfo) {}
-
-    virtual ~DispSyncThread() {}
-
-    void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        Mutex::Autolock lock(mMutex);
-
-        mPhase = phase;
-        const bool referenceTimeChanged = mReferenceTime != referenceTime;
-        mReferenceTime = referenceTime;
-        if (mPeriod != 0 && mPeriod != period && mReferenceTime != 0) {
-            // Inflate the reference time to be the most recent predicted
-            // vsync before the current time.
-            const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-            const nsecs_t baseTime = now - mReferenceTime;
-            const nsecs_t numOldPeriods = baseTime / mPeriod;
-            mReferenceTime = mReferenceTime + (numOldPeriods)*mPeriod;
-        }
-        mPeriod = period;
-        if (!mModelLocked && referenceTimeChanged) {
-            for (auto& eventListener : mEventListeners) {
-                eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase;
-                // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets
-                // are used) we treat it as like it happened in previous period.
-                if (eventListener.mLastEventTime > mReferenceTime) {
-                    eventListener.mLastEventTime -= mPeriod;
-                }
-            }
-        }
-        if (mTraceDetailedInfo) {
-            ATRACE_INT64("DispSync:Period", mPeriod);
-            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
-            ATRACE_INT64("DispSync:Reference Time", mReferenceTime);
-        }
-        ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
-              " mReferenceTime = %" PRId64,
-              mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
-        mCond.signal();
-    }
-
-    void stop() {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        Mutex::Autolock lock(mMutex);
-        mStop = true;
-        mCond.signal();
-    }
-
-    void lockModel() {
-        Mutex::Autolock lock(mMutex);
-        mModelLocked = true;
-    }
-
-    void unlockModel() {
-        Mutex::Autolock lock(mMutex);
-        mModelLocked = false;
-    }
-
-    virtual bool threadLoop() {
-        status_t err;
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-
-        while (true) {
-            std::vector<CallbackInvocation> callbackInvocations;
-
-            nsecs_t targetTime = 0;
-
-            { // Scope for lock
-                Mutex::Autolock lock(mMutex);
-
-                if (mTraceDetailedInfo) {
-                    ATRACE_INT64("DispSync:Frame", mFrameNumber);
-                }
-                ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber);
-                ++mFrameNumber;
-
-                if (mStop) {
-                    return false;
-                }
-
-                if (mPeriod == 0) {
-                    err = mCond.wait(mMutex);
-                    if (err != NO_ERROR) {
-                        ALOGE("error waiting for new events: %s (%d)", strerror(-err), err);
-                        return false;
-                    }
-                    continue;
-                }
-
-                targetTime = computeNextEventTimeLocked(now);
-
-                bool isWakeup = false;
-
-                if (now < targetTime) {
-                    if (mTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
-
-                    if (targetTime == INT64_MAX) {
-                        ALOGV("[%s] Waiting forever", mName);
-                        err = mCond.wait(mMutex);
-                    } else {
-                        ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime));
-                        err = mCond.waitRelative(mMutex, targetTime - now);
-                    }
-
-                    if (err == TIMED_OUT) {
-                        isWakeup = true;
-                    } else if (err != NO_ERROR) {
-                        ALOGE("error waiting for next event: %s (%d)", strerror(-err), err);
-                        return false;
-                    }
-                }
-
-                now = systemTime(SYSTEM_TIME_MONOTONIC);
-
-                // Don't correct by more than 1.5 ms
-                static const nsecs_t kMaxWakeupLatency = us2ns(1500);
-
-                if (isWakeup) {
-                    mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
-                    mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
-                    if (mTraceDetailedInfo) {
-                        ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
-                        ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
-                    }
-                }
-
-                callbackInvocations =
-                        gatherCallbackInvocationsLocked(now, computeNextRefreshLocked(0, now));
-            }
-
-            if (callbackInvocations.size() > 0) {
-                fireCallbackInvocations(callbackInvocations);
-            }
-        }
-
-        return false;
-    }
-
-    status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
-                              nsecs_t lastCallbackTime) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        Mutex::Autolock lock(mMutex);
-
-        for (size_t i = 0; i < mEventListeners.size(); i++) {
-            if (mEventListeners[i].mCallback == callback) {
-                return BAD_VALUE;
-            }
-        }
-
-        EventListener listener;
-        listener.mName = name;
-        listener.mPhase = phase;
-        listener.mCallback = callback;
-
-        // We want to allow the firstmost future event to fire without
-        // allowing any past events to fire. To do this extrapolate from
-        // mReferenceTime the most recent hardware vsync, and pin the
-        // last event time there.
-        const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-        if (mPeriod != 0) {
-            const nsecs_t baseTime = now - mReferenceTime;
-            const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
-            const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
-            const nsecs_t phaseCorrection = mPhase + listener.mPhase;
-            const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
-            if (predictedLastEventTime >= now) {
-                // Make sure that the last event time does not exceed the current time.
-                // If it would, then back the last event time by a period.
-                listener.mLastEventTime = predictedLastEventTime - mPeriod;
-            } else {
-                listener.mLastEventTime = predictedLastEventTime;
-            }
-        } else {
-            listener.mLastEventTime = now + mPhase - mWakeupLatency;
-        }
-
-        if (lastCallbackTime <= 0) {
-            // If there is no prior callback time, try to infer one based on the
-            // logical last event time.
-            listener.mLastCallbackTime = listener.mLastEventTime + mWakeupLatency;
-        } else {
-            listener.mLastCallbackTime = lastCallbackTime;
-        }
-
-        mEventListeners.push_back(listener);
-
-        mCond.signal();
-
-        return NO_ERROR;
-    }
-
-    status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        Mutex::Autolock lock(mMutex);
-
-        for (std::vector<EventListener>::iterator it = mEventListeners.begin();
-             it != mEventListeners.end(); ++it) {
-            if (it->mCallback == callback) {
-                *outLastCallback = it->mLastCallbackTime;
-                mEventListeners.erase(it);
-                mCond.signal();
-                return NO_ERROR;
-            }
-        }
-
-        return BAD_VALUE;
-    }
-
-    status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        Mutex::Autolock lock(mMutex);
-
-        for (auto& eventListener : mEventListeners) {
-            if (eventListener.mCallback == callback) {
-                const nsecs_t oldPhase = eventListener.mPhase;
-                eventListener.mPhase = phase;
-
-                // Pretend that the last time this event was handled at the same frame but with the
-                // new offset to allow for a seamless offset change without double-firing or
-                // skipping.
-                nsecs_t diff = oldPhase - phase;
-                eventListener.mLastEventTime -= diff;
-                eventListener.mLastCallbackTime -= diff;
-                mCond.signal();
-                return NO_ERROR;
-            }
-        }
-        return BAD_VALUE;
-    }
-
-    nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const {
-        Mutex::Autolock lock(mMutex);
-        return computeNextRefreshLocked(periodOffset, now);
-    }
-
-private:
-    struct EventListener {
-        const char* mName;
-        nsecs_t mPhase;
-        nsecs_t mLastEventTime;
-        nsecs_t mLastCallbackTime;
-        DispSync::Callback* mCallback;
-    };
-
-    struct CallbackInvocation {
-        DispSync::Callback* mCallback;
-        nsecs_t mEventTime;
-        nsecs_t mExpectedVSyncTime;
-    };
-
-    nsecs_t computeNextEventTimeLocked(nsecs_t now) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] computeNextEventTimeLocked", mName);
-        nsecs_t nextEventTime = INT64_MAX;
-        for (size_t i = 0; i < mEventListeners.size(); i++) {
-            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now);
-
-            if (t < nextEventTime) {
-                nextEventTime = t;
-            }
-        }
-
-        ALOGV("[%s] nextEventTime = %" PRId64, mName, ns2us(nextEventTime));
-        return nextEventTime;
-    }
-
-    // Check that the duration is close enough in length to a period without
-    // falling into double-rate vsyncs.
-    bool isCloseToPeriod(nsecs_t duration) {
-        // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
-        return duration < (3 * mPeriod) / 5;
-    }
-
-    std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now,
-                                                                    nsecs_t expectedVSyncTime) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
-
-        std::vector<CallbackInvocation> callbackInvocations;
-        nsecs_t onePeriodAgo = now - mPeriod;
-
-        for (auto& eventListener : mEventListeners) {
-            nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
-
-            if (t < now) {
-                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
-                    eventListener.mLastEventTime = t;
-                    ALOGV("[%s] [%s] Skipping event due to model error", mName,
-                          eventListener.mName);
-                    continue;
-                }
-
-                CallbackInvocation ci;
-                ci.mCallback = eventListener.mCallback;
-                ci.mEventTime = t;
-                ci.mExpectedVSyncTime = expectedVSyncTime;
-                if (eventListener.mPhase < 0) {
-                    ci.mExpectedVSyncTime += mPeriod;
-                }
-                ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName,
-                      t - eventListener.mLastEventTime);
-                callbackInvocations.push_back(ci);
-                eventListener.mLastEventTime = t;
-                eventListener.mLastCallbackTime = now;
-            }
-        }
-
-        return callbackInvocations;
-    }
-
-    nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
-              ns2us(baseTime));
-
-        nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
-        ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
-        if (baseTime < lastEventTime) {
-            baseTime = lastEventTime;
-            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime));
-        }
-
-        baseTime -= mReferenceTime;
-        ALOGV("[%s] Relative baseTime = %" PRId64, mName, ns2us(baseTime));
-        nsecs_t phase = mPhase + listener.mPhase;
-        ALOGV("[%s] Phase = %" PRId64, mName, ns2us(phase));
-        baseTime -= phase;
-        ALOGV("[%s] baseTime - phase = %" PRId64, mName, ns2us(baseTime));
-
-        // If our previous time is before the reference (because the reference
-        // has since been updated), the division by mPeriod will truncate
-        // towards zero instead of computing the floor. Since in all cases
-        // before the reference we want the next time to be effectively now, we
-        // set baseTime to -mPeriod so that numPeriods will be -1.
-        // When we add 1 and the phase, we will be at the correct event time for
-        // this period.
-        if (baseTime < 0) {
-            ALOGV("[%s] Correcting negative baseTime", mName);
-            baseTime = -mPeriod;
-        }
-
-        nsecs_t numPeriods = baseTime / mPeriod;
-        ALOGV("[%s] numPeriods = %" PRId64, mName, numPeriods);
-        nsecs_t t = (numPeriods + 1) * mPeriod + phase;
-        ALOGV("[%s] t = %" PRId64, mName, ns2us(t));
-        t += mReferenceTime;
-        ALOGV("[%s] Absolute t = %" PRId64, mName, ns2us(t));
-
-        // Check that it's been slightly more than half a period since the last
-        // event so that we don't accidentally fall into double-rate vsyncs
-        if (isCloseToPeriod(t - listener.mLastEventTime)) {
-            t += mPeriod;
-            ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
-        }
-
-        t -= mWakeupLatency;
-        ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t));
-
-        return t;
-    }
-
-    void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
-        if (mTraceDetailedInfo) ATRACE_CALL();
-        for (size_t i = 0; i < callbacks.size(); i++) {
-            callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime,
-                                                    callbacks[i].mExpectedVSyncTime);
-        }
-    }
-
-    nsecs_t computeNextRefreshLocked(int periodOffset, nsecs_t now) const {
-        nsecs_t phase = mReferenceTime + mPhase;
-        if (mPeriod == 0) {
-            return 0;
-        }
-        return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
-    }
-
-    const char* const mName;
-
-    bool mStop;
-    TracedOrdinal<bool> mModelLocked;
-
-    nsecs_t mPeriod;
-    nsecs_t mPhase;
-    nsecs_t mReferenceTime;
-    nsecs_t mWakeupLatency;
-
-    int64_t mFrameNumber;
-
-    std::vector<EventListener> mEventListeners;
-
-    mutable Mutex mMutex;
-    Condition mCond;
-
-    // Flag to turn on logging in systrace.
-    const bool mTraceDetailedInfo;
-};
-
-#undef LOG_TAG
-#define LOG_TAG "DispSync"
-
-class ZeroPhaseTracer : public DispSync::Callback {
-public:
-    ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {}
-
-    virtual void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) {
-        mParity = !mParity;
-    }
-
-private:
-    TracedOrdinal<bool> mParity;
-};
-
-DispSync::DispSync(const char* name, bool hasSyncFramework)
-      : mName(name), mIgnorePresentFences(!hasSyncFramework) {
-    // This flag offers the ability to turn on systrace logging from the shell.
-    char value[PROPERTY_VALUE_MAX];
-    property_get("debug.sf.dispsync_trace_detailed_info", value, "0");
-    mTraceDetailedInfo = atoi(value);
-
-    mThread = new DispSyncThread(name, mTraceDetailedInfo);
-    mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-
-    // set DispSync to SCHED_FIFO to minimize jitter
-    struct sched_param param = {0};
-    param.sched_priority = 2;
-    if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
-    }
-
-    beginResync();
-
-    if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
-        mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
-        addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get(), 0);
-    }
-}
-
-DispSync::~DispSync() {
-    mThread->stop();
-    mThread->requestExitAndWait();
-}
-
-void DispSync::reset() {
-    Mutex::Autolock lock(mMutex);
-    resetLocked();
-}
-
-void DispSync::resetLocked() {
-    mPhase = 0;
-    const size_t lastSampleIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES;
-    // Keep the most recent sample, when we resync to hardware we'll overwrite this
-    // with a more accurate signal
-    if (mResyncSamples[lastSampleIdx] != 0) {
-        mReferenceTime = mResyncSamples[lastSampleIdx];
-    }
-    mModelUpdated = false;
-    for (size_t i = 0; i < MAX_RESYNC_SAMPLES; i++) {
-        mResyncSamples[i] = 0;
-    }
-    mNumResyncSamples = 0;
-    mFirstResyncSample = 0;
-    mNumResyncSamplesSincePresent = 0;
-    mThread->unlockModel();
-    resetErrorLocked();
-}
-
-bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
-    Mutex::Autolock lock(mMutex);
-
-    if (mIgnorePresentFences) {
-        return true;
-    }
-
-    mPresentFences[mPresentSampleOffset] = fenceTime;
-    mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
-    mNumResyncSamplesSincePresent = 0;
-
-    updateErrorLocked();
-
-    return !mModelUpdated || mError > kErrorThreshold;
-}
-
-void DispSync::beginResync() {
-    Mutex::Autolock lock(mMutex);
-    ALOGV("[%s] beginResync", mName);
-    resetLocked();
-}
-
-bool DispSync::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> /*hwcVsyncPeriod*/,
-                               bool* periodFlushed) {
-    Mutex::Autolock lock(mMutex);
-
-    ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
-
-    *periodFlushed = false;
-    const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
-    mResyncSamples[idx] = timestamp;
-    if (mNumResyncSamples == 0) {
-        mPhase = 0;
-        ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
-              "mReferenceTime = %" PRId64,
-              mName, ns2us(mPeriod), ns2us(timestamp));
-    } else if (mPendingPeriod > 0) {
-        // mNumResyncSamples > 0, so priorIdx won't overflow
-        const size_t priorIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES;
-        const nsecs_t lastTimestamp = mResyncSamples[priorIdx];
-
-        const nsecs_t observedVsync = std::abs(timestamp - lastTimestamp);
-        if (std::abs(observedVsync - mPendingPeriod) <= std::abs(observedVsync - mIntendedPeriod)) {
-            // Either the observed vsync is closer to the pending period, (and
-            // thus we detected a period change), or the period change will
-            // no-op. In either case, reset the model and flush the pending
-            // period.
-            resetLocked();
-            mIntendedPeriod = mPendingPeriod;
-            mPeriod = mPendingPeriod;
-            mPendingPeriod = 0;
-            if (mTraceDetailedInfo) {
-                ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
-                ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
-            }
-            *periodFlushed = true;
-        }
-    }
-    // Always update the reference time with the most recent timestamp.
-    mReferenceTime = timestamp;
-    mThread->updateModel(mPeriod, mPhase, mReferenceTime);
-
-    if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
-        mNumResyncSamples++;
-    } else {
-        mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
-    }
-
-    updateModelLocked();
-
-    if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {
-        resetErrorLocked();
-    }
-
-    if (mIgnorePresentFences) {
-        // If we're ignoring the present fences we have no way to know whether
-        // or not we're synchronized with the HW vsyncs, so we just request
-        // that the HW vsync events be turned on.
-        return true;
-    }
-
-    // Check against kErrorThreshold / 2 to add some hysteresis before having to
-    // resync again
-    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0;
-    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
-    if (modelLocked) {
-        *periodFlushed = true;
-        mThread->lockModel();
-    }
-    return !modelLocked;
-}
-
-void DispSync::endResync() {
-    mThread->lockModel();
-}
-
-status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback,
-                                    nsecs_t lastCallbackTime) {
-    Mutex::Autolock lock(mMutex);
-    return mThread->addEventListener(name, phase, callback, lastCallbackTime);
-}
-
-status_t DispSync::removeEventListener(Callback* callback, nsecs_t* outLastCallbackTime) {
-    Mutex::Autolock lock(mMutex);
-    return mThread->removeEventListener(callback, outLastCallbackTime);
-}
-
-status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
-    Mutex::Autolock lock(mMutex);
-    return mThread->changePhaseOffset(callback, phase);
-}
-
-void DispSync::setPeriod(nsecs_t period) {
-    Mutex::Autolock lock(mMutex);
-
-    const bool pendingPeriodShouldChange =
-            period != mIntendedPeriod || (period == mIntendedPeriod && mPendingPeriod != 0);
-
-    if (pendingPeriodShouldChange) {
-        mPendingPeriod = period;
-    }
-    if (mTraceDetailedInfo) {
-        ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
-        ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
-    }
-}
-
-nsecs_t DispSync::getPeriod() {
-    // lock mutex as mPeriod changes multiple times in updateModelLocked
-    Mutex::Autolock lock(mMutex);
-    return mPeriod;
-}
-
-void DispSync::updateModelLocked() {
-    ALOGV("[%s] updateModelLocked %zu", mName, mNumResyncSamples);
-    if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
-        ALOGV("[%s] Computing...", mName);
-        nsecs_t durationSum = 0;
-        nsecs_t minDuration = INT64_MAX;
-        nsecs_t maxDuration = 0;
-        // We skip the first 2 samples because the first vsync duration on some
-        // devices may be much more inaccurate than on other devices, e.g. due
-        // to delays in ramping up from a power collapse. By doing so this
-        // actually increases the accuracy of the DispSync model even though
-        // we're effectively relying on fewer sample points.
-        static constexpr size_t numSamplesSkipped = 2;
-        for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
-            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
-            size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
-            nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
-            durationSum += duration;
-            minDuration = min(minDuration, duration);
-            maxDuration = max(maxDuration, duration);
-        }
-
-        // Exclude the min and max from the average
-        durationSum -= minDuration + maxDuration;
-        mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2);
-
-        ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
-
-        double sampleAvgX = 0;
-        double sampleAvgY = 0;
-        double scale = 2.0 * M_PI / double(mPeriod);
-        for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
-            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
-            nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
-            double samplePhase = double(sample % mPeriod) * scale;
-            sampleAvgX += cos(samplePhase);
-            sampleAvgY += sin(samplePhase);
-        }
-
-        sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped);
-        sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped);
-
-        mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
-
-        ALOGV("[%s] mPhase = %" PRId64, mName, ns2us(mPhase));
-
-        if (mPhase < -(mPeriod / 2)) {
-            mPhase += mPeriod;
-            ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
-        }
-
-        mThread->updateModel(mPeriod, mPhase, mReferenceTime);
-        mModelUpdated = true;
-    }
-}
-
-void DispSync::updateErrorLocked() {
-    if (!mModelUpdated) {
-        return;
-    }
-
-    int numErrSamples = 0;
-    nsecs_t sqErrSum = 0;
-
-    for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        // Only check for the cached value of signal time to avoid unecessary
-        // syscalls. It is the responsibility of the DispSync owner to
-        // call getSignalTime() periodically so the cache is updated when the
-        // fence signals.
-        nsecs_t time = mPresentFences[i]->getCachedSignalTime();
-        if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) {
-            continue;
-        }
-
-        nsecs_t sample = time - mReferenceTime;
-        if (sample <= mPhase) {
-            continue;
-        }
-
-        nsecs_t sampleErr = (sample - mPhase) % mPeriod;
-        if (sampleErr > mPeriod / 2) {
-            sampleErr -= mPeriod;
-        }
-        sqErrSum += sampleErr * sampleErr;
-        numErrSamples++;
-    }
-
-    if (numErrSamples > 0) {
-        mError = sqErrSum / numErrSamples;
-        mZeroErrSamplesCount = 0;
-    } else {
-        mError = 0;
-        // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
-        mZeroErrSamplesCount++;
-        ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
-                 "No present times for model error.");
-    }
-
-    if (mTraceDetailedInfo) {
-        ATRACE_INT64("DispSync:Error", mError);
-    }
-}
-
-void DispSync::resetErrorLocked() {
-    mPresentSampleOffset = 0;
-    mError = 0;
-    mZeroErrSamplesCount = 0;
-    if (mTraceDetailedInfo) {
-        ATRACE_INT64("DispSync:Error", mError);
-    }
-    for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        mPresentFences[i] = FenceTime::NO_FENCE;
-    }
-}
-
-nsecs_t DispSync::computeNextRefresh(int periodOffset, nsecs_t now) const {
-    Mutex::Autolock lock(mMutex);
-    nsecs_t phase = mReferenceTime + mPhase;
-    if (mPeriod == 0) {
-        return 0;
-    }
-    return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
-}
-
-void DispSync::setIgnorePresentFences(bool ignore) {
-    Mutex::Autolock lock(mMutex);
-    if (mIgnorePresentFences != ignore) {
-        mIgnorePresentFences = ignore;
-        resetLocked();
-    }
-}
-
-void DispSync::dump(std::string& result) const {
-    Mutex::Autolock lock(mMutex);
-    StringAppendF(&result, "present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
-    StringAppendF(&result, "mPeriod: %" PRId64 " ns (%.3f fps)\n", mPeriod, 1000000000.0 / mPeriod);
-    StringAppendF(&result, "mPhase: %" PRId64 " ns\n", mPhase);
-    StringAppendF(&result, "mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
-    StringAppendF(&result, "mNumResyncSamplesSincePresent: %d (limit %d)\n",
-                  mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
-    StringAppendF(&result, "mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples,
-                  MAX_RESYNC_SAMPLES);
-
-    result.append("mResyncSamples:\n");
-    nsecs_t previous = -1;
-    for (size_t i = 0; i < mNumResyncSamples; i++) {
-        size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
-        nsecs_t sampleTime = mResyncSamples[idx];
-        if (i == 0) {
-            StringAppendF(&result, "  %" PRId64 "\n", sampleTime);
-        } else {
-            StringAppendF(&result, "  %" PRId64 " (+%" PRId64 ")\n", sampleTime,
-                          sampleTime - previous);
-        }
-        previous = sampleTime;
-    }
-
-    StringAppendF(&result, "mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    previous = Fence::SIGNAL_TIME_INVALID;
-    for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
-        nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
-        if (presentTime == Fence::SIGNAL_TIME_PENDING) {
-            StringAppendF(&result, "  [unsignaled fence]\n");
-        } else if (presentTime == Fence::SIGNAL_TIME_INVALID) {
-            StringAppendF(&result, "  [invalid fence]\n");
-        } else if (previous == Fence::SIGNAL_TIME_PENDING ||
-                   previous == Fence::SIGNAL_TIME_INVALID) {
-            StringAppendF(&result, "  %" PRId64 "  (%.3f ms ago)\n", presentTime,
-                          (now - presentTime) / 1000000.0);
-        } else {
-            StringAppendF(&result, "  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n",
-                          presentTime, presentTime - previous,
-                          (presentTime - previous) / (double)mPeriod,
-                          (now - presentTime) / 1000000.0);
-        }
-        previous = presentTime;
-    }
-
-    StringAppendF(&result, "current monotonic time: %" PRId64 "\n", now);
-}
-
-nsecs_t DispSync::expectedPresentTime(nsecs_t now) {
-    // The HWC doesn't currently have a way to report additional latency.
-    // Assume that whatever we submit now will appear right after the flip.
-    // For a smart panel this might be 1.  This is expressed in frames,
-    // rather than time, because we expect to have a constant frame delay
-    // regardless of the refresh rate.
-    const uint32_t hwcLatency = 0;
-
-    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
-    return mThread->computeNextRefresh(hwcLatency, now);
-}
-
-} // namespace impl
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 6fb5654..f34aabc 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -32,32 +32,15 @@
 
 class DispSync {
 public:
-    class Callback {
-    public:
-        Callback() = default;
-        virtual ~Callback();
-        virtual void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0;
-
-    protected:
-        Callback(Callback const&) = delete;
-        Callback& operator=(Callback const&) = delete;
-    };
-
     DispSync() = default;
-    virtual ~DispSync();
+    virtual ~DispSync() = default;
 
-    virtual void reset() = 0;
     virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
     virtual void beginResync() = 0;
     virtual bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                                  bool* periodFlushed) = 0;
-    virtual void endResync() = 0;
     virtual void setPeriod(nsecs_t period) = 0;
     virtual nsecs_t getPeriod() = 0;
-    virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
-                                      nsecs_t lastCallbackTime) = 0;
-    virtual status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) = 0;
-    virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
     virtual nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const = 0;
     virtual void setIgnorePresentFences(bool ignore) = 0;
     virtual nsecs_t expectedPresentTime(nsecs_t now) = 0;
@@ -69,199 +52,4 @@
     DispSync& operator=(DispSync const&) = delete;
 };
 
-namespace impl {
-
-class DispSyncThread;
-
-// DispSync maintains a model of the periodic hardware-based vsync events of a
-// display and uses that model to execute period callbacks at specific phase
-// offsets from the hardware vsync events.  The model is constructed by
-// feeding consecutive hardware event timestamps to the DispSync object via
-// the addResyncSample method.
-//
-// The model is validated using timestamps from Fence objects that are passed
-// to the DispSync object via the addPresentFence method.  These fence
-// timestamps should correspond to a hardware vsync event, but they need not
-// be consecutive hardware vsync times.  If this method determines that the
-// current model accurately represents the hardware event times it will return
-// false to indicate that a resynchronization (via addResyncSample) is not
-// needed.
-class DispSync : public android::DispSync {
-public:
-    // hasSyncFramework specifies whether the platform supports present fences.
-    DispSync(const char* name, bool hasSyncFramework);
-    ~DispSync() override;
-
-    // reset clears the resync samples and error value.
-    void reset() override;
-
-    // addPresentFence adds a fence for use in validating the current vsync
-    // event model.  The fence need not be signaled at the time
-    // addPresentFence is called.  When the fence does signal, its timestamp
-    // should correspond to a hardware vsync event.  Unlike the
-    // addResyncSample method, the timestamps of consecutive fences need not
-    // correspond to consecutive hardware vsync events.
-    //
-    // This method should be called with the retire fence from each HWComposer
-    // set call that affects the display.
-    bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) override;
-
-    // The beginResync, addResyncSample, and endResync methods are used to re-
-    // synchronize the DispSync's model to the hardware vsync events.  The re-
-    // synchronization process involves first calling beginResync, then
-    // calling addResyncSample with a sequence of consecutive hardware vsync
-    // event timestamps, and finally calling endResync when addResyncSample
-    // indicates that no more samples are needed by returning false.
-    //
-    // This resynchronization process should be performed whenever the display
-    // is turned on (i.e. once immediately after it's turned on) and whenever
-    // addPresentFence returns true indicating that the model has drifted away
-    // from the hardware vsync events.
-    void beginResync() override;
-    // Adds a vsync sample to the dispsync model. The timestamp is the time
-    // of the vsync event that fired. periodFlushed will return true if the
-    // vsync period was detected to have changed to mPendingPeriod.
-    //
-    // This method will return true if more vsync samples are needed to lock
-    // down the DispSync model, and false otherwise.
-    // periodFlushed will be set to true if mPendingPeriod is flushed to
-    // mIntendedPeriod, and false otherwise.
-    bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
-                         bool* periodFlushed) override;
-    void endResync() override;
-
-    // The setPeriod method sets the vsync event model's period to a specific
-    // value. This should be used to prime the model when a display is first
-    // turned on, or when a refresh rate change is requested.
-    void setPeriod(nsecs_t period) override;
-
-    // The getPeriod method returns the current vsync period.
-    nsecs_t getPeriod() override;
-
-    // addEventListener registers a callback to be called repeatedly at the
-    // given phase offset from the hardware vsync events.  The callback is
-    // called from a separate thread and it should return reasonably quickly
-    // (i.e. within a few hundred microseconds).
-    // If the callback was previously registered, and the last clock time the
-    // callback was invoked was known to the caller (e.g. via removeEventListener),
-    // then the caller may pass that through to lastCallbackTime, so that
-    // callbacks do not accidentally double-fire if they are unregistered and
-    // reregistered in rapid succession.
-    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
-                              nsecs_t lastCallbackTime) override;
-
-    // removeEventListener removes an already-registered event callback.  Once
-    // this method returns that callback will no longer be called by the
-    // DispSync object.
-    // outLastCallbackTime will contain the last time that the callback was invoked.
-    // If the caller wishes to reregister the same callback, they should pass the
-    // callback time back into lastCallbackTime (see addEventListener).
-    status_t removeEventListener(Callback* callback, nsecs_t* outLastCallbackTime) override;
-
-    // changePhaseOffset changes the phase offset of an already-registered event callback. The
-    // method will make sure that there is no skipping or double-firing on the listener per frame,
-    // even when changing the offsets multiple times.
-    status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;
-
-    // computeNextRefresh computes when the next refresh is expected to begin.
-    // The periodOffset value can be used to move forward or backward; an
-    // offset of zero is the next refresh, -1 is the previous refresh, 1 is
-    // the refresh after next. etc.
-    nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const override;
-
-    // In certain situations the present fences aren't a good indicator of vsync
-    // time, e.g. when vr flinger is active, or simply aren't available,
-    // e.g. when the sync framework isn't present. Use this method to toggle
-    // whether or not DispSync ignores present fences. If present fences are
-    // ignored, DispSync will always ask for hardware vsync events by returning
-    // true from addPresentFence() and addResyncSample().
-    void setIgnorePresentFences(bool ignore) override;
-
-    // Determine the expected present time when a buffer acquired now will be displayed.
-    nsecs_t expectedPresentTime(nsecs_t now);
-
-    // dump appends human-readable debug info to the result string.
-    void dump(std::string& result) const override;
-
-private:
-    void updateModelLocked();
-    void updateErrorLocked();
-    void resetLocked();
-    void resetErrorLocked();
-
-    enum { MAX_RESYNC_SAMPLES = 32 };
-    enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
-    enum { NUM_PRESENT_SAMPLES = 8 };
-    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
-    enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 };
-
-    const char* const mName;
-
-    // mPeriod is the computed period of the modeled vsync events in
-    // nanoseconds.
-    nsecs_t mPeriod;
-
-    // mIntendedPeriod is the intended period of the modeled vsync events in
-    // nanoseconds. Under ideal conditions this should be similar if not the
-    // same as mPeriod, plus or minus an observed error.
-    nsecs_t mIntendedPeriod = 0;
-
-    // mPendingPeriod is the proposed period change in nanoseconds.
-    // If mPendingPeriod differs from mPeriod and is nonzero, it will
-    // be flushed to mPeriod when we detect that the hardware switched
-    // vsync frequency.
-    nsecs_t mPendingPeriod = 0;
-
-    // mPhase is the phase offset of the modeled vsync events.  It is the
-    // number of nanoseconds from time 0 to the first vsync event.
-    nsecs_t mPhase;
-
-    // mReferenceTime is the reference time of the modeled vsync events.
-    // It is the nanosecond timestamp of the first vsync event after a resync.
-    nsecs_t mReferenceTime;
-
-    // mError is the computed model error.  It is based on the difference
-    // between the estimated vsync event times and those observed in the
-    // mPresentFences array.
-    nsecs_t mError;
-
-    // mZeroErrSamplesCount keeps track of how many times in a row there were
-    // zero timestamps available in the mPresentFences array.
-    // Used to check that we are able to calculate the model error.
-    size_t mZeroErrSamplesCount;
-
-    // Whether we have updated the vsync event model since the last resync.
-    bool mModelUpdated;
-
-    // These member variables are the state used during the resynchronization
-    // process to store information about the hardware vsync event times used
-    // to compute the model.
-    nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0};
-    size_t mFirstResyncSample = 0;
-    size_t mNumResyncSamples = 0;
-    int mNumResyncSamplesSincePresent;
-
-    // These member variables store information about the present fences used
-    // to validate the currently computed model.
-    std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE};
-    size_t mPresentSampleOffset;
-
-    // mThread is the thread from which all the callbacks are called.
-    sp<DispSyncThread> mThread;
-
-    // mMutex is used to protect access to all member variables.
-    mutable Mutex mMutex;
-
-    // Ignore present (retire) fences if the device doesn't have support for the
-    // sync framework
-    bool mIgnorePresentFences;
-
-    std::unique_ptr<Callback> mZeroPhaseTracer;
-
-    // Flag to turn on logging in systrace.
-    bool mTraceDetailedInfo = false;
-};
-
-} // namespace impl
-
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 8752b66..75f072d 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "DispSyncSource.h"
@@ -29,34 +25,129 @@
 #include "DispSync.h"
 #include "EventThread.h"
 
-namespace android {
+namespace android::scheduler {
 using base::StringAppendF;
+using namespace std::chrono_literals;
 
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
+// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
+// for now.
+class CallbackRepeater {
+public:
+    CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
+                     std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
+                     std::chrono::nanoseconds notBefore)
+          : mName(name),
+            mCallback(cb),
+            mRegistration(dispatch,
+                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
+                                    std::placeholders::_2, std::placeholders::_3),
+                          mName),
+            mStarted(false),
+            mWorkDuration(workDuration),
+            mReadyDuration(readyDuration),
+            mLastCallTime(notBefore) {}
+
+    ~CallbackRepeater() {
+        std::lock_guard lock(mMutex);
+        mRegistration.cancel();
+    }
+
+    void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
+        std::lock_guard lock(mMutex);
+        mStarted = true;
+        mWorkDuration = workDuration;
+        mReadyDuration = readyDuration;
+
+        auto const scheduleResult =
+                mRegistration.schedule({.workDuration = mWorkDuration.count(),
+                                        .readyDuration = mReadyDuration.count(),
+                                        .earliestVsync = mLastCallTime.count()});
+        LOG_ALWAYS_FATAL_IF((scheduleResult != scheduler::ScheduleResult::Scheduled),
+                            "Error scheduling callback: rc %X", scheduleResult);
+    }
+
+    void stop() {
+        std::lock_guard lock(mMutex);
+        LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
+        mStarted = false;
+        mRegistration.cancel();
+    }
+
+    void dump(std::string& result) const {
+        std::lock_guard lock(mMutex);
+        const auto relativeLastCallTime =
+                mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
+        StringAppendF(&result, "\t%s: ", mName.c_str());
+        StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
+                      mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
+        StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
+                      mStarted ? "running" : "stopped");
+    }
+
+private:
+    void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
+        {
+            std::lock_guard lock(mMutex);
+            mLastCallTime = std::chrono::nanoseconds(vsyncTime);
+        }
+
+        mCallback(vsyncTime, wakeupTime, readyTime);
+
+        {
+            std::lock_guard lock(mMutex);
+            if (!mStarted) {
+                return;
+            }
+            auto const scheduleResult =
+                    mRegistration.schedule({.workDuration = mWorkDuration.count(),
+                                            .readyDuration = mReadyDuration.count(),
+                                            .earliestVsync = vsyncTime});
+            LOG_ALWAYS_FATAL_IF((scheduleResult != ScheduleResult::Scheduled),
+                                "Error rescheduling callback: rc %X", scheduleResult);
+        }
+    }
+
+    const std::string mName;
+    scheduler::VSyncDispatch::Callback mCallback;
+
+    mutable std::mutex mMutex;
+    VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
+    bool mStarted GUARDED_BY(mMutex) = false;
+    std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
+    std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
+    std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
+};
+
+DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
+                               std::chrono::nanoseconds workDuration,
+                               std::chrono::nanoseconds readyDuration, bool traceVsync,
                                const char* name)
       : mName(name),
         mValue(base::StringPrintf("VSYNC-%s", name), 0),
         mTraceVsync(traceVsync),
         mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
-        mDispSync(dispSync),
-        mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {}
+        mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
+        mReadyDuration(readyDuration) {
+    mCallbackRepeater =
+            std::make_unique<CallbackRepeater>(vSyncDispatch,
+                                               std::bind(&DispSyncSource::onVsyncCallback, this,
+                                                         std::placeholders::_1,
+                                                         std::placeholders::_2,
+                                                         std::placeholders::_3),
+                                               name, workDuration, readyDuration,
+                                               std::chrono::steady_clock::now().time_since_epoch());
+}
+
+DispSyncSource::~DispSyncSource() = default;
 
 void DispSyncSource::setVSyncEnabled(bool enable) {
     std::lock_guard lock(mVsyncMutex);
     if (enable) {
-        status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
-                                                   static_cast<DispSync::Callback*>(this),
-                                                   mLastCallbackTime);
-        if (err != NO_ERROR) {
-            ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
-        }
+        mCallbackRepeater->start(mWorkDuration, mReadyDuration);
         // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
     } else {
-        status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this),
-                                                      &mLastCallbackTime);
-        if (err != NO_ERROR) {
-            ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err);
-        }
+        mCallbackRepeater->stop();
         // ATRACE_INT(mVsyncOnLabel.c_str(), 0);
     }
     mEnabled = enable;
@@ -67,32 +158,22 @@
     mCallback = callback;
 }
 
-void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
+void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
+                                 std::chrono::nanoseconds readyDuration) {
     std::lock_guard lock(mVsyncMutex);
-    const nsecs_t period = mDispSync->getPeriod();
-
-    // Normalize phaseOffset to [-period, period)
-    const int numPeriods = phaseOffset / period;
-    phaseOffset -= numPeriods * period;
-    if (mPhaseOffset == phaseOffset) {
-        return;
-    }
-
-    mPhaseOffset = phaseOffset;
+    mWorkDuration = workDuration;
+    mReadyDuration = readyDuration;
 
     // If we're not enabled, we don't need to mess with the listeners
     if (!mEnabled) {
         return;
     }
 
-    status_t err =
-            mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this), mPhaseOffset);
-    if (err != NO_ERROR) {
-        ALOGE("error changing vsync offset: %s (%d)", strerror(-err), err);
-    }
+    mCallbackRepeater->start(mWorkDuration, mReadyDuration);
 }
 
-void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
+void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
+                                     nsecs_t readyTime) {
     VSyncSource::Callback* callback;
     {
         std::lock_guard lock(mCallbackMutex);
@@ -104,17 +185,13 @@
     }
 
     if (callback != nullptr) {
-        callback->onVSyncEvent(when, expectedVSyncTimestamp);
+        callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
     }
 }
 
 void DispSyncSource::dump(std::string& result) const {
     std::lock_guard lock(mVsyncMutex);
     StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
-    mDispSync->dump(result);
 }
 
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 2aee3f6..2fce235 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -18,45 +18,47 @@
 #include <mutex>
 #include <string>
 
-#include "DispSync.h"
 #include "EventThread.h"
 #include "TracedOrdinal.h"
+#include "VSyncDispatch.h"
 
-namespace android {
+namespace android::scheduler {
+class CallbackRepeater;
 
-class DispSyncSource final : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource {
 public:
-    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+    DispSyncSource(VSyncDispatch& vSyncDispatch, std::chrono::nanoseconds workDuration,
+                   std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name);
 
-    ~DispSyncSource() override = default;
+    ~DispSyncSource() override;
 
     // The following methods are implementation of VSyncSource.
     const char* getName() const override { return mName; }
     void setVSyncEnabled(bool enable) override;
     void setCallback(VSyncSource::Callback* callback) override;
-    void setPhaseOffset(nsecs_t phaseOffset) override;
+    void setDuration(std::chrono::nanoseconds workDuration,
+                     std::chrono::nanoseconds readyDuration) override;
 
     void dump(std::string&) const override;
 
 private:
-    // The following method is the implementation of the DispSync::Callback.
-    void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
+    void onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
 
     const char* const mName;
     TracedOrdinal<int> mValue;
 
     const bool mTraceVsync;
     const std::string mVsyncOnLabel;
-    nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
 
-    DispSync* mDispSync;
+    std::unique_ptr<CallbackRepeater> mCallbackRepeater;
 
     std::mutex mCallbackMutex;
     VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
 
     mutable std::mutex mVsyncMutex;
-    TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
+    TracedOrdinal<std::chrono::nanoseconds> mWorkDuration GUARDED_BY(mVsyncMutex);
+    std::chrono::nanoseconds mReadyDuration GUARDED_BY(mVsyncMutex);
     bool mEnabled GUARDED_BY(mVsyncMutex) = false;
 };
 
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 846190c..559626b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -200,9 +200,10 @@
     mThread.join();
 }
 
-void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
+void EventThread::setDuration(std::chrono::nanoseconds workDuration,
+                              std::chrono::nanoseconds readyDuration) {
     std::lock_guard<std::mutex> lock(mMutex);
-    mVSyncSource->setPhaseOffset(phaseOffset);
+    mVSyncSource->setDuration(workDuration, readyDuration);
 }
 
 sp<EventThreadConnection> EventThread::createEventConnection(
@@ -283,7 +284,8 @@
     mCondition.notify_all();
 }
 
-void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) {
+void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
+                               nsecs_t /*deadlineTimestamp*/) {
     std::lock_guard<std::mutex> lock(mMutex);
 
     LOG_FATAL_IF(!mVSyncState);
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 49f624c..fa1ca64 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -57,7 +57,8 @@
     class Callback {
     public:
         virtual ~Callback() {}
-        virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0;
+        virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+                                  nsecs_t deadlineTimestamp) = 0;
     };
 
     virtual ~VSyncSource() {}
@@ -65,7 +66,8 @@
     virtual const char* getName() const = 0;
     virtual void setVSyncEnabled(bool enable) = 0;
     virtual void setCallback(Callback* callback) = 0;
-    virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+    virtual void setDuration(std::chrono::nanoseconds workDuration,
+                             std::chrono::nanoseconds readyDuration) = 0;
 
     virtual void dump(std::string& result) const = 0;
 };
@@ -116,7 +118,8 @@
 
     virtual void dump(std::string& result) const = 0;
 
-    virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+    virtual void setDuration(std::chrono::nanoseconds workDuration,
+                             std::chrono::nanoseconds readyDuration) = 0;
 
     virtual status_t registerDisplayEventConnection(
             const sp<EventThreadConnection>& connection) = 0;
@@ -157,7 +160,8 @@
 
     void dump(std::string& result) const override;
 
-    void setPhaseOffset(nsecs_t phaseOffset) override;
+    void setDuration(std::chrono::nanoseconds workDuration,
+                     std::chrono::nanoseconds readyDuration) override;
 
     size_t getEventThreadConnectionCount() override;
 
@@ -177,7 +181,8 @@
             REQUIRES(mMutex);
 
     // Implements VSyncSource::Callback
-    void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) override;
+    void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
+                      nsecs_t deadlineTimestamp) override;
 
     const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
 
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 975c9db..016b076 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -35,16 +35,17 @@
         mCallback = callback;
     }
 
-    void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
+    void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+                           nsecs_t deadlineTimestamp) {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
         if (mCallback) {
-            mCallback->onVSyncEvent(when, expectedVSyncTimestamp);
+            mCallback->onVSyncEvent(when, expectedVSyncTimestamp, deadlineTimestamp);
         }
     }
 
     const char* getName() const override { return "inject"; }
     void setVSyncEnabled(bool) override {}
-    void setPhaseOffset(nsecs_t) override {}
+    void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {}
     void dump(std::string&) const override {}
 
 private:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4f4c1d0..b0b5e2e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -95,14 +95,32 @@
 
 } // namespace
 
+class PredictedVsyncTracer {
+public:
+    PredictedVsyncTracer(scheduler::VSyncDispatch& dispatch)
+          : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this),
+                          "PredictedVsyncTracer") {
+        scheduleRegistration();
+    }
+
+private:
+    TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0};
+    scheduler::VSyncCallbackRegistration mRegistration;
+
+    void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); }
+
+    void callback() {
+        mParity = !mParity;
+        scheduleRegistration();
+    }
+};
+
 Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
       : Scheduler(configs, callback,
                   {.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
                    .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false),
                    .useContentDetectionV2 =
-                           base::GetBoolProperty("debug.sf.use_content_detection_v2"s, true),
-                   // TODO(b/140302863): Remove this and use the vsync_reactor system.
-                   .useVsyncPredictor = base::GetBoolProperty("debug.sf.vsync_reactor"s, true)}) {}
+                           base::GetBoolProperty("debug.sf.use_content_detection_v2"s, true)}) {}
 
 Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback,
                      Options options)
@@ -147,7 +165,11 @@
         mVsyncSchedule(std::move(schedule)),
         mLayerHistory(std::move(layerHistory)),
         mSchedulerCallback(schedulerCallback),
-        mRefreshRateConfigs(configs) {
+        mRefreshRateConfigs(configs),
+        mPredictedVsyncTracer(
+                base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
+                        ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
+                        : nullptr) {
     mSchedulerCallback.setVsyncEnabled(false);
 }
 
@@ -159,21 +181,15 @@
 }
 
 Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(Options options) {
-    if (!options.useVsyncPredictor) {
-        auto sync = std::make_unique<impl::DispSync>("SchedulerDispSync",
-                                                     sysprop::running_without_sync_framework(true));
-        return {std::move(sync), nullptr, nullptr};
-    }
-
     auto clock = std::make_unique<scheduler::SystemClock>();
     auto tracker = createVSyncTracker();
     auto dispatch = createVSyncDispatch(*tracker);
 
     // TODO(b/144707443): Tune constants.
     constexpr size_t pendingFenceLimit = 20;
-    auto sync = std::make_unique<scheduler::VSyncReactor>(std::move(clock), *dispatch, *tracker,
-                                                          pendingFenceLimit,
-                                                          options.supportKernelTimer);
+    auto sync =
+            std::make_unique<scheduler::VSyncReactor>(std::move(clock), *tracker, pendingFenceLimit,
+                                                      options.supportKernelTimer);
     return {std::move(sync), std::move(tracker), std::move(dispatch)};
 }
 
@@ -192,16 +208,18 @@
     return *mVsyncSchedule.sync;
 }
 
-std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(const char* name,
-                                                                  nsecs_t phaseOffsetNs) {
-    return std::make_unique<DispSyncSource>(&getPrimaryDispSync(), phaseOffsetNs,
-                                            true /* traceVsync */, name);
+std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
+        const char* name, std::chrono::nanoseconds workDuration,
+        std::chrono::nanoseconds readyDuration, bool traceVsync) {
+    return std::make_unique<scheduler::DispSyncSource>(*mVsyncSchedule.dispatch, workDuration,
+                                                       readyDuration, traceVsync, name);
 }
 
 Scheduler::ConnectionHandle Scheduler::createConnection(
-        const char* connectionName, nsecs_t phaseOffsetNs,
+        const char* connectionName, std::chrono::nanoseconds workDuration,
+        std::chrono::nanoseconds readyDuration,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
-    auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs);
+    auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
     auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
                                                            std::move(interceptCallback));
     return createConnection(std::move(eventThread));
@@ -294,9 +312,10 @@
     mConnections.at(handle).thread->dump(result);
 }
 
-void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration,
+                            std::chrono::nanoseconds readyDuration) {
     RETURN_IF_INVALID_HANDLE(handle);
-    mConnections[handle].thread->setPhaseOffset(phaseOffset);
+    mConnections[handle].thread->setDuration(workDuration, readyDuration);
 }
 
 void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
@@ -326,12 +345,12 @@
     return mInjectorConnectionHandle;
 }
 
-bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime) {
+bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp) {
     if (!mInjectVSyncs || !mVSyncInjector) {
         return false;
     }
 
-    mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime);
+    mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime, deadlineTimestamp);
     return true;
 }
 
@@ -348,7 +367,6 @@
     std::lock_guard<std::mutex> lock(mHWVsyncLock);
     if (mPrimaryHWVsyncEnabled) {
         mSchedulerCallback.setVsyncEnabled(false);
-        getPrimaryDispSync().endResync();
         mPrimaryHWVsyncEnabled = false;
     }
     if (makeUnavailable) {
@@ -606,6 +624,15 @@
                   mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
 }
 
+void Scheduler::dumpVSync(std::string& s) const {
+    using base::StringAppendF;
+
+    StringAppendF(&s, "VSyncReactor:\n");
+    mVsyncSchedule.sync->dump(s);
+    StringAppendF(&s, "VSyncDispatch:\n");
+    mVsyncSchedule.dispatch->dump(s);
+}
+
 template <class T>
 bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
     HwcConfigIndexType newConfigId;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 4e7a9a1..9a4ac36 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -43,6 +43,7 @@
 class DispSync;
 class FenceTime;
 class InjectVSyncSource;
+class PredictedVsyncTracer;
 
 namespace scheduler {
 class VSyncDispatch;
@@ -71,7 +72,9 @@
     DispSync& getPrimaryDispSync();
 
     using ConnectionHandle = scheduler::ConnectionHandle;
-    ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+    ConnectionHandle createConnection(const char* connectionName,
+                                      std::chrono::nanoseconds workDuration,
+                                      std::chrono::nanoseconds readyDuration,
                                       impl::EventThread::InterceptVSyncsCallback);
 
     sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
@@ -88,17 +91,16 @@
     void onScreenAcquired(ConnectionHandle);
     void onScreenReleased(ConnectionHandle);
 
-    // Modifies phase offset in the event thread.
-    void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset);
+    // Modifies work duration in the event thread.
+    void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
+                     std::chrono::nanoseconds readyDuration);
 
     void getDisplayStatInfo(DisplayStatInfo* stats);
 
     // Returns injector handle if injection has toggled, or an invalid handle otherwise.
     ConnectionHandle enableVSyncInjection(bool enable);
-
     // Returns false if injection is disabled.
-    bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime);
-
+    bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp);
     void enableHardwareVsync();
     void disableHardwareVsync(bool makeUnavailable);
 
@@ -136,6 +138,7 @@
 
     void dump(std::string&) const;
     void dump(ConnectionHandle, std::string&) const;
+    void dumpVSync(std::string&) const;
 
     // Get the appropriate refresh for current conditions.
     std::optional<HwcConfigIndexType> getPreferredConfigId();
@@ -151,6 +154,11 @@
 
     size_t getEventThreadConnectionCount(ConnectionHandle handle);
 
+    std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name,
+                                                           std::chrono::nanoseconds workDuration,
+                                                           std::chrono::nanoseconds readyDuration,
+                                                           bool traceVsync = true);
+
 private:
     friend class TestableScheduler;
 
@@ -167,8 +175,6 @@
         bool useContentDetection;
         // Whether to use improved content detection.
         bool useContentDetectionV2;
-        // Whether to use improved DispSync implementation.
-        bool useVsyncPredictor;
     };
 
     struct VsyncSchedule {
@@ -188,8 +194,6 @@
     static std::unique_ptr<LayerHistory> createLayerHistory(const scheduler::RefreshRateConfigs&,
                                                             bool useContentDetectionV2);
 
-    std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);
-
     // Create a connection on the given EventThread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread>);
     sp<EventThreadConnection> createConnectionInternal(EventThread*,
@@ -282,6 +286,8 @@
     std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
             GUARDED_BY(mVsyncTimelineLock);
     static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
+
+    const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/TimeKeeper.h
index da2195c..40dd841 100644
--- a/services/surfaceflinger/Scheduler/TimeKeeper.h
+++ b/services/surfaceflinger/Scheduler/TimeKeeper.h
@@ -43,10 +43,10 @@
     virtual ~TimeKeeper();
 
     /*
-     * Arms callback to fired in time nanoseconds.
+     * Arms callback to fired when time is current based on CLOCK_MONOTONIC
      * There is only one timer, and subsequent calls will reset the callback function and the time.
      */
-    virtual void alarmIn(std::function<void()> const& callback, nsecs_t time) = 0;
+    virtual void alarmAt(std::function<void()> const& callback, nsecs_t time) = 0;
 
     /*
      * Cancels an existing pending callback
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index 7c5058e..59c336a 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -88,7 +88,7 @@
     return systemTime(SYSTEM_TIME_MONOTONIC);
 }
 
-void Timer::alarmIn(std::function<void()> const& cb, nsecs_t fireIn) {
+void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
     std::lock_guard<decltype(mMutex)> lk(mMutex);
     using namespace std::literals;
     static constexpr int ns_per_s =
@@ -99,11 +99,11 @@
     struct itimerspec old_timer;
     struct itimerspec new_timer {
         .it_interval = {.tv_sec = 0, .tv_nsec = 0},
-        .it_value = {.tv_sec = static_cast<long>(fireIn / ns_per_s),
-                     .tv_nsec = static_cast<long>(fireIn % ns_per_s)},
+        .it_value = {.tv_sec = static_cast<long>(time / ns_per_s),
+                     .tv_nsec = static_cast<long>(time % ns_per_s)},
     };
 
-    if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
+    if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
         ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
     }
 }
diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h
index a8e2d5a..69ce079 100644
--- a/services/surfaceflinger/Scheduler/Timer.h
+++ b/services/surfaceflinger/Scheduler/Timer.h
@@ -30,9 +30,9 @@
     ~Timer();
     nsecs_t now() const final;
 
-    // NB: alarmIn and alarmCancel are threadsafe; with the last-returning function being effectual
+    // NB: alarmAt and alarmCancel are threadsafe; with the last-returning function being effectual
     //     Most users will want to serialize thes calls so as to be aware of the timer state.
-    void alarmIn(std::function<void()> const& cb, nsecs_t fireIn) final;
+    void alarmAt(std::function<void()> const& cb, nsecs_t time) final;
     void alarmCancel() final;
     void dump(std::string& result) const final;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 2a2d7c5..0407900 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -40,11 +40,13 @@
 
     /*
      * A callback that can be registered to be awoken at a given time relative to a vsync event.
-     * \param [in] vsyncTime The timestamp of the vsync the callback is for.
-     * \param [in] targetWakeupTime The timestamp of intended wakeup time of the cb.
-     *
+     * \param [in] vsyncTime:        The timestamp of the vsync the callback is for.
+     * \param [in] targetWakeupTime: The timestamp of intended wakeup time of the cb.
+     * \param [in] readyTime:        The timestamp of intended time where client needs to finish
+     *                               its work by.
      */
-    using Callback = std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime)>;
+    using Callback =
+            std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime)>;
 
     /*
      * Registers a callback that will be called at designated points on the vsync timeline.
@@ -71,33 +73,54 @@
     virtual void unregisterCallback(CallbackToken token) = 0;
 
     /*
+     * Timing information about a scheduled callback
+     *
+     * @workDuration:  The time needed for the client to perform its work
+     * @readyDuration: The time needed for the client to be ready before a vsync event.
+     *                 For external (non-SF) clients, not only do we need to account for their
+     *                 workDuration, but we also need to account for the time SF will take to
+     *                 process their buffer/transaction. In this case, readyDuration will be set
+     *                 to the SF duration in order to provide enough end-to-end time, and to be
+     *                 able to provide the ready-by time (deadline) on the callback.
+     *                 For internal clients, we don't need to add additional padding, so
+     *                 readyDuration will typically be 0.
+     * @earliestVsync: The targeted display time. This will be snapped to the closest
+     *                 predicted vsync time after earliestVsync.
+     *
+     * callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
+     * event.
+     */
+    struct ScheduleTiming {
+        nsecs_t workDuration = 0;
+        nsecs_t readyDuration = 0;
+        nsecs_t earliestVsync = 0;
+    };
+
+    /*
      * Schedules the registered callback to be dispatched.
      *
-     * The callback will be dispatched at 'workDuration' nanoseconds before a vsync event.
+     * The callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
+     * event.
      *
      * The caller designates the earliest vsync event that should be targeted by the earliestVsync
      * parameter.
-     * The callback will be scheduled at (workDuration - predictedVsync), where predictedVsync
-     * is the first vsync event time where ( predictedVsync >= earliestVsync ).
+     * The callback will be scheduled at (workDuration + readyDuration - predictedVsync), where
+     * predictedVsync is the first vsync event time where ( predictedVsync >= earliestVsync ).
      *
-     * If (workDuration - earliestVsync) is in the past, or if a callback has already been
-     * dispatched for the predictedVsync, an error will be returned.
+     * If (workDuration + readyDuration - earliestVsync) is in the past, or if a callback has
+     * already been dispatched for the predictedVsync, an error will be returned.
      *
      * It is valid to reschedule a callback to a different time.
      *
      * \param [in] token           The callback to schedule.
-     * \param [in] workDuration    The time before the actual vsync time to invoke the callback
-     *                             associated with token.
-     * \param [in] earliestVsync   The targeted display time. This will be snapped to the closest
-     *                             predicted vsync time after earliestVsync.
+     * \param [in] scheduleTiming  The timing information for this schedule call
      * \return                     A ScheduleResult::Scheduled if callback was scheduled.
      *                             A ScheduleResult::CannotSchedule
-     *                             if (workDuration - earliestVsync) is in the past, or
-     *                             if a callback was dispatched for the predictedVsync already.
-     *                             A ScheduleResult::Error if there was another error.
+     *                             if (workDuration + readyDuration - earliestVsync) is in the past,
+     * or if a callback was dispatched for the predictedVsync already. A ScheduleResult::Error if
+     * there was another error.
      */
-    virtual ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
-                                    nsecs_t earliestVsync) = 0;
+    virtual ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
 
     /* Cancels a scheduled callback, if possible.
      *
@@ -129,7 +152,7 @@
     ~VSyncCallbackRegistration();
 
     // See documentation for VSyncDispatch::schedule.
-    ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync);
+    ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
 
     // See documentation for VSyncDispatch::cancel.
     CancelResult cancel();
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 2a6fd05..2154a40 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -35,8 +35,6 @@
                                                            nsecs_t minVsyncDistance)
       : mName(name),
         mCallback(cb),
-        mWorkDuration(0),
-        mEarliestVsync(0),
         mMinVsyncDistance(minVsyncDistance) {}
 
 std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
@@ -54,6 +52,13 @@
     return {mArmedInfo->mActualWakeupTime};
 }
 
+std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
+    if (!mArmedInfo) {
+        return {};
+    }
+    return {mArmedInfo->mActualReadyTime};
+}
+
 std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
     if (!mArmedInfo) {
         return {};
@@ -61,10 +66,10 @@
     return {mArmedInfo->mActualVsyncTime};
 }
 
-ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
+ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
                                                       VSyncTracker& tracker, nsecs_t now) {
-    auto nextVsyncTime =
-            tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration));
+    auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
+            std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
 
     bool const wouldSkipAVsyncTarget =
             mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
@@ -80,16 +85,15 @@
                 tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
     }
 
-    auto const nextWakeupTime = nextVsyncTime - workDuration;
-    mWorkDuration = workDuration;
-    mEarliestVsync = earliestVsync;
-    mArmedInfo = {nextWakeupTime, nextVsyncTime};
+    auto const nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
+    auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
+    mScheduleTiming = timing;
+    mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
     return ScheduleResult::Scheduled;
 }
 
-void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(nsecs_t workDuration,
-                                                            nsecs_t earliestVsync) {
-    mWorkloadUpdateInfo = {.earliestVsync = earliestVsync, .duration = workDuration};
+void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
+    mWorkloadUpdateInfo = timing;
 }
 
 bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
@@ -102,14 +106,18 @@
     }
 
     if (mWorkloadUpdateInfo) {
-        mEarliestVsync = mWorkloadUpdateInfo->earliestVsync;
-        mWorkDuration = mWorkloadUpdateInfo->duration;
+        mScheduleTiming = *mWorkloadUpdateInfo;
         mWorkloadUpdateInfo.reset();
     }
 
-    auto const nextVsyncTime =
-            tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration));
-    mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime};
+    const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
+    const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
+
+    const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync);
+    const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
+    const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
+
+    mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
 }
 
 void VSyncDispatchTimerQueueEntry::disarm() {
@@ -122,13 +130,14 @@
     return *mLastDispatchTime;
 }
 
-void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) {
+void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
+                                            nsecs_t deadlineTimestamp) {
     {
         std::lock_guard<std::mutex> lk(mRunningMutex);
         mRunning = true;
     }
 
-    mCallback(vsyncTimestamp, wakeupTimestamp);
+    mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
 
     std::lock_guard<std::mutex> lk(mRunningMutex);
     mRunning = false;
@@ -144,15 +153,20 @@
     std::lock_guard<std::mutex> lk(mRunningMutex);
     std::string armedInfo;
     if (mArmedInfo) {
-        StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]",
+        StringAppendF(&armedInfo,
+                      "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
                       (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
+                      (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
                       (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
     }
 
     StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
                   mRunning ? "(in callback function)" : "", armedInfo.c_str());
-    StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n",
-                  mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f);
+    StringAppendF(&result,
+                  "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative "
+                  "to now\n",
+                  mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
+                  (mScheduleTiming.earliestVsync - systemTime()) / 1e6f);
 
     if (mLastDispatchTime) {
         StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
@@ -180,10 +194,10 @@
     mTimeKeeper->alarmCancel();
 }
 
-void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
+void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
     mIntendedWakeupTime = targetTime;
-    mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
-                         targetTime - now);
+    mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
+                         mIntendedWakeupTime);
     mLastTimerSchedule = mTimeKeeper->now();
 }
 
@@ -239,6 +253,7 @@
         std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
         nsecs_t vsyncTimestamp;
         nsecs_t wakeupTimestamp;
+        nsecs_t deadlineTimestamp;
     };
     std::vector<Invocation> invocations;
     {
@@ -252,11 +267,13 @@
                 continue;
             }
 
+            auto const readyTime = callback->readyTime();
+
             auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
             if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
                 callback->executing();
-                invocations.emplace_back(
-                        Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
+                invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
+                                                    *wakeupTime, *readyTime});
             }
         }
 
@@ -265,7 +282,8 @@
     }
 
     for (auto const& invocation : invocations) {
-        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp);
+        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
+                                      invocation.deadlineTimestamp);
     }
 }
 
@@ -297,8 +315,8 @@
     }
 }
 
-ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
-                                                 nsecs_t earliestVsync) {
+ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
+                                                 ScheduleTiming scheduleTiming) {
     auto result = ScheduleResult::Error;
     {
         std::lock_guard<decltype(mMutex)> lk(mMutex);
@@ -314,11 +332,11 @@
          * timer recalculation to avoid cancelling a callback that is about to fire. */
         auto const rearmImminent = now > mIntendedWakeupTime;
         if (CC_UNLIKELY(rearmImminent)) {
-            callback->addPendingWorkloadUpdate(workDuration, earliestVsync);
+            callback->addPendingWorkloadUpdate(scheduleTiming);
             return ScheduleResult::Scheduled;
         }
 
-        result = callback->schedule(workDuration, earliestVsync, mTracker, now);
+        result = callback->schedule(scheduleTiming, mTracker, now);
         if (result == ScheduleResult::CannotSchedule) {
             return result;
         }
@@ -396,11 +414,11 @@
     if (mValidToken) mDispatch.get().unregisterCallback(mToken);
 }
 
-ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
+ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
     if (!mValidToken) {
         return ScheduleResult::Error;
     }
-    return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
+    return mDispatch.get().schedule(mToken, scheduleTiming);
 }
 
 CancelResult VSyncCallbackRegistration::cancel() {
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 957c0d1..26237b6 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -47,7 +47,7 @@
     std::optional<nsecs_t> lastExecutedVsyncTarget() const;
 
     // This moves the state from disarmed->armed and will calculate the wakeupTime.
-    ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker,
+    ScheduleResult schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker,
                             nsecs_t now);
     // This will update armed entries with the latest vsync information. Entry remains armed.
     void update(VSyncTracker& tracker, nsecs_t now);
@@ -56,6 +56,8 @@
     // It will not update the wakeupTime.
     std::optional<nsecs_t> wakeupTime() const;
 
+    std::optional<nsecs_t> readyTime() const;
+
     std::optional<nsecs_t> targetVsync() const;
 
     // This moves state from armed->disarmed.
@@ -67,14 +69,14 @@
 
     // Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
     // call to update()
-    void addPendingWorkloadUpdate(nsecs_t workDuration, nsecs_t earliestVsync);
+    void addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming);
 
     // Checks if there is a pending update to the workload, returning true if so.
     bool hasPendingWorkloadUpdate() const;
     // End: functions that are not threadsafe.
 
     // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
-    void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp);
+    void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp);
     // Block calling thread while the callback is executing.
     void ensureNotRunning();
 
@@ -84,22 +86,18 @@
     std::string const mName;
     VSyncDispatch::Callback const mCallback;
 
-    nsecs_t mWorkDuration;
-    nsecs_t mEarliestVsync;
+    VSyncDispatch::ScheduleTiming mScheduleTiming;
     nsecs_t const mMinVsyncDistance;
 
     struct ArmingInfo {
         nsecs_t mActualWakeupTime;
         nsecs_t mActualVsyncTime;
+        nsecs_t mActualReadyTime;
     };
     std::optional<ArmingInfo> mArmedInfo;
     std::optional<nsecs_t> mLastDispatchTime;
 
-    struct WorkloadUpdateInfo {
-        nsecs_t duration;
-        nsecs_t earliestVsync;
-    };
-    std::optional<WorkloadUpdateInfo> mWorkloadUpdateInfo;
+    std::optional<VSyncDispatch::ScheduleTiming> mWorkloadUpdateInfo;
 
     mutable std::mutex mRunningMutex;
     std::condition_variable mCv;
@@ -125,7 +123,7 @@
 
     CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
     void unregisterCallback(CallbackToken token) final;
-    ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
+    ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final;
     CancelResult cancel(CallbackToken token) final;
     void dump(std::string& result) const final;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61f3fbb..e90edf7 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 #include "VSyncPredictor.h"
@@ -54,7 +50,7 @@
     }
 }
 
-inline size_t VSyncPredictor::next(int i) const {
+inline size_t VSyncPredictor::next(size_t i) const {
     return (i + 1) % mTimestamps.size();
 }
 
@@ -69,12 +65,12 @@
 }
 
 nsecs_t VSyncPredictor::currentPeriod() const {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     return std::get<0>(mRateMap.find(mIdealPeriod)->second);
 }
 
 bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
 
     if (!validate(timestamp)) {
         // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
@@ -138,14 +134,14 @@
 
     auto meanTS = scheduler::calculate_mean(vsyncTS);
     auto meanOrdinal = scheduler::calculate_mean(ordinals);
-    for (auto i = 0; i < vsyncTS.size(); i++) {
+    for (size_t i = 0; i < vsyncTS.size(); i++) {
         vsyncTS[i] -= meanTS;
         ordinals[i] -= meanOrdinal;
     }
 
     auto top = 0ll;
     auto bottom = 0ll;
-    for (auto i = 0; i < vsyncTS.size(); i++) {
+    for (size_t i = 0; i < vsyncTS.size(); i++) {
         top += vsyncTS[i] * ordinals[i];
         bottom += ordinals[i] * ordinals[i];
     }
@@ -177,9 +173,9 @@
 }
 
 nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
 
-    auto const [slope, intercept] = getVSyncPredictionModel(lk);
+    auto const [slope, intercept] = getVSyncPredictionModel(lock);
 
     if (mTimestamps.empty()) {
         traceInt64If("VSP-mode", 1);
@@ -215,8 +211,8 @@
 }
 
 std::tuple<nsecs_t, nsecs_t> VSyncPredictor::getVSyncPredictionModel() const {
-    std::lock_guard<std::mutex> lk(mMutex);
-    return VSyncPredictor::getVSyncPredictionModel(lk);
+    std::lock_guard lock(mMutex);
+    return VSyncPredictor::getVSyncPredictionModel(lock);
 }
 
 std::tuple<nsecs_t, nsecs_t> VSyncPredictor::getVSyncPredictionModel(
@@ -227,7 +223,7 @@
 void VSyncPredictor::setPeriod(nsecs_t period) {
     ATRACE_CALL();
 
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     static constexpr size_t kSizeLimit = 30;
     if (CC_UNLIKELY(mRateMap.size() == kSizeLimit)) {
         mRateMap.erase(mRateMap.begin());
@@ -256,18 +252,18 @@
 }
 
 bool VSyncPredictor::needsMoreSamples() const {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     return mTimestamps.size() < kMinimumSamplesForPrediction;
 }
 
 void VSyncPredictor::resetModel() {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
     clearTimestamps();
 }
 
 void VSyncPredictor::dump(std::string& result) const {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f);
     StringAppendF(&result, "\tRefresh Rate Map:\n");
     for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) {
@@ -280,5 +276,3 @@
 
 } // namespace android::scheduler
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 5f3c418..5f2ec49 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -74,7 +74,7 @@
     size_t const kOutlierTolerancePercent;
 
     std::mutex mutable mMutex;
-    size_t next(int i) const REQUIRES(mMutex);
+    size_t next(size_t i) const REQUIRES(mMutex);
     bool validate(nsecs_t timestamp) const REQUIRES(mMutex);
     std::tuple<nsecs_t, nsecs_t> getVSyncPredictionModel(std::lock_guard<std::mutex> const&) const
             REQUIRES(mMutex);
@@ -84,7 +84,7 @@
 
     std::unordered_map<nsecs_t, std::tuple<nsecs_t, nsecs_t>> mutable mRateMap GUARDED_BY(mMutex);
 
-    int mLastTimestampIndex GUARDED_BY(mMutex) = 0;
+    size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0;
     std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
 };
 
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index a2b279b..3c5b3f1 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -35,130 +35,15 @@
     return systemTime(SYSTEM_TIME_MONOTONIC);
 }
 
-class PredictedVsyncTracer {
-public:
-    PredictedVsyncTracer(VSyncDispatch& dispatch)
-          : mRegistration(dispatch,
-                          std::bind(&PredictedVsyncTracer::callback, this, std::placeholders::_1,
-                                    std::placeholders::_2),
-                          "PredictedVsyncTracer") {
-        mRegistration.schedule(0, 0);
-    }
-
-private:
-    TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0};
-    VSyncCallbackRegistration mRegistration;
-
-    void callback(nsecs_t /*vsyncTime*/, nsecs_t /*targetWakeupTim*/) {
-        mParity = !mParity;
-        mRegistration.schedule(0, 0);
-    }
-};
-
-VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch,
-                           VSyncTracker& tracker, size_t pendingFenceLimit,
-                           bool supportKernelIdleTimer)
+VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker,
+                           size_t pendingFenceLimit, bool supportKernelIdleTimer)
       : mClock(std::move(clock)),
         mTracker(tracker),
-        mDispatch(dispatch),
         mPendingLimit(pendingFenceLimit),
-        mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false)
-                                      ? std::make_unique<PredictedVsyncTracer>(mDispatch)
-                                      : nullptr),
         mSupportKernelIdleTimer(supportKernelIdleTimer) {}
 
 VSyncReactor::~VSyncReactor() = default;
 
-// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
-// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
-// for now.
-class CallbackRepeater {
-public:
-    CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name,
-                     nsecs_t period, nsecs_t offset, nsecs_t notBefore)
-          : mName(name),
-            mCallback(cb),
-            mRegistration(dispatch,
-                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
-                                    std::placeholders::_2),
-                          mName),
-            mPeriod(period),
-            mOffset(offset),
-            mLastCallTime(notBefore) {}
-
-    ~CallbackRepeater() {
-        std::lock_guard<std::mutex> lk(mMutex);
-        mRegistration.cancel();
-    }
-
-    void start(nsecs_t offset) {
-        std::lock_guard<std::mutex> lk(mMutex);
-        mStopped = false;
-        mOffset = offset;
-
-        auto const schedule_result = mRegistration.schedule(calculateWorkload(), mLastCallTime);
-        LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
-                            "Error scheduling callback: rc %X", schedule_result);
-    }
-
-    void setPeriod(nsecs_t period) {
-        std::lock_guard<std::mutex> lk(mMutex);
-        if (period == mPeriod) {
-            return;
-        }
-        mPeriod = period;
-    }
-
-    void stop() {
-        std::lock_guard<std::mutex> lk(mMutex);
-        LOG_ALWAYS_FATAL_IF(mStopped, "DispSyncInterface misuse: callback already stopped");
-        mStopped = true;
-        mRegistration.cancel();
-    }
-
-    void dump(std::string& result) const {
-        std::lock_guard<std::mutex> lk(mMutex);
-        StringAppendF(&result, "\t%s: mPeriod=%.2f last vsync time %.2fms relative to now (%s)\n",
-                      mName.c_str(), mPeriod / 1e6f, (mLastCallTime - systemTime()) / 1e6f,
-                      mStopped ? "stopped" : "running");
-    }
-
-private:
-    void callback(nsecs_t vsynctime, nsecs_t wakeupTime) {
-        {
-            std::lock_guard<std::mutex> lk(mMutex);
-            mLastCallTime = vsynctime;
-        }
-
-        mCallback->onDispSyncEvent(wakeupTime, vsynctime);
-
-        {
-            std::lock_guard<std::mutex> lk(mMutex);
-            if (mStopped) {
-                return;
-            }
-            auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime);
-            LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
-                                "Error rescheduling callback: rc %X", schedule_result);
-        }
-    }
-
-    // DispSync offsets are defined as time after the vsync before presentation.
-    // VSyncReactor workloads are defined as time before the intended presentation vsync.
-    // Note change in sign between the two defnitions.
-    nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; }
-
-    const std::string mName;
-    DispSync::Callback* const mCallback;
-
-    std::mutex mutable mMutex;
-    VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
-    bool mStopped GUARDED_BY(mMutex) = false;
-    nsecs_t mPeriod GUARDED_BY(mMutex);
-    nsecs_t mOffset GUARDED_BY(mMutex);
-    nsecs_t mLastCallTime GUARDED_BY(mMutex);
-};
-
 bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) {
     if (!fence) {
         return false;
@@ -169,7 +54,7 @@
         return true;
     }
 
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     if (mExternalIgnoreFences || mInternalIgnoreFences) {
         return true;
     }
@@ -207,7 +92,7 @@
 }
 
 void VSyncReactor::setIgnorePresentFences(bool ignoration) {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     mExternalIgnoreFences = ignoration;
     updateIgnorePresentFencesInternal();
 }
@@ -269,8 +154,6 @@
     mTracker.resetModel();
 }
 
-void VSyncReactor::endResync() {}
-
 bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> HwcVsyncPeriod) {
     if (!mPeriodConfirmationInProgress) {
         return false;
@@ -303,14 +186,11 @@
                                    bool* periodFlushed) {
     assert(periodFlushed);
 
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
         ATRACE_NAME("VSR: period confirmed");
         if (mPeriodTransitioningTo) {
             mTracker.setPeriod(*mPeriodTransitioningTo);
-            for (auto& entry : mCallbacks) {
-                entry.second->setPeriod(*mPeriodTransitioningTo);
-            }
             *periodFlushed = true;
         }
 
@@ -339,51 +219,8 @@
     return mMoreSamplesNeeded;
 }
 
-status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase,
-                                        DispSync::Callback* callback,
-                                        nsecs_t /* lastCallbackTime */) {
-    std::lock_guard<std::mutex> lk(mMutex);
-    auto it = mCallbacks.find(callback);
-    if (it == mCallbacks.end()) {
-        // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f.
-        static auto constexpr maxListeners = 4;
-        if (mCallbacks.size() >= maxListeners) {
-            ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name,
-                  maxListeners, mCallbacks.size());
-            return NO_MEMORY;
-        }
-
-        auto const period = mTracker.currentPeriod();
-        auto repeater = std::make_unique<CallbackRepeater>(mDispatch, callback, name, period, phase,
-                                                           mClock->now());
-        it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first;
-    }
-
-    it->second->start(phase);
-    return NO_ERROR;
-}
-
-status_t VSyncReactor::removeEventListener(DispSync::Callback* callback,
-                                           nsecs_t* /* outLastCallback */) {
-    std::lock_guard<std::mutex> lk(mMutex);
-    auto const it = mCallbacks.find(callback);
-    LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback %p not registered", callback);
-
-    it->second->stop();
-    return NO_ERROR;
-}
-
-status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
-    std::lock_guard<std::mutex> lk(mMutex);
-    auto const it = mCallbacks.find(callback);
-    LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback was %p not registered", callback);
-
-    it->second->start(phase);
-    return NO_ERROR;
-}
-
 void VSyncReactor::dump(std::string& result) const {
-    std::lock_guard<std::mutex> lk(mMutex);
+    std::lock_guard lock(mMutex);
     StringAppendF(&result, "VsyncReactor in use\n");
     StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size());
     StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n",
@@ -403,17 +240,8 @@
         StringAppendF(&result, "No Last HW vsync\n");
     }
 
-    StringAppendF(&result, "CallbackRepeaters:\n");
-    for (const auto& [callback, repeater] : mCallbacks) {
-        repeater->dump(result);
-    }
-
     StringAppendF(&result, "VSyncTracker:\n");
     mTracker.dump(result);
-    StringAppendF(&result, "VSyncDispatch:\n");
-    mDispatch.dump(result);
 }
 
-void VSyncReactor::reset() {}
-
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 22ceb39..80b5232 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -29,14 +29,12 @@
 class Clock;
 class VSyncDispatch;
 class VSyncTracker;
-class CallbackRepeater;
-class PredictedVsyncTracer;
 
 // TODO (b/145217110): consider renaming.
 class VSyncReactor : public android::DispSync {
 public:
-    VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch, VSyncTracker& tracker,
-                 size_t pendingFenceLimit, bool supportKernelIdleTimer);
+    VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker, size_t pendingFenceLimit,
+                 bool supportKernelIdleTimer);
     ~VSyncReactor();
 
     bool addPresentFence(const std::shared_ptr<FenceTime>& fence) final;
@@ -52,15 +50,8 @@
     void beginResync() final;
     bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                          bool* periodFlushed) final;
-    void endResync() final;
-
-    status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
-                              nsecs_t lastCallbackTime) final;
-    status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback) final;
-    status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) final;
 
     void dump(std::string& result) const final;
-    void reset() final;
 
 private:
     void setIgnorePresentFencesInternal(bool ignoration) REQUIRES(mMutex);
@@ -72,7 +63,6 @@
 
     std::unique_ptr<Clock> const mClock;
     VSyncTracker& mTracker;
-    VSyncDispatch& mDispatch;
     size_t const mPendingLimit;
 
     mutable std::mutex mMutex;
@@ -85,10 +75,6 @@
     std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
     std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
 
-    std::unordered_map<DispSync::Callback*, std::unique_ptr<CallbackRepeater>> mCallbacks
-            GUARDED_BY(mMutex);
-
-    const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
     const bool mSupportKernelIdleTimer = false;
 };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f6028d5..7572be3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1452,7 +1452,11 @@
 
 status_t SurfaceFlinger::injectVSync(nsecs_t when) {
     Mutex::Autolock lock(mStateLock);
-    return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE;
+    const auto expectedPresent = calculateExpectedPresentTime(when);
+    return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent,
+                                   /*deadlineTimestamp=*/expectedPresent)
+            ? NO_ERROR
+            : BAD_VALUE;
 }
 
 status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
@@ -2984,14 +2988,16 @@
 
     // start the EventThread
     mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
+    const auto configs = mVsyncConfiguration->getCurrentConfigs();
     mAppConnectionHandle =
             mScheduler->createConnection("app",
-                                         mVsyncConfiguration->getCurrentConfigs().late.appOffset,
+                                         /*workDuration=*/configs.late.appWorkDuration,
+                                         /*readyDuration=*/configs.late.sfWorkDuration,
                                          impl::EventThread::InterceptVSyncsCallback());
     mSfConnectionHandle =
             mScheduler->createConnection("sf",
-                                         mVsyncConfiguration->getCurrentConfigs().late.sfOffset,
-                                         [this](nsecs_t timestamp) {
+                                         /*workDuration=*/configs.late.sfWorkDuration,
+                                         /*readyDuration=*/0ns, [this](nsecs_t timestamp) {
                                              mInterceptor->saveVSyncEvent(timestamp);
                                          });
 
@@ -3024,8 +3030,12 @@
 }
 
 void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config) {
-    mScheduler->setPhaseOffset(mAppConnectionHandle, config.appOffset);
-    mScheduler->setPhaseOffset(mSfConnectionHandle, config.sfOffset);
+    mScheduler->setDuration(mAppConnectionHandle,
+                            /*workDuration=*/config.appWorkDuration,
+                            /*readyDuration=*/config.sfWorkDuration);
+    mScheduler->setDuration(mSfConnectionHandle,
+                            /*workDuration=*/config.sfWorkDuration,
+                            /*readyDuration=*/0ns);
 }
 
 void SurfaceFlinger::commitTransaction() {
@@ -3356,7 +3366,7 @@
     return true;
 }
 
-void SurfaceFlinger::setTransactionState(
+status_t SurfaceFlinger::setTransactionState(
         const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags,
         const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands,
         int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
@@ -3402,12 +3412,13 @@
                                                hasListenerCallbacks, listenerCallbacks, originPID,
                                                originUID);
         setTransactionFlags(eTransactionFlushNeeded);
-        return;
+        return NO_ERROR;
     }
 
     applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
                           uncacheBuffer, postTime, privileged, hasListenerCallbacks,
                           listenerCallbacks, originPID, originUID, /*isMainThread*/ false);
+    return NO_ERROR;
 }
 
 void SurfaceFlinger::applyTransactionState(
@@ -4341,8 +4352,7 @@
     } else {
         static const std::unordered_map<std::string, Dumper> dumpers = {
                 {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
-                {"--dispsync"s,
-                 dumper([this](std::string& s) { mScheduler->getPrimaryDispSync().dump(s); })},
+                {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVSync(s); })},
                 {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
                 {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
                 {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
@@ -4813,12 +4823,21 @@
     if (const auto displayId = getInternalDisplayIdLocked();
         displayId && getHwComposer().isConnected(*displayId)) {
         const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+        std::string fps, xDpi, yDpi;
+        if (activeConfig) {
+            fps = std::to_string(1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId)) + " fps";
+            xDpi = activeConfig->getDpiX();
+            yDpi = activeConfig->getDpiY();
+        } else {
+            fps = "unknown";
+            xDpi = "unknown";
+            yDpi = "unknown";
+        }
         StringAppendF(&result,
-                      "  refresh-rate              : %f fps\n"
-                      "  x-dpi                     : %f\n"
-                      "  y-dpi                     : %f\n",
-                      1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId),
-                      activeConfig->getDpiX(), activeConfig->getDpiY());
+                      "  refresh-rate              : %s\n"
+                      "  x-dpi                     : %s\n"
+                      "  y-dpi                     : %s\n",
+                      fps.c_str(), xDpi.c_str(), yDpi.c_str());
     }
 
     StringAppendF(&result, "  transaction time: %f us\n", inTransactionDuration / 1000.0);
@@ -5160,14 +5179,14 @@
                 mForceFullDamage = n != 0;
                 return NO_ERROR;
             }
-            case 1018: { // Modify Choreographer's phase offset
+            case 1018: { // Modify Choreographer's duration
                 n = data.readInt32();
-                mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
+                mScheduler->setDuration(mAppConnectionHandle, std::chrono::nanoseconds(n), 0ns);
                 return NO_ERROR;
             }
-            case 1019: { // Modify SurfaceFlinger's phase offset
+            case 1019: { // Modify SurfaceFlinger's duration
                 n = data.readInt32();
-                mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
+                mScheduler->setDuration(mSfConnectionHandle, std::chrono::nanoseconds(n), 0ns);
                 return NO_ERROR;
             }
             case 1020: { // Layer updates interceptor
@@ -5474,7 +5493,7 @@
 }
 
 status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
-                                        ScreenCaptureResults& captureResults) {
+                                        const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
     status_t validate = validateScreenshotPermissions(args);
@@ -5512,8 +5531,12 @@
     auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) {
         traverseLayersInLayerStack(layerStack, args.uid, visitor);
     };
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, captureResults);
+    ScreenCaptureResults captureResults;
+    status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+                                          args.pixelFormat, captureResults);
+    captureResults.result = status;
+    captureListener->onScreenCaptureComplete(captureResults);
+    return status;
 }
 
 status_t SurfaceFlinger::setSchedFifo(bool enabled) {
@@ -5556,7 +5579,7 @@
 }
 
 status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
-                                        ScreenCaptureResults& captureResults) {
+                                        const sp<IScreenCaptureListener>& captureListener) {
     ui::LayerStack layerStack;
     wp<DisplayDevice> displayWeak;
     ui::Size size;
@@ -5577,8 +5600,7 @@
     }
 
     RenderAreaFuture renderAreaFuture = promise::defer([=] {
-        return DisplayRenderArea::create(displayWeak, Rect(), size,
-                                         captureResults.capturedDataspace,
+        return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace,
                                          false /* useIdentityTransform */,
                                          false /* captureSecureLayers */);
     });
@@ -5587,12 +5609,16 @@
         traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
-                               ui::PixelFormat::RGBA_8888, captureResults);
+    ScreenCaptureResults captureResults;
+    status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+                                          ui::PixelFormat::RGBA_8888, captureResults);
+    captureResults.result = status;
+    captureListener->onScreenCaptureComplete(captureResults);
+    return status;
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
-                                       ScreenCaptureResults& captureResults) {
+                                       const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
     status_t validate = validateScreenshotPermissions(args);
@@ -5701,8 +5727,12 @@
         });
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, captureResults);
+    ScreenCaptureResults captureResults;
+    status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+                                          args.pixelFormat, captureResults);
+    captureResults.result = status;
+    captureListener->onScreenCaptureComplete(captureResults);
+    return status;
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 24837b8..fb79989 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -183,8 +183,15 @@
                        private HWC2::ComposerCallback,
                        private ISchedulerCallback {
 public:
-    SurfaceFlingerBE& getBE() { return mBE; }
-    const SurfaceFlingerBE& getBE() const { return mBE; }
+    struct SkipInitializationTag {};
+
+    SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
+    explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
+
+    // set main thread scheduling policy
+    static status_t setSchedFifo(bool enabled) ANDROID_API;
+
+    static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
 
     // This is the phase offset in nanoseconds of the software vsync event
     // relative to the vsync event reported by HWComposer.  The software vsync
@@ -263,17 +270,7 @@
     // overhead that is caused by reading from sysprop.
     static bool useFrameRateApi;
 
-    // set main thread scheduling policy
-    static status_t setSchedFifo(bool enabled) ANDROID_API;
-
-    static char const* getServiceName() ANDROID_API {
-        return "SurfaceFlinger";
-    }
-
-    struct SkipInitializationTag {};
     static constexpr SkipInitializationTag SkipInitialization;
-    SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
-    explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
 
     // must be called before clients can connect
     void init() ANDROID_API;
@@ -281,6 +278,9 @@
     // starts SurfaceFlinger main loop in the current thread
     void run() ANDROID_API;
 
+    SurfaceFlingerBE& getBE() { return mBE; }
+    const SurfaceFlingerBE& getBE() const { return mBE; }
+
     // Schedule an asynchronous or synchronous task on the main thread.
     template <typename F, typename T = std::invoke_result_t<F>>
     [[nodiscard]] std::future<T> schedule(F&&);
@@ -334,6 +334,24 @@
     bool mDisableClientCompositionCache = false;
     void setInputWindowsFinished();
 
+protected:
+    // We're reference counted, never destroy SurfaceFlinger directly
+    virtual ~SurfaceFlinger();
+
+    virtual uint32_t setClientStateLocked(
+            const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime,
+            bool privileged,
+            std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
+            REQUIRES(mStateLock);
+    virtual void commitTransactionLocked();
+
+    // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
+    // root layers on a particular display in layer-coordinate space. The
+    // layers (and effectively their children) will be clipped against this
+    // rectangle. The base behavior is to clip to the visible region of the
+    // display.
+    virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const;
+
 private:
     friend class BufferLayer;
     friend class BufferQueueLayer;
@@ -349,21 +367,18 @@
     friend class TestableSurfaceFlinger;
     friend class TransactionApplicationTest;
 
+    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
+    using VsyncModulator = scheduler::VsyncModulator;
+    using TransactionSchedule = scheduler::TransactionSchedule;
+    using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
+    using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
+    using DumpArgs = Vector<String16>;
+    using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
+
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
 
-    static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
-
-protected:
-    // We're reference counted, never destroy SurfaceFlinger directly
-    virtual ~SurfaceFlinger();
-
-private:
-    /* ------------------------------------------------------------------------
-     * Internal data structures
-     */
-
     class State {
     public:
         explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
@@ -395,29 +410,111 @@
         void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
     };
 
-    /* ------------------------------------------------------------------------
-     * IBinder interface
-     */
+    struct ActiveConfigInfo {
+        HwcConfigIndexType configId;
+        Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None;
+
+        bool operator!=(const ActiveConfigInfo& other) const {
+            return configId != other.configId || event != other.event;
+        }
+    };
+
+    enum class BootStage {
+        BOOTLOADER,
+        BOOTANIMATION,
+        FINISHED,
+    };
+
+    struct HotplugEvent {
+        hal::HWDisplayId hwcDisplayId;
+        hal::Connection connection = hal::Connection::INVALID;
+    };
+
+    struct TransactionState {
+        TransactionState(const Vector<ComposerState>& composerStates,
+                         const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+                         int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+                         int64_t postTime, bool privileged, bool hasListenerCallbacks,
+                         std::vector<ListenerCallbacks> listenerCallbacks, int originPID,
+                         int originUID)
+              : states(composerStates),
+                displays(displayStates),
+                flags(transactionFlags),
+                desiredPresentTime(desiredPresentTime),
+                buffer(uncacheBuffer),
+                postTime(postTime),
+                privileged(privileged),
+                hasListenerCallbacks(hasListenerCallbacks),
+                listenerCallbacks(listenerCallbacks),
+                originPID(originPID),
+                originUID(originUID) {}
+
+        Vector<ComposerState> states;
+        Vector<DisplayState> displays;
+        uint32_t flags;
+        const int64_t desiredPresentTime;
+        client_cache_t buffer;
+        const int64_t postTime;
+        bool privileged;
+        bool hasListenerCallbacks;
+        std::vector<ListenerCallbacks> listenerCallbacks;
+        int originPID;
+        int originUID;
+    };
+
+    template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
+    static Dumper dumper(F&& dump) {
+        using namespace std::placeholders;
+        return std::bind(std::forward<F>(dump), _3);
+    }
+
+    template <typename F, std::enable_if_t<std::is_member_function_pointer_v<F>>* = nullptr>
+    Dumper dumper(F dump) {
+        using namespace std::placeholders;
+        return std::bind(dump, this, _3);
+    }
+
+    template <typename F>
+    Dumper argsDumper(F dump) {
+        using namespace std::placeholders;
+        return std::bind(dump, this, _1, _3);
+    }
+
+    template <typename F>
+    Dumper protoDumper(F dump) {
+        using namespace std::placeholders;
+        return std::bind(dump, this, _1, _2, _3);
+    }
+
+    template <typename... Args,
+              typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
+    void modulateVsync(Handler handler, Args... args) {
+        if (const auto config = (*mVsyncModulator.*handler)(args...)) {
+            setVsyncConfig(*config);
+        }
+    }
+
+    static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
+
+    // Implements IBinder.
     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
     status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
     bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
             EXCLUDES(mStateLock);
 
-    /* ------------------------------------------------------------------------
-     * ISurfaceComposer interface
-     */
+    // Implements ISurfaceComposer
     sp<ISurfaceComposerClient> createConnection() override;
     sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
     void destroyDisplay(const sp<IBinder>& displayToken) override;
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
-    void setTransactionState(const Vector<ComposerState>& state,
-                             const Vector<DisplayState>& displays, uint32_t flags,
-                             const sp<IBinder>& applyToken,
-                             const InputWindowCommands& inputWindowCommands,
-                             int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
-                             bool hasListenerCallbacks,
-                             const std::vector<ListenerCallbacks>& listenerCallbacks) override;
+    status_t setTransactionState(const Vector<ComposerState>& state,
+                                 const Vector<DisplayState>& displays, uint32_t flags,
+                                 const sp<IBinder>& applyToken,
+                                 const InputWindowCommands& inputWindowCommands,
+                                 int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+                                 bool hasListenerCallbacks,
+                                 const std::vector<ListenerCallbacks>& listenerCallbacks) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -427,11 +524,11 @@
             ISurfaceComposer::ConfigChanged configChanged =
                     ISurfaceComposer::eConfigChangedSuppress) override;
     status_t captureDisplay(const DisplayCaptureArgs& args,
-                            ScreenCaptureResults& captureResults) override;
+                            const sp<IScreenCaptureListener>& captureListener) override;
     status_t captureDisplay(uint64_t displayOrLayerStack,
-                            ScreenCaptureResults& captureResults) override;
+                            const sp<IScreenCaptureListener>& captureListener) override;
     status_t captureLayers(const LayerCaptureArgs& args,
-                           ScreenCaptureResults& captureResults) override;
+                           const sp<IScreenCaptureListener>& captureListener) override;
 
     status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
     status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) override;
@@ -495,17 +592,14 @@
     status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
                           int8_t compatibility) override;
     status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override;
-    /* ------------------------------------------------------------------------
-     * DeathRecipient interface
-     */
+
+    // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
 
-    /* ------------------------------------------------------------------------
-     * RefBase interface
-     */
+    // Implements RefBase.
     void onFirstRef() override;
 
-    /* ------------------------------------------------------------------------
+    /*
      * HWC2::ComposerCallback / HWComposer::EventHandler interface
      */
     void onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, int64_t timestamp,
@@ -518,7 +612,7 @@
             const hal::VsyncPeriodChangeTimeline& updatedTimeline) override;
     void onSeamlessPossible(int32_t sequenceId, hal::HWDisplayId display) override;
 
-    /* ------------------------------------------------------------------------
+    /*
      * ISchedulerCallback
      */
 
@@ -540,7 +634,7 @@
     // Show spinner with refresh rate overlay
     bool mRefreshRateOverlaySpinner = false;
 
-    /* ------------------------------------------------------------------------
+    /*
      * Message handling
      */
     // Can only be called from the main thread or with mStateLock held
@@ -549,15 +643,6 @@
     void signalLayerUpdate();
     void signalRefresh();
 
-    struct ActiveConfigInfo {
-        HwcConfigIndexType configId;
-        Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None;
-
-        bool operator!=(const ActiveConfigInfo& other) const {
-            return configId != other.configId || event != other.event;
-        }
-    };
-
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
@@ -603,9 +688,6 @@
     void commitInputWindowCommands() REQUIRES(mStateLock);
     void updateCursorAsync();
 
-    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
-    using VsyncModulator = scheduler::VsyncModulator;
-
     void initScheduler(PhysicalDisplayId primaryDisplayId);
     void updatePhaseConfiguration(const RefreshRate&);
     void setVsyncConfig(const VsyncModulator::VsyncConfig&);
@@ -616,11 +698,9 @@
      */
     bool handlePageFlip();
 
-    /* ------------------------------------------------------------------------
+    /*
      * Transactions
      */
-    using TransactionSchedule = scheduler::TransactionSchedule;
-
     void applyTransactionState(const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
@@ -652,24 +732,7 @@
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
             REQUIRES(mStateLock);
-
-protected:
-    virtual uint32_t setClientStateLocked(
-            const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime,
-            bool privileged,
-            std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
-            REQUIRES(mStateLock);
-    virtual void commitTransactionLocked();
-
-    // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
-    // root layers on a particular display in layer-coordinate space. The
-    // layers (and effectively their children) will be clipped against this
-    // rectangle. The base behavior is to clip to the visible region of the
-    // display.
-    virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const;
-
-private:
-    /* ------------------------------------------------------------------------
+    /*
      * Layer management
      */
     status_t createLayer(const String8& name, const sp<Client>& client, uint32_t w, uint32_t h,
@@ -715,15 +778,9 @@
     // Traverse through all the layers and compute and cache its bounds.
     void computeLayerBounds();
 
-    /* ------------------------------------------------------------------------
-     * Boot animation, on/off animations and screen capture
-     */
-
+    // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
-    using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
-    using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
-
     status_t renderScreenImplLocked(const RenderArea& renderArea,
                                     TraverseLayersFunction traverseLayers,
                                     const sp<GraphicBuffer>& buffer, bool forSystem, int* outSyncFd,
@@ -739,20 +796,12 @@
     // matching ownerUid
     void traverseLayersInLayerStack(ui::LayerStack, const int32_t uid, const LayerVector::Visitor&);
 
-    sp<StartPropertySetThread> mStartPropertySetThread;
-
-    /* ------------------------------------------------------------------------
-     * Properties
-     */
     void readPersistentProperties();
 
-    /* ------------------------------------------------------------------------
-     * EGL
-     */
     size_t getMaxTextureSize() const;
     size_t getMaxViewportDims() const;
 
-    /* ------------------------------------------------------------------------
+    /*
      * Display and layer stack management
      */
     // called when starting, or restarting after system_server death
@@ -788,7 +837,7 @@
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
-    /* ------------------------------------------------------------------------
+    /*
      * H/W composer
      */
 
@@ -814,7 +863,7 @@
     // acquiring mStateLock.
     HWComposer& getHwComposer() const;
 
-    /* ------------------------------------------------------------------------
+    /*
      * Compositing
      */
     void invalidateHwcGeometry();
@@ -828,7 +877,7 @@
 
     void postFrame();
 
-    /* ------------------------------------------------------------------------
+    /*
      * Display management
      */
     sp<DisplayDevice> setupNewDisplayDeviceInternal(
@@ -848,7 +897,7 @@
 
     void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
 
-    /* ------------------------------------------------------------------------
+    /*
      * VSYNC
      */
     nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
@@ -912,33 +961,6 @@
     /*
      * Debugging & dumpsys
      */
-    using DumpArgs = Vector<String16>;
-    using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
-
-    template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
-    static Dumper dumper(F&& dump) {
-        using namespace std::placeholders;
-        return std::bind(std::forward<F>(dump), _3);
-    }
-
-    template <typename F, std::enable_if_t<std::is_member_function_pointer_v<F>>* = nullptr>
-    Dumper dumper(F dump) {
-        using namespace std::placeholders;
-        return std::bind(dump, this, _3);
-    }
-
-    template <typename F>
-    Dumper argsDumper(F dump) {
-        using namespace std::placeholders;
-        return std::bind(dump, this, _1, _3);
-    }
-
-    template <typename F>
-    Dumper protoDumper(F dump) {
-        using namespace std::placeholders;
-        return std::bind(dump, this, _1, _2, _3);
-    }
-
     void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
 
     void appendSfConfigString(std::string& result) const;
@@ -982,7 +1004,7 @@
 
     void onFrameRateFlexibilityTokenReleased();
 
-    /* ------------------------------------------------------------------------
+    /*
      * VrFlinger
      */
     void resetDisplayState() REQUIRES(mStateLock);
@@ -992,10 +1014,26 @@
 
     void updateColorMatrixLocked();
 
-    /* ------------------------------------------------------------------------
-     * Attributes
+    // Verify that transaction is being called by an approved process:
+    // either AID_GRAPHICS or AID_SYSTEM.
+    status_t CheckTransactCodeCredentials(uint32_t code);
+
+    /*
+     * Generic Layer Metadata
+     */
+    const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
+
+    /*
+     * Misc
      */
 
+    std::optional<ActiveConfigInfo> getDesiredActiveConfig() EXCLUDES(mActiveConfigLock) {
+        std::lock_guard<std::mutex> lock(mActiveConfigLock);
+        if (mDesiredActiveConfigChanged) return mDesiredActiveConfig;
+        return std::nullopt;
+    }
+
+    sp<StartPropertySetThread> mStartPropertySetThread;
     surfaceflinger::Factory& mFactory;
 
     // access must be protected by mStateLock
@@ -1057,17 +1095,8 @@
     // did not change.
     bool mReusedClientComposition = false;
 
-    enum class BootStage {
-        BOOTLOADER,
-        BOOTANIMATION,
-        FINISHED,
-    };
     BootStage mBootStage = BootStage::BOOTLOADER;
 
-    struct HotplugEvent {
-        hal::HWDisplayId hwcDisplayId;
-        hal::Connection connection = hal::Connection::INVALID;
-    };
     std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock);
 
     // this may only be written from the main thread with mStateLock held
@@ -1130,40 +1159,9 @@
     uint32_t mTexturePoolSize = 0;
     std::vector<uint32_t> mTexturePool;
 
-    struct TransactionState {
-        TransactionState(const Vector<ComposerState>& composerStates,
-                         const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
-                         int64_t postTime, bool privileged, bool hasListenerCallbacks,
-                         std::vector<ListenerCallbacks> listenerCallbacks, int originPID,
-                         int originUID)
-              : states(composerStates),
-                displays(displayStates),
-                flags(transactionFlags),
-                desiredPresentTime(desiredPresentTime),
-                buffer(uncacheBuffer),
-                postTime(postTime),
-                privileged(privileged),
-                hasListenerCallbacks(hasListenerCallbacks),
-                listenerCallbacks(listenerCallbacks),
-                originPID(originPID),
-                originUID(originUID) {}
-
-        Vector<ComposerState> states;
-        Vector<DisplayState> displays;
-        uint32_t flags;
-        const int64_t desiredPresentTime;
-        client_cache_t buffer;
-        const int64_t postTime;
-        bool privileged;
-        bool hasListenerCallbacks;
-        std::vector<ListenerCallbacks> listenerCallbacks;
-        int originPID;
-        int originUID;
-    };
     std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
 
-    /* ------------------------------------------------------------------------
+    /*
      * Feature prototyping
      */
 
@@ -1172,10 +1170,6 @@
 
     std::atomic<size_t> mNumLayers = 0;
 
-    // Verify that transaction is being called by an approved process:
-    // either AID_GRAPHICS or AID_SYSTEM.
-    status_t CheckTransactCodeCredentials(uint32_t code);
-
     // to linkToDeath
     sp<IBinder> mWindowManager;
     // We want to avoid multiple calls to BOOT_FINISHED as they come in on
@@ -1206,7 +1200,7 @@
     SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
 
-    /* ------------------------------------------------------------------------
+    /*
      * Scheduler
      */
     std::unique_ptr<Scheduler> mScheduler;
@@ -1225,29 +1219,6 @@
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
 
-    template <typename... Args,
-              typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
-    void modulateVsync(Handler handler, Args... args) {
-        if (const auto config = (*mVsyncModulator.*handler)(args...)) {
-            setVsyncConfig(*config);
-        }
-    }
-
-    /* ------------------------------------------------------------------------
-     * Generic Layer Metadata
-     */
-    const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
-
-    /* ------------------------------------------------------------------------
-     * Misc
-     */
-
-    std::optional<ActiveConfigInfo> getDesiredActiveConfig() EXCLUDES(mActiveConfigLock) {
-        std::lock_guard<std::mutex> lock(mActiveConfigLock);
-        if (mDesiredActiveConfigChanged) return mDesiredActiveConfig;
-        return std::nullopt;
-    }
-
     std::mutex mActiveConfigLock;
     // This bit is set once we start setting the config. We read from this bit during the
     // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 54ce60e..2e52155 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -46,10 +46,6 @@
 
 DefaultFactory::~DefaultFactory() = default;
 
-std::unique_ptr<DispSync> DefaultFactory::createDispSync(const char* name, bool hasSyncFramework) {
-    return std::make_unique<android::impl::DispSync>(name, hasSyncFramework);
-}
-
 std::unique_ptr<HWComposer> DefaultFactory::createHWComposer(const std::string& serviceName) {
     return std::make_unique<android::impl::HWComposer>(serviceName);
 }
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 04af8b0..86e5a7a 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -26,7 +26,6 @@
 public:
     virtual ~DefaultFactory();
 
-    std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override;
     std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
     std::unique_ptr<MessageQueue> createMessageQueue() override;
     std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 784a77b..a0dd999 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -67,7 +67,6 @@
 // of each interface.
 class Factory {
 public:
-    virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) = 0;
     virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
     virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
     virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index 4e7f67d..49cf80c 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -21,12 +21,32 @@
 #include <cmath>
 #include <string>
 
+namespace std {
+template <class Rep, class Period>
+bool signbit(std::chrono::duration<Rep, Period> v) {
+    return signbit(std::chrono::duration_cast<std::chrono::nanoseconds>(v).count());
+}
+} // namespace std
+
 namespace android {
 
+namespace {
+template <typename T>
+int64_t to_int64(T v) {
+    return int64_t(v);
+}
+
+template <class Rep, class Period>
+int64_t to_int64(std::chrono::duration<Rep, Period> v) {
+    return int64_t(v.count());
+}
+} // namespace
+
 template <typename T>
 class TracedOrdinal {
 public:
-    static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()),
+    static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()) ||
+                          std::is_same<std::chrono::nanoseconds, T>(),
                   "Type is not supported. Please test it with systrace before adding "
                   "it to the list.");
 
@@ -57,12 +77,12 @@
         }
 
         if (!std::signbit(mData)) {
-            ATRACE_INT64(mName.c_str(), int64_t(mData));
+            ATRACE_INT64(mName.c_str(), to_int64(mData));
             if (mHasGoneNegative) {
                 ATRACE_INT64(mNameNegative.c_str(), 0);
             }
         } else {
-            ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
+            ATRACE_INT64(mNameNegative.c_str(), -to_int64(mData));
             ATRACE_INT64(mName.c_str(), 0);
         }
     }
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 41d6d08..f3f5626 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -193,8 +193,8 @@
 
     uint32 surface_inset = 5;
     bool visible = 6;
-    bool can_receive_keys = 7;
-    bool has_focus = 8;
+    bool can_receive_keys = 7  [deprecated=true];
+    bool focusable = 8;
     bool has_wallpaper = 9;
 
     float global_scale_factor = 10;
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 10a517e..5128394 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -1,3 +1,23 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gtest/gtest.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerDebugInfo.h>
@@ -7,8 +27,8 @@
 #include <private/gui/ComposerService.h>
 #include <ui/DisplayConfig.h>
 #include <utils/String8.h>
-
 #include <functional>
+#include "utils/ScreenshotUtils.h"
 
 namespace android {
 
@@ -262,7 +282,7 @@
         DisplayCaptureArgs captureArgs;
         captureArgs.displayToken = display;
         ScreenCaptureResults captureResults;
-        return ScreenshotClient::captureDisplay(captureArgs, captureResults);
+        return ScreenCapture::captureDisplay(captureArgs, captureResults);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
@@ -276,7 +296,7 @@
         captureArgs.sourceCrop = {0, 0, 1, 1};
 
         ScreenCaptureResults captureResults;
-        return ScreenshotClient::captureLayers(captureArgs, captureResults);
+        return ScreenCapture::captureLayers(captureArgs, captureResults);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 300e9c7..cfec0d2 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <binder/Binder.h>
 
 #include <gtest/gtest.h>
@@ -22,6 +26,7 @@
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
 #include <ui/Rect.h>
+#include "utils/ScreenshotUtils.h"
 
 namespace android {
 namespace {
@@ -56,13 +61,11 @@
 }
 
 TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
     LayerCaptureArgs args;
     args.layerHandle = mNotSc->getHandle();
 
     ScreenCaptureResults captureResults;
-    ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(args, captureResults));
+    ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index 785c2c3..e66df4a 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -83,6 +83,7 @@
     results.buffer = new GraphicBuffer(100, 200, PIXEL_FORMAT_RGBA_8888, 1, 0);
     results.capturedSecureLayers = true;
     results.capturedDataspace = ui::Dataspace::DISPLAY_P3;
+    results.result = BAD_VALUE;
 
     Parcel p;
     results.write(p);
@@ -98,6 +99,7 @@
     ASSERT_EQ(results.buffer->getPixelFormat(), results2.buffer->getPixelFormat());
     ASSERT_EQ(results.capturedSecureLayers, results2.capturedSecureLayers);
     ASSERT_EQ(results.capturedDataspace, results2.capturedDataspace);
+    ASSERT_EQ(results.result, results2.result);
 }
 
 } // namespace test
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index e3b9489..ab74c50 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -167,7 +167,6 @@
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
     ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
     sp<GraphicBuffer> outBuffer;
     Transaction()
             .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
@@ -177,11 +176,12 @@
     args.displayToken = mDisplay;
 
     ScreenCaptureResults captureResults;
-    ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(args, captureResults));
+    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
 
     Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
-    ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, captureResults));
+    ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults));
 }
+
 TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 690f758..962a0cf 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -84,14 +84,13 @@
 
     Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);
 
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
-    ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
 
     UIDFaker f(AID_SYSTEM);
 
     // By default the system can capture screenshots with secure layers but they
     // will be blacked out
-    ASSERT_EQ(NO_ERROR, composer->captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
 
     {
         SCOPED_TRACE("as system");
@@ -104,7 +103,7 @@
     DisplayCaptureArgs args;
     args.displayToken = mDisplay;
     args.captureSecureLayers = true;
-    ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, mCaptureResults));
+    ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, mCaptureResults));
     ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
     ScreenCapture sc(mCaptureResults.buffer);
     sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
@@ -307,21 +306,17 @@
     sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
     SurfaceComposerClient::Transaction().show(child).apply(true);
 
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
     LayerCaptureArgs args;
     args.layerHandle = child->getHandle();
 
     ScreenCaptureResults captureResults;
-    ASSERT_EQ(BAD_VALUE, sf->captureLayers(args, captureResults));
+    ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults));
 }
 
 TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) {
     sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
     SurfaceComposerClient::Transaction().show(child).apply(true);
-
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     sp<GraphicBuffer> outBuffer;
 
     LayerCaptureArgs args;
@@ -329,11 +324,11 @@
     args.childrenOnly = false;
 
     ScreenCaptureResults captureResults;
-    ASSERT_EQ(BAD_VALUE, sf->captureLayers(args, captureResults));
+    ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults));
 
     TransactionUtils::fillSurfaceRGBA8(child, Color::RED);
     SurfaceComposerClient::Transaction().apply(true);
-    ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
+    ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults));
     ScreenCapture sc(captureResults.buffer);
     sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
 }
@@ -482,9 +477,8 @@
     args.layerHandle = redLayerHandle;
 
     ScreenCaptureResults captureResults;
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
-    ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(args, captureResults));
+    ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
 }
 
 TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
@@ -505,15 +499,13 @@
             .setLayer(redLayer, INT32_MAX)
             .apply();
 
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
     LayerCaptureArgs args;
     args.layerHandle = redLayerHandle;
     args.childrenOnly = false;
     ScreenCaptureResults captureResults;
 
     // Call from outside system with secure layers will result in permission denied
-    ASSERT_EQ(PERMISSION_DENIED, sf->captureLayers(args, captureResults));
+    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
 
     UIDFaker f(AID_SYSTEM);
 
@@ -551,8 +543,7 @@
 
     // From non system uid, can't request screenshot without a specified uid.
     UIDFaker f(fakeUid);
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
-    ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(captureArgs, mCaptureResults));
+    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(captureArgs, mCaptureResults));
 
     // Make screenshot request with current uid set. No layers were created with the current
     // uid so screenshot will be black.
@@ -604,8 +595,7 @@
     // From non system uid, can't request screenshot without a specified uid.
     std::unique_ptr<UIDFaker> uidFaker = std::make_unique<UIDFaker>(fakeUid);
 
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
-    ASSERT_EQ(PERMISSION_DENIED, composer->captureLayers(captureArgs, mCaptureResults));
+    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(captureArgs, mCaptureResults));
 
     // Make screenshot request with current uid set. No layers were created with the current
     // uid so screenshot will be black.
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7cc9cef..8d4aa0c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -56,6 +56,7 @@
         "RegionSamplingTest.cpp",
         "TimeStatsTest.cpp",
         "FrameTracerTest.cpp",
+        "TimerTest.cpp",
         "TransactionApplicationTest.cpp",
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index afebc40..54f4c7c 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -27,13 +27,99 @@
 
 #include "AsyncCallRecorder.h"
 #include "Scheduler/DispSyncSource.h"
-#include "mock/MockDispSync.h"
+#include "Scheduler/VSyncDispatch.h"
 
 namespace android {
 namespace {
 
 using namespace std::chrono_literals;
-using testing::Return;
+using namespace testing;
+
+class MockVSyncDispatch : public scheduler::VSyncDispatch {
+public:
+    MOCK_METHOD2(registerCallback,
+                 CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
+    MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+    MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
+    MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+
+    MockVSyncDispatch() {
+        ON_CALL(*this, registerCallback)
+                .WillByDefault(
+                        [this](std::function<void(nsecs_t, nsecs_t, nsecs_t)> const& callback,
+                               std::string) {
+                            CallbackToken token(mNextToken);
+                            mNextToken++;
+
+                            mCallbacks.emplace(token, CallbackData(callback));
+                            ALOGD("registerCallback: %zu", token.value());
+                            return token;
+                        });
+
+        ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) {
+            ALOGD("unregisterCallback: %zu", token.value());
+            mCallbacks.erase(token);
+        });
+
+        ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) {
+            ALOGD("schedule: %zu", token.value());
+            if (mCallbacks.count(token) == 0) {
+                ALOGD("schedule: callback %zu not registered", token.value());
+                return scheduler::ScheduleResult::Error;
+            }
+
+            auto& callback = mCallbacks.at(token);
+            callback.scheduled = true;
+            callback.vsyncTime = timing.earliestVsync;
+            callback.targetWakeupTime =
+                    timing.earliestVsync - timing.workDuration - timing.readyDuration;
+            ALOGD("schedule: callback %zu scheduled", token.value());
+            return scheduler::ScheduleResult::Scheduled;
+        });
+
+        ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) {
+            ALOGD("cancel: %zu", token.value());
+            if (mCallbacks.count(token) == 0) {
+                ALOGD("cancel: callback %zu is not registered", token.value());
+                return scheduler::CancelResult::Error;
+            }
+
+            auto& callback = mCallbacks.at(token);
+            callback.scheduled = false;
+            ALOGD("cancel: callback %zu cancelled", token.value());
+            return scheduler::CancelResult::Cancelled;
+        });
+    }
+
+    void triggerCallbacks() {
+        ALOGD("triggerCallbacks");
+        for (auto& [token, callback] : mCallbacks) {
+            if (callback.scheduled) {
+                ALOGD("triggerCallbacks: callback %zu", token.value());
+                callback.scheduled = false;
+                callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime);
+            } else {
+                ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value());
+            }
+        }
+    }
+
+private:
+    struct CallbackData {
+        explicit CallbackData(std::function<void(nsecs_t, nsecs_t, nsecs_t)> func)
+              : func(std::move(func)) {}
+
+        std::function<void(nsecs_t, nsecs_t, nsecs_t)> func;
+        bool scheduled = false;
+        nsecs_t vsyncTime = 0;
+        nsecs_t targetWakeupTime = 0;
+        nsecs_t readyTime = 0;
+    };
+
+    std::unordered_map<CallbackToken, CallbackData> mCallbacks;
+    size_t mNextToken;
+};
 
 class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback {
 protected:
@@ -43,15 +129,19 @@
     void createDispSync();
     void createDispSyncSource();
 
-    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
+    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+                      nsecs_t deadlineTimestamp) override;
 
-    std::unique_ptr<mock::DispSync> mDispSync;
-    std::unique_ptr<DispSyncSource> mDispSyncSource;
+    std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
+    std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
 
-    AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
+    AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder;
 
-    static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+    static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
+    static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
     static constexpr int mIterations = 100;
+    const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398};
+    const std::string mName = "DispSyncSourceTest";
 };
 
 DispSyncSourceTest::DispSyncSourceTest() {
@@ -66,20 +156,21 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) {
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+                                      nsecs_t deadlineTimestamp) {
     ALOGD("onVSyncEvent: %" PRId64, when);
 
-    mVSyncEventCallRecorder.recordCall(when);
+    mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp);
 }
 
 void DispSyncSourceTest::createDispSync() {
-    mDispSync = std::make_unique<mock::DispSync>();
+    mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
 }
 
 void DispSyncSourceTest::createDispSyncSource() {
-    createDispSync();
-    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
-                                                       "DispSyncSourceTest");
+    mDispSyncSource =
+            std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
+                                                        mReadyDuration, true, mName.c_str());
     mDispSyncSource->setCallback(this);
 }
 
@@ -89,57 +180,119 @@
 
 TEST_F(DispSyncSourceTest, createDispSync) {
     createDispSync();
-    EXPECT_TRUE(mDispSync);
+    EXPECT_TRUE(mVSyncDispatch);
 }
 
 TEST_F(DispSyncSourceTest, createDispSyncSource) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
+            .WillOnce(Return(scheduler::CancelResult::Cancelled));
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return());
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 }
 
 TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 
     // DispSyncSource starts with Vsync disabled
-    mDispSync->triggerCallback();
+    mVSyncDispatch->triggerCallbacks();
     EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
 }
 
 TEST_F(DispSyncSourceTest, waitForCallbacks) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch,
+                schedule(_, Truly([&](auto timings) {
+                             return timings.workDuration == mWorkDuration.count() &&
+                                     timings.readyDuration == mReadyDuration.count();
+                         })))
+            .Times(mIterations + 1);
+    EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 
     mDispSyncSource->setVSyncEnabled(true);
-    EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());
-
     for (int i = 0; i < mIterations; i++) {
-        mDispSync->triggerCallback();
-        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+        mVSyncDispatch->triggerCallbacks();
+        const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+        ASSERT_TRUE(callbackData.has_value());
+        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+        EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
     }
 }
 
-TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) {
+TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch,
+                schedule(_, Truly([&](auto timings) {
+                             return timings.workDuration == mWorkDuration.count() &&
+                                     timings.readyDuration == mReadyDuration.count();
+                         })))
+            .Times(1);
+
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 
     mDispSyncSource->setVSyncEnabled(true);
-    EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());
-
+    EXPECT_CALL(*mVSyncDispatch,
+                schedule(_, Truly([&](auto timings) {
+                             return timings.workDuration == mWorkDuration.count() &&
+                                     timings.readyDuration == mReadyDuration.count();
+                         })))
+            .Times(mIterations);
     for (int i = 0; i < mIterations; i++) {
-        mDispSync->triggerCallback();
-        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+        mVSyncDispatch->triggerCallbacks();
+        const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+        ASSERT_TRUE(callbackData.has_value());
+        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+        EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
     }
 
-    EXPECT_CALL(*mDispSync, getPeriod()).Times(1).WillOnce(Return(16666666));
-    mDispSyncSource->setPhaseOffset((mPhaseOffset / 2).count());
+    const auto newDuration = mWorkDuration / 2;
+    EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
+                                              return timings.workDuration == newDuration.count() &&
+                                                      timings.readyDuration == 0;
+                                          })))
+            .Times(1);
+    mDispSyncSource->setDuration(newDuration, 0ns);
 
-    EXPECT_EQ(mDispSync->getCallbackPhase(), (mPhaseOffset / 2).count());
-
+    EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
+                                              return timings.workDuration == newDuration.count() &&
+                                                      timings.readyDuration == 0;
+                                          })))
+            .Times(mIterations);
     for (int i = 0; i < mIterations; i++) {
-        mDispSync->triggerCallback();
-        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+        mVSyncDispatch->triggerCallbacks();
+        const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+        ASSERT_TRUE(callbackData.has_value());
+        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+        EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count());
     }
+
+    EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 7fade0d..b9c9fe7 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1325,8 +1325,6 @@
     // The call disable vsyncs
     EXPECT_CALL(mSchedulerCallback, setVsyncEnabled(false)).Times(1);
 
-    // The call ends any display resyncs
-    EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -3265,16 +3263,11 @@
         EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1);
         EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1);
     }
-
-    static void setupEndResyncCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mPrimaryDispSync, endResync()).Times(1);
-    }
 };
 
 struct DispSyncNotSupportedVariant {
     static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {}
 
-    static void setupEndResyncCallExpectations(DisplayTransactionTest* /* test */) {}
 };
 
 // --------------------------------------------------------------------
@@ -3326,7 +3319,6 @@
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
-        Case::DispSync::setupEndResyncCallExpectations(test);
         Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
     }
 
@@ -3389,7 +3381,6 @@
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
-        Case::DispSync::setupEndResyncCallExpectations(test);
         Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
     }
 };
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index aab6d01..ae94f16 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -46,7 +46,9 @@
 
     MOCK_METHOD1(setVSyncEnabled, void(bool));
     MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
-    MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
+    MOCK_METHOD2(setDuration,
+                 void(std::chrono::nanoseconds workDuration,
+                      std::chrono::nanoseconds readyDuration));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
@@ -74,7 +76,8 @@
                                                    ISurfaceComposer::ConfigChanged configChanged);
 
     void expectVSyncSetEnabledCallReceived(bool expectedState);
-    void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
+    void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration,
+                                            std::chrono::nanoseconds expectedReadyDuration);
     VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
     void expectInterceptCallReceived(nsecs_t expectedTimestamp);
     void expectVsyncEventReceivedByConnection(const char* name,
@@ -89,7 +92,8 @@
 
     AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
     AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
-    AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
+    AsyncCallRecorder<void (*)(std::chrono::nanoseconds, std::chrono::nanoseconds)>
+            mVSyncSetDurationCallRecorder;
     AsyncCallRecorder<void (*)()> mResyncCallRecorder;
     AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
     ConnectionEventRecorder mConnectionEventCallRecorder{0};
@@ -114,8 +118,8 @@
     EXPECT_CALL(*mVSyncSource, setCallback(_))
             .WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
 
-    EXPECT_CALL(*mVSyncSource, setPhaseOffset(_))
-            .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
+    EXPECT_CALL(*mVSyncSource, setDuration(_, _))
+            .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable()));
 
     createThread(std::move(vsyncSource));
     mConnection = createConnection(mConnectionEventCallRecorder,
@@ -159,10 +163,12 @@
     EXPECT_EQ(expectedState, std::get<0>(args.value()));
 }
 
-void EventThreadTest::expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset) {
-    auto args = mVSyncSetPhaseOffsetCallRecorder.waitForCall();
+void EventThreadTest::expectVSyncSetDurationCallReceived(
+        std::chrono::nanoseconds expectedDuration, std::chrono::nanoseconds expectedReadyDuration) {
+    auto args = mVSyncSetDurationCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
-    EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value()));
+    EXPECT_EQ(expectedDuration, std::get<0>(args.value()));
+    EXPECT_EQ(expectedReadyDuration, std::get<1>(args.value()));
 }
 
 VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
@@ -229,7 +235,7 @@
 TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) {
     EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
     EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
-    EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mVSyncSetDurationCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
@@ -258,14 +264,14 @@
 
     // Use the received callback to signal a first vsync event.
     // The interceptor should receive the event, as well as the connection.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // Use the received callback to signal a second vsync event.
     // The interceptor should receive the event, but the the connection should
     // not as it was only interested in the first.
-    mCallback->onVSyncEvent(456, 123);
+    mCallback->onVSyncEvent(456, 123, 0);
     expectInterceptCallReceived(456);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -299,7 +305,7 @@
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the second connection. The first connection should not
     // get the event.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 0);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
     expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -314,17 +320,17 @@
 
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the connection.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // A second event should go to the same places.
-    mCallback->onVSyncEvent(456, 123);
+    mCallback->onVSyncEvent(456, 123, 0);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // A third event should go to the same places.
-    mCallback->onVSyncEvent(789, 777);
+    mCallback->onVSyncEvent(789, 777, 111);
     expectInterceptCallReceived(789);
     expectVsyncEventReceivedByConnection(789, 3u);
 }
@@ -336,22 +342,22 @@
     expectVSyncSetEnabledCallReceived(true);
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
     // The second event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(456, 123);
+    mCallback->onVSyncEvent(456, 123, 0);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // The third event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(789, 777);
+    mCallback->onVSyncEvent(789, 777, 744);
     expectInterceptCallReceived(789);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
     // The fourth event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(101112, 7847);
+    mCallback->onVSyncEvent(101112, 7847, 86);
     expectInterceptCallReceived(101112);
     expectVsyncEventReceivedByConnection(101112, 4u);
 }
@@ -366,7 +372,7 @@
     mConnection = nullptr;
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -386,13 +392,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor and not by the
     // connection.
-    mCallback->onVSyncEvent(456, 123);
+    mCallback->onVSyncEvent(456, 123, 0);
     expectInterceptCallReceived(456);
     EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
 
@@ -420,7 +426,7 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
     expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
@@ -440,13 +446,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an non-fatal error.
-    mCallback->onVSyncEvent(123, 456);
+    mCallback->onVSyncEvent(123, 456, 789);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor, and by the connection,
     // which still then returns an non-fatal error.
-    mCallback->onVSyncEvent(456, 123);
+    mCallback->onVSyncEvent(456, 123, 0);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
 
@@ -455,8 +461,8 @@
 }
 
 TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) {
-    mThread->setPhaseOffset(321);
-    expectVSyncSetPhaseOffsetCallReceived(321);
+    mThread->setDuration(321ns, 456ns);
+    expectVSyncSetDurationCallReceived(321ns, 456ns);
 }
 
 TEST_F(EventThreadTest, postHotplugInternalDisconnect) {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 39e793a..35619a3 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -120,8 +120,8 @@
     mScheduler.dump(handle, output);
     EXPECT_TRUE(output.empty());
 
-    EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
-    mScheduler.setPhaseOffset(handle, 10);
+    EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(0);
+    mScheduler.setDuration(handle, 10ns, 20ns);
 }
 
 TEST_F(SchedulerTest, validConnectionHandle) {
@@ -146,8 +146,8 @@
     mScheduler.dump(mConnectionHandle, output);
     EXPECT_FALSE(output.empty());
 
-    EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
-    mScheduler.setPhaseOffset(mConnectionHandle, 10);
+    EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(1);
+    mScheduler.setDuration(mConnectionHandle, 10ns, 20ns);
 
     static constexpr size_t kEventConnections = 5;
     EXPECT_CALL(*mEventThread, getEventThreadConnectionCount()).WillOnce(Return(kEventConnections));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d78546d..ebb2d76 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -42,8 +42,7 @@
                       createLayerHistory(configs, useContentDetectionV2),
                       {.supportKernelTimer = false,
                        .useContentDetection = true,
-                       .useContentDetectionV2 = useContentDetectionV2,
-                       .useVsyncPredictor = false}) {}
+                       .useContentDetectionV2 = useContentDetectionV2}) {}
 
     // Used to inject mock event thread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index a1049d8..8c4232d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -65,10 +65,6 @@
 public:
     ~Factory() = default;
 
-    std::unique_ptr<DispSync> createDispSync(const char*, bool) override {
-        return nullptr;
-    }
-
     std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
         return nullptr;
     }
diff --git a/services/surfaceflinger/tests/unittests/TimerTest.cpp b/services/surfaceflinger/tests/unittests/TimerTest.cpp
new file mode 100644
index 0000000..cda6bbf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TimerTest.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include "AsyncCallRecorder.h"
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/Timer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+struct TimerTest : testing::Test {
+    static constexpr int mIterations = 20;
+
+    AsyncCallRecorder<void (*)()> mCallbackRecorder;
+    Timer mTimer;
+
+    void timerCallback() { mCallbackRecorder.recordCall(); }
+};
+
+TEST_F(TimerTest, callsCallbackIfScheduledInPast) {
+    for (int i = 0; i < mIterations; i++) {
+        mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00);
+        EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value());
+        EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
+    }
+}
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index c2a7752..3408fed 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -104,14 +104,18 @@
 
 class RepeatingCallbackReceiver {
 public:
-    RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl)
-          : mWorkload(wl),
+    RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t workload, nsecs_t readyDuration)
+          : mWorkload(workload),
+            mReadyDuration(readyDuration),
             mCallback(
-                    dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {}
+                    dispatch, [&](auto time, auto, auto) { callback_called(time); }, "repeat0") {}
 
     void repeatedly_schedule(size_t iterations, std::function<void(nsecs_t)> const& onEachFrame) {
         mCallbackTimes.reserve(iterations);
-        mCallback.schedule(mWorkload, systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload);
+        mCallback.schedule(
+                {.workDuration = mWorkload,
+                 .readyDuration = mReadyDuration,
+                 .earliestVsync = systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload + mReadyDuration});
 
         for (auto i = 0u; i < iterations - 1; i++) {
             std::unique_lock<decltype(mMutex)> lk(mMutex);
@@ -122,7 +126,9 @@
 
             onEachFrame(last);
 
-            mCallback.schedule(mWorkload, last + mWorkload);
+            mCallback.schedule({.workDuration = mWorkload,
+                                .readyDuration = mReadyDuration,
+                                .earliestVsync = last + mWorkload + mReadyDuration});
         }
 
         // wait for the last callback.
@@ -144,6 +150,7 @@
     }
 
     nsecs_t const mWorkload;
+    nsecs_t const mReadyDuration;
     VSyncCallbackRegistration mCallback;
 
     std::mutex mMutex;
@@ -160,9 +167,9 @@
 
     static size_t constexpr num_clients = 3;
     std::array<RepeatingCallbackReceiver, num_clients>
-            cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us)),
-                        RepeatingCallbackReceiver(dispatch, toNs(0h)),
-                        RepeatingCallbackReceiver(dispatch, toNs(1ms))};
+            cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us), toNs(2500us)),
+                        RepeatingCallbackReceiver(dispatch, toNs(0h), toNs(0h)),
+                        RepeatingCallbackReceiver(dispatch, toNs(1ms), toNs(3ms))};
 
     auto const on_each_frame = [](nsecs_t) {};
     std::array<std::thread, num_clients> threads{
@@ -187,7 +194,7 @@
     VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
                                      mVsyncMoveThreshold);
 
-    RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+    RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms), toNs(5ms));
 
     auto const on_each_frame = [&](nsecs_t last_known) {
         tracker.set_interval(next_vsync_interval += toNs(1ms), last_known);
@@ -205,7 +212,7 @@
     VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
                                      mVsyncMoveThreshold);
 
-    RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+    RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms), toNs(5ms));
 
     auto jump_frame_counter = 0u;
     auto constexpr jump_frame_at = 10u;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 373f6a5..24e243f 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -64,19 +64,19 @@
 class ControllableClock : public TimeKeeper {
 public:
     ControllableClock() {
-        ON_CALL(*this, alarmIn(_, _))
-                .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
+        ON_CALL(*this, alarmAt(_, _))
+                .WillByDefault(Invoke(this, &ControllableClock::alarmAtDefaultBehavior));
         ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
     }
 
     MOCK_CONST_METHOD0(now, nsecs_t());
-    MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
+    MOCK_METHOD2(alarmAt, void(std::function<void()> const&, nsecs_t time));
     MOCK_METHOD0(alarmCancel, void());
     MOCK_CONST_METHOD1(dump, void(std::string&));
 
-    void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+    void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
         mCallback = callback;
-        mNextCallbackTime = time + mCurrentTime;
+        mNextCallbackTime = time;
     }
 
     nsecs_t fakeTime() const { return mCurrentTime; }
@@ -109,22 +109,24 @@
     CountingCallback(VSyncDispatch& dispatch)
           : mDispatch(dispatch),
             mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
-                                                       std::placeholders::_1,
-                                                       std::placeholders::_2),
+                                                       std::placeholders::_1, std::placeholders::_2,
+                                                       std::placeholders::_3),
                                              "test")) {}
     ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
 
     operator VSyncDispatch::CallbackToken() const { return mToken; }
 
-    void counter(nsecs_t time, nsecs_t wakeup_time) {
+    void counter(nsecs_t time, nsecs_t wakeup_time, nsecs_t readyTime) {
         mCalls.push_back(time);
         mWakeupTime.push_back(wakeup_time);
+        mReadyTime.push_back(readyTime);
     }
 
     VSyncDispatch& mDispatch;
     VSyncDispatch::CallbackToken mToken;
     std::vector<nsecs_t> mCalls;
     std::vector<nsecs_t> mWakeupTime;
+    std::vector<nsecs_t> mReadyTime;
 };
 
 class PausingCallback {
@@ -192,8 +194,8 @@
         class TimeKeeperWrapper : public TimeKeeper {
         public:
             TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
-            void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
-                mControllableClock.alarmIn(callback, time);
+            void alarmAt(std::function<void()> const& callback, nsecs_t time) final {
+                mControllableClock.alarmAt(callback, time);
             }
             void alarmCancel() final { mControllableClock.alarmCancel(); }
             nsecs_t now() const final { return mControllableClock.now(); }
@@ -222,22 +224,30 @@
 };
 
 TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
     {
         VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
                                           mVsyncMoveThreshold};
         CountingCallback cb(mDispatch);
-        EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
+        EXPECT_EQ(mDispatch.schedule(cb,
+                                     {.workDuration = 100,
+                                      .readyDuration = 0,
+                                      .earliestVsync = 1000}),
+                  ScheduleResult::Scheduled);
     }
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
     auto intended = mPeriod - 230;
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
 
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 100,
+                                  .readyDuration = 0,
+                                  .earliestVsync = intended}),
+              ScheduleResult::Scheduled);
     advanceToNextCallback();
 
     ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -246,10 +256,10 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
-    EXPECT_CALL(mMockClock, alarmIn(_, 1050));
+    EXPECT_CALL(mMockClock, alarmAt(_, 1050));
 
     CountingCallback cb(mDispatch);
-    mDispatch.schedule(cb, 100, mPeriod);
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
     advanceToNextCallback();
 
     ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -262,37 +272,53 @@
     auto const workDuration = 10 * mPeriod;
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
             .WillOnce(Return(mPeriod * 11));
-    EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
+    EXPECT_CALL(mMockClock, alarmAt(_, mPeriod));
 
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = workDuration,
+                                  .readyDuration = 0,
+                                  .earliestVsync = mPeriod}),
+              ScheduleResult::Scheduled);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 100,
+                                  .readyDuration = 0,
+                                  .earliestVsync = mPeriod}),
+              ScheduleResult::Scheduled);
     EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 100,
+                                  .readyDuration = 0,
+                                  .earliestVsync = mPeriod}),
+              ScheduleResult::Scheduled);
     mMockClock.advanceBy(950);
     EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
-    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 100,
+                                  .readyDuration = 0,
+                                  .earliestVsync = mPeriod}),
+              ScheduleResult::Scheduled);
 
     std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
     EXPECT_TRUE(cb.waitForPause());
@@ -302,14 +328,18 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     auto resource = std::make_shared<int>(110);
 
     PausingCallback cb(mDispatch, 50ms);
     cb.stashResource(resource);
-    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 100,
+                                  .readyDuration = 0,
+                                  .earliestVsync = mPeriod}),
+              ScheduleResult::Scheduled);
 
     std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
     EXPECT_TRUE(cb.waitForPause());
@@ -332,15 +362,15 @@
             .WillOnce(Return(1075));
 
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 955)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 813)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 975)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 100, mPeriod);
-    mDispatch.schedule(cb1, 250, mPeriod);
+    mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
+    mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod});
 
     advanceToNextCallback();
     advanceToNextCallback();
@@ -360,53 +390,54 @@
             .WillOnce(Return(10000));
 
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 750)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 100, mPeriod * 10);
-    mDispatch.schedule(cb1, 250, mPeriod);
+    mDispatch.schedule(cb0,
+                       {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod * 10});
+    mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod});
     mDispatch.cancel(cb1);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 700)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 400, 1000);
-    mDispatch.schedule(cb1, 200, 1000);
-    mDispatch.schedule(cb1, 300, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 300, .readyDuration = 0, .earliestVsync = 1000});
     advanceToNextCallback();
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 400, 1000);
-    mDispatch.schedule(cb1, 200, 1000);
-    mDispatch.schedule(cb1, 500, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
     advanceToNextCallback();
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1590)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
 
     auto offset = 400;
     auto closeOffset = offset + mDispatchGroupThreshold - 1;
@@ -415,9 +446,10 @@
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 400, 1000);
-    mDispatch.schedule(cb1, 200, 1000);
-    mDispatch.schedule(cb1, closeOffset, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1,
+                       {.workDuration = closeOffset, .readyDuration = 0, .earliestVsync = 1000});
 
     advanceToNextCallback();
     ASSERT_THAT(cb0.mCalls.size(), Eq(1));
@@ -425,8 +457,9 @@
     ASSERT_THAT(cb1.mCalls.size(), Eq(1));
     EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
 
-    mDispatch.schedule(cb0, 400, 2000);
-    mDispatch.schedule(cb1, notCloseOffset, 2000);
+    mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 2000});
+    mDispatch.schedule(cb1,
+                       {.workDuration = notCloseOffset, .readyDuration = 0, .earliestVsync = 2000});
     advanceToNextCallback();
     ASSERT_THAT(cb1.mCalls.size(), Eq(2));
     EXPECT_THAT(cb1.mCalls[1], Eq(2000));
@@ -437,16 +470,17 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
-    EXPECT_CALL(mMockClock, alarmIn(_, 800));
-    EXPECT_CALL(mMockClock, alarmIn(_, 100));
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 800)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
     EXPECT_CALL(mMockClock, alarmCancel());
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 100, 1000);
-    mDispatch.schedule(cb1, 200, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
     advanceToNextCallback();
     EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
 }
@@ -459,32 +493,38 @@
             .WillOnce(Return(2950));
 
     CountingCallback cb(mDispatch);
-    mDispatch.schedule(cb, 100, 920);
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 920});
 
     mMockClock.advanceBy(850);
     EXPECT_THAT(cb.mCalls.size(), Eq(1));
 
-    mDispatch.schedule(cb, 100, 1900);
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1900});
     mMockClock.advanceBy(900);
     EXPECT_THAT(cb.mCalls.size(), Eq(1));
     mMockClock.advanceBy(125);
     EXPECT_THAT(cb.mCalls.size(), Eq(2));
 
-    mDispatch.schedule(cb, 100, 2900);
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2900});
     mMockClock.advanceBy(975);
     EXPECT_THAT(cb.mCalls.size(), Eq(3));
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
 
     VSyncDispatch::CallbackToken tmp;
-    tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
-                                     "o.o");
+    tmp = mDispatch.registerCallback(
+            [&](auto, auto, auto) {
+                mDispatch.schedule(tmp,
+                                   {.workDuration = 100,
+                                    .readyDuration = 0,
+                                    .earliestVsync = 2000});
+            },
+            "o.o");
 
-    mDispatch.schedule(tmp, 100, 1000);
+    mDispatch.schedule(tmp, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
     advanceToNextCallback();
 }
 
@@ -492,17 +532,27 @@
     VSyncDispatch::CallbackToken tmp;
     std::optional<nsecs_t> lastTarget;
     tmp = mDispatch.registerCallback(
-            [&](auto timestamp, auto) {
-                EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
+            [&](auto timestamp, auto, auto) {
+                EXPECT_EQ(mDispatch.schedule(tmp,
+                                             {.workDuration = 400,
+                                              .readyDuration = 0,
+                                              .earliestVsync = timestamp - mVsyncMoveThreshold}),
                           ScheduleResult::Scheduled);
-                EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
-                EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
+                EXPECT_EQ(mDispatch.schedule(tmp,
+                                             {.workDuration = 400,
+                                              .readyDuration = 0,
+                                              .earliestVsync = timestamp}),
+                          ScheduleResult::Scheduled);
+                EXPECT_EQ(mDispatch.schedule(tmp,
+                                             {.workDuration = 400,
+                                              .readyDuration = 0,
+                                              .earliestVsync = timestamp + mVsyncMoveThreshold}),
                           ScheduleResult::Scheduled);
                 lastTarget = timestamp;
             },
             "oo");
 
-    mDispatch.schedule(tmp, 999, 1000);
+    mDispatch.schedule(tmp, {.workDuration = 999, .readyDuration = 0, .earliestVsync = 1000});
     advanceToNextCallback();
     EXPECT_THAT(lastTarget, Eq(1000));
 
@@ -512,40 +562,40 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 950)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1950)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
 
     CountingCallback cb(mDispatch);
-    mDispatch.schedule(cb, 0, 1000);
+    mDispatch.schedule(cb, {.workDuration = 0, .readyDuration = 0, .earliestVsync = 1000});
 
     mMockClock.advanceBy(750);
-    mDispatch.schedule(cb, 50, 1000);
+    mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 1000});
 
     advanceToNextCallback();
-    mDispatch.schedule(cb, 50, 2000);
+    mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 2000});
 
     mMockClock.advanceBy(800);
-    mDispatch.schedule(cb, 100, 2000);
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 850)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1800)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
 
-    mDispatch.schedule(cb0, 500, 1000);
-    mDispatch.schedule(cb1, 100, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
 
     advanceToNextCallback();
-    mDispatch.schedule(cb0, 200, 2000);
-    mDispatch.schedule(cb1, 150, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 2000});
+    mDispatch.schedule(cb1, {.workDuration = 150, .readyDuration = 0, .earliestVsync = 1000});
 
     advanceToNextCallback();
     advanceToNextCallback();
@@ -553,46 +603,58 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
-    mDispatch.schedule(cb0, 500, 1000);
-    mDispatch.schedule(cb1, 500, 20000);
+    mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
+    mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 20000});
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
-    mDispatch.schedule(cb0, 500, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
     mDispatch.cancel(cb0);
-    mDispatch.schedule(cb0, 100, 1000);
+    mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
     VSyncDispatch::CallbackToken token(100);
-    EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
+    EXPECT_THAT(mDispatch.schedule(token,
+                                   {.workDuration = 100,
+                                    .readyDuration = 0,
+                                    .earliestVsync = 1000}),
+                Eq(ScheduleResult::Error));
     EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
     CountingCallback cb0(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
-    EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0,
+                                 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0,
+                                 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 }
 
 // b/1450138150
 TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 500));
+    EXPECT_CALL(mMockClock, alarmAt(_, 500));
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
     mMockClock.advanceBy(400);
 
-    EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
     advanceToNextCallback();
     ASSERT_THAT(cb.mCalls.size(), Eq(1));
 }
@@ -603,83 +665,103 @@
             .WillOnce(Return(1000))
             .WillOnce(Return(1002));
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
     mMockClock.advanceBy(400);
-    EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
     CountingCallback cb0(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0,
+                                 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
     advanceToNextCallback();
-    EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0,
+                                 {.workDuration = 1100, .readyDuration = 0, .earliestVsync = 2000}),
+              ScheduleResult::Scheduled);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq);
     CountingCallback cb0(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0,
+                                 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
     advanceToNextCallback();
-    EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0,
+                                 {.workDuration = 1900, .readyDuration = 0, .earliestVsync = 2000}),
+              ScheduleResult::Scheduled);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 600));
+    EXPECT_CALL(mMockClock, alarmAt(_, 600));
 
     CountingCallback cb(mDispatch);
-    EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 
-    EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 
     advanceToNextCallback();
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
 
     VSyncCallbackRegistration cb(
-            mDispatch, [](auto, auto) {}, "");
+            mDispatch, [](auto, auto, auto) {}, "");
     VSyncCallbackRegistration cb1(std::move(cb));
-    cb.schedule(100, 1000);
+    cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
     cb.cancel();
 
-    cb1.schedule(500, 1000);
+    cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
     cb1.cancel();
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
 
     VSyncCallbackRegistration cb(
-            mDispatch, [](auto, auto) {}, "");
+            mDispatch, [](auto, auto, auto) {}, "");
     VSyncCallbackRegistration cb1(
-            mDispatch, [](auto, auto) {}, "");
+            mDispatch, [](auto, auto, auto) {}, "");
     cb1 = std::move(cb);
-    cb.schedule(100, 1000);
+    cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
     cb.cancel();
 
-    cb1.schedule(500, 1000);
+    cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
     cb1.cancel();
 }
 
 // b/154303580
 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1200)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
     CountingCallback cb1(mDispatch);
     CountingCallback cb2(mDispatch);
 
-    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb1,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 
     mMockClock.setLag(100);
     mMockClock.advanceBy(620);
 
-    EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2,
+                                 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}),
+              ScheduleResult::Scheduled);
     mMockClock.advanceBy(80);
 
     EXPECT_THAT(cb1.mCalls.size(), Eq(1));
@@ -691,16 +773,20 @@
 // update later, as opposed to blocking the calling thread.
 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 930)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
     CountingCallback cb(mDispatch);
 
-    EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 
     mMockClock.setLag(100);
     mMockClock.advanceBy(620);
 
-    EXPECT_EQ(mDispatch.schedule(cb, 370, 2000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 370, .readyDuration = 0, .earliestVsync = 2000}),
+              ScheduleResult::Scheduled);
     mMockClock.advanceBy(80);
 
     EXPECT_THAT(cb.mCalls.size(), Eq(1));
@@ -709,13 +795,17 @@
 // b/154303580.
 TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 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);
+    EXPECT_EQ(mDispatch.schedule(cb1,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2,
+                                 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}),
+              ScheduleResult::Scheduled);
 
     mMockClock.setLag(100);
     mMockClock.advanceBy(620);
@@ -730,14 +820,18 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).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);
+    EXPECT_EQ(mDispatch.schedule(cb1,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2,
+                                 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}),
+              ScheduleResult::Scheduled);
 
     mMockClock.setLag(100);
     mMockClock.advanceBy(620);
@@ -760,21 +854,49 @@
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
             .InSequence(seq)
             .WillOnce(Return(1000));
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
             .InSequence(seq)
             .WillOnce(Return(1000));
 
-    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
-    EXPECT_EQ(mDispatch.schedule(cb2, 390, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb1,
+                                 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2,
+                                 {.workDuration = 390, .readyDuration = 0, .earliestVsync = 1000}),
+              ScheduleResult::Scheduled);
 
     mMockClock.setLag(100);
     mMockClock.advanceBy(700);
 
     ASSERT_THAT(cb1.mWakeupTime.size(), Eq(1));
     EXPECT_THAT(cb1.mWakeupTime[0], Eq(600));
+    ASSERT_THAT(cb1.mReadyTime.size(), Eq(1));
+    EXPECT_THAT(cb1.mReadyTime[0], Eq(1000));
     ASSERT_THAT(cb2.mWakeupTime.size(), Eq(1));
     EXPECT_THAT(cb2.mWakeupTime[0], Eq(610));
+    ASSERT_THAT(cb2.mReadyTime.size(), Eq(1));
+    EXPECT_THAT(cb2.mReadyTime[0], Eq(1000));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithReadyDuration) {
+    auto intended = mPeriod - 230;
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
+
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb,
+                                 {.workDuration = 70,
+                                  .readyDuration = 30,
+                                  .earliestVsync = intended}),
+              ScheduleResult::Scheduled);
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
+    ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
+    EXPECT_THAT(cb.mWakeupTime[0], 900);
+    ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
+    EXPECT_THAT(cb.mReadyTime[0], 970);
 }
 
 class VSyncDispatchTimerQueueEntryTest : public testing::Test {
@@ -787,7 +909,7 @@
 TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
     std::string name("basicname");
     VSyncDispatchTimerQueueEntry entry(
-            name, [](auto, auto) {}, mVsyncMoveThreshold);
+            name, [](auto, auto, auto) {}, mVsyncMoveThreshold);
     EXPECT_THAT(entry.name(), Eq(name));
     EXPECT_FALSE(entry.lastExecutedVsyncTarget());
     EXPECT_FALSE(entry.wakeupTime());
@@ -795,10 +917,12 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
 
     EXPECT_FALSE(entry.wakeupTime());
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     auto const wakeup = entry.wakeupTime();
     ASSERT_TRUE(wakeup);
     EXPECT_THAT(*wakeup, Eq(900));
@@ -815,10 +939,12 @@
             .Times(1)
             .WillOnce(Return(10000));
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
 
     EXPECT_FALSE(entry.wakeupTime());
-    EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 994},
+                               mStubTracker, now),
+                Eq(ScheduleResult::Scheduled));
     auto const wakeup = entry.wakeupTime();
     ASSERT_TRUE(wakeup);
     EXPECT_THAT(*wakeup, Eq(9500));
@@ -828,21 +954,29 @@
     auto callCount = 0;
     auto vsyncCalledTime = 0;
     auto wakeupCalledTime = 0;
+    auto readyCalledTime = 0;
     VSyncDispatchTimerQueueEntry entry(
             "test",
-            [&](auto vsyncTime, auto wakeupTime) {
+            [&](auto vsyncTime, auto wakeupTime, auto readyTime) {
                 callCount++;
                 vsyncCalledTime = vsyncTime;
                 wakeupCalledTime = wakeupTime;
+                readyCalledTime = readyTime;
             },
             mVsyncMoveThreshold);
 
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     auto const wakeup = entry.wakeupTime();
     ASSERT_TRUE(wakeup);
     EXPECT_THAT(*wakeup, Eq(900));
 
-    entry.callback(entry.executing(), *wakeup);
+    auto const ready = entry.readyTime();
+    ASSERT_TRUE(ready);
+    EXPECT_THAT(*ready, Eq(1000));
+
+    entry.callback(entry.executing(), *wakeup, *ready);
 
     EXPECT_THAT(callCount, Eq(1));
     EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
@@ -860,13 +994,15 @@
             .WillOnce(Return(1020));
 
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
 
     EXPECT_FALSE(entry.wakeupTime());
     entry.update(mStubTracker, 0);
     EXPECT_FALSE(entry.wakeupTime());
 
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     auto wakeup = entry.wakeupTime();
     ASSERT_TRUE(wakeup);
     EXPECT_THAT(wakeup, Eq(900));
@@ -879,8 +1015,10 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     entry.update(mStubTracker, 0);
 
     auto const wakeup = entry.wakeupTime();
@@ -890,24 +1028,35 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     entry.executing(); // 1000 is executing
     // had 1000 not been executing, this could have been scheduled for time 800.
-    EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+    EXPECT_THAT(*entry.readyTime(), Eq(2000));
 
-    EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
+    EXPECT_THAT(*entry.readyTime(), Eq(2000));
 
-    EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 1001},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
     EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+    EXPECT_THAT(*entry.readyTime(), Eq(2000));
 }
 
 TEST_F(VSyncDispatchTimerQueueEntryTest,
        willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
 
     Sequence seq;
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
@@ -920,35 +1069,85 @@
             .InSequence(seq)
             .WillOnce(Return(2000));
 
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
 
     entry.executing(); // 1000 is executing
 
-    EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
 }
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
-    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
-    EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
-    EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
-    EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule({.workDuration = 1200, .readyDuration = 0, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
 }
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
     static constexpr auto effectualOffset = 200;
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
     EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
-    entry.addPendingWorkloadUpdate(100, 400);
-    entry.addPendingWorkloadUpdate(effectualOffset, 700);
+    entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .earliestVsync = 400});
+    entry.addPendingWorkloadUpdate(
+            {.workDuration = effectualOffset, .readyDuration = 0, .earliestVsync = 400});
     EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
     entry.update(mStubTracker, 0);
     EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
     EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
 }
 
+TEST_F(VSyncDispatchTimerQueueEntryTest, runCallbackWithReadyDuration) {
+    auto callCount = 0;
+    auto vsyncCalledTime = 0;
+    auto wakeupCalledTime = 0;
+    auto readyCalledTime = 0;
+    VSyncDispatchTimerQueueEntry entry(
+            "test",
+            [&](auto vsyncTime, auto wakeupTime, auto readyTime) {
+                callCount++;
+                vsyncCalledTime = vsyncTime;
+                wakeupCalledTime = wakeupTime;
+                readyCalledTime = readyTime;
+            },
+            mVsyncMoveThreshold);
+
+    EXPECT_THAT(entry.schedule({.workDuration = 70, .readyDuration = 30, .earliestVsync = 500},
+                               mStubTracker, 0),
+                Eq(ScheduleResult::Scheduled));
+    auto const wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(*wakeup, Eq(900));
+
+    auto const ready = entry.readyTime();
+    ASSERT_TRUE(ready);
+    EXPECT_THAT(*ready, Eq(970));
+
+    entry.callback(entry.executing(), *wakeup, *ready);
+
+    EXPECT_THAT(callCount, Eq(1));
+    EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
+    EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
+    EXPECT_FALSE(entry.wakeupTime());
+    auto lastCalledTarget = entry.lastExecutedVsyncTarget();
+    ASSERT_TRUE(lastCalledTarget);
+    EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
+}
+
 } // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index c5cddf3..0eae01e 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -63,9 +63,9 @@
 class MockVSyncDispatch : public VSyncDispatch {
 public:
     MOCK_METHOD2(registerCallback,
-                 CallbackToken(std::function<void(nsecs_t, nsecs_t)> const&, std::string));
+                 CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
     MOCK_METHOD1(unregisterCallback, void(CallbackToken));
-    MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
+    MOCK_METHOD2(schedule, ScheduleResult(CallbackToken, ScheduleTiming));
     MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
@@ -92,35 +92,17 @@
     return ft;
 }
 
-class StubCallback : public DispSync::Callback {
-public:
-    void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
-        std::lock_guard<std::mutex> lk(mMutex);
-        mLastCallTime = when;
-    }
-    std::optional<nsecs_t> lastCallTime() const {
-        std::lock_guard<std::mutex> lk(mMutex);
-        return mLastCallTime;
-    }
-
-private:
-    std::mutex mutable mMutex;
-    std::optional<nsecs_t> mLastCallTime GUARDED_BY(mMutex);
-};
-
 class VSyncReactorTest : public testing::Test {
 protected:
     VSyncReactorTest()
-          : mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
-            mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
+          : mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
             mMockClock(std::make_shared<NiceMock<MockClock>>()),
-            mReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
-                     kPendingLimit, false /* supportKernelIdleTimer */) {
+            mReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockTracker, kPendingLimit,
+                     false /* supportKernelIdleTimer */) {
         ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
         ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
     }
 
-    std::shared_ptr<MockVSyncDispatch> mMockDispatch;
     std::shared_ptr<MockVSyncTracker> mMockTracker;
     std::shared_ptr<MockClock> mMockClock;
     static constexpr size_t kPendingLimit = 3;
@@ -135,7 +117,7 @@
     VSyncDispatch::CallbackToken const mFakeToken{2398};
 
     nsecs_t lastCallbackTime = 0;
-    StubCallback outerCb;
+    // StubCallback outerCb;
     std::function<void(nsecs_t, nsecs_t)> innerCb;
 
     VSyncReactor mReactor;
@@ -489,192 +471,6 @@
     EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
 }
 
-static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
-    return period - phase;
-}
-
-TEST_F(VSyncReactorTest, addEventListener) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(Return(mFakeToken));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    mReactor.removeEventListener(&outerCb, &lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(Return(mFakeToken));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch,
-                schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch,
-                schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
-            .Times(2)
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    ASSERT_TRUE(innerCb);
-    innerCb(mFakeVSyncTime, mFakeWakeupTime);
-    innerCb(mFakeVSyncTime, mFakeWakeupTime);
-}
-
-TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
-            .InSequence(seq)
-            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch,
-                schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
-            .InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    ASSERT_TRUE(innerCb);
-    innerCb(mFakeVSyncTime, mFakeWakeupTime);
-    EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime));
-}
-
-TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(Return(mFakeToken));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-}
-
-// b/149221293
-TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) {
-    class SelfRemovingCallback : public DispSync::Callback {
-    public:
-        SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {}
-        void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
-            mVsr.removeEventListener(this, &when);
-        }
-
-    private:
-        VSyncReactor& mVsr;
-    } selfRemover(mReactor);
-
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime);
-    innerCb(0, 0);
-}
-
-TEST_F(VSyncReactorTest, addEventListenerChangePeriod) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(Return(mFakeToken));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch,
-                schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) {
-    static constexpr nsecs_t anotherPeriod = 23333;
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(Return(mFakeToken));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
-            .InSequence(seq);
-    EXPECT_CALL(*mMockTracker, setPeriod(anotherPeriod));
-    EXPECT_CALL(*mMockDispatch,
-                schedule(mFakeToken, computeWorkload(anotherPeriod, mPhase), mFakeNow))
-            .InSequence(seq);
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-
-    bool periodFlushed = false;
-    mReactor.setPeriod(anotherPeriod);
-    EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed));
-    EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed));
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) {
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _))
-            .InSequence(seq)
-            .WillOnce(Return(ScheduleResult::Scheduled));
-
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
-            .InSequence(seq)
-            .WillOnce(Return(ScheduleResult::Scheduled));
-
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
-            .InSequence(seq)
-            .WillOnce(Return(ScheduleResult::Scheduled));
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
-    ASSERT_TRUE(innerCb);
-    innerCb(mFakeVSyncTime, mFakeWakeupTime);
-}
-
-TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
-    nsecs_t const negativePhase = -4000;
-    Sequence seq;
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .InSequence(seq)
-            .WillOnce(Return(mFakeToken));
-    EXPECT_CALL(*mMockDispatch,
-                schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow))
-            .InSequence(seq);
-    mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
-}
-
 TEST_F(VSyncReactorTest, beginResyncResetsModel) {
     EXPECT_CALL(*mMockTracker, resetModel());
     mReactor.beginResync();
@@ -700,9 +496,8 @@
 
 TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) {
     // Create a reactor which supports the kernel idle timer
-    auto idleReactor =
-            VSyncReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
-                         kPendingLimit, true /* supportKernelIdleTimer */);
+    auto idleReactor = VSyncReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockTracker,
+                                    kPendingLimit, true /* supportKernelIdleTimer */);
 
     bool periodFlushed = true;
     EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(4);
@@ -734,42 +529,4 @@
     EXPECT_TRUE(idleReactor.addPresentFence(generateSignalledFenceWithTime(0)));
 }
 
-using VSyncReactorDeathTest = VSyncReactorTest;
-TEST_F(VSyncReactorDeathTest, invalidRemoval) {
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    mReactor.removeEventListener(&outerCb, &lastCallbackTime);
-    EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*");
-}
-
-TEST_F(VSyncReactorDeathTest, invalidChange) {
-    EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*");
-
-    // the current DispSync-interface usage pattern has evolved around an implementation quirk,
-    // which is a callback is assumed to always exist, and it is valid api usage to change the
-    // offset of an object that is in the removed state.
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    mReactor.removeEventListener(&outerCb, &lastCallbackTime);
-    mReactor.changePhaseOffset(&outerCb, mPhase);
-}
-
-TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) {
-    ON_CALL(*mMockDispatch, schedule(_, _, _))
-            .WillByDefault(Return(ScheduleResult::CannotSchedule));
-    EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*");
-}
-
-TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) {
-    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
-            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
-    EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled));
-
-    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-    ASSERT_TRUE(innerCb);
-    Mock::VerifyAndClearExpectations(mMockDispatch.get());
-
-    ON_CALL(*mMockDispatch, schedule(_, _, _))
-            .WillByDefault(Return(ScheduleResult::CannotSchedule));
-    EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*");
-}
-
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
index 1c8c44d..bbd9f77 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -25,40 +25,5 @@
 DispSync::DispSync() = default;
 DispSync::~DispSync() = default;
 
-status_t DispSync::addEventListener(const char* /*name*/, nsecs_t phase, Callback* callback,
-                                    nsecs_t /*lastCallbackTime*/) {
-    if (mCallback.callback != nullptr) {
-        return BAD_VALUE;
-    }
-
-    mCallback = {callback, phase};
-    return NO_ERROR;
-}
-status_t DispSync::removeEventListener(Callback* callback, nsecs_t* /*outLastCallback*/) {
-    if (mCallback.callback != callback) {
-        return BAD_VALUE;
-    }
-
-    mCallback = {nullptr, 0};
-    return NO_ERROR;
-}
-
-status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
-    if (mCallback.callback != callback) {
-        return BAD_VALUE;
-    }
-
-    mCallback.phase = phase;
-    return NO_ERROR;
-}
-
-void DispSync::triggerCallback() {
-    if (mCallback.callback == nullptr) return;
-
-    const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch();
-    const auto expectedVSyncTime = now + 16ms;
-    mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count());
-}
-
 } // namespace mock
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index b39487c..41445c8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -28,11 +28,9 @@
     DispSync();
     ~DispSync() override;
 
-    MOCK_METHOD0(reset, void());
     MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
     MOCK_METHOD0(beginResync, void());
     MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional<nsecs_t>, bool*));
-    MOCK_METHOD0(endResync, void());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(getPeriod, nsecs_t());
     MOCK_METHOD0(getIntendedPeriod, nsecs_t());
@@ -42,22 +40,6 @@
     MOCK_METHOD1(expectedPresentTime, nsecs_t(nsecs_t));
 
     MOCK_CONST_METHOD1(dump, void(std::string&));
-
-    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
-                              nsecs_t lastCallbackTime) override;
-    status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) override;
-    status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;
-
-    nsecs_t getCallbackPhase() { return mCallback.phase; }
-
-    void triggerCallback();
-
-private:
-    struct CallbackType {
-        Callback* callback = nullptr;
-        nsecs_t phase;
-    };
-    CallbackType mCallback;
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 054aaf8..eefdec1 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -35,7 +35,9 @@
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
     MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
     MOCK_CONST_METHOD1(dump, void(std::string&));
-    MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
+    MOCK_METHOD2(setDuration,
+                 void(std::chrono::nanoseconds workDuration,
+                      std::chrono::nanoseconds readyDuration));
     MOCK_METHOD1(registerDisplayEventConnection,
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index 081d18b..fbf5ecf 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -17,28 +17,50 @@
 
 #include <ui/Rect.h>
 #include <utils/String8.h>
+#include <functional>
+#include <future>
 #include "TransactionUtils.h"
 
 namespace android {
 
 namespace {
 
+class SyncScreenCaptureListener : public BnScreenCaptureListener {
+public:
+    status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
+        resultsPromise.set_value(captureResults);
+        return NO_ERROR;
+    }
+
+    ScreenCaptureResults waitForResults() {
+        std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
+        return resultsFuture.get();
+    }
+
+private:
+    std::promise<ScreenCaptureResults> resultsPromise;
+};
+
 // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
 // individual pixel values for testing purposes.
 class ScreenCapture : public RefBase {
 public:
-    static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
-        captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
-    }
-
-    static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
-                               const DisplayCaptureArgs& captureArgs) {
+    static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
+                                   ScreenCaptureResults& captureResults) {
         const auto sf = ComposerService::getComposerService();
         SurfaceComposerClient::Transaction().apply(true);
 
-        ScreenCaptureResults captureResults;
-        ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
-        *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+        const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+        status_t status = sf->captureDisplay(captureArgs, captureListener);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        captureResults = captureListener->waitForResults();
+        return captureResults.result;
+    }
+
+    static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+        captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
     }
 
     static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
@@ -47,13 +69,30 @@
         captureDisplay(sc, args);
     }
 
-    static void captureLayers(std::unique_ptr<ScreenCapture>* sc,
-                              const LayerCaptureArgs& captureArgs) {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
+                               DisplayCaptureArgs& captureArgs) {
+        ScreenCaptureResults captureResults;
+        ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
+        *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+    }
+
+    static status_t captureLayers(LayerCaptureArgs& captureArgs,
+                                  ScreenCaptureResults& captureResults) {
+        const auto sf = ComposerService::getComposerService();
         SurfaceComposerClient::Transaction().apply(true);
 
+        const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+        status_t status = sf->captureLayers(captureArgs, captureListener);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        captureResults = captureListener->waitForResults();
+        return captureResults.result;
+    }
+
+    static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
         ScreenCaptureResults captureResults;
-        ASSERT_EQ(NO_ERROR, sf->captureLayers(captureArgs, captureResults));
+        ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
         *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
     }