Merge "Refactor use of services in InputMappers."
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index be7e3e1..acca11a 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -76,6 +76,7 @@
     defaults: ["dumpstate_cflag_defaults"],
     shared_libs: [
         "android.hardware.dumpstate@1.0",
+        "android.hardware.dumpstate@1.1",
         "libziparchive",
         "libbase",
         "libbinder",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8e0f8a3..814a4ed 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -64,6 +64,8 @@
 #include <android-base/unique_fd.h>
 #include <android/content/pm/IPackageManagerNative.h>
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/types.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <android/os/IIncidentCompanion.h>
 #include <binder/IServiceManager.h>
@@ -85,7 +87,11 @@
 #include "DumpstateService.h"
 #include "dumpstate.h"
 
-using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
+using ::android::hardware::dumpstate::V1_1::DumpstateMode;
+using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
+using ::android::hardware::dumpstate::V1_1::toString;
 using ::std::literals::chrono_literals::operator""ms;
 using ::std::literals::chrono_literals::operator""s;
 
@@ -1666,7 +1672,7 @@
 // information. This information MUST NOT identify user-installed packages (UIDs are OK, package
 // names are not), and MUST NOT contain logs of user application traffic.
 // TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead.
-static void DumpstateTelephonyOnly() {
+static void DumpstateTelephonyOnly(const std::string& calling_package) {
     DurationReporter duration_reporter("DUMPSTATE");
 
     const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
@@ -1689,11 +1695,18 @@
 
     RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
-    // TODO(b/146521742) build out an argument to include bound services here for user builds
-    RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
-               SEC_TO_MSEC(10));
-    RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
-               SEC_TO_MSEC(10));
+    if (include_sensitive_info) {
+        // Carrier apps' services will be dumped below in dumpsys activity service all-non-platform.
+        RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
+                   SEC_TO_MSEC(10));
+    } else {
+        // If the caller is a carrier app and has a carrier service, dump it here since we aren't
+        // running dumpsys activity service all-non-platform below. Due to the increased output, we
+        // give a higher timeout as well.
+        RunDumpsys("DUMPSYS", {"carrier_config", "--requesting-package", calling_package},
+                   CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(30));
+    }
+    RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
@@ -1892,8 +1905,8 @@
             std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
     }
 
-    sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
-    if (dumpstate_device == nullptr) {
+    sp<IDumpstateDevice_1_0> dumpstate_device_1_0(IDumpstateDevice_1_0::getService());
+    if (dumpstate_device_1_0 == nullptr) {
         MYLOGE("No IDumpstateDevice implementation\n");
         return;
     }
@@ -1924,29 +1937,54 @@
         handle.get()->data[i] = fd.release();
     }
 
-    // Given that bugreport is required to diagnose failures, it's better to
-    // set an arbitrary amount of timeout for IDumpstateDevice than to block the
-    // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
-    // and grab whatever dumped
-    std::packaged_task<bool()>
-            dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
-            android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
+    // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
+    // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
+    // will kill the HAL and grab whatever it dumped in time.
+    constexpr size_t timeout_sec = 30;
+    // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
+    // implement just 1.0.
+    const char* descriptor_to_kill;
+    using DumpstateBoardTask = std::packaged_task<bool()>;
+    DumpstateBoardTask dumpstate_board_task;
+    sp<IDumpstateDevice_1_1> dumpstate_device_1_1(
+        IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0));
+    if (dumpstate_device_1_1 != nullptr) {
+        MYLOGI("Using IDumpstateDevice v1.1");
+        descriptor_to_kill = IDumpstateDevice_1_1::descriptor;
+        dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool {
+            ::android::hardware::Return<DumpstateStatus> status =
+                dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode,
+                                                         SEC_TO_MSEC(timeout_sec));
+            if (!status.isOk()) {
+                MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+                return false;
+            } else if (status != DumpstateStatus::OK) {
+                MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str());
+                return false;
+            }
+            return true;
+        });
+    } else {
+        MYLOGI("Using IDumpstateDevice v1.0");
+        descriptor_to_kill = IDumpstateDevice_1_0::descriptor;
+        dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool {
+            ::android::hardware::Return<void> status =
+                dumpstate_device_1_0->dumpstateBoard(handle.get());
             if (!status.isOk()) {
                 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
                 return false;
             }
             return true;
         });
+    }
+    auto result = dumpstate_board_task.get_future();
+    std::thread(std::move(dumpstate_board_task)).detach();
 
-    auto result = dumpstate_task.get_future();
-    std::thread(std::move(dumpstate_task)).detach();
-
-    constexpr size_t timeout_sec = 30;
     if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
         MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
-        if (!android::base::SetProperty("ctl.interface_restart",
-                                        android::base::StringPrintf("%s/default",
-                                                                    IDumpstateDevice::descriptor))) {
+        if (!android::base::SetProperty(
+                "ctl.interface_restart",
+                android::base::StringPrintf("%s/default", descriptor_to_kill))) {
             MYLOGE("Couldn't restart dumpstate HAL\n");
         }
     }
@@ -1978,15 +2016,14 @@
             continue;
         }
         AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
+        printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
     }
-
-    printf("*** See dumpstate-board.txt entry ***\n");
 }
 
 static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
-            "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
+            "[-z] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
             "  -h: display this help message\n"
             "  -b: play sound file instead of vibrate, at beginning of job\n"
             "  -e: play sound file instead of vibrate, at end of job\n"
@@ -2196,33 +2233,40 @@
     switch (mode) {
         case Dumpstate::BugreportMode::BUGREPORT_FULL:
             options->do_fb = true;
+            options->dumpstate_hal_mode = DumpstateMode::FULL;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
             // Currently, the dumpstate binder is only used by Shell to update progress.
             options->do_start_service = true;
             options->do_progress_updates = true;
             options->do_fb = false;
+            options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
             options->do_vibrate = false;
             options->is_remote_mode = true;
             options->do_fb = false;
+            options->dumpstate_hal_mode = DumpstateMode::REMOTE;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WEAR:
             options->do_start_service = true;
             options->do_progress_updates = true;
             options->do_zip_file = true;
             options->do_fb = true;
+            options->dumpstate_hal_mode = DumpstateMode::WEAR;
             break;
+        // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
         case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
             options->telephony_only = true;
             options->do_progress_updates = true;
             options->do_fb = false;
+            options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WIFI:
             options->wifi_only = true;
             options->do_zip_file = true;
             options->do_fb = false;
+            options->dumpstate_hal_mode = DumpstateMode::WIFI;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
             break;
@@ -2233,11 +2277,13 @@
     MYLOGI(
         "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_fb: %d "
         "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d "
-        "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s args: %s\n",
+        "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
+        "args: %s\n",
         options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
         options.do_fb, options.is_remote_mode, options.show_header_only, options.do_start_service,
         options.telephony_only, options.wifi_only, options.do_progress_updates,
-        options.bugreport_fd.get(), options.bugreport_mode.c_str(), options.args.c_str());
+        options.bugreport_fd.get(), options.bugreport_mode.c_str(),
+        toString(options.dumpstate_hal_mode).c_str(), options.args.c_str());
 }
 
 void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
@@ -2548,7 +2594,7 @@
 
     if (options_->telephony_only) {
         MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateTelephonyOnly();
+        DumpstateTelephonyOnly(calling_package);
         DumpstateBoard();
     } else if (options_->wifi_only) {
         MaybeCheckUserConsent(calling_uid, calling_package);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7d9b113..111c098 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,7 @@
 
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.1/types.h>
 #include <android/os/BnIncidentAuthListener.h>
 #include <android/os/IDumpstate.h>
 #include <android/os/IDumpstateListener.h>
@@ -366,6 +367,11 @@
         bool wifi_only = false;
         // Whether progress updates should be published.
         bool do_progress_updates = false;
+        // The mode we'll use when calling IDumpstateDevice::dumpstateBoard.
+        // TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead.
+        // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
+        ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
+            ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
         // File descriptor to output zip file.
         android::base::unique_fd bugreport_fd;
         // File descriptor to screenshot file.
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 718f459..76b9960 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -36,20 +36,22 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/properties.h>
 #include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/properties.h>
 
 namespace android {
 namespace os {
 namespace dumpstate {
 
+using ::android::hardware::dumpstate::V1_1::DumpstateMode;
 using ::testing::EndsWith;
 using ::testing::HasSubstr;
-using ::testing::IsNull;
 using ::testing::IsEmpty;
+using ::testing::IsNull;
 using ::testing::NotNull;
-using ::testing::StrEq;
 using ::testing::StartsWith;
+using ::testing::StrEq;
 using ::testing::Test;
 using ::testing::internal::CaptureStderr;
 using ::testing::internal::CaptureStdout;
@@ -174,6 +176,7 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -200,6 +203,7 @@
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
     EXPECT_FALSE(options_.use_socket);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
@@ -224,6 +228,7 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
@@ -231,6 +236,7 @@
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -249,6 +255,7 @@
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_start_service);
     EXPECT_FALSE(options_.do_fb);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -265,6 +272,7 @@
     EXPECT_TRUE(options_.is_remote_mode);
     EXPECT_FALSE(options_.do_vibrate);
     EXPECT_FALSE(options_.do_fb);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
 
     // Other options retain default values
     EXPECT_FALSE(options_.use_control_socket);
@@ -280,6 +288,7 @@
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_start_service);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -296,6 +305,7 @@
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.telephony_only);
     EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -311,6 +321,7 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.wifi_only);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -337,6 +348,7 @@
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -375,6 +387,7 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -403,6 +416,7 @@
     EXPECT_FALSE(options_.do_zip_file);
     EXPECT_FALSE(options_.use_socket);
     EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeHelp) {
diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp
index 344aefb..6e079eb 100644
--- a/cmds/installd/CrateManager.cpp
+++ b/cmds/installd/CrateManager.cpp
@@ -16,6 +16,8 @@
 
 #include "CrateManager.h"
 
+#ifdef ENABLE_STORAGE_CRATES
+
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/log.h>
@@ -127,3 +129,5 @@
 
 } // namespace installd
 } // namespace android
+
+#endif // ENABLE_STORAGE_CRATES
\ No newline at end of file
diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h
index 1776622..4332d4c 100644
--- a/cmds/installd/CrateManager.h
+++ b/cmds/installd/CrateManager.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
 #define ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
 
+#ifdef ENABLE_STORAGE_CRATES
+
 #include <android/os/storage/CrateMetadata.h>
 #include <cutils/multiuser.h>
 #include <fts.h>
@@ -79,4 +81,9 @@
 } // namespace installd
 } // namespace android
 
+#else // ENABLE_STORAGE_CRATES
+#include <android/os/storage/CrateMetadata.h>
+using android::os::storage::CrateMetadata;
+#endif // ENABLE_STORAGE_CRATES
+
 #endif // ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 08d4657..3713e87 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2054,6 +2054,7 @@
     for (const auto& packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     }
+#ifdef ENABLE_STORAGE_CRATES
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
@@ -2083,6 +2084,14 @@
 #endif
 
     *_aidl_return = std::move(retVector);
+#else // ENABLE_STORAGE_CRATES
+    *_aidl_return = nullptr;
+
+    /* prevent compile warning fail */
+    if (userId < 0) {
+        return error();
+    }
+#endif // ENABLE_STORAGE_CRATES
     return ok();
 }
 
@@ -2091,6 +2100,7 @@
         std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+#ifdef ENABLE_STORAGE_CRATES
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
@@ -2118,6 +2128,14 @@
 #endif
 
     *_aidl_return = std::move(retVector);
+#else // ENABLE_STORAGE_CRATES
+    *_aidl_return = nullptr;
+
+    /* prevent compile warning fail */
+    if (userId < 0) {
+        return error();
+    }
+#endif // ENABLE_STORAGE_CRATES
     return ok();
 }
 
@@ -2684,7 +2702,7 @@
 }
 
 // Mount volume's CE and DE storage to mirror
-binder::Status InstalldNativeService::onPrivateVolumeMounted(
+binder::Status InstalldNativeService::tryMountDataMirror(
         const std::unique_ptr<std::string>& uuid) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -2696,24 +2714,50 @@
     }
 
     const char* uuid_ = uuid->c_str();
-    // Mount CE mirror
+
     std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
     std::lock_guard<std::recursive_mutex> lock(mLock);
-    if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+    if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
         return error("Failed to create CE mirror");
     }
-    auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str());
+
+    std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+    if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+        return error("Failed to create DE mirror");
+    }
+
+    auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
+    auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+
+    if (access(cePath.c_str(), F_OK) != 0) {
+        return error("Cannot access CE path: " + cePath);
+    }
+    if (access(dePath.c_str(), F_OK) != 0) {
+        return error("Cannot access DE path: " + dePath);
+    }
+
+    struct stat ceStat, mirrorCeStat;
+    if (stat(cePath.c_str(), &ceStat) != 0) {
+        return error("Failed to stat " + cePath);
+    }
+    if (stat(mirrorVolCePath.c_str(), &mirrorCeStat) != 0) {
+        return error("Failed to stat " + mirrorVolCePath);
+    }
+
+    if (mirrorCeStat.st_ino == ceStat.st_ino) {
+        // As it's being called by prepareUserStorage, it can be called multiple times.
+        // Hence, we if we mount it already, we should skip it.
+        LOG(WARNING) << "CE dir is mounted already: " + cePath;
+        return ok();
+    }
+
+    // Mount CE mirror
     if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL,
             MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
         return error("Failed to mount " + mirrorVolCePath);
     }
 
     // Mount DE mirror
-    std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
-    if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
-        return error("Failed to create DE mirror");
-    }
-    auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
     if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL,
             MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
         return error("Failed to mount " + mirrorVolDePath);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index eb35fd3..27c59b0 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -155,7 +155,7 @@
     binder::Status invalidateMounts();
     binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
             bool* _aidl_return);
-    binder::Status onPrivateVolumeMounted(const std::unique_ptr<std::string>& volumeUuid);
+    binder::Status tryMountDataMirror(const std::unique_ptr<std::string>& volumeUuid);
     binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);
 
     binder::Status prepareAppProfile(const std::string& packageName,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 80d9703..f2e86ba 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -116,7 +116,7 @@
             int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
     void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
             int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
-    void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid);
+    void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid);
     void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
 
     void migrateLegacyObbData();
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 7c989f6..6459805 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -61,11 +61,15 @@
 
 static std::vector<apex::ApexFile> ActivateApexPackages() {
     // The logic here is (partially) copied and adapted from
-    // system/apex/apexd/apexd_main.cpp.
+    // system/apex/apexd/apexd.cpp.
     //
-    // Only scan the APEX directory under /system (within the chroot dir).
-    // Cast call to void to suppress warn_unused_result.
-    static_cast<void>(apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir));
+    // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
+    std::vector<const char*> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
+                                       apex::kApexPackageVendorDir};
+    for (const auto& dir : apex_dirs) {
+        // Cast call to void to suppress warn_unused_result.
+        static_cast<void>(apex::scanPackagesDirAndActivate(dir));
+    }
     return apex::getActivePackages();
 }
 
diff --git a/include/android/sensor.h b/include/android/sensor.h
index e63ac4b..eb40779 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -244,6 +244,9 @@
     ASENSOR_TYPE_ACCELEROMETER_UNCALIBRATED = 35,
     /**
      * {@link ASENSOR_TYPE_HINGE_ANGLE}
+     * reporting-mode: on-change
+     *
+     * The hinge angle sensor value is returned in degrees.
      */
     ASENSOR_TYPE_HINGE_ANGLE = 36,
 };
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index 7331ba2..e6b743b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -86,9 +86,15 @@
         return t->template ref<T>();
     }
 
+    static void operator delete(void* p) { std::free(p); }
+
    private:
     std::once_flag mFlagThis;
     std::weak_ptr<SharedRefBase> mThis;
+
+    // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
+    // ownership. Making this operator private to avoid double-ownership.
+    static void* operator new(size_t s) { return std::malloc(s); }
 };
 
 /**
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index f18e118..f0ea237 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -242,23 +242,18 @@
 }
 
 binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
-    std::unique_ptr<ParcelFileDescriptor> parcelFd;
-
     if (fd < 0) {
         if (fd != -1) {
             return STATUS_UNKNOWN_ERROR;
         }
-        // parcelFd = nullptr
-    } else {  // fd >= 0
-        parcelFd = std::make_unique<ParcelFileDescriptor>(unique_fd(fd));
+        return parcel->get()->writeInt32(0);  // null
     }
 
-    status_t status = parcel->get()->writeNullableParcelable(parcelFd);
+    ParcelFileDescriptor parcelFd = ParcelFileDescriptor(unique_fd(fd));
+    status_t status = parcel->get()->writeParcelable(parcelFd);
 
     // ownership is retained by caller
-    if (parcelFd != nullptr) {
-        (void)parcelFd->release().release();
-    }
+    (void)parcelFd.release().release();
 
     return PruneStatusT(status);
 }
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 99d3856..7f57f5d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -189,6 +189,10 @@
         },
     },
 
+    whole_static_libs: [
+        "LibGuiProperties",
+    ],
+
     shared_libs: [
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.bufferqueue@2.0",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index e2f5d31..acd833f 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -19,6 +19,8 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <cutils/properties.h>
+
 #include <gui/BLASTBufferQueue.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/GLConsumer.h>
@@ -99,7 +101,11 @@
         mHeight(height),
         mNextTransaction(nullptr) {
     BufferQueue::createBufferQueue(&mProducer, &mConsumer);
-    mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
+
+    int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0);
+    if (!disableTripleBuffer) {
+        mProducer->setMaxDequeuedBufferCount(2);
+    }
     mBufferItemConsumer =
             new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
     static int32_t id = 0;
@@ -174,14 +180,16 @@
     }
     mPendingReleaseItem.item = std::move(mSubmitted.front());
     mSubmitted.pop();
+
     processNextBufferLocked();
+
     mCallbackCV.notify_all();
     decStrong((void*)transactionCallbackThunk);
 }
 
 void BLASTBufferQueue::processNextBufferLocked() {
     ATRACE_CALL();
-    if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) {
+    if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
         return;
     }
 
@@ -193,7 +201,7 @@
     SurfaceComposerClient::Transaction localTransaction;
     bool applyTransaction = true;
     SurfaceComposerClient::Transaction* t = &localTransaction;
-    if (mNextTransaction != nullptr) {
+    if (mNextTransaction != nullptr && mUseNextTransaction) {
         t = mNextTransaction;
         mNextTransaction = nullptr;
         applyTransaction = false;
@@ -252,8 +260,14 @@
 
 void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) {
     ATRACE_CALL();
-    std::lock_guard _lock{mMutex};
+    std::unique_lock _lock{mMutex};
 
+    if (mNextTransaction != nullptr) {
+        while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
+            mCallbackCV.wait(_lock);
+        }
+        mUseNextTransaction = true;
+    }
     // add to shadow queue
     mNumFrameAvailable++;
     processNextBufferLocked();
@@ -261,6 +275,7 @@
 
 void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
     std::lock_guard _lock{mMutex};
+    mUseNextTransaction = false;
     mNextTransaction = t;
 }
 
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 6749c3c..e2ea3f9 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -18,6 +18,7 @@
 
 #define LOG_TAG "FrameEvents"
 
+#include <LibGuiProperties.sysprop.h>
 #include <android-base/stringprintf.h>
 #include <cutils/compiler.h>  // For CC_[UN]LIKELY
 #include <inttypes.h>
@@ -167,6 +168,11 @@
 
 }  // namespace
 
+const size_t FrameEventHistory::MAX_FRAME_HISTORY =
+        sysprop::LibGuiProperties::frame_event_history_size().value_or(8);
+
+FrameEventHistory::FrameEventHistory() : mFrames(std::vector<FrameEvents>(MAX_FRAME_HISTORY)) {}
+
 FrameEventHistory::~FrameEventHistory() = default;
 
 FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) {
@@ -348,6 +354,9 @@
 // ConsumerFrameEventHistory
 // ============================================================================
 
+ConsumerFrameEventHistory::ConsumerFrameEventHistory()
+      : mFramesDirty(std::vector<FrameEventDirtyFields>(MAX_FRAME_HISTORY)) {}
+
 ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
 
 void ConsumerFrameEventHistory::onDisconnect() {
@@ -447,9 +456,8 @@
     mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>();
 }
 
-void ConsumerFrameEventHistory::getFrameDelta(
-        FrameEventHistoryDelta* delta,
-        const std::array<FrameEvents, MAX_FRAME_HISTORY>::iterator& frame) {
+void ConsumerFrameEventHistory::getFrameDelta(FrameEventHistoryDelta* delta,
+                                              const std::vector<FrameEvents>::iterator& frame) {
     mProducerWantsEvents = true;
     size_t i = static_cast<size_t>(std::distance(mFrames.begin(), frame));
     if (mFramesDirty[i].anyDirty()) {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 23532e7..278cc59 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1180,6 +1180,9 @@
         allocateBuffers();
         res = NO_ERROR;
         break;
+    case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER:
+        res = dispatchGetLastQueuedBuffer(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1452,6 +1455,30 @@
     return NO_ERROR;
 }
 
+int Surface::dispatchGetLastQueuedBuffer(va_list args) {
+    AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**);
+    int* fence = va_arg(args, int*);
+    float* matrix = va_arg(args, float*);
+    sp<GraphicBuffer> graphicBuffer;
+    sp<Fence> spFence;
+
+    int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix);
+
+    if (graphicBuffer != nullptr) {
+        *buffer = reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get());
+        AHardwareBuffer_acquire(*buffer);
+    } else {
+        *buffer = nullptr;
+    }
+
+    if (spFence != nullptr) {
+        *fence = spFence->dup();
+    } else {
+        *fence = -1;
+    }
+    return result;
+}
+
 bool Surface::transformToDisplayInverse() {
     return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7017b7c..ff8b719 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -526,21 +526,6 @@
     mDesiredPresentTime = -1;
 }
 
-void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    Vector<ComposerState> composerStates;
-    Vector<DisplayState> displayStates;
-
-    ComposerState s;
-    s.state.surface = handle;
-    s.state.what |= layer_state_t::eReparent;
-    s.state.parentHandleForChild = nullptr;
-
-    composerStates.add(s);
-    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
-    sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, false, {});
-}
-
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
@@ -1558,7 +1543,7 @@
         }
         ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
         if (err == NO_ERROR) {
-            return new SurfaceControl(this, handle, gbp, true /* owned */, transformHint);
+            return new SurfaceControl(this, handle, gbp, transformHint);
         }
     }
     return nullptr;
@@ -1589,7 +1574,7 @@
         }
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */, transformHint);
+            *outSurface = new SurfaceControl(this, handle, gbp, transformHint);
         }
     }
     return err;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 6292388..a332a1f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -46,34 +46,22 @@
 // ============================================================================
 
 SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
-                               const sp<IGraphicBufferProducer>& gbp, bool owned,
+                               const sp<IGraphicBufferProducer>& gbp,
                                uint32_t transform)
       : mClient(client),
         mHandle(handle),
         mGraphicBufferProducer(gbp),
-        mOwned(owned),
         mTransformHint(transform) {}
 
 SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
     mClient = other->mClient;
     mHandle = other->mHandle;
     mGraphicBufferProducer = other->mGraphicBufferProducer;
-    mOwned = false;
     mTransformHint = other->mTransformHint;
 }
 
 SurfaceControl::~SurfaceControl()
 {
-    // Avoid reparenting the server-side surface to null if we are not the owner of it,
-    // meaning that we retrieved it from another process.
-    if (mHandle != nullptr && mOwned) {
-        SurfaceComposerClient::doDropReferenceTransaction(mHandle);
-    }
-    release();
-}
-
-void SurfaceControl::release()
-{
     // Trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
     mClient.clear();
@@ -157,7 +145,6 @@
 
 sp<IBinder> SurfaceControl::getHandle() const
 {
-    Mutex::Autolock lock(mLock);
     return mHandle;
 }
 
@@ -206,7 +193,7 @@
     return new SurfaceControl(new SurfaceComposerClient(
                                       interface_cast<ISurfaceComposerClient>(client)),
                               handle.get(), interface_cast<IGraphicBufferProducer>(gbp),
-                              false /* owned */, transformHint);
+                               transformHint);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index d72eb5a..64c21e0 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -98,7 +98,9 @@
     std::mutex mMutex;
     std::condition_variable mCallbackCV;
 
-    static const int MAX_ACQUIRED_BUFFERS = 2;
+    // BufferQueue internally allows 1 more than
+    // the max to be acquired
+    static const int MAX_ACQUIRED_BUFFERS = 1;
 
     int32_t mNumFrameAvailable GUARDED_BY(mMutex);
     int32_t mNumAcquired GUARDED_BY(mMutex);
@@ -121,6 +123,8 @@
     sp<BLASTBufferItemConsumer> mBufferItemConsumer;
 
     SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
+
+    bool mUseNextTransaction = false;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 4af8659..0750080 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -106,6 +106,7 @@
 // producer via deltas.
 class FrameEventHistory {
 public:
+    FrameEventHistory();
     virtual ~FrameEventHistory();
 
     FrameEvents* getFrame(uint64_t frameNumber);
@@ -113,10 +114,10 @@
     void checkFencesForCompletion();
     void dump(std::string& outString) const;
 
-    static constexpr size_t MAX_FRAME_HISTORY = 8;
+    static const size_t MAX_FRAME_HISTORY;
 
 protected:
-    std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+    std::vector<FrameEvents> mFrames;
 
     CompositorTiming mCompositorTiming;
 };
@@ -203,6 +204,7 @@
 // The consumer's interface to FrameEventHistory
 class ConsumerFrameEventHistory : public FrameEventHistory {
 public:
+    ConsumerFrameEventHistory();
     ~ConsumerFrameEventHistory() override;
 
     void onDisconnect();
@@ -224,9 +226,9 @@
 
 private:
     void getFrameDelta(FrameEventHistoryDelta* delta,
-            const std::array<FrameEvents, MAX_FRAME_HISTORY>::iterator& frame);
+                       const std::vector<FrameEvents>::iterator& frame);
 
-    std::array<FrameEventDirtyFields, MAX_FRAME_HISTORY> mFramesDirty;
+    std::vector<FrameEventDirtyFields> mFramesDirty;
 
     size_t mQueueOffset{0};
     size_t mCompositionOffset{0};
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2b65d2f..6366529 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -44,7 +44,7 @@
         eCursorWindow = 0x00002000,
 
         eFXSurfaceBufferQueue = 0x00000000,
-        eFXSurfaceColor = 0x00020000,
+        eFXSurfaceEffect = 0x00020000,
         eFXSurfaceBufferState = 0x00040000,
         eFXSurfaceContainer = 0x00080000,
         eFXSurfaceMask = 0x000F0000,
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0139507..4a353fc 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -262,6 +262,7 @@
     int dispatchAddDequeueInterceptor(va_list args);
     int dispatchAddPerformInterceptor(va_list args);
     int dispatchAddQueueInterceptor(va_list args);
+    int dispatchGetLastQueuedBuffer(va_list args);
     bool transformToDisplayInverse();
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d0bb6a3..27877bb 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -184,12 +184,6 @@
     static bool getProtectedContentSupport();
 
     /**
-     * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
-     * to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
-     */
-    static void doDropReferenceTransaction(const sp<IBinder>& handle);
-
-    /**
      * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
      * in order with other transactions that use buffers.
      */
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 7bc7c68..ac2bbcc 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -58,10 +58,6 @@
     static bool isSameSurface(
             const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
 
-    // Release the handles assosciated with the SurfaceControl, without reparenting
-    // them off-screen. At the moment if this isn't executed before ~SurfaceControl
-    // is called then the destructor will reparent the layer off-screen for you.
-    void        release();
     // Reparent off-screen and release. This is invoked by the destructor.
     void destroy();
 
@@ -89,7 +85,7 @@
     explicit SurfaceControl(const sp<SurfaceControl>& other);
 
     SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
-                   const sp<IGraphicBufferProducer>& gbp, bool owned, uint32_t transformHint = 0);
+                   const sp<IGraphicBufferProducer>& gbp, uint32_t transformHint = 0);
 
 private:
     // can't be copied
@@ -109,7 +105,6 @@
     sp<IGraphicBufferProducer>  mGraphicBufferProducer;
     mutable Mutex               mLock;
     mutable sp<Surface>         mSurfaceData;
-    bool                        mOwned;
     uint32_t mTransformHint;
 };
 
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
new file mode 100644
index 0000000..e7f7c1f
--- /dev/null
+++ b/libs/gui/sysprop/Android.bp
@@ -0,0 +1,7 @@
+sysprop_library {
+    name: "LibGuiProperties",
+    srcs: ["*.sysprop"],
+    api_packages: ["android.sysprop"],
+    property_owner: "Platform",
+    vendor_available: true,
+}
diff --git a/libs/gui/sysprop/LibGuiProperties.sysprop b/libs/gui/sysprop/LibGuiProperties.sysprop
new file mode 100644
index 0000000..0d54711
--- /dev/null
+++ b/libs/gui/sysprop/LibGuiProperties.sysprop
@@ -0,0 +1,25 @@
+# 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.
+
+module: "android.sysprop.LibGuiProperties"
+owner: Platform
+
+# Indicates how many elements should be present in the frame event histories.
+prop {
+    api_name: "frame_event_history_size"
+    type: Integer
+    scope: Public
+    access: Readonly
+    prop_name: "ro.lib_gui.frame_event_history_size"
+}
diff --git a/libs/gui/sysprop/api/LibGuiProperties-current.txt b/libs/gui/sysprop/api/LibGuiProperties-current.txt
new file mode 100644
index 0000000..5b7f74e
--- /dev/null
+++ b/libs/gui/sysprop/api/LibGuiProperties-current.txt
@@ -0,0 +1,8 @@
+props {
+  module: "android.sysprop.LibGuiProperties"
+  prop {
+    api_name: "frame_event_history_size"
+    type: Integer
+    prop_name: "ro.lib_gui.frame_event_history_size"
+  }
+}
diff --git a/libs/gui/sysprop/api/LibGuiProperties-latest.txt b/libs/gui/sysprop/api/LibGuiProperties-latest.txt
new file mode 100644
index 0000000..5b7f74e
--- /dev/null
+++ b/libs/gui/sysprop/api/LibGuiProperties-latest.txt
@@ -0,0 +1,8 @@
+props {
+  module: "android.sysprop.LibGuiProperties"
+  prop {
+    api_name: "frame_event_history_size"
+    type: Integer
+    prop_name: "ro.lib_gui.frame_event_history_size"
+  }
+}
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index e184c7f..a87ccd6 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -403,7 +403,7 @@
     int32_t finalCropSideLength = bufferSideLength / 2;
 
     auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                     ISurfaceComposerClient::eFXSurfaceColor);
+                                     ISurfaceComposerClient::eFXSurfaceEffect);
     ASSERT_NE(nullptr, bg.get());
     Transaction t;
     t.setLayerStack(bg, 0)
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 1a623e2..c59afba 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -82,7 +82,8 @@
                                                                int width, int height) {
         sp<SurfaceControl> surfaceControl =
                 scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
-                                   PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect);
         return std::make_unique<InputSurface>(surfaceControl, width, height);
     }
 
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index c9de37d..dbd4ef9 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -183,7 +183,7 @@
         mBackgroundLayer =
                 mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
                                                       0, PIXEL_FORMAT_RGBA_8888,
-                                                      ISurfaceComposerClient::eFXSurfaceColor);
+                                                      ISurfaceComposerClient::eFXSurfaceEffect);
         uint32_t layerPositionBottom = 0x7E000000;
         SurfaceComposerClient::Transaction{}
                 .setLayer(mBackgroundLayer, layerPositionBottom)
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
index 9891587..5c1bebb 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -39,7 +39,7 @@
         sp<SurfaceComposerClient> client = new SurfaceComposerClient;
 
         mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                        ISurfaceComposerClient::eFXSurfaceColor);
+                                        ISurfaceComposerClient::eFXSurfaceEffect);
 
         const int32_t width = samplingArea.getWidth();
         const int32_t height = samplingArea.getHeight();
@@ -55,7 +55,7 @@
                 .apply();
 
         mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                             ISurfaceComposerClient::eFXSurfaceColor);
+                                             ISurfaceComposerClient::eFXSurfaceEffect);
 
         SurfaceComposerClient::Transaction{}
                 .setLayer(mButtonBlend, 0x7ffffffe)
@@ -73,7 +73,7 @@
         if (HIGHLIGHT_SAMPLING_AREA) {
             mSamplingArea =
                     client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                          ISurfaceComposerClient::eFXSurfaceColor);
+                                          ISurfaceComposerClient::eFXSurfaceEffect);
 
             SurfaceComposerClient::Transaction{}
                     .setLayer(mSamplingArea, 0x7ffffffd)
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index a1c9eb8..98b76fd 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -165,6 +165,14 @@
     return native_window_set_frame_rate(window, frameRate);
 }
 
+void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) {
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
+        return;
+    }
+    window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
+}
+
+
 /**************************************************************************************************
  * vndk-stable
  **************************************************************************************************/
@@ -328,10 +336,6 @@
     return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data);
 }
 
-void ANativeWindow_allocateBuffers(ANativeWindow* window) {
-    window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
-}
-
 int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
     return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID);
 }
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 262aee3..4b426c5 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -261,6 +261,17 @@
  */
 int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30);
 
+/**
+ * Provides a hint to the window that buffers should be preallocated ahead of
+ * time. Note that the window implementation is not guaranteed to preallocate
+ * any buffers, for instance if an implementation disallows allocation of new
+ * buffers, or if there is insufficient memory in the system to preallocate
+ * additional buffers
+ *
+ * Available since API level 30.
+ */
+void ANativeWindow_tryAllocateBuffers(ANativeWindow* window);
+
 #endif // __ANDROID_API__ >= 30
 
 #ifdef __cplusplus
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 121374b..f686147 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -253,6 +253,7 @@
     NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR         = 43,    /* private */
     NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR           = 44,    /* private */
     NATIVE_WINDOW_ALLOCATE_BUFFERS                = 45,    /* private */
+    NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER          = 46,    /* private */
     // clang-format on
 };
 
@@ -1018,4 +1019,34 @@
     return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate);
 }
 
+// ------------------------------------------------------------------------------------------------
+// Candidates for APEX visibility
+// These functions are planned to be made stable for APEX modules, but have not
+// yet been stabilized to a specific api version.
+// ------------------------------------------------------------------------------------------------
+
+/**
+ * Retrieves the last queued buffer for this window, along with the fence that
+ * fires when the buffer is ready to be read, and the 4x4 coordinate
+ * transform matrix that should be applied to the buffer's content. The
+ * transform matrix is represented in column-major order.
+ *
+ * If there was no buffer previously queued, then outBuffer will be NULL and
+ * the value of outFence will be -1.
+ *
+ * Note that if outBuffer is not NULL, then the caller will hold a reference
+ * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release
+ * when the buffer is no longer needed so that the system may reclaim the
+ * buffer.
+ *
+ * \return NO_ERROR on success.
+ * \return NO_MEMORY if there was insufficient memory.
+ */
+static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window,
+                                                    AHardwareBuffer** outBuffer, int* outFence,
+                                                    float outTransformMatrix[16]) {
+    return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER, outBuffer, outFence,
+                           outTransformMatrix);
+}
+
 __END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index e0e20c3..154eb8e 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -17,7 +17,6 @@
     ANativeWindow_OemStorageGet; # llndk
     ANativeWindow_OemStorageSet; # llndk
     ANativeWindow_acquire;
-    ANativeWindow_allocateBuffers; # apex # introduced=30
     ANativeWindow_cancelBuffer; # llndk
     ANativeWindow_dequeueBuffer; # llndk
     ANativeWindow_getBuffersDataSpace; # introduced=28
@@ -51,6 +50,7 @@
     ANativeWindow_setSwapInterval; # llndk
     ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setUsage; # llndk
+    ANativeWindow_tryAllocateBuffers; # introduced=30
     ANativeWindow_unlockAndPost;
   local:
     *;
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index b1a84bd..eb66c8f 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -132,8 +132,7 @@
 }
 
 string BlurFilter::getVertexShader() const {
-    return R"SHADER(
-        #version 310 es
+    return R"SHADER(#version 310 es
 
         in vec2 aPosition;
         in highp vec2 aUV;
@@ -147,8 +146,7 @@
 }
 
 string BlurFilter::getMixFragShader() const {
-    string shader = R"SHADER(
-        #version 310 es
+    string shader = R"SHADER(#version 310 es
         precision mediump float;
 
         in highp vec2 vUV;
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
index 4d7bf44..a0d7af8 100644
--- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
@@ -43,7 +43,7 @@
     mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition");
     mVUvLoc = mVerticalProgram.getAttributeLocation("aUV");
     mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture");
-    mVIncrementLoc = mVerticalProgram.getUniformLocation("uIncrement");
+    mVGaussianOffsetLoc = mVerticalProgram.getUniformLocation("uGaussianOffsets");
     mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples");
     mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights");
 
@@ -51,7 +51,7 @@
     mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition");
     mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV");
     mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture");
-    mHIncrementLoc = mHorizontalProgram.getUniformLocation("uIncrement");
+    mHGaussianOffsetLoc = mHorizontalProgram.getUniformLocation("uGaussianOffsets");
     mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples");
     mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights");
 }
@@ -60,6 +60,36 @@
     mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight());
 }
 
+static void calculateLinearGaussian(uint32_t samples, double dimension,
+                                    GLfloat* gaussianLinearOffsets, GLfloat* gaussianWeights,
+                                    GLfloat* gaussianLinearWeights) {
+    // The central point in the symmetric bell curve is not offset.
+    // This decision allows one less sampling in the GPU.
+    gaussianLinearWeights[0] = gaussianWeights[0];
+    gaussianLinearOffsets[0] = 0.0;
+
+    // Calculate the linear weights.
+    // This is a vector reduction where an element of the packed reduced array
+    // contains the sum of two adjacent members of the original packed array.
+    // We start preserving the element 1 of the array and then perform sum for
+    // every other (i+=2) element of the gaussianWeights array.
+    gaussianLinearWeights[1] = gaussianWeights[1];
+    const auto start = 1 + ((samples - 1) & 0x1);
+    for (size_t i = start; i < samples; i += 2) {
+        gaussianLinearWeights[start + i / 2] = gaussianWeights[i] + gaussianWeights[i + 1];
+    }
+
+    // Calculate the texture coordinates offsets as an average of the initial offsets,
+    // weighted by the Gaussian weights as described in the original article.
+    gaussianLinearOffsets[1] = 1.0 / dimension;
+    for (size_t i = start; i < samples; i += 2) {
+        GLfloat offset_1 = float(i) / dimension;
+        GLfloat offset_2 = float(i + 1) / dimension;
+        gaussianLinearOffsets[start + i / 2] =
+                (offset_1 * gaussianWeights[i] + offset_2 * gaussianWeights[i + 1]) /
+                gaussianLinearWeights[start + i / 2];
+    }
+}
 status_t GaussianBlurFilter::prepare() {
     ATRACE_NAME("GaussianBlurFilter::prepare");
 
@@ -88,27 +118,47 @@
     mVerticalPassFbo.bind();
     mVerticalProgram.useProgram();
 
-    // Precompute gaussian bell curve, and send it to the shader to avoid
-    // unnecessary computations.
-    auto samples = min(mRadius, kNumSamples);
+    // Precompute gaussian bell curve, and send it to the shader to avoid unnecessary computations.
+    double radiusD = fmax(1.0, mRadius * kFboScale);
+    auto samples = int(fmin(radiusD, kNumSamples));
     GLfloat gaussianWeights[kNumSamples] = {};
-    for (size_t i = 0; i < samples; i++) {
-        float normalized = float(i) / samples;
+
+    gaussianWeights[0] = 1.0f;
+    auto totalWeight = gaussianWeights[0];
+
+    // Gaussian weights calculation.
+    for (size_t i = 1; i < samples; i++) {
+        const double normalized = i / radiusD;
         gaussianWeights[i] = (float)exp(-K * normalized * normalized);
+        totalWeight += 2.0 * gaussianWeights[i];
     }
 
-    // set uniforms
+    // Gaussian weights normalization to avoid work in the GPU.
+    for (size_t i = 0; i < samples; i++) {
+        gaussianWeights[i] /= totalWeight;
+    }
+
     auto width = mVerticalPassFbo.getBufferWidth();
     auto height = mVerticalPassFbo.getBufferHeight();
-    auto radiusF = fmax(1.0f, mRadius * kFboScale);
     glViewport(0, 0, width, height);
+
+    // Allocate space for the corrected Gaussian weights and offsets.
+    // We could use less space, but let's keep the code simple.
+    GLfloat gaussianLinearWeights[kNumSamples] = {};
+    GLfloat gaussianLinearOffsets[kNumSamples] = {};
+
+    // Calculate the weights and offsets for the vertical pass.
+    // This only need to be called every time mRadius or height changes, so it could be optimized.
+    calculateLinearGaussian(samples, double(height), gaussianLinearOffsets, gaussianWeights,
+                            gaussianLinearWeights);
+    // set uniforms
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName());
     glUniform1i(mVTextureLoc, 0);
-    glUniform2f(mVIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f));
-    glUniform1i(mVNumSamplesLoc, samples);
-    glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianWeights);
-    mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
+    glUniform1i(mVNumSamplesLoc, 1 + (samples + 1) / 2);
+    glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianLinearWeights);
+    glUniform1fv(mVGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets);
+    mEngine.checkErrors("Setting vertical pass uniforms");
 
     drawMesh(mVUvLoc, mVPosLoc);
 
@@ -116,14 +166,18 @@
     mBlurredFbo.bind();
     mHorizontalProgram.useProgram();
 
+    // Calculate the weights and offsets for the horizontal pass.
+    // This only needs to be called every time mRadius or width change, so it could be optimized.
+    calculateLinearGaussian(samples, double(width), gaussianLinearOffsets, gaussianWeights,
+                            gaussianLinearWeights);
     // set uniforms
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName());
     glUniform1i(mHTextureLoc, 0);
-    glUniform2f(mHIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f));
-    glUniform1i(mHNumSamplesLoc, samples);
-    glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianWeights);
-    mEngine.checkErrors("Setting vertical pass uniforms");
+    glUniform1i(mHNumSamplesLoc, 1 + (samples + 1) / 2);
+    glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianLinearWeights);
+    glUniform1fv(mHGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets);
+    mEngine.checkErrors("Setting horizontal pass uniforms");
 
     drawMesh(mHUvLoc, mHPosLoc);
 
@@ -142,43 +196,37 @@
     stringstream shader;
     shader << "#version 310 es\n"
            << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n"
-           << "#define NUM_SAMPLES " << kNumSamples <<
+           << "#define NUM_SAMPLES " << 1 + (kNumSamples + 1) / 2 <<
             R"SHADER(
         precision mediump float;
 
         uniform sampler2D uTexture;
-        uniform vec2 uIncrement;
         uniform float[NUM_SAMPLES] uGaussianWeights;
+        uniform float[NUM_SAMPLES] uGaussianOffsets;
         uniform int uSamples;
 
         highp in vec2 vUV;
         out vec4 fragColor;
 
-        vec3 gaussianBlur(sampler2D texture, highp vec2 uv, float inc, vec2 direction) {
-            float totalWeight = 0.0;
-            vec3 blurred = vec3(0.0);
-            float fSamples = 1.0 / float(uSamples);
-
-            for (int i = -uSamples; i <= uSamples; i++) {
-                float weight = uGaussianWeights[abs(i)];
-                float normalized = float(i) * fSamples;
-                float radInc = inc * normalized;
-                blurred += weight * (texture(texture, radInc * direction + uv, 0.0)).rgb;
-                totalWeight += weight;
-            }
-
-            return blurred / totalWeight;
-        }
-
         void main() {
             #if DIRECTION == 1
-            vec3 color = gaussianBlur(uTexture, vUV, uIncrement.x, vec2(1.0, 0.0));
+            const vec2 direction = vec2(1.0, 0.0);
             #else
-            vec3 color = gaussianBlur(uTexture, vUV, uIncrement.y, vec2(0.0, 1.0));
+            const vec2 direction = vec2(0.0, 1.0);
             #endif
-            fragColor = vec4(color, 1.0);
-        }
 
+            // Iteration zero outside loop to avoid sampling the central point twice.
+            vec4 blurred = uGaussianWeights[0] * (texture(uTexture, vUV, 0.0));
+
+            // Iterate one side of the bell to halve the loop iterations.
+            for (int i = 1; i <= uSamples; i++) {
+                vec2 offset = uGaussianOffsets[i] * direction;
+                blurred += uGaussianWeights[i] * (texture(uTexture, vUV + offset, 0.0));
+                blurred += uGaussianWeights[i] * (texture(uTexture, vUV - offset, 0.0));
+            }
+
+            fragColor = vec4(blurred.rgb, 1.0);
+        }
     )SHADER";
     return shader.str();
 }
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h
index 8580522..44f5fde 100644
--- a/libs/renderengine/gl/filters/GaussianBlurFilter.h
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h
@@ -28,9 +28,12 @@
 namespace renderengine {
 namespace gl {
 
+// Class that implements a Gaussian Filter that uses Linear Sampling
+// to halve the number of samples and reduce runtime by 40% as described in:
+// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling
 class GaussianBlurFilter : public BlurFilter {
 public:
-    static constexpr uint32_t kNumSamples = 12;
+    static constexpr uint32_t kNumSamples = 22;
 
     explicit GaussianBlurFilter(GLESRenderEngine& engine);
     status_t prepare() override;
@@ -47,7 +50,7 @@
     GLuint mVPosLoc;
     GLuint mVUvLoc;
     GLuint mVTextureLoc;
-    GLuint mVIncrementLoc;
+    GLuint mVGaussianOffsetLoc;
     GLuint mVNumSamplesLoc;
     GLuint mVGaussianWeightLoc;
 
@@ -56,7 +59,7 @@
     GLuint mHPosLoc;
     GLuint mHUvLoc;
     GLuint mHTextureLoc;
-    GLuint mHIncrementLoc;
+    GLuint mHGaussianOffsetLoc;
     GLuint mHNumSamplesLoc;
     GLuint mHGaussianWeightLoc;
 };
diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
index fc26bcc..7524c6d 100644
--- a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
+++ b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
@@ -106,21 +106,19 @@
         precision mediump float;
 
         uniform sampler2D uTexture;
-        highp uniform vec2 uOffset;
+        uniform vec2 uOffset;
 
         highp in vec2 vUV;
         out vec4 fragColor;
 
-        vec4 kawaseBlur() {
-            return (texture(uTexture, vec2(-1.0, 1.0) * uOffset + vUV, 0.0)
-                    + texture(uTexture, uOffset + vUV, 0.0)
-                    + texture(uTexture, vec2(1.0, -1.0) * uOffset + vUV, 0.0)
-                    + texture(uTexture, vec2(-1.0) * uOffset + vUV, 0.0))
-                * 0.25;
-        }
-
         void main() {
-            fragColor = kawaseBlur();
+            fragColor  = texture(uTexture, vUV, 0.0);
+            fragColor += texture(uTexture, vUV + vec2( uOffset.x,  uOffset.y), 0.0);
+            fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0);
+            fragColor += texture(uTexture, vUV + vec2(-uOffset.x,  uOffset.y), 0.0);
+            fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0);
+
+            fragColor = vec4(fragColor.rgb * 0.2, 1.0);
         }
     )SHADER";
 }
diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h
index ec81f81..20009cf 100644
--- a/libs/renderengine/gl/filters/KawaseBlurFilter.h
+++ b/libs/renderengine/gl/filters/KawaseBlurFilter.h
@@ -30,7 +30,7 @@
 
 class KawaseBlurFilter : public BlurFilter {
 public:
-    static constexpr uint32_t kMaxPasses = 8;
+    static constexpr uint32_t kMaxPasses = 6;
 
     explicit KawaseBlurFilter(GLESRenderEngine& engine);
     status_t prepare() override;
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 7773319..69f86d3 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,8 +20,11 @@
 
 namespace android {
 
+enum class DisplayConnectionType { Internal, External };
+
 // Immutable information about physical display.
 struct DisplayInfo {
+    DisplayConnectionType connectionType = DisplayConnectionType::Internal;
     float density = 0.f;
     bool secure = false;
 };
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index d94fb27..8ff0711 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -36,4 +36,8 @@
     local_include_dirs: [
         "include",
     ],
+
+    cflags: [
+        "-DLOG_TAG=\"AutomotiveDisplayService\""
+    ],
 }
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index 3cd8e39..4767406 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -27,97 +27,163 @@
 namespace V1_0 {
 namespace implementation {
 
-Return<sp<IGraphicBufferProducer>>
-AutomotiveDisplayProxyService::getIGraphicBufferProducer() {
-    if (mSurface == nullptr) {
-        status_t err;
-        mSurfaceComposerClient = new SurfaceComposerClient();
 
-        err = mSurfaceComposerClient->initCheck();
+Return<sp<IGraphicBufferProducer>>
+AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) {
+    auto it = mDisplays.find(id);
+    sp<IBinder> displayToken = nullptr;
+    sp<SurfaceControl> surfaceControl = nullptr;
+    if (it == mDisplays.end()) {
+        displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id);
+        if (displayToken == nullptr) {
+            ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
+            return nullptr;
+        }
+
+        // Get the resolution from stored display state.
+        DisplayConfig displayConfig = {};
+        auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+        if (err != NO_ERROR) {
+            ALOGE("Failed to get display configuration of %lX.  "
+                  "This display will be ignored.", (unsigned long)id);
+            return nullptr;
+        }
+
+        ui::DisplayState displayState = {};
+        err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+        if (err != NO_ERROR) {
+            ALOGE("Failed to get current display status of %lX.  "
+                  "This display will be ignored.", (unsigned long)id);
+            return nullptr;
+        }
+
+        auto displayWidth  = displayConfig.resolution.getWidth();
+        auto displayHeight = displayConfig.resolution.getHeight();
+        if ((displayState.orientation != ui::ROTATION_0) &&
+            (displayState.orientation != ui::ROTATION_180)) {
+            std::swap(displayWidth, displayHeight);
+        }
+
+        sp<android::SurfaceComposerClient> surfaceClient = new SurfaceComposerClient();
+        err = surfaceClient->initCheck();
         if (err != NO_ERROR) {
             ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
-            mSurfaceComposerClient = nullptr;
             return nullptr;
         }
 
-        const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
-        if (displayToken == nullptr) {
-            ALOGE("Failed to get internal display ");
-            return nullptr;
-        }
-
-        err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &mDpyConfig);
-        if (err != NO_ERROR) {
-            ALOGE("Failed to get active display config");
-            return nullptr;
-        }
-
-        err = SurfaceComposerClient::getDisplayState(displayToken, &mDpyState);
-        if (err != NO_ERROR) {
-            ALOGE("Failed to get display state");
-            return nullptr;
-        }
-
-        const ui::Size& resolution = mDpyConfig.resolution;
-        auto width = resolution.getWidth();
-        auto height = resolution.getHeight();
-
-        if (mDpyState.orientation == ui::ROTATION_90 ||
-            mDpyState.orientation == ui::ROTATION_270) {
-            std::swap(width, height);
-        }
-
-        mSurfaceControl = mSurfaceComposerClient->createSurface(
-                String8("Automotive Display"), width, height,
+        // Create a SurfaceControl instance
+        surfaceControl = surfaceClient->createSurface(
+                String8::format("AutomotiveDisplay::%lX", (unsigned long)id),
+                displayWidth, displayHeight,
                 PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
-        if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) {
-            ALOGE("Failed to create SurfaceControl");
-            mSurfaceComposerClient = nullptr;
-            mSurfaceControl = nullptr;
+        if (surfaceControl == nullptr || !surfaceControl->isValid()) {
+            ALOGE("Failed to create SurfaceControl.");
             return nullptr;
         }
 
-        // SurfaceControl::getSurface is guaranteed to be not null.
-        mSurface = mSurfaceControl->getSurface();
+        // Store
+        DisplayDesc descriptor = {displayToken, surfaceControl};
+        mDisplays.insert_or_assign(id, std::move(descriptor));
+    } else {
+        displayToken = it->second.token;
+        surfaceControl = it->second.surfaceControl;
     }
 
+    // SurfaceControl::getSurface is guaranteed to be not null.
+    auto targetSurface = surfaceControl->getSurface();
     return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
-                    B2HGraphicBufferProducer(
-                        mSurface->getIGraphicBufferProducer());
+               B2HGraphicBufferProducer(targetSurface->getIGraphicBufferProducer());
 }
 
-Return<bool> AutomotiveDisplayProxyService::showWindow() {
-    status_t status = NO_ERROR;
 
-    if (mSurfaceControl != nullptr) {
-        status = SurfaceComposerClient::Transaction{}
-                         .setLayer(
-                             mSurfaceControl, 0x7FFFFFFF) // always on top
-                         .show(mSurfaceControl)
-                         .apply();
-    } else {
-        ALOGE("showWindow: Failed to get a valid SurfaceControl!");
+Return<bool> AutomotiveDisplayProxyService::showWindow(uint64_t id) {
+    auto it = mDisplays.find(id);
+    if (it == mDisplays.end()) {
+        ALOGE("Given display token is invalid or unknown.");
         return false;
     }
 
+    ui::DisplayState displayState;
+    auto err = SurfaceComposerClient::getDisplayState(it->second.token, &displayState);
+    if (err != NO_ERROR) {
+        ALOGE("Failed to get current state of the display 0x%lX", (unsigned long)id);
+        return false;
+    }
+
+    SurfaceComposerClient::Transaction t;
+    t.setDisplayLayerStack(it->second.token, displayState.layerStack);
+    t.setLayerStack(it->second.surfaceControl, displayState.layerStack);
+
+    status_t status = t.setLayer(it->second.surfaceControl, 0x7FFFFFFF)
+                      .show(it->second.surfaceControl)
+                      .apply();
+
     return status == NO_ERROR;
 }
 
-Return<bool> AutomotiveDisplayProxyService::hideWindow() {
-    status_t status = NO_ERROR;
 
-    if (mSurfaceControl != nullptr) {
-        status = SurfaceComposerClient::Transaction{}
-                        .hide(mSurfaceControl)
-                        .apply();
-    } else {
-        ALOGE("hideWindow: Failed to get a valid SurfaceControl!");
+Return<bool> AutomotiveDisplayProxyService::hideWindow(uint64_t id) {
+    auto it = mDisplays.find(id);
+    if (it == mDisplays.end()) {
+        ALOGE("Given display token is invalid or unknown.");
         return false;
     }
 
+    status_t status = SurfaceComposerClient::Transaction{}
+                      .hide(it->second.surfaceControl)
+                      .apply();
+
     return status == NO_ERROR;
 }
 
+
+Return<void> AutomotiveDisplayProxyService::getDisplayIdList(getDisplayIdList_cb _cb) {
+    hardware::hidl_vec<uint64_t> ids;
+
+    // Get stable IDs of all available displays and get their tokens and
+    // descriptors.
+    auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
+    ids.resize(displayIds.size());
+    for (auto i = 0; i < displayIds.size(); ++i) {
+        ids[i] = displayIds[i];
+    }
+
+    _cb(ids);
+    return hardware::Void();
+}
+
+
+Return<void> AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDisplayInfo_cb _cb) {
+    HwDisplayConfig activeConfig;
+    HwDisplayState  activeState;
+
+    auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id);
+    if (displayToken == nullptr) {
+        ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
+    } else {
+        DisplayConfig displayConfig = {};
+        auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+        if (err != NO_ERROR) {
+            ALOGW("Failed to get display configuration of %lX.  "
+                  "This display will be ignored.", (unsigned long)id);
+        }
+
+        ui::DisplayState displayState = {};
+        err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+        if (err != NO_ERROR) {
+            ALOGW("Failed to get current display status of %lX.  "
+                  "This display will be ignored.", (unsigned long)id);
+        }
+
+        activeConfig.setToExternal((uint8_t*)&displayConfig, sizeof(DisplayConfig));
+        activeState.setToExternal((uint8_t*)&displayState, sizeof(DisplayState));
+    }
+
+    _cb(activeConfig, activeState);
+    return hardware::Void();
+}
+
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace display
diff --git a/services/automotive/display/include/AutomotiveDisplayProxyService.h b/services/automotive/display/include/AutomotiveDisplayProxyService.h
index 3956602..e2fc0d2 100644
--- a/services/automotive/display/include/AutomotiveDisplayProxyService.h
+++ b/services/automotive/display/include/AutomotiveDisplayProxyService.h
@@ -16,12 +16,14 @@
 #pragma once
 
 #include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <ui/DisplayConfig.h>
 #include <ui/DisplayState.h>
+#include <tuple>
+#include <vector>
 
 namespace android {
 namespace frameworks {
@@ -31,32 +33,30 @@
 namespace implementation {
 
 using ::android::hardware::Return;
-using ::android::sp;
 using ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
+using ::android::sp;
+
+
+typedef struct DisplayDesc {
+    sp<IBinder>        token;
+    sp<SurfaceControl> surfaceControl;
+} DisplayDesc;
+
 
 class AutomotiveDisplayProxyService : public IAutomotiveDisplayProxyService {
 public:
-    Return<sp<IGraphicBufferProducer>> getIGraphicBufferProducer() override;
-    Return<bool> showWindow() override;
-    Return<bool> hideWindow() override;
-    Return<void> getDisplayInfo(getDisplayInfo_cb _info_cb) override {
-        HwDisplayConfig cfg;
-        cfg.setToExternal((uint8_t*)&mDpyConfig, sizeof(DisplayConfig));
-
-        HwDisplayState state;
-        state.setToExternal((uint8_t*)&mDpyState, sizeof(DisplayState));
-
-       _info_cb(cfg, state);
-        return hardware::Void();
-    }
+    Return<sp<IGraphicBufferProducer>> getIGraphicBufferProducer(uint64_t id) override;
+    Return<bool> showWindow(uint64_t id) override;
+    Return<bool> hideWindow(uint64_t id) override;
+    Return<void> getDisplayIdList(getDisplayIdList_cb _cb) override;
+    Return<void> getDisplayInfo(uint64_t, getDisplayInfo_cb _cb) override;
 
 private:
-    sp<android::Surface> mSurface;
-    sp<android::SurfaceComposerClient> mSurfaceComposerClient;
-    sp<android::SurfaceControl> mSurfaceControl;
-    DisplayConfig mDpyConfig;
-    ui::DisplayState mDpyState;
+    uint8_t getDisplayPort(const uint64_t id) { return (id & 0xF); }
+
+    std::unordered_map<uint64_t, DisplayDesc> mDisplays;
 };
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace display
diff --git a/services/automotive/display/main_automotivedisplayproxy.cpp b/services/automotive/display/main_automotivedisplayproxy.cpp
index 626c185..59b584c 100644
--- a/services/automotive/display/main_automotivedisplayproxy.cpp
+++ b/services/automotive/display/main_automotivedisplayproxy.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AutomotiveDisplayService"
-
 #include <unistd.h>
 
 #include <hidl/HidlTransportSupport.h>
@@ -39,9 +37,10 @@
 const static char kServiceName[] = "default";
 
 int main() {
-    ALOGI("Car Window Service is starting");
+    ALOGI("Automotive Display Proxy Service is starting");
 
-    android::sp<IAutomotiveDisplayProxyService> service = new AutomotiveDisplayProxyService();
+    android::sp<IAutomotiveDisplayProxyService> service =
+        new AutomotiveDisplayProxyService();
 
     configureRpcThreadpool(1, true /* callerWillJoin */);
 
@@ -56,7 +55,7 @@
     }
 
     // In normal operation, we don't expect the thread pool to exit
-    ALOGE("Car Window Service is shutting down");
+    ALOGE("Automotive Window Service is shutting down");
 
     return 1;
 }
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 308e93a..5c80d55 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -40,6 +40,7 @@
         "libinputreporter",
         "libinputreader",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "libhidlbase",
         "libinput",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index a556aad..3f956a8 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -28,6 +28,7 @@
     ],
     shared_libs: [
         "libbase",
+        "libcrypto",
         "libcutils",
         "libinput",
         "libinputreporter",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a8158ba..75bc0aa 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -60,7 +60,10 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/stringprintf.h>
 #include <binder/Binder.h>
+#include <input/InputDevice.h>
 #include <log/log.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
 #include <powermanager/PowerManager.h>
 #include <utils/Trace.h>
 
@@ -325,6 +328,55 @@
     return dispatchEntry;
 }
 
+static std::array<uint8_t, 128> getRandomKey() {
+    std::array<uint8_t, 128> key;
+    if (RAND_bytes(key.data(), key.size()) != 1) {
+        LOG_ALWAYS_FATAL("Can't generate HMAC key");
+    }
+    return key;
+}
+
+// --- HmacKeyManager ---
+
+HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {}
+
+std::array<uint8_t, 32> HmacKeyManager::sign(const VerifiedInputEvent& event) const {
+    size_t size;
+    switch (event.type) {
+        case VerifiedInputEvent::Type::KEY: {
+            size = sizeof(VerifiedKeyEvent);
+            break;
+        }
+        case VerifiedInputEvent::Type::MOTION: {
+            size = sizeof(VerifiedMotionEvent);
+            break;
+        }
+    }
+    std::vector<uint8_t> data;
+    const uint8_t* start = reinterpret_cast<const uint8_t*>(&event);
+    data.assign(start, start + size);
+    return sign(data);
+}
+
+std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const {
+    // SHA256 always generates 32-bytes result
+    std::array<uint8_t, 32> hash;
+    unsigned int hashLen = 0;
+    uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(),
+                           hash.data(), &hashLen);
+    if (result == nullptr) {
+        ALOGE("Could not sign the data using HMAC");
+        return INVALID_HMAC;
+    }
+
+    if (hashLen != hash.size()) {
+        ALOGE("HMAC-SHA256 has unexpected length");
+        return INVALID_HMAC;
+    }
+
+    return hash;
+}
+
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -3153,22 +3205,22 @@
     std::queue<EventEntry*> injectedEntries;
     switch (event->getType()) {
         case AINPUT_EVENT_TYPE_KEY: {
-            KeyEvent keyEvent;
-            keyEvent.initialize(*static_cast<const KeyEvent*>(event));
-            int32_t action = keyEvent.getAction();
+            const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
+            int32_t action = incomingKey.getAction();
             if (!validateKeyEvent(action)) {
                 return INPUT_EVENT_INJECTION_FAILED;
             }
 
-            int32_t flags = keyEvent.getFlags();
-            int32_t keyCode = keyEvent.getKeyCode();
-            int32_t metaState = keyEvent.getMetaState();
-            accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
+            int32_t flags = incomingKey.getFlags();
+            int32_t keyCode = incomingKey.getKeyCode();
+            int32_t metaState = incomingKey.getMetaState();
+            accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action,
                                     /*byref*/ keyCode, /*byref*/ metaState);
-            keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(),
-                                keyEvent.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
-                                keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
-                                keyEvent.getDownTime(), keyEvent.getEventTime());
+            KeyEvent keyEvent;
+            keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+                                incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
+                                incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
+                                incomingKey.getDownTime(), incomingKey.getEventTime());
 
             if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
                 policyFlags |= POLICY_FLAG_VIRTUAL;
@@ -3186,11 +3238,10 @@
             mLock.lock();
             KeyEntry* injectedEntry =
                     new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
-                                 keyEvent.getDeviceId(), keyEvent.getSource(),
-                                 keyEvent.getDisplayId(), policyFlags, action, flags,
-                                 keyEvent.getKeyCode(), keyEvent.getScanCode(),
-                                 keyEvent.getMetaState(), keyEvent.getRepeatCount(),
-                                 keyEvent.getDownTime());
+                                 VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(),
+                                 policyFlags, action, flags, keyEvent.getKeyCode(),
+                                 keyEvent.getScanCode(), keyEvent.getMetaState(),
+                                 keyEvent.getRepeatCount(), keyEvent.getDownTime());
             injectedEntries.push(injectedEntry);
             break;
         }
@@ -3221,7 +3272,7 @@
             const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
             MotionEntry* injectedEntry =
                     new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
-                                    motionEvent->getDeviceId(), motionEvent->getSource(),
+                                    VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
                                     motionEvent->getDisplayId(), policyFlags, action, actionButton,
                                     motionEvent->getFlags(), motionEvent->getMetaState(),
                                     motionEvent->getButtonState(), motionEvent->getClassification(),
@@ -3238,7 +3289,7 @@
                 samplePointerCoords += pointerCount;
                 MotionEntry* nextInjectedEntry =
                         new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
-                                        motionEvent->getDeviceId(), motionEvent->getSource(),
+                                        VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
                                         motionEvent->getDisplayId(), policyFlags, action,
                                         actionButton, motionEvent->getFlags(),
                                         motionEvent->getMetaState(), motionEvent->getButtonState(),
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 72511e9..ded59a5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -56,6 +56,16 @@
 
 class Connection;
 
+class HmacKeyManager {
+public:
+    HmacKeyManager();
+    std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
+
+private:
+    std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const;
+    const std::array<uint8_t, 128> mHmacKey;
+};
+
 /* Dispatches events to input targets.  Some functions of the input dispatcher, such as
  * identifying input targets, are controlled by a separate policy object.
  *
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 09ecb13..f913d82 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -10,6 +10,7 @@
         "InputClassifierConverter_test.cpp",
         "InputDispatcher_test.cpp",
         "InputReader_test.cpp",
+        "UinputDevice.cpp",
     ],
     cflags: [
         "-Wall",
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index 6504738..be2e19e 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -16,7 +16,8 @@
 
 #include "EventHub.h"
 
-#include <android-base/stringprintf.h>
+#include "UinputDevice.h"
+
 #include <gtest/gtest.h>
 #include <inttypes.h>
 #include <linux/uinput.h>
@@ -25,16 +26,16 @@
 
 #define TAG "EventHub_test"
 
+using android::createUinputDevice;
 using android::EventHub;
 using android::EventHubInterface;
 using android::InputDeviceIdentifier;
 using android::RawEvent;
 using android::sp;
-using android::base::StringPrintf;
+using android::UinputHomeKey;
 using std::chrono_literals::operator""ms;
 
 static constexpr bool DEBUG = false;
-static const char* DEVICE_NAME = "EventHub Test Device";
 
 static void dumpEvents(const std::vector<RawEvent>& events) {
     for (const RawEvent& event : events) {
@@ -62,27 +63,26 @@
 protected:
     std::unique_ptr<EventHubInterface> mEventHub;
     // We are only going to emulate a single input device currently.
-    android::base::unique_fd mDeviceFd;
+    std::unique_ptr<UinputHomeKey> mKeyboard;
     int32_t mDeviceId;
+
     virtual void SetUp() override {
         mEventHub = std::make_unique<EventHub>();
         consumeInitialDeviceAddedEvents();
-        createDevice();
+        mKeyboard = createUinputDevice<UinputHomeKey>();
         mDeviceId = waitForDeviceCreation();
     }
     virtual void TearDown() override {
-        mDeviceFd.reset();
+        mKeyboard.reset();
         waitForDeviceClose(mDeviceId);
     }
 
-    void createDevice();
     /**
      * Return the device id of the created device.
      */
     int32_t waitForDeviceCreation();
     void waitForDeviceClose(int32_t deviceId);
     void consumeInitialDeviceAddedEvents();
-    void sendEvent(uint16_t type, uint16_t code, int32_t value);
     std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms);
 };
 
@@ -105,48 +105,6 @@
     return events;
 }
 
-void EventHubTest::createDevice() {
-    mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
-    if (mDeviceFd < 0) {
-        FAIL() << "Can't open /dev/uinput :" << strerror(errno);
-    }
-
-    /**
-     * Signal which type of events this input device supports.
-     * We will emulate a keyboard here.
-     */
-    // enable key press/release event
-    if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) {
-        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
-    }
-
-    // enable set of KEY events
-    if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) {
-        ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno);
-    }
-
-    // enable synchronization event
-    if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) {
-        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
-    }
-
-    struct uinput_user_dev keyboard = {};
-    strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE);
-    keyboard.id.bustype = BUS_USB;
-    keyboard.id.vendor = 0x01;
-    keyboard.id.product = 0x01;
-    keyboard.id.version = 1;
-
-    if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) {
-        FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
-               << strerror(errno);
-    }
-
-    if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
-        FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
-    }
-}
-
 /**
  * Since the test runs on a real platform, there will be existing devices
  * in addition to the test devices being added. Therefore, when EventHub is first created,
@@ -176,7 +134,7 @@
     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type);
     InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId);
     const int32_t deviceId = deviceAddedEvent.deviceId;
-    EXPECT_EQ(identifier.name, DEVICE_NAME);
+    EXPECT_EQ(identifier.name, mKeyboard->getName());
     const RawEvent& finishedDeviceScanEvent = events[1];
     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN),
               finishedDeviceScanEvent.type);
@@ -194,22 +152,6 @@
               finishedDeviceScanEvent.type);
 }
 
-void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) {
-    struct input_event event = {};
-    event.type = type;
-    event.code = code;
-    event.value = value;
-    event.time = {}; // uinput ignores the timestamp
-
-    if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
-        std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16
-                                       " with value %" PRId32 " : %s",
-                                       type, code, value, strerror(errno));
-        ALOGE("%s", msg.c_str());
-        ADD_FAILURE() << msg.c_str();
-    }
-}
-
 /**
  * Ensure that input_events are generated with monotonic clock.
  * That means input_event should receive a timestamp that is in the future of the time
@@ -218,13 +160,7 @@
  */
 TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) {
     nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    // key press
-    sendEvent(EV_KEY, KEY_HOME, 1);
-    sendEvent(EV_SYN, SYN_REPORT, 0);
-
-    // key release
-    sendEvent(EV_KEY, KEY_HOME, 0);
-    sendEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey());
 
     std::vector<RawEvent> events = getEvents();
     ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events";
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 27db8f5..c4092cd 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -43,6 +43,18 @@
     float y;
 };
 
+/**
+ * Return a DOWN key event with KEYCODE_A.
+ */
+static KeyEvent getTestKeyEvent() {
+    KeyEvent event;
+
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
+                     AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
+                     ARBITRARY_TIME);
+    return event;
+}
+
 // --- FakeInputDispatcherPolicy ---
 
 class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -197,6 +209,69 @@
     }
 };
 
+// --- HmacKeyManagerTest ---
+
+class HmacKeyManagerTest : public testing::Test {
+protected:
+    HmacKeyManager mHmacKeyManager;
+};
+
+/**
+ * Ensure that separate calls to sign the same data are generating the same key.
+ * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
+ * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
+ * tests.
+ */
+TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) {
+    KeyEvent event = getTestKeyEvent();
+    VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
+
+    std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(verifiedEvent);
+    std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(verifiedEvent);
+    ASSERT_EQ(hmac1, hmac2);
+}
+
+/**
+ * Ensure that changes in VerifiedKeyEvent produce a different hmac.
+ */
+TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) {
+    KeyEvent event = getTestKeyEvent();
+    VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
+    std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(verifiedEvent);
+
+    verifiedEvent.deviceId += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.source += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.eventTimeNanos += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.displayId += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.action += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.downTimeNanos += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.flags += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.keyCode += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.scanCode += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.metaState += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+    verifiedEvent.repeatCount += 1;
+    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+}
 
 // --- InputDispatcherTest ---
 
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
new file mode 100644
index 0000000..2775d21
--- /dev/null
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "UinputDevice.h"
+
+#include <android-base/stringprintf.h>
+
+namespace android {
+
+// --- UinputDevice ---
+
+UinputDevice::UinputDevice(const char* name) : mName(name) {}
+
+UinputDevice::~UinputDevice() {
+    if (ioctl(mDeviceFd, UI_DEV_DESTROY)) {
+        ALOGE("Error while destroying uinput device: %s", strerror(errno));
+    }
+    mDeviceFd.reset();
+}
+
+void UinputDevice::init() {
+    mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+    if (mDeviceFd < 0) {
+        FAIL() << "Can't open /dev/uinput :" << strerror(errno);
+    }
+
+    struct uinput_user_dev device = {};
+    strlcpy(device.name, mName, UINPUT_MAX_NAME_SIZE);
+    device.id.bustype = BUS_USB;
+    device.id.vendor = 0x01;
+    device.id.product = 0x01;
+    device.id.version = 1;
+
+    // Using EXPECT instead of ASSERT to allow the device creation to continue even when
+    // some failures are reported when configuring the device.
+    EXPECT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
+
+    if (write(mDeviceFd, &device, sizeof(device)) < 0) {
+        FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
+               << strerror(errno);
+    }
+
+    if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
+        FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
+    }
+}
+
+void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
+    struct input_event event = {};
+    event.type = type;
+    event.code = code;
+    event.value = value;
+    event.time = {}; // uinput ignores the timestamp
+
+    if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
+        std::string msg = base::StringPrintf("Could not write event %" PRIu16 " %" PRIu16
+                                             " with value %" PRId32 " : %s",
+                                             type, code, value, strerror(errno));
+        ALOGE("%s", msg.c_str());
+        ADD_FAILURE() << msg.c_str();
+    }
+}
+
+// --- UinputKeyboard ---
+
+UinputKeyboard::UinputKeyboard(std::initializer_list<int> keys)
+      : UinputDevice(UinputKeyboard::KEYBOARD_NAME), mKeys(keys.begin(), keys.end()) {}
+
+void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) {
+    // enable key press/release event
+    if (ioctl(fd, UI_SET_EVBIT, EV_KEY)) {
+        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
+    }
+
+    // enable set of KEY events
+    std::for_each(mKeys.begin(), mKeys.end(), [fd](int key) {
+        if (ioctl(fd, UI_SET_KEYBIT, key)) {
+            ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
+        }
+    });
+
+    // enable synchronization event
+    if (ioctl(fd, UI_SET_EVBIT, EV_SYN)) {
+        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
+    }
+}
+
+void UinputKeyboard::pressKey(int key) {
+    if (mKeys.find(key) == mKeys.end()) {
+        ADD_FAILURE() << mName << ": Cannot inject key press: Key not found: " << key;
+    }
+    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 1));
+    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputKeyboard::releaseKey(int key) {
+    if (mKeys.find(key) == mKeys.end()) {
+        ADD_FAILURE() << mName << ": Cannot inject key release: Key not found: " << key;
+    }
+    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 0));
+    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputKeyboard::pressAndReleaseKey(int key) {
+    EXPECT_NO_FATAL_FAILURE(pressKey(key));
+    EXPECT_NO_FATAL_FAILURE(releaseKey(key));
+}
+
+// --- UinputHomeKey---
+
+UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {}
+
+void UinputHomeKey::pressAndReleaseHomeKey() {
+    EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME));
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
new file mode 100644
index 0000000..57d9011
--- /dev/null
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -0,0 +1,111 @@
+/*
+ * 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 _UI_TEST_INPUT_UINPUT_INJECTOR_H
+#define _UI_TEST_INPUT_UINPUT_INJECTOR_H
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <linux/uinput.h>
+#include <log/log.h>
+
+#include <memory>
+
+namespace android {
+
+// This is the factory method that must be used to create a UinputDevice.
+template <class D, class... Ts>
+std::unique_ptr<D> createUinputDevice(Ts... args) {
+    // Using `new` to access non-public constructors.
+    std::unique_ptr<D> dev(new D(&args...));
+    EXPECT_NO_FATAL_FAILURE(dev->init());
+    return dev;
+}
+
+// --- UinputDevice ---
+
+class UinputDevice {
+public:
+    virtual ~UinputDevice();
+
+    inline const char* getName() const { return mName; }
+
+    // Subclasses must either provide a public constructor or must be-friend the factory method.
+    template <class D, class... Ts>
+    friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+protected:
+    const char* mName;
+
+    UinputDevice(const char* name);
+
+    // Signals which types of events this device supports before it is created.
+    // This must be overridden by subclasses.
+    virtual void configureDevice(int fd, uinput_user_dev* device) = 0;
+
+    void injectEvent(uint16_t type, uint16_t code, int32_t value);
+
+private:
+    base::unique_fd mDeviceFd;
+
+    // This is called once by the factory method createUinputDevice().
+    void init();
+};
+
+// --- UinputKeyboard ---
+
+class UinputKeyboard : public UinputDevice {
+public:
+    static constexpr const char* KEYBOARD_NAME = "Test Keyboard Device";
+
+    // Injects key press and sync.
+    void pressKey(int key);
+    // Injects key release and sync.
+    void releaseKey(int key);
+    // Injects 4 events: key press, sync, key release, and sync.
+    void pressAndReleaseKey(int key);
+
+    template <class D, class... Ts>
+    friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+protected:
+    UinputKeyboard(std::initializer_list<int> keys = {});
+
+private:
+    void configureDevice(int fd, uinput_user_dev* device) override;
+
+    std::set<int> mKeys;
+};
+
+// --- UinputHomeKey---
+
+// A keyboard device that has a single HOME key.
+class UinputHomeKey : public UinputKeyboard {
+public:
+    // Injects 4 events: key press, sync, key release, and sync.
+    void pressAndReleaseHomeKey();
+
+    template <class D, class... Ts>
+    friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+private:
+    UinputHomeKey();
+};
+
+} // namespace android
+
+#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 914a4cb..22a15c6 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -210,12 +210,6 @@
                 registerSensor(new RotationVectorSensor(), !needRotationVector, true);
                 registerSensor(new OrientationSensor(), !needRotationVector, true);
 
-                bool needLinearAcceleration =
-                        (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
-
-                registerSensor(new LinearAccelerationSensor(list, count),
-                               !needLinearAcceleration, true);
-
                 // virtual debugging sensors are not for user
                 registerSensor( new CorrectedGyroSensor(list, count), true, true);
                 registerSensor( new GyroDriftSensor(), true, true);
@@ -225,6 +219,11 @@
                 bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0;
                 registerSensor(new GravitySensor(list, count), !needGravitySensor, true);
 
+                bool needLinearAcceleration =
+                        (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
+                registerSensor(new LinearAccelerationSensor(list, count),
+                               !needLinearAcceleration, true);
+
                 bool needGameRotationVector =
                         (virtualSensorsNeeds & (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) != 0;
                 registerSensor(new GameRotationVectorSensor(), !needGameRotationVector, true);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 1b1e889..4ffdf97 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -136,7 +136,7 @@
         "BufferStateLayer.cpp",
         "ClientCache.cpp",
         "Client.cpp",
-        "ColorLayer.cpp",
+        "EffectLayer.cpp",
         "ContainerLayer.cpp",
         "DisplayDevice.cpp",
         "DisplayHardware/ComposerHal.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f4f45be..d7ec868 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -180,95 +180,91 @@
     }
     bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
             (isSecure() && !targetSettings.isSecure);
-    const State& s(getDrawingState());
     compositionengine::LayerFE::LayerSettings& layer = *result;
-    if (!blackOutLayer) {
-        layer.source.buffer.buffer = mBufferInfo.mBuffer;
-        layer.source.buffer.isOpaque = isOpaque(s);
-        layer.source.buffer.fence = mBufferInfo.mFence;
-        layer.source.buffer.textureName = mTextureName;
-        layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
-        layer.source.buffer.isY410BT2020 = isHdrY410();
-        bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
-        bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
-        layer.source.buffer.maxMasteringLuminance = hasSmpte2086
-                ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
-                : defaultMaxMasteringLuminance;
-        layer.source.buffer.maxContentLuminance = hasCta861_3
-                ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
-                : defaultMaxContentLuminance;
-        layer.frameNumber = mCurrentFrameNumber;
-        layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
-
-        // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
-
-        // Query the texture matrix given our current filtering mode.
-        float textureMatrix[16];
-        getDrawingTransformMatrix(useFiltering, textureMatrix);
-
-        if (getTransformToDisplayInverse()) {
-            /*
-             * the code below applies the primary display's inverse transform to
-             * the texture transform
-             */
-            uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
-            mat4 tr = inverseOrientation(transform);
-
-            /**
-             * TODO(b/36727915): This is basically a hack.
-             *
-             * Ensure that regardless of the parent transformation,
-             * this buffer is always transformed from native display
-             * orientation to display orientation. For example, in the case
-             * of a camera where the buffer remains in native orientation,
-             * we want the pixels to always be upright.
-             */
-            sp<Layer> p = mDrawingParent.promote();
-            if (p != nullptr) {
-                const auto parentTransform = p->getTransform();
-                tr = tr * inverseOrientation(parentTransform.getOrientation());
-            }
-
-            // and finally apply it to the original texture matrix
-            const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
-            memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
-        }
-
-        const Rect win{getBounds()};
-        float bufferWidth = getBufferSize(s).getWidth();
-        float bufferHeight = getBufferSize(s).getHeight();
-
-        // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
-        // been set and there is no parent layer bounds. In that case, the scale is meaningless so
-        // ignore them.
-        if (!getBufferSize(s).isValid()) {
-            bufferWidth = float(win.right) - float(win.left);
-            bufferHeight = float(win.bottom) - float(win.top);
-        }
-
-        const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
-        const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
-        const float translateY = float(win.top) / bufferHeight;
-        const float translateX = float(win.left) / bufferWidth;
-
-        // Flip y-coordinates because GLConsumer expects OpenGL convention.
-        mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
-                mat4::translate(vec4(-.5, -.5, 0, 1)) *
-                mat4::translate(vec4(translateX, translateY, 0, 1)) *
-                mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
-
-        layer.source.buffer.useTextureFiltering = useFiltering;
-        layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
-    } else {
-        // If layer is blacked out, force alpha to 1 so that we draw a black color
-        // layer.
-        layer.source.buffer.buffer = nullptr;
-        layer.alpha = 1.0;
-        layer.frameNumber = 0;
-        layer.bufferId = 0;
+    if (blackOutLayer) {
+        prepareClearClientComposition(layer, true /* blackout */);
+        return layer;
     }
 
+    const State& s(getDrawingState());
+    layer.source.buffer.buffer = mBufferInfo.mBuffer;
+    layer.source.buffer.isOpaque = isOpaque(s);
+    layer.source.buffer.fence = mBufferInfo.mFence;
+    layer.source.buffer.textureName = mTextureName;
+    layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+    layer.source.buffer.isY410BT2020 = isHdrY410();
+    bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+    bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+    layer.source.buffer.maxMasteringLuminance = hasSmpte2086
+            ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
+            : defaultMaxMasteringLuminance;
+    layer.source.buffer.maxContentLuminance = hasCta861_3
+            ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
+            : defaultMaxContentLuminance;
+    layer.frameNumber = mCurrentFrameNumber;
+    layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
+    // TODO: we could be more subtle with isFixedSize()
+    const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+
+    // Query the texture matrix given our current filtering mode.
+    float textureMatrix[16];
+    getDrawingTransformMatrix(useFiltering, textureMatrix);
+
+    if (getTransformToDisplayInverse()) {
+        /*
+         * the code below applies the primary display's inverse transform to
+         * the texture transform
+         */
+        uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+        mat4 tr = inverseOrientation(transform);
+
+        /**
+         * TODO(b/36727915): This is basically a hack.
+         *
+         * Ensure that regardless of the parent transformation,
+         * this buffer is always transformed from native display
+         * orientation to display orientation. For example, in the case
+         * of a camera where the buffer remains in native orientation,
+         * we want the pixels to always be upright.
+         */
+        sp<Layer> p = mDrawingParent.promote();
+        if (p != nullptr) {
+            const auto parentTransform = p->getTransform();
+            tr = tr * inverseOrientation(parentTransform.getOrientation());
+        }
+
+        // and finally apply it to the original texture matrix
+        const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+        memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+    }
+
+    const Rect win{getBounds()};
+    float bufferWidth = getBufferSize(s).getWidth();
+    float bufferHeight = getBufferSize(s).getHeight();
+
+    // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
+    // been set and there is no parent layer bounds. In that case, the scale is meaningless so
+    // ignore them.
+    if (!getBufferSize(s).isValid()) {
+        bufferWidth = float(win.right) - float(win.left);
+        bufferHeight = float(win.bottom) - float(win.top);
+    }
+
+    const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+    const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+    const float translateY = float(win.top) / bufferHeight;
+    const float translateX = float(win.left) / bufferWidth;
+
+    // Flip y-coordinates because GLConsumer expects OpenGL convention.
+    mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+            mat4::translate(vec4(-.5, -.5, 0, 1)) *
+            mat4::translate(vec4(translateX, translateY, 0, 1)) *
+            mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
+
+    layer.source.buffer.useTextureFiltering = useFiltering;
+    layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
+
     return layer;
 }
 
@@ -329,6 +325,7 @@
         Mutex::Autolock lock(mFrameEventHistoryMutex);
         mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
                                               compositorTiming);
+        finalizeFrameEventHistory(glDoneFence, compositorTiming);
     }
 
     // Update mFrameTracker.
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 4085b52..f678910 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -173,14 +173,15 @@
     BufferInfo mBufferInfo;
     virtual void gatherBufferInfo() = 0;
 
+    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+
     /*
      * compositionengine::LayerFE overrides
      */
     const compositionengine::LayerFECompositionState* getCompositionState() const override;
     bool onPreComposition(nsecs_t) override;
     void preparePerFrameCompositionState() override;
-    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
 
     // Loads the corresponding system property once per process
     static bool latchUnsignaledBuffers();
@@ -202,12 +203,12 @@
     void updateCloneBufferInfo() override;
     uint64_t mPreviousFrameNumber = 0;
 
+    virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+
 private:
     // Returns true if this layer requires filtering
     bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
 
-    uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
-
     // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
     // and its parent layer is not bounded
     Rect getBufferSize(const State& s) const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 371b802..de5429b 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -32,7 +32,7 @@
 #include <private/gui/SyncFeatures.h>
 #include <renderengine/Image.h>
 
-#include "ColorLayer.h"
+#include "EffectLayer.h"
 #include "FrameTracer/FrameTracer.h"
 #include "TimeStats/TimeStats.h"
 
@@ -468,6 +468,32 @@
     return mDrawingState.frameNumber;
 }
 
+/**
+ * This is the frameNumber used for deferred transaction signalling. We need to use this because
+ * of cases where we defer a transaction for a surface to itself. In the BLAST world this
+ * may not make a huge amount of sense (Why not just merge the Buffer transaction with the
+ * deferred transaction?) but this is an important legacy use case, for example moving
+ * a window at the same time it draws makes use of this kind of technique. So anyway
+ * imagine we have something like this:
+ *
+ * Transaction { // containing
+ *     Buffer -> frameNumber = 2
+ *     DeferTransactionUntil -> frameNumber = 2
+ *     Random other stuff
+ *  }
+ * Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber).
+ * Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we
+ * haven't swapped mCurrentState to mDrawingState yet we will think the sync point
+ * is not ready. So we will return false from applyPendingState and not swap
+ * current state to drawing state. But because we don't swap current state
+ * to drawing state the number will never update and we will be stuck. This way
+ * we can see we need to return the frame number for the buffer we are about
+ * to apply.
+ */
+uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const {
+    return mCurrentState.frameNumber;
+}
+
 bool BufferStateLayer::getAutoRefresh() const {
     // TODO(marissaw): support shared buffer mode
     return false;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 539442a..753a742 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -116,6 +116,7 @@
 
 protected:
     void gatherBufferInfo() override;
+    uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
 
 private:
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
deleted file mode 100644
index 83050c4..0000000
--- a/services/surfaceflinger/ColorLayer.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2007 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 LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "ColorLayer"
-
-#include "ColorLayer.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <renderengine/RenderEngine.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include "DisplayDevice.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-ColorLayer::ColorLayer(const LayerCreationArgs& args)
-      : Layer(args),
-        mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
-
-ColorLayer::~ColorLayer() = default;
-
-std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClientComposition(
-        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
-    auto result = Layer::prepareClientComposition(targetSettings);
-    if (!result) {
-        return result;
-    }
-    result->source.solidColor = getColor().rgb;
-    return result;
-}
-
-bool ColorLayer::isVisible() const {
-    return !isHiddenByPolicy() && getAlpha() > 0.0_hf;
-}
-
-bool ColorLayer::setColor(const half3& color) {
-    if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
-        mCurrentState.color.b == color.b) {
-        return false;
-    }
-
-    mCurrentState.sequence++;
-    mCurrentState.color.r = color.r;
-    mCurrentState.color.g = color.g;
-    mCurrentState.color.b = color.b;
-    mCurrentState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool ColorLayer::setDataspace(ui::Dataspace dataspace) {
-    if (mCurrentState.dataspace == dataspace) {
-        return false;
-    }
-
-    mCurrentState.sequence++;
-    mCurrentState.dataspace = dataspace;
-    mCurrentState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-void ColorLayer::preparePerFrameCompositionState() {
-    Layer::preparePerFrameCompositionState();
-
-    auto* compositionState = editCompositionState();
-    compositionState->color = getColor();
-    compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
-}
-
-sp<compositionengine::LayerFE> ColorLayer::getCompositionEngineLayerFE() const {
-    return asLayerFE();
-}
-
-compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() {
-    return mCompositionState.get();
-}
-
-const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const {
-    return mCompositionState.get();
-}
-
-bool ColorLayer::isOpaque(const Layer::State& s) const {
-    // Consider the layer to be opaque if its opaque flag is set or its effective
-    // alpha (considering the alpha of its parents as well) is 1.0;
-    return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
-}
-
-ui::Dataspace ColorLayer::getDataSpace() const {
-    return mDrawingState.dataspace;
-}
-
-sp<Layer> ColorLayer::createClone() {
-    sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
-                              LayerMetadata()));
-    layer->setInitialValuesForClone(this);
-    return layer;
-}
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 912dffd..6cc90cb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -97,6 +97,21 @@
         // Modified by each call to prepareClientComposition to indicate the
         // region of the target buffer that should be cleared.
         Region& clearRegion;
+
+        // Viewport of the target being rendered to. This is used to determine
+        // the shadow light position.
+        const Rect& viewport;
+
+        // Dataspace of the output so we can optimize how to render the shadow
+        // by avoiding unnecessary color space conversions.
+        const ui::Dataspace dataspace;
+
+        // True if the region excluding the shadow is visible.
+        const bool realContentIsVisible;
+
+        // If set to true, change the layer settings to render a clear output.
+        // This may be requested by the HWC
+        const bool clearContent;
     };
 
     // A superset of LayerSettings required by RenderEngine to compose a layer
@@ -109,18 +124,12 @@
         uint64_t frameNumber = 0;
     };
 
-    // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
-    // nullopt_t if the layer does not render
-    virtual std::optional<LayerSettings> prepareClientComposition(
+    // Returns the z-ordered list of LayerSettings to pass to RenderEngine::drawLayers. The list
+    // may contain shadows casted by the layer or the content of the layer itself.  If the layer
+    // does not render then an empty list will be returned.
+    virtual std::vector<LayerSettings> prepareClientCompositionList(
             ClientCompositionTargetSettings&) = 0;
 
-    // Returns the LayerSettings used to draw shadows around a layer. It is passed
-    // to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render
-    // shadows.
-    virtual std::optional<LayerSettings> prepareShadowClientComposition(
-            const LayerSettings& layerSettings, const Rect& displayViewport,
-            ui::Dataspace outputDataspace) = 0;
-
     // Called after the layer is displayed to update the presentation fence
     virtual void onLayerDisplayed(const sp<Fence>&) = 0;
 
@@ -142,7 +151,10 @@
             lhs.useIdentityTransform == rhs.useIdentityTransform &&
             lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure &&
             lhs.supportsProtectedContent == rhs.supportsProtectedContent &&
-            lhs.clearRegion.hasSameRects(rhs.clearRegion);
+            lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport &&
+            lhs.dataspace == rhs.dataspace &&
+            lhs.realContentIsVisible == rhs.realContentIsVisible &&
+            lhs.clearContent == rhs.clearContent;
 }
 
 static inline bool operator==(const LayerFE::LayerSettings& lhs,
@@ -164,6 +176,12 @@
     *os << "\n    .supportsProtectedContent = " << settings.supportsProtectedContent;
     *os << "\n    .clearRegion = ";
     PrintTo(settings.clearRegion, os);
+    *os << "\n    .viewport = ";
+    PrintTo(settings.viewport, os);
+    *os << "\n    .dataspace = ";
+    PrintTo(settings.dataspace, os);
+    *os << "\n    .realContentIsVisible = " << settings.realContentIsVisible;
+    *os << "\n    .clearContent = " << settings.clearContent;
     *os << "\n}";
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 40cd3e0..d8ce629 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -40,6 +40,29 @@
 
 namespace android::compositionengine {
 
+// More complex metadata for this layer
+struct GenericLayerMetadataEntry {
+    // True if the metadata may affect the composed result.
+    // See setLayerGenericMetadata in IComposerClient.hal
+    bool mandatory;
+
+    // Byte blob or parcel
+    std::vector<uint8_t> value;
+
+    std::string dumpAsString() const;
+};
+
+inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) {
+    return lhs.mandatory == rhs.mandatory && lhs.value == rhs.value;
+}
+
+// Defining PrintTo helps with Google Tests.
+inline void PrintTo(const GenericLayerMetadataEntry& v, ::std::ostream* os) {
+    *os << v.dumpAsString();
+}
+
+using GenericLayerMetadataMap = std::unordered_map<std::string, GenericLayerMetadataEntry>;
+
 /*
  * Used by LayerFE::getCompositionState
  */
@@ -115,6 +138,8 @@
     // The appId for this layer
     int appId{0};
 
+    GenericLayerMetadataMap metadata;
+
     /*
      * Per-frame content
      */
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 5c2ad15..45891a7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -35,11 +35,9 @@
     MOCK_METHOD1(onPreComposition, bool(nsecs_t));
 
     MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset));
-    MOCK_METHOD1(prepareClientComposition,
-                 std::optional<LayerSettings>(
+    MOCK_METHOD1(prepareClientCompositionList,
+                 std::vector<compositionengine::LayerFE::LayerSettings>(
                          compositionengine::LayerFE::ClientCompositionTargetSettings&));
-    MOCK_METHOD3(prepareShadowClientComposition,
-                 std::optional<LayerSettings>(const LayerSettings&, const Rect&, ui::Dataspace));
 
     MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
 
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 3e0f803..02e3a45 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -32,6 +32,20 @@
 
 } // namespace
 
+std::string GenericLayerMetadataEntry::dumpAsString() const {
+    using android::base::StringAppendF;
+    std::string out;
+
+    out.append("GenericLayerMetadataEntry{mandatory: ");
+    StringAppendF(&out, "%d", mandatory);
+    out.append(" value: ");
+    for (uint8_t byte : value) {
+        StringAppendF(&out, "0x08%" PRIx8 " ", byte);
+    }
+    out.append("]}");
+    return out;
+}
+
 LayerFECompositionState::~LayerFECompositionState() = default;
 
 void LayerFECompositionState::dump(std::string& out) const {
@@ -65,6 +79,17 @@
     dumpVal(out, "type", type);
     dumpVal(out, "appId", appId);
 
+    if (!metadata.empty()) {
+        out.append("\n      metadata {");
+        for (const auto& [key, entry] : metadata) {
+            out.append("\n           ");
+            out.append(key);
+            out.append("=");
+            out.append(entry.dumpAsString());
+        }
+        out.append("\n      }\n      ");
+    }
+
     dumpVal(out, "composition type", toString(compositionType), compositionType);
 
     out.append("\n      buffer: ");
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index a389bf3..e792f45 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -963,11 +963,16 @@
         // rectangle, as by definition the layer must blend with whatever is
         // underneath. We also skip the first layer as the buffer target is
         // guaranteed to start out cleared.
-        bool clearClientComposition =
+        const bool clearClientComposition =
                 layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer;
 
         ALOGV("  Composition type: client %d clear %d", clientComposition, clearClientComposition);
 
+        // If the layer casts a shadow but the content casting the shadow is occluded, skip
+        // composing the non-shadow content and only draw the shadows.
+        const bool realContentIsVisible = clientComposition &&
+                !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
+
         if (clientComposition || clearClientComposition) {
             compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
                     clip,
@@ -976,35 +981,21 @@
                     outputState.isSecure,
                     supportsProtectedContent,
                     clientComposition ? clearRegion : dummyRegion,
+                    outputState.viewport,
+                    outputDataspace,
+                    realContentIsVisible,
+                    !clientComposition, /* clearContent  */
             };
-            if (std::optional<LayerFE::LayerSettings> result =
-                        layerFE.prepareClientComposition(targetSettings)) {
-                if (!clientComposition) {
-                    LayerFE::LayerSettings& layerSettings = *result;
-                    layerSettings.source.buffer.buffer = nullptr;
-                    layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
-                    layerSettings.alpha = half(0.0);
-                    layerSettings.disableBlending = true;
-                    layerSettings.frameNumber = 0;
-                } else {
-                    std::optional<LayerFE::LayerSettings> shadowLayer =
-                            layerFE.prepareShadowClientComposition(*result, outputState.viewport,
-                                                                   outputDataspace);
-                    if (shadowLayer) {
-                        clientCompositionLayers.push_back(*shadowLayer);
-                    }
-                }
-
-                // If the layer casts a shadow but the content casting the shadow is occluded, skip
-                // composing the non-shadow content and only draw the shadows.
-                const bool skipNonShadowContentComposition = clientComposition &&
-                        layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
-
-                if (!skipNonShadowContentComposition) {
-                    layer->editState().clientCompositionTimestamp = systemTime();
-                    clientCompositionLayers.push_back(*result);
-                }
+            std::vector<LayerFE::LayerSettings> results =
+                    layerFE.prepareClientCompositionList(targetSettings);
+            if (realContentIsVisible && !results.empty()) {
+                layer->editState().clientCompositionTimestamp = systemTime();
             }
+
+            clientCompositionLayers.insert(clientCompositionLayers.end(),
+                                           std::make_move_iterator(results.begin()),
+                                           std::make_move_iterator(results.end()));
+            results.clear();
         }
 
         firstLayer = false;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index b538d75..3aa7956 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -406,6 +406,14 @@
         ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
+
+    for (const auto& [name, entry] : outputIndependentState.metadata) {
+        if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value);
+            error != HWC2::Error::None) {
+            ALOGE("[%s] Failed to set generic metadata %s %s (%d)", getLayerFE().getDebugName(),
+                  name.c_str(), to_string(error).c_str(), static_cast<int32_t>(error));
+        }
+    }
 }
 
 void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
@@ -661,4 +669,3 @@
 
 } // namespace impl
 } // namespace android::compositionengine
-
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index a51cc67..be89c1a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -65,6 +65,8 @@
     MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
 
     MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
+    MOCK_METHOD3(setLayerGenericMetadata,
+                 Error(const std::string&, bool, const std::vector<uint8_t>&));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 502a33f..02226ab 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -36,7 +36,7 @@
     HWComposer();
     ~HWComposer() override;
 
-    MOCK_METHOD2(registerCallback, void(HWC2::ComposerCallback*, int32_t));
+    MOCK_METHOD2(setConfiguration, void(HWC2::ComposerCallback*, int32_t));
     MOCK_CONST_METHOD3(getDisplayIdentificationData,
                        bool(hwc2_display_t, uint8_t*, DisplayIdentificationData*));
     MOCK_CONST_METHOD1(hasCapability, bool(HWC2::Capability));
@@ -88,6 +88,7 @@
     MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(DisplayId));
     MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent));
     MOCK_CONST_METHOD0(isUsingVrComposer, bool());
+    MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(DisplayId));
     MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(DisplayId));
     MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(DisplayId));
     MOCK_METHOD4(setActiveConfigWithConstraints,
@@ -96,6 +97,8 @@
     MOCK_METHOD2(setAutoLowLatencyMode, status_t(DisplayId, bool));
     MOCK_METHOD2(getSupportedContentTypes, status_t(DisplayId, std::vector<HWC2::ContentType>*));
     MOCK_METHOD2(setContentType, status_t(DisplayId, HWC2::ContentType));
+    MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata,
+                       const std::unordered_map<std::string, bool>&());
 
     MOCK_CONST_METHOD1(dump, void(std::string&));
     MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 963062f..1b5617c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -625,6 +625,8 @@
     static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
     static constexpr int kSupportedPerFrameMetadata = 101;
     static constexpr int kExpectedHwcSlot = 0;
+    static constexpr bool kLayerGenericMetadata1Mandatory = true;
+    static constexpr bool kLayerGenericMetadata2Mandatory = true;
 
     static const half4 kColor;
     static const Rect kDisplayFrame;
@@ -635,6 +637,10 @@
     static native_handle_t* kSidebandStreamHandle;
     static const sp<GraphicBuffer> kBuffer;
     static const sp<Fence> kFence;
+    static const std::string kLayerGenericMetadata1Key;
+    static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+    static const std::string kLayerGenericMetadata2Key;
+    static const std::vector<uint8_t> kLayerGenericMetadata2Value;
 
     OutputLayerWriteStateToHWCTest() {
         auto& outputLayerState = mOutputLayer.editState();
@@ -669,6 +675,13 @@
     // Some tests may need to simulate unsupported HWC calls
     enum class SimulateUnsupported { None, ColorTransform };
 
+    void includeGenericLayerMetadataInState() {
+        mLayerFEState.metadata[kLayerGenericMetadata1Key] = {kLayerGenericMetadata1Mandatory,
+                                                             kLayerGenericMetadata1Value};
+        mLayerFEState.metadata[kLayerGenericMetadata2Key] = {kLayerGenericMetadata2Mandatory,
+                                                             kLayerGenericMetadata2Value};
+    }
+
     void expectGeometryCommonCalls() {
         EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -720,6 +733,18 @@
         EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
     }
 
+    void expectGenericLayerMetadataCalls() {
+        // Note: Can be in any order.
+        EXPECT_CALL(*mHwcLayer,
+                    setLayerGenericMetadata(kLayerGenericMetadata1Key,
+                                            kLayerGenericMetadata1Mandatory,
+                                            kLayerGenericMetadata1Value));
+        EXPECT_CALL(*mHwcLayer,
+                    setLayerGenericMetadata(kLayerGenericMetadata2Key,
+                                            kLayerGenericMetadata2Mandatory,
+                                            kLayerGenericMetadata2Value));
+    }
+
     std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
     StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
 };
@@ -739,6 +764,13 @@
         reinterpret_cast<native_handle_t*>(1031);
 const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
 const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
+const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
+        "com.example.metadata.1";
+const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}};
+const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Key =
+        "com.example.metadata.2";
+const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Value{
+        {4, 5, 6, 7}};
 
 TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) {
     EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
@@ -862,6 +894,30 @@
     mOutputLayer.writeStateToHWC(false);
 }
 
+TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    includeGenericLayerMetadataInState();
+
+    expectGeometryCommonCalls();
+    expectPerFrameCommonCalls();
+    expectSetHdrMetadataAndBufferCalls();
+    expectGenericLayerMetadataCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+    mOutputLayer.writeStateToHWC(true);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    includeGenericLayerMetadataInState();
+
+    expectPerFrameCommonCalls();
+    expectSetHdrMetadataAndBufferCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+    mOutputLayer.writeStateToHWC(false);
+}
+
 /*
  * OutputLayer::writeCursorPositionToHWC()
  */
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 2b45046..be0e9e4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3425,19 +3425,13 @@
     LayerFE::LayerSettings mShadowSettings;
     mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
 
-    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[1].mLayerSettings));
-    EXPECT_CALL(mLayers[1].mLayerFE,
-                prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport,
-                                               kDisplayDataspace))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[2].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE,
-                prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
-                                               kDisplayDataspace))
-            .WillOnce(Return(mShadowSettings));
+    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(_))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(_))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[1].mLayerSettings})));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>(
+                    {mShadowSettings, mLayers[2].mLayerSettings})));
 
     Region accumClearRegion(Rect(10, 11, 12, 13));
     auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3469,10 +3463,8 @@
     mLayers[1].mLayerFEState.isOpaque = true;
     mLayers[2].mLayerFEState.isOpaque = true;
 
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[2].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
 
     Region accumClearRegion(Rect(10, 11, 12, 13));
     auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3497,10 +3489,8 @@
     mLayers[1].mLayerFEState.isOpaque = false;
     mLayers[2].mLayerFEState.isOpaque = false;
 
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[2].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
 
     Region accumClearRegion(Rect(10, 11, 12, 13));
     auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3529,25 +3519,51 @@
     mLayers[0].mLayerFEState.isOpaque = true;
     mLayers[1].mLayerFEState.isOpaque = true;
     mLayers[2].mLayerFEState.isOpaque = true;
-
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[1].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[2].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
-            .WillOnce(Return(std::nullopt));
-
     Region accumClearRegion(Rect(10, 11, 12, 13));
+    Region dummyRegion;
+
+    compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
+            Region(kDisplayFrame),
+            false,       /* identity transform */
+            false,       /* needs filtering */
+            false,       /* secure */
+            false,       /* supports protected content */
+            dummyRegion, /* clear region */
+            kDisplayViewport,
+            kDisplayDataspace,
+            false /* realContentIsVisible */,
+            true /* clearContent */,
+    };
+    compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
+            Region(kDisplayFrame),
+            false, /* identity transform */
+            false, /* needs filtering */
+            false, /* secure */
+            false, /* supports protected content */
+            accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
+    };
+
+    LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings;
+    mBlackoutSettings.source.buffer.buffer = nullptr;
+    mBlackoutSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+    mBlackoutSettings.alpha = 0.f;
+    mBlackoutSettings.disableBlending = true;
+
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mBlackoutSettings})));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
+
     auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
                                                               accumClearRegion, kDisplayDataspace);
     ASSERT_EQ(2u, requests.size());
 
     // The second layer is expected to be rendered as alpha=0 black with no blending
-    EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
-    EXPECT_FALSE(requests[0].source.buffer.buffer);
-    EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor);
-    EXPECT_EQ(0.f, static_cast<float>(requests[0].alpha));
-    EXPECT_EQ(true, requests[0].disableBlending);
+    EXPECT_EQ(mBlackoutSettings, requests[0]);
 
     EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
 
@@ -3569,6 +3585,10 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(Rect(0, 0, 30, 30)),
@@ -3577,6 +3597,10 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(Rect(0, 0, 40, 201)),
@@ -3585,14 +3609,18 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
-    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
 
     static_cast<void>(
             mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3613,6 +3641,10 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -3621,6 +3653,10 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -3629,14 +3665,18 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
-    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
 
     static_cast<void>(
             mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3657,6 +3697,11 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
+
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -3665,6 +3710,10 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -3673,14 +3722,18 @@
             false, /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
-    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
 
     static_cast<void>(
             mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3700,6 +3753,10 @@
             true,  /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -3708,6 +3765,10 @@
             true,  /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -3716,14 +3777,18 @@
             true,  /* secure */
             false, /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
-    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
 
     static_cast<void>(
             mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3741,6 +3806,10 @@
             false, /* secure */
             true,  /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -3749,6 +3818,10 @@
             false, /* secure */
             true,  /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -3757,14 +3830,18 @@
             false, /* secure */
             true,  /* supports protected content */
             accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
-    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
-            .WillOnce(Return(std::nullopt));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
 
     static_cast<void>(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */,
                                                                 accumClearRegion,
@@ -3847,16 +3924,16 @@
             true,  /* secure */
             true,  /* supports protected content */
             accumClearRegion,
+            kPortraitViewport,
+            kOutputDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
     EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
     EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
-    EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings))))
-            .WillOnce(Return(leftLayer.mLayerSettings));
-    EXPECT_CALL(leftLayer.mLayerFE,
-                prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport,
-                                               kOutputDataspace))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({leftLayer.mLayerSettings})));
 
     compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{
             Region(Rect(1000, 0, 2000, 1000)),
@@ -3865,16 +3942,16 @@
             true,  /* secure */
             true,  /* supports protected content */
             accumClearRegion,
+            kPortraitViewport,
+            kOutputDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
     };
 
     EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
     EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
-    EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings))))
-            .WillOnce(Return(rightLayer.mLayerSettings));
-    EXPECT_CALL(rightLayer.mLayerFE,
-                prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport,
-                                               kOutputDataspace))
-            .WillOnce(Return(std::nullopt));
+    EXPECT_CALL(rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({rightLayer.mLayerSettings})));
 
     constexpr bool supportsProtectedContent = true;
     auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent,
@@ -3891,6 +3968,20 @@
     const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent);
     const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80));
 
+    Region accumClearRegion(Rect(10, 11, 12, 13));
+    compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
+            Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
+            false,                                                    /* identity transform */
+            false,                                                    /* needs filtering */
+            false,                                                    /* secure */
+            false, /* supports protected content */
+            accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            false /* realContentIsVisible */,
+            false /* clearContent */,
+    };
+
     LayerFE::LayerSettings mShadowSettings;
     mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
 
@@ -3899,14 +3990,9 @@
 
     EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
     EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[2].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE,
-                prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
-                                               kDisplayDataspace))
-            .WillOnce(Return(mShadowSettings));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mShadowSettings})));
 
-    Region accumClearRegion(Rect(10, 11, 12, 13));
     auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
                                                               accumClearRegion, kDisplayDataspace);
     ASSERT_EQ(1u, requests.size());
@@ -3928,16 +4014,26 @@
     mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion;
     mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
 
+    Region accumClearRegion(Rect(10, 11, 12, 13));
+    compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
+            Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
+            false,                                                    /* identity transform */
+            false,                                                    /* needs filtering */
+            false,                                                    /* secure */
+            false, /* supports protected content */
+            accumClearRegion,
+            kDisplayViewport,
+            kDisplayDataspace,
+            true /* realContentIsVisible */,
+            false /* clearContent */,
+    };
+
     EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
     EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
-    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
-            .WillOnce(Return(mLayers[2].mLayerSettings));
-    EXPECT_CALL(mLayers[2].mLayerFE,
-                prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
-                                               kDisplayDataspace))
-            .WillOnce(Return(mShadowSettings));
+    EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings))))
+            .WillOnce(Return(std::vector<LayerFE::LayerSettings>(
+                    {mShadowSettings, mLayers[2].mLayerSettings})));
 
-    Region accumClearRegion(Rect(10, 11, 12, 13));
     auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
                                                               accumClearRegion, kDisplayDataspace);
     ASSERT_EQ(2u, requests.size());
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6ff39b4..cd6bbd1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -49,16 +49,16 @@
 
 DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
                                                      const wp<IBinder>& displayToken,
-                                                     const std::optional<DisplayId>& displayId)
+                                                     std::optional<DisplayId> displayId)
       : flinger(flinger), displayToken(displayToken), displayId(displayId) {}
 
 DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
       : mFlinger(args.flinger),
         mDisplayToken(args.displayToken),
         mSequenceId(args.sequenceId),
-        mIsVirtual(args.isVirtual),
+        mConnectionType(args.connectionType),
         mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
-                compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
+                compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId,
                                                        args.powerAdvisor})},
         mPhysicalOrientation(args.physicalOrientation),
         mIsPrimary(args.isPrimary) {
@@ -248,10 +248,18 @@
 }
 
 std::string DisplayDevice::getDebugName() const {
-    const auto id = getId() ? to_string(*getId()) + ", " : std::string();
-    return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
-                              isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
-                              mDisplayName.c_str());
+    std::string displayId;
+    if (const auto id = getId()) {
+        displayId = to_string(*id) + ", ";
+    }
+
+    const char* type = "virtual";
+    if (mConnectionType) {
+        type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external";
+    }
+
+    return base::StringPrintf("DisplayDevice{%s%s%s, \"%s\"}", displayId.c_str(), type,
+                              isPrimary() ? ", primary" : "", mDisplayName.c_str());
 }
 
 void DisplayDevice::dump(std::string& result) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index f45feae..d970b82 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,6 +28,7 @@
 #include <math/mat4.h>
 #include <renderengine/RenderEngine.h>
 #include <system/window.h>
+#include <ui/DisplayInfo.h>
 #include <ui/DisplayState.h>
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
@@ -52,7 +53,6 @@
 
 struct CompositionInfo;
 struct DisplayDeviceCreationArgs;
-struct DisplayInfo;
 
 namespace compositionengine {
 class Display;
@@ -71,7 +71,9 @@
         return mCompositionDisplay;
     }
 
-    bool isVirtual() const { return mIsVirtual; }
+    std::optional<DisplayConnectionType> getConnectionType() const { return mConnectionType; }
+
+    bool isVirtual() const { return !mConnectionType; }
     bool isPrimary() const { return mIsPrimary; }
 
     // isSecure indicates whether this display can be trusted to display
@@ -159,7 +161,7 @@
     const sp<SurfaceFlinger> mFlinger;
     const wp<IBinder> mDisplayToken;
     const int32_t mSequenceId;
-    const bool mIsVirtual;
+    const std::optional<DisplayConnectionType> mConnectionType;
 
     const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
 
@@ -178,10 +180,19 @@
 };
 
 struct DisplayDeviceState {
-    bool isVirtual() const { return !displayId.has_value(); }
+    struct Physical {
+        DisplayId id;
+        DisplayConnectionType type;
+
+        bool operator==(const Physical& other) const {
+            return id == other.id && type == other.type;
+        }
+    };
+
+    bool isVirtual() const { return !physical; }
 
     int32_t sequenceId = sNextSequenceId++;
-    std::optional<DisplayId> displayId;
+    std::optional<Physical> physical;
     sp<IGraphicBufferProducer> surface;
     ui::LayerStack layerStack = ui::NO_LAYER_STACK;
     Rect viewport;
@@ -199,15 +210,17 @@
 struct DisplayDeviceCreationArgs {
     // We use a constructor to ensure some of the values are set, without
     // assuming a default value.
-    DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
-                              const std::optional<DisplayId>& displayId);
+    DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, const wp<IBinder>& displayToken,
+                              std::optional<DisplayId>);
+
+    bool isVirtual() const { return !connectionType; }
 
     const sp<SurfaceFlinger> flinger;
     const wp<IBinder> displayToken;
     const std::optional<DisplayId> displayId;
 
     int32_t sequenceId{0};
-    bool isVirtual{false};
+    std::optional<DisplayConnectionType> connectionType;
     bool isSecure{false};
     sp<ANativeWindow> nativeWindow;
     sp<compositionengine::DisplaySurface> displaySurface;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 41e7879..fc5d441 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -95,13 +95,13 @@
 }
 
 namespace impl {
+
 Display::Display(android::Hwc2::Composer& composer,
                  const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
                  DisplayType type)
       : mComposer(composer),
         mCapabilities(capabilities),
         mId(id),
-        mIsConnected(false),
         mType(type) {
     ALOGV("Created display %" PRIu64, id);
 }
@@ -109,20 +109,27 @@
 Display::~Display() {
     mLayers.clear();
 
-    if (mType == DisplayType::Virtual) {
-        ALOGV("Destroying virtual display");
-        auto intError = mComposer.destroyVirtualDisplay(mId);
-        auto error = static_cast<Error>(intError);
-        ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64
-                ") failed: %s (%d)", mId, to_string(error).c_str(), intError);
-    } else if (mType == DisplayType::Physical) {
-        auto error = setVsyncEnabled(HWC2::Vsync::Disable);
-        if (error != Error::None) {
-            ALOGE("~Display: Failed to disable vsync for display %" PRIu64
-                    ": %s (%d)", mId, to_string(error).c_str(),
-                    static_cast<int32_t>(error));
-        }
+    Error error = Error::None;
+    const char* msg;
+    switch (mType) {
+        case DisplayType::Physical:
+            error = setVsyncEnabled(HWC2::Vsync::Disable);
+            msg = "disable VSYNC for";
+            break;
+
+        case DisplayType::Virtual:
+            error = static_cast<Error>(mComposer.destroyVirtualDisplay(mId));
+            msg = "destroy virtual";
+            break;
+
+        case DisplayType::Invalid: // Used in unit tests.
+            break;
     }
+
+    ALOGE_IF(error != Error::None, "%s: Failed to %s display %" PRIu64 ": %s (%d)", __FUNCTION__,
+             msg, mId, to_string(error).c_str(), static_cast<int32_t>(error));
+
+    ALOGV("Destroyed display %" PRIu64, mId);
 }
 
 // Required by HWC2 display
@@ -372,9 +379,19 @@
     return Error::None;
 }
 
-Error Display::getType(DisplayType* outType) const
-{
-    *outType = mType;
+Error Display::getConnectionType(android::DisplayConnectionType* outType) const {
+    if (mType != DisplayType::Physical) return Error::BadDisplay;
+
+    using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType;
+    ConnectionType connectionType;
+    const auto error = static_cast<Error>(mComposer.getDisplayConnectionType(mId, &connectionType));
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outType = connectionType == ConnectionType::INTERNAL
+            ? android::DisplayConnectionType::Internal
+            : android::DisplayConnectionType::External;
     return Error::None;
 }
 
@@ -734,12 +751,11 @@
 
 Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
              hwc2_display_t displayId, hwc2_layer_t layerId)
-  : mComposer(composer),
-    mCapabilities(capabilities),
-    mDisplayId(displayId),
-    mId(layerId),
-    mColorMatrix(android::mat4())
-{
+      : mComposer(composer),
+        mCapabilities(capabilities),
+        mDisplayId(displayId),
+        mId(layerId),
+        mColorMatrix(android::mat4()) {
     ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId);
 }
 
@@ -979,6 +995,13 @@
     return error;
 }
 
+// Composer HAL 2.4
+Error Layer::setLayerGenericMetadata(const std::string& name, bool mandatory,
+                                     const std::vector<uint8_t>& value) {
+    auto intError = mComposer.setLayerGenericMetadata(mDisplayId, mId, name, mandatory, value);
+    return static_cast<Error>(intError);
+}
+
 } // namespace impl
 } // namespace HWC2
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e7cf5ff..6549525 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -25,6 +25,7 @@
 
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
+#include <ui/DisplayInfo.h>
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
@@ -191,7 +192,8 @@
     [[clang::warn_unused_result]] virtual Error getRequests(
             DisplayRequest* outDisplayRequests,
             std::unordered_map<Layer*, LayerRequest>* outLayerRequests) = 0;
-    [[clang::warn_unused_result]] virtual Error getType(DisplayType* outType) const = 0;
+    [[clang::warn_unused_result]] virtual Error getConnectionType(
+            android::DisplayConnectionType*) const = 0;
     [[clang::warn_unused_result]] virtual Error supportsDoze(bool* outSupport) const = 0;
     [[clang::warn_unused_result]] virtual Error getHdrCapabilities(
             android::HdrCapabilities* outCapabilities) const = 0;
@@ -268,7 +270,7 @@
     Error getName(std::string* outName) const override;
     Error getRequests(DisplayRequest* outDisplayRequests,
                       std::unordered_map<Layer*, LayerRequest>* outLayerRequests) override;
-    Error getType(DisplayType* outType) const override;
+    Error getConnectionType(android::DisplayConnectionType*) const override;
     Error supportsDoze(bool* outSupport) const override;
     Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
     Error getDisplayedContentSamplingAttributes(android::ui::PixelFormat* outFormat,
@@ -332,16 +334,17 @@
     android::Hwc2::Composer& mComposer;
     const std::unordered_set<Capability>& mCapabilities;
 
-    hwc2_display_t mId;
-    bool mIsConnected;
+    const hwc2_display_t mId;
     DisplayType mType;
-    std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
+    bool mIsConnected = false;
 
+    std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
     std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
 
     std::once_flag mDisplayCapabilityQueryFlag;
     std::unordered_set<DisplayCapability> mDisplayCapabilities;
 };
+
 } // namespace impl
 
 class Layer {
@@ -374,6 +377,10 @@
 
     // Composer HAL 2.3
     [[clang::warn_unused_result]] virtual Error setColorTransform(const android::mat4& matrix) = 0;
+
+    // Composer HAL 2.4
+    [[clang::warn_unused_result]] virtual Error setLayerGenericMetadata(
+            const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
 };
 
 namespace impl {
@@ -382,8 +389,7 @@
 
 class Layer : public HWC2::Layer {
 public:
-    Layer(android::Hwc2::Composer& composer,
-          const std::unordered_set<Capability>& capabilities,
+    Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
           hwc2_display_t displayId, hwc2_layer_t layerId);
     ~Layer() override;
 
@@ -412,6 +418,10 @@
     // Composer HAL 2.3
     Error setColorTransform(const android::mat4& matrix) override;
 
+    // Composer HAL 2.4
+    Error setLayerGenericMetadata(const std::string& name, bool mandatory,
+                                  const std::vector<uint8_t>& value) override;
+
 private:
     // These are references to data owned by HWC2::Device, which will outlive
     // this HWC2::Layer, so these references are guaranteed to be valid for
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f8d45c0..784fa74 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -148,20 +148,20 @@
 namespace impl {
 
 HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer) : mComposer(std::move(composer)) {
-    loadCapabilities();
 }
 
 HWComposer::HWComposer(const std::string& composerServiceName)
       : mComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {
-    loadCapabilities();
 }
 
 HWComposer::~HWComposer() {
     mDisplayData.clear();
 }
 
-void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
-                                  int32_t sequenceId) {
+void HWComposer::setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) {
+    loadCapabilities();
+    loadLayerMetadataSupport();
+
     if (mRegisteredCallback) {
         ALOGW("Callback already registered. Ignored extra registration attempt.");
         return;
@@ -405,18 +405,32 @@
 
 // Composer 2.4
 
+DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal);
+    const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
+
+    DisplayConnectionType type;
+    const auto error = hwcDisplay->getConnectionType(&type);
+
+    const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
+            ? DisplayConnectionType::Internal
+            : DisplayConnectionType::External;
+
+    RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
+    return type;
+}
+
 bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
     return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
 }
 
 nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, 0);
+
     nsecs_t vsyncPeriodNanos;
     auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
-    if (error != HWC2::Error::None) {
-        LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period");
-        return 0;
-    }
-
+    RETURN_IF_HWC_ERROR(error, displayId, 0);
     return vsyncPeriodNanos;
 }
 
@@ -871,6 +885,10 @@
     return NO_ERROR;
 }
 
+const std::unordered_map<std::string, bool>& HWComposer::getSupportedLayerGenericMetadata() const {
+    return mSupportedLayerGenericMetadata;
+}
+
 void HWComposer::dump(std::string& result) const {
     result.append(mComposer->dumpDebugInfo());
 }
@@ -946,6 +964,22 @@
     }
 }
 
+void HWComposer::loadLayerMetadataSupport() {
+    mSupportedLayerGenericMetadata.clear();
+
+    std::vector<Hwc2::IComposerClient::LayerGenericMetadataKey> supportedMetadataKeyInfo;
+    const auto error = mComposer->getLayerGenericMetadataKeys(&supportedMetadataKeyInfo);
+    if (error != hardware::graphics::composer::V2_4::Error::NONE) {
+        ALOGE("%s: %s failed: %s (%d)", __FUNCTION__, "getLayerGenericMetadataKeys",
+              toString(error).c_str(), static_cast<int32_t>(error));
+        return;
+    }
+
+    for (const auto& [name, mandatory] : supportedMetadataKeyInfo) {
+        mSupportedLayerGenericMetadata.emplace(name, mandatory);
+    }
+}
+
 uint32_t HWComposer::getMaxVirtualDisplayCount() const {
     return mComposer->getMaxVirtualDisplayCount();
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index effe43b..41db501 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -55,11 +55,16 @@
 class Output;
 } // namespace compositionengine
 
+struct KnownHWCGenericLayerMetadata {
+    const char* name;
+    const uint32_t id;
+};
+
 class HWComposer {
 public:
     virtual ~HWComposer();
 
-    virtual void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
+    virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
 
     virtual bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
                                               DisplayIdentificationData* outData) const = 0;
@@ -184,6 +189,7 @@
     virtual bool isUsingVrComposer() const = 0;
 
     // Composer 2.4
+    virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
     virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0;
     virtual status_t setActiveConfigWithConstraints(
@@ -194,6 +200,8 @@
     virtual status_t getSupportedContentTypes(
             DisplayId displayId, std::vector<HWC2::ContentType>* outSupportedContentTypes) = 0;
     virtual status_t setContentType(DisplayId displayId, HWC2::ContentType contentType) = 0;
+    virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata()
+            const = 0;
 
     // for debugging ----------------------------------------------------------
     virtual void dump(std::string& out) const = 0;
@@ -217,7 +225,7 @@
 
     ~HWComposer() override;
 
-    void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) override;
+    void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) override;
 
     bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
                                       DisplayIdentificationData* outData) const override;
@@ -319,6 +327,7 @@
     bool isUsingVrComposer() const override;
 
     // Composer 2.4
+    DisplayConnectionType getDisplayConnectionType(DisplayId) const override;
     bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
     nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override;
     status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
@@ -329,6 +338,8 @@
                                       std::vector<HWC2::ContentType>*) override;
     status_t setContentType(DisplayId displayId, HWC2::ContentType) override;
 
+    const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const override;
+
     // for debugging ----------------------------------------------------------
     void dump(std::string& out) const override;
 
@@ -351,6 +362,7 @@
 
     std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
     void loadCapabilities();
+    void loadLayerMetadataSupport();
     uint32_t getMaxVirtualDisplayCount() const;
 
     struct DisplayData {
@@ -379,6 +391,7 @@
 
     std::unique_ptr<android::Hwc2::Composer> mComposer;
     std::unordered_set<HWC2::Capability> mCapabilities;
+    std::unordered_map<std::string, bool> mSupportedLayerGenericMetadata;
     bool mRegisteredCallback = false;
 
     std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
new file mode 100644
index 0000000..9d45e33
--- /dev/null
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 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 LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "EffectLayer"
+
+#include "EffectLayer.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerFECompositionState.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "DisplayDevice.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+EffectLayer::EffectLayer(const LayerCreationArgs& args)
+      : Layer(args),
+        mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
+
+EffectLayer::~EffectLayer() = default;
+
+std::vector<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientCompositionList(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+    std::vector<compositionengine::LayerFE::LayerSettings> results;
+    std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+            prepareClientComposition(targetSettings);
+    // Nothing to render.
+    if (!layerSettings) {
+        return {};
+    }
+
+    std::optional<compositionengine::LayerFE::LayerSettings> shadowSettings =
+            prepareShadowClientComposition(*layerSettings, targetSettings.viewport,
+                                           targetSettings.dataspace);
+    if (shadowSettings) {
+        results.push_back(*shadowSettings);
+    }
+
+    // If fill bounds are occluded or the fill color is invalid skip the fill settings.
+    if (targetSettings.realContentIsVisible && fillsColor()) {
+        // Set color for color fill settings.
+        layerSettings->source.solidColor = getColor().rgb;
+        results.push_back(*layerSettings);
+    }
+
+    return results;
+}
+
+bool EffectLayer::isVisible() const {
+    return !isHiddenByPolicy() && getAlpha() > 0.0_hf && hasSomethingToDraw();
+}
+
+bool EffectLayer::setColor(const half3& color) {
+    if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
+        mCurrentState.color.b == color.b) {
+        return false;
+    }
+
+    mCurrentState.sequence++;
+    mCurrentState.color.r = color.r;
+    mCurrentState.color.g = color.g;
+    mCurrentState.color.b = color.b;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool EffectLayer::setDataspace(ui::Dataspace dataspace) {
+    if (mCurrentState.dataspace == dataspace) {
+        return false;
+    }
+
+    mCurrentState.sequence++;
+    mCurrentState.dataspace = dataspace;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+void EffectLayer::preparePerFrameCompositionState() {
+    Layer::preparePerFrameCompositionState();
+
+    auto* compositionState = editCompositionState();
+    compositionState->color = getColor();
+    compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+}
+
+sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
+    return asLayerFE();
+}
+
+compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
+    return mCompositionState.get();
+}
+
+const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const {
+    return mCompositionState.get();
+}
+
+bool EffectLayer::isOpaque(const Layer::State& s) const {
+    // Consider the layer to be opaque if its opaque flag is set or its effective
+    // alpha (considering the alpha of its parents as well) is 1.0;
+    return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
+}
+
+ui::Dataspace EffectLayer::getDataSpace() const {
+    return mDrawingState.dataspace;
+}
+
+sp<Layer> EffectLayer::createClone() {
+    sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+                              LayerMetadata()));
+    layer->setInitialValuesForClone(this);
+    return layer;
+}
+
+bool EffectLayer::fillsColor() const {
+    return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf &&
+            mDrawingState.color.b >= 0.0_hf;
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/EffectLayer.h
similarity index 68%
rename from services/surfaceflinger/ColorLayer.h
rename to services/surfaceflinger/EffectLayer.h
index 4deb162..33758b6 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/EffectLayer.h
@@ -23,15 +23,19 @@
 
 namespace android {
 
-class ColorLayer : public Layer {
+// A layer that can render a combination of the following effects.
+//   * fill the bounds of the layer with a color
+//   * render a shadow cast by the bounds of the layer
+// If no effects are enabled, the layer is considered to be invisible.
+class EffectLayer : public Layer {
 public:
-    explicit ColorLayer(const LayerCreationArgs&);
-    ~ColorLayer() override;
+    explicit EffectLayer(const LayerCreationArgs&);
+    ~EffectLayer() override;
 
     sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
     compositionengine::LayerFECompositionState* editCompositionState() override;
 
-    const char* getType() const override { return "ColorLayer"; }
+    const char* getType() const override { return "EffectLayer"; }
     bool isVisible() const override;
 
     bool setColor(const half3& color) override;
@@ -48,12 +52,17 @@
      */
     const compositionengine::LayerFECompositionState* getCompositionState() const override;
     void preparePerFrameCompositionState() override;
-    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+    std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
+            compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) override;
 
     std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
 
     sp<Layer> createClone() override;
+
+private:
+    // Returns true if there is a valid color to fill.
+    bool fillsColor() const;
+    bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ff23c5..da26a37 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -56,10 +56,10 @@
 #include <sstream>
 
 #include "BufferLayer.h"
-#include "ColorLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWComposer.h"
+#include "EffectLayer.h"
 #include "FrameTracer/FrameTracer.h"
 #include "LayerProtoHelper.h"
 #include "LayerRejecter.h"
@@ -164,7 +164,7 @@
 /*
  * onLayerDisplayed is only meaningful for BufferLayer, but, is called through
  * Layer.  So, the implementation is done in BufferLayer.  When called on a
- * ColorLayer object, it's essentially a NOP.
+ * EffectLayer object, it's essentially a NOP.
  */
 void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
 
@@ -475,6 +475,26 @@
 
     compositionState->type = type;
     compositionState->appId = appId;
+
+    compositionState->metadata.clear();
+    const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
+    for (const auto& [key, mandatory] : supportedMetadata) {
+        const auto& genericLayerMetadataCompatibilityMap =
+                mFlinger->getGenericLayerMetadataKeyMap();
+        auto compatIter = genericLayerMetadataCompatibilityMap.find(key);
+        if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) {
+            continue;
+        }
+        const uint32_t id = compatIter->second;
+
+        auto it = drawingState.metadata.mMap.find(id);
+        if (it == std::end(drawingState.metadata.mMap)) {
+            continue;
+        }
+
+        compositionState->metadata
+                .emplace(key, compositionengine::GenericLayerMetadataEntry{mandatory, it->second});
+    }
 }
 
 void Layer::preparePerFrameCompositionState() {
@@ -491,13 +511,12 @@
     compositionState->hasProtectedContent = isProtected();
 
     const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
-    const bool drawsShadows = mEffectiveShadowRadius != 0.f;
 
     compositionState->isOpaque =
             isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
 
     // Force client composition for special cases known only to the front-end.
-    if (isHdrY410() || usesRoundedCorners || drawsShadows) {
+    if (isHdrY410() || usesRoundedCorners || drawShadows()) {
         compositionState->forceClientComposition = true;
     }
 }
@@ -652,6 +671,49 @@
     return shadowLayer;
 }
 
+void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings,
+                                          bool blackout) const {
+    layerSettings.source.buffer.buffer = nullptr;
+    layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+    layerSettings.disableBlending = true;
+    layerSettings.frameNumber = 0;
+
+    // If layer is blacked out, force alpha to 1 so that we draw a black color layer.
+    layerSettings.alpha = blackout ? 1.0f : 0.0f;
+}
+
+std::vector<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionList(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+    std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+            prepareClientComposition(targetSettings);
+    // Nothing to render.
+    if (!layerSettings) {
+        return {};
+    }
+
+    // HWC requests to clear this layer.
+    if (targetSettings.clearContent) {
+        prepareClearClientComposition(*layerSettings, false /* blackout */);
+        return {*layerSettings};
+    }
+
+    std::optional<compositionengine::LayerFE::LayerSettings> shadowSettings =
+            prepareShadowClientComposition(*layerSettings, targetSettings.viewport,
+                                           targetSettings.dataspace);
+    // There are no shadows to render.
+    if (!shadowSettings) {
+        return {*layerSettings};
+    }
+
+    // If the layer casts a shadow but the content casting the shadow is occluded, skip
+    // composing the non-shadow content and only draw the shadows.
+    if (targetSettings.realContentIsVisible) {
+        return {*shadowSettings, *layerSettings};
+    }
+
+    return {*shadowSettings};
+}
+
 Hwc2::IComposerClient::Composition Layer::getCompositionType(
         const sp<const DisplayDevice>& display) const {
     const auto outputLayer = findOutputLayerForDisplay(display);
@@ -1091,9 +1153,9 @@
 
     if (!mCurrentState.bgColorLayer && alpha != 0) {
         // create background color layer if one does not yet exist
-        uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
+        uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect;
         std::string name = mName + "BackgroundColorLayer";
-        mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer(
+        mCurrentState.bgColorLayer = mFlinger->getFactory().createEffectLayer(
                 LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags,
                                   LayerMetadata()));
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c110462..37ae340 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -212,7 +212,7 @@
         InputWindowInfo inputInfo;
         wp<Layer> touchableRegionCrop;
 
-        // dataspace is only used by BufferStateLayer and ColorLayer
+        // dataspace is only used by BufferStateLayer and EffectLayer
         ui::Dataspace dataspace;
 
         // The fields below this point are only used by BufferStateLayer
@@ -552,6 +552,14 @@
     void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
     void addChildToDrawing(const sp<Layer>& 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& layerSettings, const Rect& displayViewport,
+            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& layerSettings, bool blackout) const;
 
 public:
     /*
@@ -560,11 +568,8 @@
     const compositionengine::LayerFECompositionState* getCompositionState() const override;
     bool onPreComposition(nsecs_t) override;
     void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
-    std::optional<LayerSettings> prepareClientComposition(
+    std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
             compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-    std::optional<LayerSettings> prepareShadowClientComposition(
-            const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
-            ui::Dataspace outputDataspace) override;
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
     const char* getDebugName() const override;
 
@@ -704,6 +709,7 @@
     half getAlpha() const;
     half4 getColor() const;
     int32_t getBackgroundBlurRadius() const;
+    bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
 
     // Returns how rounded corners should be drawn for this layer.
     // This will traverse the hierarchy until it reaches its root, finding topmost rounded
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index b467f24..399da19 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -53,15 +53,15 @@
 }
 
 inline size_t VSyncPredictor::next(int i) const {
-    return (i + 1) % timestamps.size();
+    return (i + 1) % mTimestamps.size();
 }
 
 bool VSyncPredictor::validate(nsecs_t timestamp) const {
-    if (lastTimestampIndex < 0 || timestamps.empty()) {
+    if (mLastTimestampIndex < 0 || mTimestamps.empty()) {
         return true;
     }
 
-    auto const aValidTimestamp = timestamps[lastTimestampIndex];
+    auto const aValidTimestamp = mTimestamps[mLastTimestampIndex];
     auto const percent = (timestamp - aValidTimestamp) % mIdealPeriod * kMaxPercent / mIdealPeriod;
     return percent < kOutlierTolerancePercent || percent > (kMaxPercent - kOutlierTolerancePercent);
 }
@@ -79,15 +79,15 @@
         return false;
     }
 
-    if (timestamps.size() != kHistorySize) {
-        timestamps.push_back(timestamp);
-        lastTimestampIndex = next(lastTimestampIndex);
+    if (mTimestamps.size() != kHistorySize) {
+        mTimestamps.push_back(timestamp);
+        mLastTimestampIndex = next(mLastTimestampIndex);
     } else {
-        lastTimestampIndex = next(lastTimestampIndex);
-        timestamps[lastTimestampIndex] = timestamp;
+        mLastTimestampIndex = next(mLastTimestampIndex);
+        mTimestamps[mLastTimestampIndex] = timestamp;
     }
 
-    if (timestamps.size() < kMinimumSamplesForPrediction) {
+    if (mTimestamps.size() < kMinimumSamplesForPrediction) {
         mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
         return true;
     }
@@ -107,11 +107,11 @@
     //
     // intercept = mean(Y) - slope * mean(X)
     //
-    std::vector<nsecs_t> vsyncTS(timestamps.size());
-    std::vector<nsecs_t> ordinals(timestamps.size());
+    std::vector<nsecs_t> vsyncTS(mTimestamps.size());
+    std::vector<nsecs_t> ordinals(mTimestamps.size());
 
     // normalizing to the oldest timestamp cuts down on error in calculating the intercept.
-    auto const oldest_ts = *std::min_element(timestamps.begin(), timestamps.end());
+    auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end());
     auto it = mRateMap.find(mIdealPeriod);
     auto const currentPeriod = std::get<0>(it->second);
     // TODO (b/144707443): its important that there's some precision in the mean of the ordinals
@@ -120,10 +120,10 @@
     //                     scheduler::utils::calculate_mean to have a fixed point fractional part.
     static constexpr int kScalingFactor = 10;
 
-    for (auto i = 0u; i < timestamps.size(); i++) {
-        traceInt64If("VSP-ts", timestamps[i]);
+    for (auto i = 0u; i < mTimestamps.size(); i++) {
+        traceInt64If("VSP-ts", mTimestamps[i]);
 
-        vsyncTS[i] = timestamps[i] - oldest_ts;
+        vsyncTS[i] = mTimestamps[i] - oldest_ts;
         ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor;
     }
 
@@ -143,12 +143,20 @@
 
     if (CC_UNLIKELY(bottom == 0)) {
         it->second = {mIdealPeriod, 0};
+        clearTimestamps();
         return false;
     }
 
     nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor;
     nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor);
 
+    auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod;
+    if (percent >= kOutlierTolerancePercent) {
+        it->second = {mIdealPeriod, 0};
+        clearTimestamps();
+        return false;
+    }
+
     traceInt64If("VSP-period", anticipatedPeriod);
     traceInt64If("VSP-intercept", intercept);
 
@@ -164,14 +172,14 @@
 
     auto const [slope, intercept] = getVSyncPredictionModel(lk);
 
-    if (timestamps.empty()) {
+    if (mTimestamps.empty()) {
         traceInt64If("VSP-mode", 1);
         auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint;
         auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1;
         return knownTimestamp + numPeriodsOut * mIdealPeriod;
     }
 
-    auto const oldest = *std::min_element(timestamps.begin(), timestamps.end());
+    auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end());
 
     // See b/145667109, the ordinal calculation must take into account the intercept.
     auto const zeroPoint = oldest + intercept;
@@ -225,10 +233,10 @@
 }
 
 void VSyncPredictor::clearTimestamps() {
-    if (!timestamps.empty()) {
-        mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
-        timestamps.clear();
-        lastTimestampIndex = 0;
+    if (!mTimestamps.empty()) {
+        mKnownTimestamp = *std::max_element(mTimestamps.begin(), mTimestamps.end());
+        mTimestamps.clear();
+        mLastTimestampIndex = 0;
     }
 }
 
@@ -236,11 +244,11 @@
     using namespace std::literals::chrono_literals;
     std::lock_guard<std::mutex> lk(mMutex);
     bool needsMoreSamples = true;
-    if (timestamps.size() >= kMinimumSamplesForPrediction) {
+    if (mTimestamps.size() >= kMinimumSamplesForPrediction) {
         nsecs_t constexpr aLongTime =
                 std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
-        if (!(lastTimestampIndex < 0 || timestamps.empty())) {
-            auto const lastTimestamp = timestamps[lastTimestampIndex];
+        if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) {
+            auto const lastTimestamp = mTimestamps[mLastTimestampIndex];
             needsMoreSamples = !((lastTimestamp + aLongTime) > now);
         }
     }
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 532fe9e..ef1d88a 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -83,8 +83,8 @@
 
     std::unordered_map<nsecs_t, std::tuple<nsecs_t, nsecs_t>> mutable mRateMap GUARDED_BY(mMutex);
 
-    int lastTimestampIndex GUARDED_BY(mMutex) = 0;
-    std::vector<nsecs_t> timestamps GUARDED_BY(mMutex);
+    int mLastTimestampIndex GUARDED_BY(mMutex) = 0;
+    std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
 };
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index da73e4e..949ba4c 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -98,6 +98,9 @@
 
         {
             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);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d971625..a98ff4f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -57,6 +57,7 @@
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IProducerListener.h>
 #include <gui/LayerDebugInfo.h>
+#include <gui/LayerMetadata.h>
 #include <gui/Surface.h>
 #include <input/IInputFlinger.h>
 #include <renderengine/RenderEngine.h>
@@ -83,10 +84,10 @@
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "Client.h"
-#include "ColorLayer.h"
 #include "Colorizer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
+#include "EffectLayer.h"
 #include "Layer.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
@@ -622,7 +623,7 @@
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
     mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
-    mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
+    mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId);
     // Process any initial hotplug and resulting display changes.
     processDisplayHotplugEventsLocked();
     const auto display = getDefaultDisplayDeviceLocked();
@@ -782,14 +783,18 @@
         return NAME_NOT_FOUND;
     }
 
-    if (display->isVirtual()) {
+    if (const auto connectionType = display->getConnectionType())
+        info->connectionType = *connectionType;
+    else {
         return INVALID_OPERATION;
     }
 
     if (mEmulatedDisplayDensity) {
         info->density = mEmulatedDisplayDensity;
     } else {
-        info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY;
+        info->density = info->connectionType == DisplayConnectionType::Internal
+                ? mInternalDisplayDensity
+                : FALLBACK_DENSITY;
     }
 
     info->secure = display->isSecure();
@@ -1682,7 +1687,7 @@
     mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
     mCompositionEngine->setHwComposer(getFactory().createHWComposer(
             vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
-    getHwComposer().registerCallback(this, ++getBE().mComposerSequenceId);
+    mCompositionEngine->getHwComposer().setConfiguration(this, ++getBE().mComposerSequenceId);
 
     LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
                         "Switched to non-remote hardware composer");
@@ -2081,7 +2086,8 @@
         }
     });
 
-    if (presentFenceTime->isValid()) {
+    if (displayDevice && displayDevice->isPrimary() &&
+        displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL && presentFenceTime->isValid()) {
         mScheduler->addPresentFence(presentFenceTime);
     }
 
@@ -2240,30 +2246,38 @@
             continue;
         }
 
+        const DisplayId displayId = info->id;
+        const auto it = mPhysicalDisplayTokens.find(displayId);
+
         if (event.connection == HWC2::Connection::Connected) {
-            if (!mPhysicalDisplayTokens.count(info->id)) {
-                ALOGV("Creating display %s", to_string(info->id).c_str());
+            if (it == mPhysicalDisplayTokens.end()) {
+                ALOGV("Creating display %s", to_string(displayId).c_str());
+
                 if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
-                    initScheduler(info->id);
+                    initScheduler(displayId);
                 }
-                mPhysicalDisplayTokens[info->id] = new BBinder();
+
                 DisplayDeviceState state;
-                state.displayId = info->id;
+                state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId)};
                 state.isSecure = true; // All physical displays are currently considered secure.
                 state.displayName = info->name;
-                mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+
+                sp<IBinder> token = new BBinder();
+                mCurrentState.displays.add(token, state);
+                mPhysicalDisplayTokens.emplace(displayId, std::move(token));
+
                 mInterceptor->saveDisplayCreation(state);
             }
         } else {
-            ALOGV("Removing display %s", to_string(info->id).c_str());
+            ALOGV("Removing display %s", to_string(displayId).c_str());
 
-            ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+            const ssize_t index = mCurrentState.displays.indexOfKey(it->second);
             if (index >= 0) {
                 const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
                 mInterceptor->saveDisplayDeletion(state.sequenceId);
                 mCurrentState.displays.removeItemsAt(index);
             }
-            mPhysicalDisplayTokens.erase(info->id);
+            mPhysicalDisplayTokens.erase(it);
         }
 
         processDisplayChangesLocked();
@@ -2283,13 +2297,16 @@
         const sp<IGraphicBufferProducer>& producer) {
     DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
     creationArgs.sequenceId = state.sequenceId;
-    creationArgs.isVirtual = state.isVirtual();
     creationArgs.isSecure = state.isSecure;
     creationArgs.displaySurface = dispSurface;
     creationArgs.hasWideColorGamut = false;
     creationArgs.supportedPerFrameMetadata = 0;
     creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
 
+    if (const auto& physical = state.physical) {
+        creationArgs.connectionType = physical->type;
+    }
+
     const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
     creationArgs.isPrimary = isInternalDisplay;
 
@@ -2480,8 +2497,8 @@
                              "surface is provided (%p), ignoring it",
                              state.surface.get());
 
-                    displayId = state.displayId;
-                    LOG_ALWAYS_FATAL_IF(!displayId);
+                    LOG_FATAL_IF(!state.physical);
+                    displayId = state.physical->id;
                     dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
                     producer = bqProducer;
                 }
@@ -3699,7 +3716,7 @@
             result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
                                             std::move(metadata), handle, outTransformHint, &layer);
             break;
-        case ISurfaceComposerClient::eFXSurfaceColor:
+        case ISurfaceComposerClient::eFXSurfaceEffect:
             // check if buffer size is set for color layer.
             if (w > 0 || h > 0) {
                 ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
@@ -3707,8 +3724,8 @@
                 return BAD_VALUE;
             }
 
-            result = createColorLayer(client, std::move(uniqueName), w, h, flags,
-                                      std::move(metadata), handle, &layer);
+            result = createEffectLayer(client, std::move(uniqueName), w, h, flags,
+                                       std::move(metadata), handle, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceContainer:
             // check if buffer size is set for container layer.
@@ -3826,10 +3843,10 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, std::string name, uint32_t w,
-                                          uint32_t h, uint32_t flags, LayerMetadata metadata,
-                                          sp<IBinder>* handle, sp<Layer>* outLayer) {
-    *outLayer = getFactory().createColorLayer(
+status_t SurfaceFlinger::createEffectLayer(const sp<Client>& client, std::string name, uint32_t w,
+                                           uint32_t h, uint32_t flags, LayerMetadata metadata,
+                                           sp<IBinder>* handle, sp<Layer>* outLayer) {
+    *outLayer = getFactory().createEffectLayer(
             {this, client, std::move(name), w, h, flags, std::move(metadata)});
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
@@ -5550,17 +5567,18 @@
                 renderArea.isSecure(),
                 supportProtectedContent,
                 clearRegion,
+                displayViewport,
+                clientCompositionDisplay.outputDataspace,
+                true,  /* realContentIsVisible */
+                false, /* clearContent */
         };
-        auto result = layer->prepareClientComposition(targetSettings);
-        if (result) {
-            std::optional<compositionengine::LayerFE::LayerSettings> shadowLayer =
-                    layer->prepareShadowClientComposition(*result, displayViewport,
-                                                          clientCompositionDisplay.outputDataspace);
-            if (shadowLayer) {
-                clientCompositionLayers.push_back(*shadowLayer);
-            }
-            clientCompositionLayers.push_back(*result);
-        }
+        std::vector<compositionengine::LayerFE::LayerSettings> results =
+                layer->prepareClientCompositionList(targetSettings);
+        clientCompositionLayers.insert(clientCompositionLayers.end(),
+                                       std::make_move_iterator(results.begin()),
+                                       std::make_move_iterator(results.end()));
+        results.clear();
+
     });
 
     std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
@@ -5854,6 +5872,21 @@
     return NO_ERROR;
 }
 
+const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayerMetadataKeyMap()
+        const {
+    // TODO(b/149500060): Remove this fixed/static mapping. Please prefer taking
+    // on the work to remove the table in that bug rather than adding more to
+    // it.
+    static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{
+            // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially
+            // supported, and exposed via the
+            // IVrComposerClient::VrCommand::SET_LAYER_INFO command.
+            {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID},
+            {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR},
+    };
+    return genericLayerMetadataKeyMap;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8cabcf0..0144b4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -653,9 +653,9 @@
                                     sp<IBinder>* outHandle, uint32_t* outTransformHint,
                                     sp<Layer>* outLayer);
 
-    status_t createColorLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
-                              uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
-                              sp<Layer>* outLayer);
+    status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
+                               uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
+                               sp<Layer>* outLayer);
 
     status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w,
                                   uint32_t h, uint32_t flags, LayerMetadata metadata,
@@ -1153,6 +1153,15 @@
 
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
 
+    /* ------------------------------------------------------------------------
+     * Generic Layer Metadata
+     */
+    const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
+
+    /* ------------------------------------------------------------------------
+     * Misc
+     */
+
     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 f9658a7..d49133d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -25,9 +25,9 @@
 #include "BufferLayerConsumer.h"
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ColorLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
+#include "EffectLayer.h"
 #include "Layer.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
@@ -139,8 +139,8 @@
     return new BufferStateLayer(args);
 }
 
-sp<ColorLayer> DefaultFactory::createColorLayer(const LayerCreationArgs& args) {
-    return new ColorLayer(args);
+sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
+    return new EffectLayer(args);
 }
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 36fae21..89194c7 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -55,7 +55,7 @@
     std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
     sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override;
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
-    sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override;
+    sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
     sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
 };
 
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index c7da730..209bd0c 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -31,7 +31,7 @@
 class BufferQueueLayer;
 class BufferStateLayer;
 class BufferLayerConsumer;
-class ColorLayer;
+class EffectLayer;
 class ContainerLayer;
 class DisplayDevice;
 class DispSync;
@@ -104,7 +104,7 @@
 
     virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
     virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
-    virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
+    virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
     virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
 
 protected:
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 6884b4c..1f9d46c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -595,8 +595,8 @@
     creation->set_id(info.sequenceId);
     creation->set_name(info.displayName);
     creation->set_is_secure(info.isSecure);
-    if (info.displayId) {
-        creation->set_display_id(info.displayId->value);
+    if (info.physical) {
+        creation->set_display_id(info.physical->id.value);
     }
 }
 
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c8c28e..8038eba 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -55,28 +55,6 @@
     return result;
 }
 
-AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    if (mTimeStats.statsStart == 0) {
-        return AStatsManager_PULL_SKIP;
-    }
-    flushPowerTimeLocked();
-
-    AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
-    mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
-    mStatsDelegate->statsEventBuild(event);
-    clearGlobalLocked();
-
-    return AStatsManager_PULL_SUCCESS;
-}
-
 namespace {
 // Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
 const std::array<std::string, 6> kHistogramNames = {
@@ -112,6 +90,37 @@
 }
 } // namespace
 
+AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (mTimeStats.statsStart == 0) {
+        return AStatsManager_PULL_SKIP;
+    }
+    flushPowerTimeLocked();
+
+    AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+    mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
+    std::string frameDurationBytes =
+            histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
+    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+                                             frameDurationBytes.size());
+    std::string renderEngineTimingBytes =
+            histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
+                                       mMaxPulledHistogramBuckets);
+    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
+                                             renderEngineTimingBytes.size());
+    mStatsDelegate->statsEventBuild(event);
+    clearGlobalLocked();
+
+    return AStatsManager_PULL_SUCCESS;
+}
+
 AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
     std::lock_guard<std::mutex> lock(mMutex);
 
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 24874b0..83e5060 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -531,7 +531,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(colorLayer =
                                     createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
 
     Transaction()
             .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
@@ -570,7 +570,7 @@
     Color priorBgColor = Color::BLUE;
     Color expectedColor = Color::BLACK;
     switch (layerType) {
-        case ISurfaceComposerClient::eFXSurfaceColor:
+        case ISurfaceComposerClient::eFXSurfaceEffect:
             ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
             Transaction()
                     .setCrop_legacy(layer, Rect(0, 0, width, height))
@@ -599,7 +599,7 @@
             return;
     }
 
-    if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
+    if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) {
         Transaction()
                 .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
                 .apply();
@@ -628,7 +628,7 @@
     bool bufferFill = false;
     float alpha = 1.0f;
     Color finalColor = Color::RED;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect,
                                                      priorColor, bufferFill, alpha, finalColor));
 }
 
@@ -744,15 +744,29 @@
     sp<SurfaceControl> colorLayer;
     ASSERT_NO_FATAL_FAILURE(colorLayer =
                                     createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
     Transaction()
             .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
-            .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
+            .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f))
             .apply();
 
     getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
+// An invalid color will not render a color and the layer will not be visible.
+TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) {
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(colorLayer =
+                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
+    Transaction()
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f))
+            .apply();
+
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
 TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
     sp<SurfaceControl> bufferLayer;
     sp<SurfaceControl> colorLayer;
@@ -760,7 +774,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(colorLayer =
                                     createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
     Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
 
     const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
@@ -787,7 +801,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
                                                      0 /* buffer height */,
-                                                     ISurfaceComposerClient::eFXSurfaceColor));
+                                                     ISurfaceComposerClient::eFXSurfaceEffect));
     Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
     const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
     const float alpha = 0.25f;
@@ -1663,7 +1677,7 @@
     sp<SurfaceControl> colorLayer;
     ASSERT_NO_FATAL_FAILURE(colorLayer =
                                     createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
     Transaction()
             .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
             .setLayer(colorLayer, mLayerZBase + 1)
@@ -1719,7 +1733,7 @@
                                                       ISurfaceComposerClient::eFXSurfaceContainer));
     ASSERT_NO_FATAL_FAILURE(
             colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                     ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+                                     ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
 
     Transaction()
             .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
@@ -1780,7 +1794,7 @@
                                                       ISurfaceComposerClient::eFXSurfaceContainer));
     ASSERT_NO_FATAL_FAILURE(
             colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                     ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+                                     ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
 
     Transaction()
             .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 5eb1739..932c7c8 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -89,7 +89,7 @@
                                         SurfaceControl* parent = nullptr) {
         auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
                                         PIXEL_FORMAT_RGBA_8888,
-                                        ISurfaceComposerClient::eFXSurfaceColor, parent);
+                                        ISurfaceComposerClient::eFXSurfaceEffect, parent);
         asTransaction([&](Transaction& t) {
             t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
             t.setAlpha(colorLayer, color.a / 255.0f);
@@ -268,7 +268,7 @@
 
         mBlackBgSurface =
                 createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
-                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
 
         // set layer stack (b/68888219)
         Transaction t;
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index dbace11..2fd2579 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -92,7 +92,8 @@
             .setRelativeLayer(layerG, layerR->getHandle(), 1)
             .apply();
 
-    layerG.clear();
+    Transaction().reparent(layerG, nullptr).apply();
+
     // layerG should have been removed
     getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 7e9202b..84780ba 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -69,13 +69,13 @@
 TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
     sp<SurfaceControl> parent =
             LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceColor);
+                                              ISurfaceComposerClient::eFXSurfaceEffect);
 
     sp<SurfaceControl> childLayer;
     ASSERT_NO_FATAL_FAILURE(
             childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
                                                            0 /* buffer height */,
-                                                           ISurfaceComposerClient::eFXSurfaceColor,
+                                                           ISurfaceComposerClient::eFXSurfaceEffect,
                                                            parent.get()));
     Transaction()
             .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
@@ -116,17 +116,17 @@
 TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
     sp<SurfaceControl> parent =
             LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceColor);
+                                              ISurfaceComposerClient::eFXSurfaceEffect);
     sp<SurfaceControl> relativeParent =
             LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
                                               0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceColor);
+                                              ISurfaceComposerClient::eFXSurfaceEffect);
 
     sp<SurfaceControl> childLayer;
     ASSERT_NO_FATAL_FAILURE(
             childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
                                                            0 /* buffer height */,
-                                                           ISurfaceComposerClient::eFXSurfaceColor,
+                                                           ISurfaceComposerClient::eFXSurfaceEffect,
                                                            parent.get()));
     Transaction()
             .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index a1c4128..cdd9d92 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -542,6 +542,7 @@
         mCapture->checkPixel(64, 64, 111, 111, 111);
     }
 
+    Transaction().reparent(mChild, nullptr).apply();
     mChild.clear();
 
     {
@@ -1114,7 +1115,7 @@
 TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
     sp<SurfaceControl> colorLayer =
             createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+                          ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
         t.setColor(colorLayer, half3{0, 0, 0});
@@ -1139,7 +1140,7 @@
     ASSERT_TRUE(cropLayer->isValid());
     sp<SurfaceControl> colorLayer =
             createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
+                          ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get());
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
         t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
@@ -1164,7 +1165,7 @@
 TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
     sp<SurfaceControl> colorLayer =
             createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+                          ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
         t.setPosition(colorLayer, 320, 320);
@@ -1195,7 +1196,7 @@
     ASSERT_TRUE(boundlessLayerDownShift->isValid());
     sp<SurfaceControl> colorLayer =
             createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
+                          ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get());
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
         t.setPosition(boundlessLayerRightShift, 32, 0);
@@ -1229,7 +1230,7 @@
     ASSERT_TRUE(boundlessLayer->isValid());
     sp<SurfaceControl> colorLayer =
             mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                   ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
+                                   ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get());
     ASSERT_TRUE(colorLayer != nullptr);
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
@@ -1261,7 +1262,7 @@
     ASSERT_TRUE(rootBoundlessLayer->isValid());
     sp<SurfaceControl> colorLayer =
             createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
+                          ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get());
 
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
@@ -1702,6 +1703,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
 
     auto redLayerHandle = redLayer->getHandle();
+    Transaction().reparent(redLayer, nullptr).apply();
     redLayer.clear();
     SurfaceComposerClient::Transaction().apply(true);
 
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index c9fdc3b..f8a5b40 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -66,7 +66,7 @@
     void createColorLayer(uint32_t layerStack) {
         mColorLayer =
                 createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
-                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
         ASSERT_TRUE(mColorLayer != nullptr);
         ASSERT_TRUE(mColorLayer->isValid());
         asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 0e7eba8..8d97f27 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -145,6 +145,7 @@
         mBGSurfaceControl.clear();
         mFGSurfaceControl.clear();
         mComposerClient.clear();
+        system("setenforce 1");
     }
 
     sp<SurfaceComposerClient> mComposerClient;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 2f89696..96a7541 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -183,6 +183,7 @@
     // Wait for mock call signaling teardown?
     property_set("debug.sf.nobootanimation", "0");
     property_set("debug.sf.hwc_service_name", "default");
+    system("setenforce 1");
     ALOGI("Test env tear down - done");
 }
 
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index e751496..32c58ad 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1827,10 +1827,11 @@
 protected:
     void SetUp() override {
         Base::SetUp();
-        Base::mChild = Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
-                                                            PIXEL_FORMAT_RGBA_8888,
-                                                            ISurfaceComposerClient::eFXSurfaceColor,
-                                                            Base::mFGSurfaceControl.get());
+        Base::mChild =
+                Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
+                                                     PIXEL_FORMAT_RGBA_8888,
+                                                     ISurfaceComposerClient::eFXSurfaceEffect,
+                                                     Base::mFGSurfaceControl.get());
         {
             TransactionScope ts(*Base::sFakeComposer);
             ts.setColor(Base::mChild,
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index d046f76..1cd8731 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,6 +42,7 @@
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
         "EventThreadTest.cpp",
+        "HWComposerTest.cpp",
         "OneShotTimerTest.cpp",
         "LayerHistoryTest.cpp",
         "LayerHistoryTestV2.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 888e009..06ef8e7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -35,7 +35,7 @@
 #include <utils/String8.h>
 
 #include "BufferQueueLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
 #include "Layer.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
@@ -116,8 +116,6 @@
 
     void setupComposer(int virtualDisplayCount) {
         mComposer = new Hwc2::mock::Composer();
-        EXPECT_CALL(*mComposer, getCapabilities())
-                .WillOnce(Return(std::vector<IComposer::Capability>()));
         EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
         mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
 
@@ -286,13 +284,14 @@
         EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
         EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
         EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
-        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
-                                                   false /* isVirtual */, true /* isPrimary */)
-                                 .setDisplaySurface(test->mDisplaySurface)
-                                 .setNativeWindow(test->mNativeWindow)
-                                 .setSecure(Derived::IS_SECURE)
-                                 .setPowerMode(Derived::INIT_POWER_MODE)
-                                 .inject();
+        test->mDisplay =
+                FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+                                          DisplayConnectionType::Internal, true /* isPrimary */)
+                        .setDisplaySurface(test->mDisplaySurface)
+                        .setNativeWindow(test->mNativeWindow)
+                        .setSecure(Derived::IS_SECURE)
+                        .setPowerMode(Derived::INIT_POWER_MODE)
+                        .inject();
         Mock::VerifyAndClear(test->mNativeWindow);
         test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
     }
@@ -713,7 +712,7 @@
 
 struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
 
-struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {
+struct EffectLayerProperties : public BaseLayerProperties<EffectLayerProperties> {
     static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
 };
 
@@ -866,16 +865,16 @@
 };
 
 template <typename LayerProperties>
-struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> {
     using Base = BaseLayerVariant<LayerProperties>;
-    using FlingerLayerType = sp<ColorLayer>;
+    using FlingerLayerType = sp<EffectLayer>;
 
     static FlingerLayerType createLayer(CompositionTest* test) {
-        FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
-            return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
-                                                    "test-layer", LayerProperties::WIDTH,
-                                                    LayerProperties::HEIGHT,
-                                                    LayerProperties::LAYER_FLAGS, LayerMetadata()));
+        FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
+            return new EffectLayer(
+                    LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), "test-layer",
+                                      LayerProperties::WIDTH, LayerProperties::HEIGHT,
+                                      LayerProperties::LAYER_FLAGS, LayerMetadata()));
         });
 
         auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
@@ -1228,31 +1227,31 @@
  *  Single-color layers
  */
 
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) {
     displayRefreshCompositionDirtyGeometry<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
                             HwcCompositionResultVariant>>();
 }
 
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) {
     displayRefreshCompositionDirtyFrame<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
                             HwcCompositionResultVariant>>();
 }
 
-TEST_F(CompositionTest, REComposedColorLayer) {
+TEST_F(CompositionTest, REComposedEffectLayer) {
     displayRefreshCompositionDirtyFrame<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
                                                          IComposerClient::Composition::CLIENT>,
                             RECompositionResultVariant>>();
 }
 
-TEST_F(CompositionTest, captureScreenColorLayer) {
+TEST_F(CompositionTest, captureScreenEffectLayer) {
     captureScreenComposition<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             NoCompositionTypeVariant, REScreenshotResultVariant>>();
 }
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index dddad92..4da0647 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -201,8 +201,6 @@
 
 void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
     mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getCapabilities())
-            .WillOnce(Return(std::vector<IComposer::Capability>()));
     EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
     mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
 
@@ -312,6 +310,16 @@
     static std::optional<DisplayId> get() { return {}; }
 };
 
+template <typename>
+struct DisplayConnectionTypeGetter {
+    static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayId<PhysicalDisplay>> {
+    static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
 // DisplayIdType can be:
 //     1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
 //     2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
@@ -320,6 +328,7 @@
           Secure secure, Primary primary, int grallocUsage>
 struct DisplayVariant {
     using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+    using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
 
     // The display width and height
     static constexpr int WIDTH = width;
@@ -345,8 +354,8 @@
 
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
         auto injector =
-                FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
-                                          static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+                FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value,
+                                          static_cast<bool>(PRIMARY));
 
         injector.setSecure(static_cast<bool>(SECURE));
         injector.setNativeWindow(test->mNativeWindow);
@@ -450,6 +459,15 @@
     }
 
     static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
+        constexpr auto CONNECTION_TYPE =
+                PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+                ? IComposerClient::DisplayConnectionType::INTERNAL
+                : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+        EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+                .WillOnce(
+                        DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(Hwc2::V2_4::Error::NONE)));
+
         EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
         EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
@@ -514,6 +532,7 @@
 
 template <bool hasIdentificationData>
 struct PrimaryDisplay {
+    static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
     static constexpr Primary PRIMARY = Primary::TRUE;
     static constexpr uint8_t PORT = 255;
     static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -522,6 +541,7 @@
 
 template <bool hasIdentificationData>
 struct ExternalDisplay {
+    static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
     static constexpr Primary PRIMARY = Primary::FALSE;
     static constexpr uint8_t PORT = 254;
     static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -1183,7 +1203,8 @@
 
     GetBestColorModeTest()
           : DisplayTransactionTest(),
-            mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+            mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+                                                DisplayConnectionType::Internal,
                                                 true /* isPrimary */)) {}
 
     void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1285,8 +1306,6 @@
 class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
 public:
     static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
-    static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false;
-    static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true;
     static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080;  // arbitrary
     static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
 
@@ -1316,8 +1335,8 @@
         EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
         EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT));
 
-        return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL,
-                                         DEFAULT_DISPLAY_IS_PRIMARY)
+        return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+                                         DisplayConnectionType::Internal, true /* isPrimary */)
                 .setNativeWindow(mNativeWindow)
                 .setPhysicalOrientation(mPhysicalOrientation)
                 .inject();
@@ -1647,8 +1666,12 @@
     // Invocation
 
     DisplayDeviceState state;
-    state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
-                                                                : Case::Display::DISPLAY_ID::get();
+    if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+        const auto displayId = Case::Display::DISPLAY_ID::get();
+        ASSERT_TRUE(displayId);
+        state.physical = {*displayId, *connectionType};
+    }
+
     state.isSecure = static_cast<bool>(Case::Display::SECURE);
 
     auto device =
@@ -1660,6 +1683,7 @@
 
     ASSERT_TRUE(device != nullptr);
     EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+    EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
     EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
     EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
     EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -1823,21 +1847,24 @@
     EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
     EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
 
+    std::optional<DisplayDeviceState::Physical> expectedPhysical;
+    if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+        const auto displayId = Case::Display::DISPLAY_ID::get();
+        ASSERT_TRUE(displayId);
+        expectedPhysical = {*displayId, *connectionType};
+    }
+
     // The display should have been set up in the current display state
     ASSERT_TRUE(hasCurrentDisplayState(displayToken));
     const auto& current = getCurrentDisplayState(displayToken);
     EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
-    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
-                                                        : Case::Display::DISPLAY_ID::get(),
-              current.displayId);
+    EXPECT_EQ(expectedPhysical, current.physical);
 
     // The display should have been set up in the drawing display state
     ASSERT_TRUE(hasDrawingDisplayState(displayToken));
     const auto& draw = getDrawingDisplayState(displayToken);
     EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
-    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
-                                                        : Case::Display::DISPLAY_ID::get(),
-              draw.displayId);
+    EXPECT_EQ(expectedPhysical, draw.physical);
 }
 
 template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
new file mode 100644
index 0000000..c6fe205
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gui/LayerMetadata.h>
+#include <log/log.h>
+
+#include "DisplayHardware/HWComposer.h"
+#include "mock/DisplayHardware/MockComposer.h"
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
+namespace android {
+namespace {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+struct MockHWC2ComposerCallback : public HWC2::ComposerCallback {
+    ~MockHWC2ComposerCallback() = default;
+
+    MOCK_METHOD3(onHotplugReceived,
+                 void(int32_t sequenceId, hwc2_display_t display, HWC2::Connection connection));
+    MOCK_METHOD2(onRefreshReceived, void(int32_t sequenceId, hwc2_display_t display));
+    MOCK_METHOD4(onVsyncReceived,
+                 void(int32_t sequenceId, hwc2_display_t display, int64_t timestamp,
+                      std::optional<hwc2_vsync_period_t> vsyncPeriod));
+    MOCK_METHOD3(onVsyncPeriodTimingChangedReceived,
+                 void(int32_t sequenceId, hwc2_display_t display,
+                      const hwc_vsync_period_change_timeline_t& updatedTimeline));
+    MOCK_METHOD2(onSeamlessPossible, void(int32_t sequenceId, hwc2_display_t display));
+};
+
+struct HWComposerTest : public testing::Test {
+    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+};
+
+struct HWComposerSetConfigurationTest : public HWComposerTest {
+    StrictMock<MockHWC2ComposerCallback> mCallback;
+};
+
+TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) {
+    const std::string kMetadata1Name = "com.example.metadata.1";
+    constexpr bool kMetadata1Mandatory = false;
+    const std::string kMetadata2Name = "com.example.metadata.2";
+    constexpr bool kMetadata2Mandatory = true;
+
+    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+    EXPECT_CALL(*mHal, getCapabilities())
+            .WillOnce(Return(std::vector<Hwc2::IComposer::Capability>{}));
+    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+            .WillOnce(DoAll(SetArgPointee<0>(
+                                    std::vector<Hwc2::IComposerClient::LayerGenericMetadataKey>{
+                                            {kMetadata1Name, kMetadata1Mandatory},
+                                            {kMetadata2Name, kMetadata2Mandatory},
+                                    }),
+                            Return(hardware::graphics::composer::V2_4::Error::NONE)));
+    EXPECT_CALL(*mHal, registerCallback(_));
+    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+    hwc.setConfiguration(&mCallback, 123);
+
+    const auto& supported = hwc.getSupportedLayerGenericMetadata();
+    EXPECT_EQ(2u, supported.size());
+    EXPECT_EQ(1u, supported.count(kMetadata1Name));
+    EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second);
+    EXPECT_EQ(1u, supported.count(kMetadata2Name));
+    EXPECT_EQ(kMetadata2Mandatory, supported.find(kMetadata2Name)->second);
+}
+
+TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
+    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+    EXPECT_CALL(*mHal, getCapabilities())
+            .WillOnce(Return(std::vector<Hwc2::IComposer::Capability>{}));
+    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+            .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+    EXPECT_CALL(*mHal, registerCallback(_));
+    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+    hwc.setConfiguration(&mCallback, 123);
+
+    const auto& supported = hwc.getSupportedLayerGenericMetadata();
+    EXPECT_EQ(0u, supported.size());
+}
+
+struct HWComposerLayerTest : public testing::Test {
+    static constexpr hwc2_display_t kDisplayId = static_cast<hwc2_display_t>(1001);
+    static constexpr hwc2_layer_t kLayerId = static_cast<hwc2_layer_t>(1002);
+
+    HWComposerLayerTest(const std::unordered_set<HWC2::Capability>& capabilities)
+          : mCapabilies(capabilities) {}
+
+    ~HWComposerLayerTest() override { EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); }
+
+    std::unique_ptr<Hwc2::mock::Composer> mHal{new StrictMock<Hwc2::mock::Composer>()};
+    const std::unordered_set<HWC2::Capability> mCapabilies;
+    HWC2::impl::Layer mLayer{*mHal, mCapabilies, kDisplayId, kLayerId};
+};
+
+struct HWComposerLayerGenericMetadataTest : public HWComposerLayerTest {
+    static const std::string kLayerGenericMetadata1Name;
+    static constexpr bool kLayerGenericMetadata1Mandatory = false;
+    static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+    static const std::string kLayerGenericMetadata2Name;
+    static constexpr bool kLayerGenericMetadata2Mandatory = true;
+    static const std::vector<uint8_t> kLayerGenericMetadata2Value;
+
+    HWComposerLayerGenericMetadataTest() : HWComposerLayerTest({}) {}
+};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Name =
+        "com.example.metadata.1";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Value = {1u,
+                                                                                              2u,
+                                                                                              3u};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Name =
+        "com.example.metadata.2";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Value = {45u,
+                                                                                              67u};
+
+TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) {
+    EXPECT_CALL(*mHal,
+                setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata1Name,
+                                        kLayerGenericMetadata1Mandatory,
+                                        kLayerGenericMetadata1Value))
+            .WillOnce(Return(hardware::graphics::composer::V2_4::Error::NONE));
+    auto result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata1Name,
+                                                 kLayerGenericMetadata1Mandatory,
+                                                 kLayerGenericMetadata1Value);
+    EXPECT_EQ(HWC2::Error::None, result);
+
+    EXPECT_CALL(*mHal,
+                setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata2Name,
+                                        kLayerGenericMetadata2Mandatory,
+                                        kLayerGenericMetadata2Value))
+            .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+    result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata2Name,
+                                            kLayerGenericMetadata2Mandatory,
+                                            kLayerGenericMetadata2Value);
+    EXPECT_EQ(HWC2::Error::Unsupported, result);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index cffdc14..18b1063 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -27,7 +27,7 @@
 
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
 #include "Layer.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
@@ -68,7 +68,7 @@
     void setupComposer(int virtualDisplayCount);
     sp<BufferQueueLayer> createBufferQueueLayer();
     sp<BufferStateLayer> createBufferStateLayer();
-    sp<ColorLayer> createColorLayer();
+    sp<EffectLayer> createEffectLayer();
 
     void setParent(Layer* child, Layer* parent);
     void commitTransaction(Layer* layer);
@@ -111,11 +111,11 @@
     return new BufferStateLayer(args);
 }
 
-sp<ColorLayer> RefreshRateSelectionTest::createColorLayer() {
+sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
     sp<Client> client;
     LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
                            LayerMetadata());
-    return new ColorLayer(args);
+    return new EffectLayer(args);
 }
 
 void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
@@ -153,8 +153,6 @@
 
 void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) {
     mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getCapabilities())
-            .WillOnce(Return(std::vector<IComposer::Capability>()));
     EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
     mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
 
@@ -244,11 +242,11 @@
     ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
 }
 
-TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) {
-    mParent = createColorLayer();
-    mChild = createColorLayer();
+TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) {
+    mParent = createEffectLayer();
+    mChild = createEffectLayer();
     setParent(mChild.get(), mParent.get());
-    mGrandChild = createColorLayer();
+    mGrandChild = createEffectLayer();
     setParent(mGrandChild.get(), mChild.get());
 
     ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 798ba76..3a4f349 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -25,9 +25,9 @@
 
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ColorLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
+#include "EffectLayer.h"
 #include "FakePhaseOffsets.h"
 #include "Layer.h"
 #include "NativeWindowSurface.h"
@@ -147,9 +147,7 @@
         return nullptr;
     }
 
-    sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
-        return nullptr;
-    }
+    sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
 
     sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
         return nullptr;
@@ -545,10 +543,11 @@
     class FakeDisplayDeviceInjector {
     public:
         FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
-                                  const std::optional<DisplayId>& displayId, bool isVirtual,
+                                  std::optional<DisplayId> displayId,
+                                  std::optional<DisplayConnectionType> connectionType,
                                   bool isPrimary)
               : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
-            mCreationArgs.isVirtual = isVirtual;
+            mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;
         }
 
@@ -611,7 +610,12 @@
 
         sp<DisplayDevice> inject() {
             DisplayDeviceState state;
-            state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
+            if (const auto type = mCreationArgs.connectionType) {
+                const auto id = mCreationArgs.displayId;
+                LOG_ALWAYS_FATAL_IF(!id);
+                state.physical = {*id, *type};
+            }
+
             state.isSecure = mCreationArgs.isSecure;
 
             sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -619,9 +623,8 @@
             mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
             mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
 
-            if (!mCreationArgs.isVirtual) {
-                LOG_ALWAYS_FATAL_IF(!state.displayId);
-                mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
+            if (const auto& physical = state.physical) {
+                mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
             }
 
             return device;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 685dfba..a7a4d48 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -797,63 +797,6 @@
     ASSERT_EQ(0, globalProto.stats_size());
 }
 
-TEST_F(TimeStatsTest, globalStatsCallback) {
-    constexpr size_t TOTAL_FRAMES = 5;
-    constexpr size_t MISSED_FRAMES = 4;
-    constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
-    constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
-
-    mTimeStats->onBootFinished();
-    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
-    for (size_t i = 0; i < TOTAL_FRAMES; i++) {
-        mTimeStats->incrementTotalFrames();
-    }
-    for (size_t i = 0; i < MISSED_FRAMES; i++) {
-        mTimeStats->incrementMissedFrames();
-    }
-    for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
-        mTimeStats->incrementClientCompositionFrames();
-    }
-
-    mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
-
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
-    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
-    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
-
-    EXPECT_THAT(mDelegate->mAtomTags,
-                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
-                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
-    EXPECT_NE(nullptr, mDelegate->mCallback);
-    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
-    {
-        InSequence seq;
-        EXPECT_CALL(*mDelegate,
-                    statsEventSetAtomId(mDelegate->mEvent,
-                                        android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
-        EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
-    }
-    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
-              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
-                                              mDelegate->mCookie));
-
-    SFTimeStatsGlobalProto globalProto;
-    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
-
-    EXPECT_EQ(0, globalProto.total_frames());
-    EXPECT_EQ(0, globalProto.missed_frames());
-    EXPECT_EQ(0, globalProto.client_composition_frames());
-    EXPECT_EQ(0, globalProto.present_to_present_size());
-}
-
 namespace {
 std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
                                              const std::vector<int32_t>& frameCounts) {
@@ -897,6 +840,80 @@
     return expected == actual;
 }
 
+TEST_F(TimeStatsTest, globalStatsCallback) {
+    constexpr size_t TOTAL_FRAMES = 5;
+    constexpr size_t MISSED_FRAMES = 4;
+    constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+    constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
+
+    mTimeStats->onBootFinished();
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+        mTimeStats->incrementTotalFrames();
+    }
+    for (size_t i = 0; i < MISSED_FRAMES; i++) {
+        mTimeStats->incrementMissedFrames();
+    }
+    for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+        mTimeStats->incrementClientCompositionFrames();
+    }
+
+    mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
+    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->recordFrameDuration(1000000, 3000000);
+    mTimeStats->recordRenderEngineDuration(2000000, 4000000);
+    mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
+
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
+    std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
+
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventSetAtomId(mDelegate->mEvent,
+                                        android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedFrameDuration.c_str(),
+                                                     expectedFrameDuration.size()),
+                                             expectedFrameDuration.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedRenderEngineTiming.c_str(),
+                                                     expectedRenderEngineTiming.size()),
+                                             expectedRenderEngineTiming.size()));
+        EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+    }
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                              mDelegate->mCookie));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    EXPECT_EQ(0, globalProto.total_frames());
+    EXPECT_EQ(0, globalProto.missed_frames());
+    EXPECT_EQ(0, globalProto.client_composition_frames());
+    EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
 TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
     constexpr size_t LATE_ACQUIRE_FRAMES = 2;
     constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 6ec3844..f834af8 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -36,7 +36,7 @@
 namespace android::scheduler {
 
 MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
-    return arg <= value + tolerance && value >= value - tolerance;
+    return arg <= value + tolerance && arg >= value - tolerance;
 }
 
 std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
@@ -370,6 +370,26 @@
                 IsCloseTo(idealPeriod, mMaxRoundingError));
 }
 
+TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
+    constexpr auto kNumVsyncs = 100;
+    auto invalidPeriod = mPeriod;
+    auto now = 0;
+    for (int i = 0; i < kNumVsyncs; i++) {
+        tracker.addVsyncTimestamp(now);
+        now += invalidPeriod;
+        invalidPeriod *= 0.9f;
+
+        auto [slope, intercept] = tracker.getVSyncPredictionModel();
+        EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
+
+        // When VsyncPredictor returns the period it means that it doesn't know how to predict and
+        // it needs to get more samples
+        if (slope == mPeriod && intercept == 0) {
+            EXPECT_TRUE(tracker.needsMoreSamples(now));
+        }
+    }
+}
+
 } // 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 2f36bb2..ac95938 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -534,6 +534,30 @@
     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) 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)))