Merge "SurfaceFlinger: fix sysprop API condition for color management"
diff --git a/cmds/atrace/TEST_MAPPING b/cmds/atrace/TEST_MAPPING
new file mode 100644
index 0000000..f43db22
--- /dev/null
+++ b/cmds/atrace/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAtraceHostTestCases"
+    }
+  ]
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 03a15bb..21de4db 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1752,7 +1752,9 @@
     }
     // TODO: Should truncate the existing file.
     // ... and re-open it for further logging.
-    redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
+    if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
+        return false;
+    }
     fprintf(stderr, "\n");
 
     int32_t err = zip_writer_->Finish();
@@ -2372,12 +2374,17 @@
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
     if (options_->use_socket) {
-        redirect_to_socket(stdout, "dumpstate");
+        if (!redirect_to_socket(stdout, "dumpstate")) {
+            return ERROR;
+        }
     }
 
     if (options_->use_control_socket) {
         MYLOGD("Opening control socket\n");
         control_socket_fd_ = open_socket("dumpstate");
+        if (control_socket_fd_ == -1) {
+            return ERROR;
+        }
         options_->do_progress_updates = 1;
     }
 
@@ -2436,7 +2443,9 @@
     if (is_redirecting) {
         // Redirect stderr to log_path_ for debugging.
         TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
-        redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()));
+        if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+            return ERROR;
+        }
         if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
                    strerror(errno));
@@ -2449,7 +2458,9 @@
         /* TODO: rather than generating a text file now and zipping it later,
            it would be more efficient to redirect stdout to the zip entry
            directly, but the libziparchive doesn't support that option yet. */
-        redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()));
+        if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+            return ERROR;
+        }
         if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
                    tmp_path_.c_str(), strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 9803f00..c326bb6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -519,14 +519,26 @@
 /** opens a socket and returns its file descriptor */
 int open_socket(const char *service);
 
-/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service);
+/*
+ * Redirects 'redirect' to a service control socket.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_socket(FILE* redirect, const char* service);
 
-/* redirect output to a new file */
-void redirect_to_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to a file indicated by 'path', truncating it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_file(FILE* redirect, char* path);
 
-/* redirect output to an existing file */
-void redirect_to_existing_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to an existing file indicated by 'path', appending it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_existing_file(FILE* redirect, char* path);
 
 /* create leading directories, if necessary */
 void create_parent_dirs(const char *path);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 4bc0e1d..2a5516d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -712,12 +712,12 @@
     int s = android_get_control_socket(service);
     if (s < 0) {
         MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
-        exit(1);
+        return -1;
     }
     fcntl(s, F_SETFD, FD_CLOEXEC);
     if (listen(s, 4) < 0) {
         MYLOGE("listen(control socket): %s\n", strerror(errno));
-        exit(1);
+        return -1;
     }
 
     struct sockaddr addr;
@@ -725,18 +725,23 @@
     int fd = accept(s, &addr, &alen);
     if (fd < 0) {
         MYLOGE("accept(control socket): %s\n", strerror(errno));
-        exit(1);
+        return -1;
     }
 
     return fd;
 }
 
 /* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service) {
+bool redirect_to_socket(FILE* redirect, const char* service) {
     int fd = open_socket(service);
+    if (fd == -1) {
+        return false;
+    }
     fflush(redirect);
-    dup2(fd, fileno(redirect));
+    // TODO: handle dup2 failure
+    TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
     close(fd);
+    return true;
 }
 
 // TODO: should call is_valid_output_file and/or be merged into it.
@@ -766,7 +771,7 @@
     }
 }
 
-void _redirect_to_file(FILE *redirect, char *path, int truncate_flag) {
+bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
     create_parent_dirs(path);
 
     int fd = TEMP_FAILURE_RETRY(open(path,
@@ -774,19 +779,20 @@
                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
     if (fd < 0) {
         MYLOGE("%s: %s\n", path, strerror(errno));
-        exit(1);
+        return false;
     }
 
     TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
     close(fd);
+    return true;
 }
 
-void redirect_to_file(FILE *redirect, char *path) {
-    _redirect_to_file(redirect, path, O_TRUNC);
+bool redirect_to_file(FILE* redirect, char* path) {
+    return _redirect_to_file(redirect, path, O_TRUNC);
 }
 
-void redirect_to_existing_file(FILE *redirect, char *path) {
-    _redirect_to_file(redirect, path, O_APPEND);
+bool redirect_to_existing_file(FILE* redirect, char* path) {
+    return _redirect_to_file(redirect, path, O_APPEND);
 }
 
 // Dump Dalvik and native stack traces, return the trace file location (nullptr if none).
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index f523725..ffd1191 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -261,6 +261,40 @@
   return "";
 }
 
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+static const char* select_execution_binary(const char* binary, const char* debug_binary,
+        bool background_job_compile) {
+    return select_execution_binary(
+        binary,
+        debug_binary,
+        background_job_compile,
+        is_debug_runtime(),
+        (android::base::GetProperty("ro.build.version.codename", "") == "REL"),
+        is_debuggable_build());
+}
+
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+// This is convenient method which is much easier to test because it doesn't read
+// system properties.
+const char* select_execution_binary(
+        const char* binary,
+        const char* debug_binary,
+        bool background_job_compile,
+        bool is_debug_runtime,
+        bool is_release,
+        bool is_debuggable_build) {
+    // Do not use debug binaries for release candidates (to give more soak time).
+    bool is_debug_bg_job = background_job_compile && is_debuggable_build && !is_release;
+
+    // If the runtime was requested to use libartd.so, we'll run the debug version - assuming
+    // the file is present (it may not be on images with very little space available).
+    bool useDebug = (is_debug_runtime || is_debug_bg_job) && (access(debug_binary, X_OK) == 0);
+
+    return useDebug ? debug_binary : binary;
+}
+
 // Namespace for Android Runtime flags applied during boot time.
 static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
 // Feature flag name for running the JIT in Zygote experiment, b/119800099.
@@ -354,16 +388,9 @@
         std::string dex2oat_large_app_threshold_arg =
             MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
 
-        // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-        const char* dex2oat_bin = kDex2oatPath;
-        // Do not use dex2oatd for release candidates (give dex2oat more soak time).
-        bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
-        if (is_debug_runtime() ||
-                (background_job_compile && is_debuggable_build() && !is_release)) {
-            if (access(kDex2oatDebugPath, X_OK) == 0) {
-                dex2oat_bin = kDex2oatDebugPath;
-            }
-        }
+
+        const char* dex2oat_bin = select_execution_binary(
+            kDex2oatPath, kDex2oatDebugPath, background_job_compile);
 
         bool generate_minidebug_info = kEnableMinidebugInfo &&
                 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
@@ -676,7 +703,12 @@
                   const std::vector<std::string>& dex_locations,
                   bool copy_and_update,
                   bool store_aggregation_counters) {
-        const char* profman_bin = is_debug_runtime() ? kProfmanDebugPath: kProfmanPath;
+
+        // TODO(calin): Assume for now we run in the bg compile job (which is in
+        // most of the invocation). With the current data flow, is not very easy or
+        // clean to discover this in RunProfman (it will require quite a messy refactoring).
+        const char* profman_bin = select_execution_binary(
+            kProfmanPath, kProfmanDebugPath, /*background_job_compile=*/ true);
 
         if (copy_and_update) {
             CHECK_EQ(1u, profile_fds.size());
@@ -1491,8 +1523,10 @@
                     bool downgrade,
                     const char* class_loader_context) {
         CHECK_GE(zip_fd, 0);
-        const char* dexoptanalyzer_bin =
-            is_debug_runtime() ? kDexoptanalyzerDebugPath : kDexoptanalyzerPath;
+
+        // We always run the analyzer in the background job.
+        const char* dexoptanalyzer_bin = select_execution_binary(
+             kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
 
         std::string dex_file_arg = "--dex-file=" + dex_file;
         std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5902659..a8c48c5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -36,7 +36,7 @@
 // Location of binaries in the Android Runtime APEX.
 static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat";
 static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd";
-static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profman";
 static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
 static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer";
 static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd";
@@ -128,6 +128,14 @@
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
 
+const char* select_execution_binary(
+        const char* binary,
+        const char* debug_binary,
+        bool background_job_compile,
+        bool is_debug_runtime,
+        bool is_release,
+        bool is_debuggable_build);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 78edce0..71b710b 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -1175,5 +1175,64 @@
     ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), ref_prof) != profiles.end());
 }
 
+TEST_F(DexoptTest, select_execution_binary) {
+    LOG(INFO) << "DexoptTestselect_execution_binary";
+
+    std::string release_str = app_private_dir_ce_  + "/release";
+    std::string debug_str = app_private_dir_ce_  + "/debug";
+
+    // Setup the binaries. Note that we only need executable files to actually
+    // test the execution binary selection
+    run_cmd("touch " + release_str);
+    run_cmd("touch " + debug_str);
+    run_cmd("chmod 777 " + release_str);
+    run_cmd("chmod 777 " + debug_str);
+
+    const char* release = release_str.c_str();
+    const char* debug = debug_str.c_str();
+
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ true,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ true,
+        /*is_debuggable_build=*/ true));
+
+    ASSERT_STREQ(debug, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ true,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+
+    ASSERT_STREQ(debug, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ true,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ true));
+
+
+    // Select the release when the debug file is not there.
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        "does_not_exist",
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ true,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index 3b8955b..71f0837 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -95,6 +95,7 @@
         strncpy(ifr.ifr_name, interface, IFNAMSIZ);
         if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
             ALOGE("Cannot bring up %s: %s", interface, strerror(errno));
+            fclose(state);
             return 1;
         }
 
@@ -102,6 +103,7 @@
         if (!set_address(&ifr.ifr_addr, address) ||
                 ioctl(s, SIOCSIFADDR, &ifr)) {
             ALOGE("Cannot set address: %s", strerror(errno));
+            fclose(state);
             return 1;
         }
 
@@ -109,6 +111,7 @@
         if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) {
             if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
                 ALOGE("Cannot set netmask: %s", strerror(errno));
+                fclose(state);
                 return 1;
             }
         }
@@ -123,6 +126,7 @@
         fprintf(state, "%s\n", env("REMOTE_ADDR"));
     } else {
         ALOGE("Cannot parse parameters");
+        fclose(state);
         return 1;
     }
 
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index f755e00..0b0bf44 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -46,6 +46,27 @@
 
         remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+        if (!outStats) return UNEXPECTED_NULL;
+
+        Parcel data, reply;
+        status_t status;
+
+        if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK)
+            return status;
+
+        if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_GLOBAL_INFO, data, &reply)) !=
+            OK)
+            return status;
+
+        int32_t result = 0;
+        if ((status = reply.readInt32(&result)) != OK) return status;
+        if (result != OK) return result;
+
+        outStats->clear();
+        return reply.readParcelableVector(outStats);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
@@ -89,6 +110,19 @@
 
             return OK;
         }
+        case GET_GPU_STATS_GLOBAL_INFO: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::vector<GpuStatsGlobalInfo> stats;
+            const status_t result = getGpuStatsGlobalInfo(&stats);
+
+            if ((status = reply->writeInt32(result)) != OK) return status;
+            if (result != OK) return result;
+
+            if ((status = reply->writeParcelableVector(stats)) != OK) return status;
+
+            return OK;
+        }
         case SHELL_COMMAND_TRANSACTION: {
             int in = data.readFileDescriptor();
             int out = data.readFileDescriptor();
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index 5f9340d..e7cdb38 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -16,12 +16,13 @@
 
 #pragma once
 
+#include <vector>
+
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
 #include <graphicsenv/GraphicsEnv.h>
 
-#include <vector>
-
 namespace android {
 
 /*
@@ -38,12 +39,16 @@
                              int64_t driverBuildTime, const std::string& appPackageName,
                              GraphicsEnv::Driver driver, bool isDriverLoaded,
                              int64_t driverLoadingTime) = 0;
+
+    // get GPU global stats from GpuStats module.
+    virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
 };
 
 class BnGpuService : public BnInterface<IGpuService> {
 public:
     enum IGpuServiceTag {
         SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
+        GET_GPU_STATS_GLOBAL_INFO,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 962d263..84ba644 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -100,6 +100,7 @@
 
     output.writeFloat(bgColorAlpha);
     output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
+    output.writeBool(colorSpaceAgnostic);
 
     return NO_ERROR;
 }
@@ -177,6 +178,7 @@
 
     bgColorAlpha = input.readFloat();
     bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+    colorSpaceAgnostic = input.readBool();
 
     return NO_ERROR;
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 050ba87..0a4ad46 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -989,6 +989,20 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorSpaceAgnostic(
+        const sp<SurfaceControl>& sc, const bool agnostic) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorSpaceAgnosticChanged;
+    s->colorSpaceAgnostic = agnostic;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 SurfaceComposerClient::Transaction&
 SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
         TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 32d7391..35e795c 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -88,6 +88,7 @@
         eCachedBufferChanged = 0x2'00000000,
         eBackgroundColorChanged = 0x4'00000000,
         eMetadataChanged = 0x8'00000000,
+        eColorSpaceAgnosticChanged = 0x10'00000000,
     };
 
     layer_state_t()
@@ -115,7 +116,8 @@
             api(-1),
             colorTransform(mat4()),
             bgColorAlpha(0),
-            bgColorDataspace(ui::Dataspace::UNKNOWN) {
+            bgColorDataspace(ui::Dataspace::UNKNOWN),
+            colorSpaceAgnostic(false) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
         hdrMetadata.validTypes = 0;
@@ -192,6 +194,10 @@
     // the background color layer
     float bgColorAlpha;
     ui::Dataspace bgColorDataspace;
+
+    // A color space agnostic layer means the color of this layer can be
+    // interpreted in any color space.
+    bool colorSpaceAgnostic;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e062339..2c483ee 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -360,6 +360,7 @@
         Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
                                        const sp<NativeHandle>& sidebandStream);
         Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
+        Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
 
         Transaction& addTransactionCompletedCallback(
                 TransactionCompletedCallbackTakesContext callback, void* callbackContext);
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index 5652c0c..d33ecfb 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -240,7 +240,7 @@
     float const luma_gray = 0.50;
 };
 
-TEST_F(RegionSamplingTest, CollectsLuma) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
     fill_render(rgba_green);
 
     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
@@ -254,7 +254,7 @@
     composer->removeRegionSamplingListener(listener);
 }
 
-TEST_F(RegionSamplingTest, CollectsChangingLuma) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
     fill_render(rgba_green);
 
     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
@@ -275,7 +275,7 @@
     composer->removeRegionSamplingListener(listener);
 }
 
-TEST_F(RegionSamplingTest, CollectsLumaFromTwoRegions) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
     fill_render(rgba_green);
     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
     sp<Listener> greenListener = new Listener();
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index a73705b..5e5cf35 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -59,6 +59,14 @@
                       appPackageName, driver, isDriverLoaded, driverLoadingTime);
 }
 
+status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+    ATRACE_CALL();
+
+    mGpuStats->pullGlobalStats(outStats);
+
+    return OK;
+}
+
 status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
     ATRACE_CALL();
 
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 0cf48bb..b984e0f 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -19,6 +19,7 @@
 
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
 #include <graphicsenv/IGpuService.h>
 #include <serviceutils/PriorityDumper.h>
 
@@ -45,7 +46,8 @@
     void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
                      uint64_t driverVersionCode, int64_t driverBuildTime,
                      const std::string& appPackageName, GraphicsEnv::Driver driver,
-                     bool isDriverLoaded, int64_t driverLoadingTime);
+                     bool isDriverLoaded, int64_t driverLoadingTime) override;
+    status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
 
     /*
      * IBinder interface
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index c4256df..146e2c2 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -184,4 +184,18 @@
     }
 }
 
+void GpuStats::pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mLock);
+    outStats->clear();
+    outStats->reserve(mGlobalStats.size());
+
+    for (const auto& ele : mGlobalStats) {
+        outStats->emplace_back(ele.second);
+    }
+
+    mGlobalStats.clear();
+}
+
 } // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
index da7fd33..9cdcd95 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -39,6 +39,8 @@
                 int64_t driverLoadingTime);
     // dumpsys interface
     void dump(const Vector<String16>& args, std::string* result);
+    // Pull gpu global stats
+    void pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats);
 
 private:
     // Dump global stats
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 756ca42..7884362 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -239,7 +239,8 @@
 
 void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
                                   const ui::Transform& transform, const Rect& viewport,
-                                  int32_t supportedPerFrameMetadata) {
+                                  int32_t supportedPerFrameMetadata,
+                                  const ui::Dataspace targetDataspace) {
     RETURN_IF_NO_HWC_LAYER(displayDevice);
 
     // Apply this display's projection's viewport to the visible region
@@ -291,10 +292,10 @@
         setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
     }
 
-    ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
-    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+    error = hwcLayer->setDataspace(dataspace);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e9dbdea..8149cba 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -81,7 +81,8 @@
     bool isHdrY410() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
-                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+                         const Rect& viewport, int32_t supportedPerFrameMetadata,
+                         const ui::Dataspace targetDataspace) override;
 
     bool onPreComposition(nsecs_t refreshStartTime) override;
     bool onPostComposition(const std::optional<DisplayId>& displayId,
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 16e8e95..7cd9e49 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -362,7 +362,7 @@
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
     (*outputLayer->editState().hwc)
-            .hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+            .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 6390e85..b2383ad 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -570,14 +570,17 @@
 void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
     const auto outputLayer = findOutputLayerForDisplay(display);
     LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
+    auto& hwcInfo = *outputLayer->editState().hwc;
+    auto& hwcLayer = hwcInfo.hwcLayer;
 
     const State& s(getDrawingState());
 
-    // TODO(marissaw): support more than one slot
+    // obtain slot
     uint32_t hwcSlot = 0;
+    sp<GraphicBuffer> buffer;
+    hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer);
 
-    auto error = hwcLayer->setBuffer(hwcSlot, s.buffer, s.acquireFence);
+    auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
               s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 2aeece7..a2692bc 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -81,7 +81,8 @@
 
 void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
                                  const ui::Transform& transform, const Rect& viewport,
-                                 int32_t /* supportedPerFrameMetadata */) {
+                                 int32_t /* supportedPerFrameMetadata */,
+                                 const ui::Dataspace targetDataspace) {
     RETURN_IF_NO_HWC_LAYER(display);
 
     Region visible = transform.transform(visibleRegion.intersect(viewport));
@@ -101,9 +102,10 @@
 
     setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
 
-    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    const ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+    error = hwcLayer->setDataspace(dataspace);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 9786419..9a72b40 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -36,7 +36,8 @@
     bool setColor(const half3& color) override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
-                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+                         const Rect& viewport, int32_t supportedPerFrameMetadata,
+                         const ui::Dataspace targetDataspace) override;
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index b45de5a..02d7890 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -19,6 +19,7 @@
 #include <cstdint>
 #include <vector>
 
+#include <gui/BufferQueue.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -39,19 +40,28 @@
 class HwcBufferCache {
 public:
     HwcBufferCache();
-
-    // Given a buffer queue slot and buffer, return the HWC cache slot and
+    // Given a buffer, return the HWC cache slot and
     // buffer to be sent to HWC.
     //
     // outBuffer is set to buffer when buffer is not in the HWC cache;
     // otherwise, outBuffer is set to nullptr.
-    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer);
 
+protected:
+    bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot);
+    uint32_t getLeastRecentlyUsedSlot();
+    uint64_t getCounter();
+
 private:
-    // a vector as we expect "slot" to be in the range of [0, 63] (that is,
-    // less than BufferQueue::NUM_BUFFER_SLOTS).
-    std::vector<sp<GraphicBuffer>> mBuffers;
+    // an array where the index corresponds to a slot and the value corresponds to a (counter,
+    // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
+    // or used and allows us to keep track of the least-recently used buffer.
+    std::pair<uint64_t, wp<GraphicBuffer>> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+
+    // The cache increments this counter value when a slot is updated or used.
+    // Used to track the least recently-used buffer
+    uint64_t mCounter = 1;
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 6f340b9..8613210 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -21,31 +21,52 @@
 namespace android::compositionengine::impl {
 
 HwcBufferCache::HwcBufferCache() {
-    mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
+    std::fill(std::begin(mBuffers), std::end(mBuffers),
+              std::pair<uint64_t, wp<GraphicBuffer>>(0, nullptr));
+}
+bool HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
+    // search for cached buffer first
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        // Weak pointers in the cache may have had their object destroyed.
+        // Comparisons between weak pointers will accurately reflect this case,
+        // but comparisons between weak and strong may not.  Thus, we create a weak
+        // pointer from strong pointer buffer
+        wp<GraphicBuffer> weakCopy(buffer);
+        if (mBuffers[i].second == weakCopy) {
+            *outSlot = i;
+            return true;
+        }
+    }
+
+    // use the least-recently used slot
+    *outSlot = getLeastRecentlyUsedSlot();
+    return false;
 }
 
-void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() {
+    auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers));
+    return std::distance(std::begin(mBuffers), iter);
+}
+
+void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                                   sp<GraphicBuffer>* outBuffer) {
-    if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
-        // default to slot 0
-        slot = 0;
-    }
+    bool cached = getSlot(buffer, outSlot);
 
-    if (static_cast<size_t>(slot) >= mBuffers.size()) {
-        mBuffers.resize(slot + 1);
-    }
-
-    *outSlot = slot;
-
-    if (mBuffers[slot] == buffer) {
+    auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
+    if (cached) {
         // already cached in HWC, skip sending the buffer
         *outBuffer = nullptr;
+        currentCounter = getCounter();
     } else {
         *outBuffer = buffer;
 
         // update cache
-        mBuffers[slot] = buffer;
+        currentBuffer = buffer;
+        currentCounter = getCounter();
     }
 }
 
+uint64_t HwcBufferCache::getCounter() {
+    return mCounter++;
+}
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index f2a1aad..ac04cb3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -22,60 +22,80 @@
 namespace android::compositionengine {
 namespace {
 
+class TestableHwcBufferCache : public impl::HwcBufferCache {
+public:
+    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+                      sp<GraphicBuffer>* outBuffer) {
+        HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
+    }
+    bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
+        return HwcBufferCache::getSlot(buffer, outSlot);
+    }
+    uint32_t getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); }
+};
+
 class HwcBufferCacheTest : public testing::Test {
 public:
     ~HwcBufferCacheTest() override = default;
 
-    void testSlot(const int inSlot, const uint32_t expectedSlot) {
-        uint32_t outSlot;
-        sp<GraphicBuffer> outBuffer;
-
-        // The first time, the output  is the same as the input
-        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
-        EXPECT_EQ(expectedSlot, outSlot);
-        EXPECT_EQ(mBuffer1, outBuffer);
-
-        // The second time with the same buffer, the outBuffer is nullptr.
-        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
-        EXPECT_EQ(expectedSlot, outSlot);
-        EXPECT_EQ(nullptr, outBuffer.get());
-
-        // With a new buffer, the outBuffer is the input.
-        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
-        EXPECT_EQ(expectedSlot, outSlot);
-        EXPECT_EQ(mBuffer2, outBuffer);
-
-        // Again, the second request with the same buffer sets outBuffer to nullptr.
-        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
-        EXPECT_EQ(expectedSlot, outSlot);
-        EXPECT_EQ(nullptr, outBuffer.get());
-
-        // Setting a slot to use nullptr lookslike works, but note that
-        // the output values make it look like no new buffer is being set....
-        mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
-        EXPECT_EQ(expectedSlot, outSlot);
-        EXPECT_EQ(nullptr, outBuffer.get());
-    }
-
-    impl::HwcBufferCache mCache;
+    TestableHwcBufferCache mCache;
     sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
     sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
 };
 
-TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
-    testSlot(0, 0);
+TEST_F(HwcBufferCacheTest, testSlot) {
+    uint32_t outSlot;
+    sp<GraphicBuffer> outBuffer;
+
+    // The first time, the output  is the same as the input
+    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    EXPECT_EQ(0, outSlot);
+    EXPECT_EQ(mBuffer1, outBuffer);
+
+    // The second time with the same buffer, the outBuffer is nullptr.
+    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    EXPECT_EQ(0, outSlot);
+    EXPECT_EQ(nullptr, outBuffer.get());
+
+    // With a new buffer, the outBuffer is the input.
+    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+    EXPECT_EQ(1, outSlot);
+    EXPECT_EQ(mBuffer2, outBuffer);
+
+    // Again, the second request with the same buffer sets outBuffer to nullptr.
+    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+    EXPECT_EQ(1, outSlot);
+    EXPECT_EQ(nullptr, outBuffer.get());
+
+    // Setting a slot to use nullptr lookslike works, but note that
+    // the output values make it look like no new buffer is being set....
+    mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer);
+    EXPECT_EQ(2, outSlot);
+    EXPECT_EQ(nullptr, outBuffer.get());
 }
 
-TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
-    testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
-}
+TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) {
+    int slot;
+    uint32_t outSlot;
+    sp<GraphicBuffer> outBuffer;
 
-TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
-    testSlot(-123, 0);
-}
+    // fill up cache
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        mCache.getHwcBuffer(buf, &outSlot, &outBuffer);
+        EXPECT_EQ(buf, outBuffer);
+        EXPECT_EQ(i, outSlot);
+    }
 
-TEST_F(HwcBufferCacheTest, cacheMapsInvalidBufferSlotToZero) {
-    testSlot(BufferQueue::INVALID_BUFFER_SLOT, 0);
+    slot = mCache.getLeastRecentlyUsedSlot();
+    EXPECT_EQ(0, slot);
+
+    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    EXPECT_EQ(0, outSlot);
+    EXPECT_EQ(mBuffer1, outBuffer);
+
+    slot = mCache.getLeastRecentlyUsedSlot();
+    EXPECT_EQ(1, slot);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 738f4b6..7927fa9 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -40,6 +40,6 @@
 }
 
 void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
-                                     const Rect&, int32_t) {}
+                                     const Rect&, int32_t, const ui::Dataspace) {}
 
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c7cfdcd..7222a3e 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,7 +34,8 @@
     bool canReceiveInput() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
-                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+                         const Rect& viewport, int32_t supportedPerFrameMetadata,
+                         const ui::Dataspace targetDataspace) override;
 
     bool isCreatedFromMainThread() const override { return true; }
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 27812f7..775fb80 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -111,8 +111,7 @@
     BufferItem item;
     status_t err = acquireBufferLocked(&item, 0);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-        mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
-                &outSlot, &outBuffer);
+        mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
         return NO_ERROR;
     } else if (err != NO_ERROR) {
         ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -138,8 +137,7 @@
     mCurrentFence = item.mFence;
 
     outFence = item.mFence;
-    mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
-            &outSlot, &outBuffer);
+    mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
     outDataspace = static_cast<Dataspace>(item.mDataSpace);
     status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index bca0abc..910a527 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -143,8 +143,8 @@
         return error;
     }
 
-    auto display = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor, mCapabilities,
-                                                   displayId, DisplayType::Virtual);
+    auto display = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities, displayId,
+                                                   DisplayType::Virtual);
     display->setConnected(true);
     *outDisplay = display.get();
     mDisplays.emplace(displayId, std::move(display));
@@ -182,8 +182,8 @@
             return;
         }
 
-        auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor,
-                                                          mCapabilities, displayId, displayType);
+        auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities,
+                                                          displayId, displayType);
         newDisplay->setConnected(true);
         mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
@@ -254,11 +254,10 @@
 }
 
 namespace impl {
-Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
+Display::Display(android::Hwc2::Composer& composer,
                  const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
                  DisplayType type)
       : mComposer(composer),
-        mPowerAdvisor(advisor),
         mCapabilities(capabilities),
         mId(id),
         mIsConnected(false),
@@ -636,12 +635,6 @@
 
 Error Display::setColorMode(ColorMode mode, RenderIntent renderIntent)
 {
-    // When the color mode is switched to DISPLAY_P3, we want to boost the GPU frequency
-    // so that GPU composition can finish in time. When color mode is switched from
-    // DISPLAY_P3, we want to reset GPU frequency.
-    const bool expensiveRenderingExpected = (mode == ColorMode::DISPLAY_P3);
-    mPowerAdvisor.setExpensiveRenderingExpected(mId, expensiveRenderingExpected);
-
     auto intError = mComposer.setColorMode(mId, mode, renderIntent);
     return static_cast<Error>(intError);
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 70358a0..f96614f 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,8 +37,6 @@
 #include <unordered_set>
 #include <vector>
 
-#include "PowerAdvisor.h"
-
 namespace android {
     struct DisplayedFrameStats;
     class Fence;
@@ -125,7 +123,6 @@
     std::unique_ptr<android::Hwc2::Composer> mComposer;
     std::unordered_set<Capability> mCapabilities;
     std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
-    android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
     bool mRegisteredCallback = false;
 };
 
@@ -273,9 +270,8 @@
 
 class Display : public HWC2::Display {
 public:
-    Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
-            const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
-            DisplayType type);
+    Display(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
+            hwc2_display_t id, DisplayType type);
     ~Display() override;
 
     // Required by HWC2
@@ -352,7 +348,6 @@
     // this HWC2::Display, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
-    android::Hwc2::PowerAdvisor& mPowerAdvisor;
     const std::unordered_set<Capability>& mCapabilities;
 
     hwc2_display_t mId;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 12bbae2..039db73 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -38,7 +38,7 @@
 
 PowerAdvisor::PowerAdvisor() = default;
 
-void PowerAdvisor::setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) {
+void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
     if (expected) {
         mExpensiveDisplays.insert(displayId);
     } else {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 573a1a9..5aa1f22 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,10 +22,12 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
+#include <unordered_set>
+
 #include <android/hardware/power/1.3/IPower.h>
 #include <utils/StrongPointer.h>
 
-#include <unordered_set>
+#include "DisplayIdentification.h"
 
 namespace android {
 namespace Hwc2 {
@@ -34,7 +36,7 @@
 public:
     virtual ~PowerAdvisor();
 
-    virtual void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) = 0;
+    virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
 };
 
 namespace impl {
@@ -48,12 +50,12 @@
     PowerAdvisor();
     ~PowerAdvisor() override;
 
-    void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) override;
+    void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
 
 private:
     sp<V1_3::IPower> getPowerHal();
 
-    std::unordered_set<hwc2_display_t> mExpensiveDisplays;
+    std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
     bool mReconnectPowerHal = false;
 };
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1c2853a..613dc77 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,8 +224,7 @@
     if (fbBuffer != nullptr) {
         uint32_t hwcSlot = 0;
         sp<GraphicBuffer> hwcBuffer;
-        mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer,
-                &hwcSlot, &hwcBuffer);
+        mHwcBufferCache.getHwcBuffer(fbBuffer, &hwcSlot, &hwcBuffer);
 
         // TODO: Correctly propagate the dataspace from GL composition
         result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a6adeb3..5c3fb05 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -103,6 +103,7 @@
     mCurrentState.cornerRadius = 0.0f;
     mCurrentState.api = -1;
     mCurrentState.hasColorTransform = false;
+    mCurrentState.colorSpaceAgnostic = false;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
@@ -147,7 +148,7 @@
             strongRelative->removeZOrderRelative(this);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
-        mCurrentState.zOrderRelativeOf = nullptr;
+        setZOrderRelativeOf(nullptr);
     }
 
     // Since we are no longer reachable from CurrentState SurfaceFlinger
@@ -1071,13 +1072,6 @@
         mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
     }
 
-    // If the layer is hidden, signal and clear out all local sync points so
-    // that transactions for layers depending on this layer's frames becoming
-    // visible are not blocked
-    if (c.flags & layer_state_t::eLayerHidden) {
-        clearSyncPoints();
-    }
-
     if (mCurrentState.inputInfoChanged) {
         flags |= eInputInfoChanged;
         mCurrentState.inputInfoChanged = false;
@@ -1164,7 +1158,7 @@
         if (strongRelative != nullptr) {
             strongRelative->removeZOrderRelative(this);
         }
-        mCurrentState.zOrderRelativeOf = nullptr;
+        setZOrderRelativeOf(nullptr);
     }
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1184,6 +1178,13 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
+void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) {
+    mCurrentState.zOrderRelativeOf = relativeOf;
+    mCurrentState.sequence++;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+}
+
 bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
     sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
     if (handle == nullptr) {
@@ -1207,7 +1208,7 @@
     if (oldZOrderRelativeOf != nullptr) {
         oldZOrderRelativeOf->removeZOrderRelative(this);
     }
-    mCurrentState.zOrderRelativeOf = relative;
+    setZOrderRelativeOf(relative);
     relative->addZOrderRelative(this);
 
     setTransactionFlags(eTransactionNeeded);
@@ -1355,6 +1356,17 @@
     return true;
 }
 
+bool Layer::setColorSpaceAgnostic(const bool agnostic) {
+    if (mCurrentState.colorSpaceAgnostic == agnostic) {
+        return false;
+    }
+    mCurrentState.sequence++;
+    mCurrentState.colorSpaceAgnostic = agnostic;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 uint32_t Layer::getLayerStack() const {
     auto p = mDrawingParent.promote();
     if (p == nullptr) {
@@ -1764,18 +1776,6 @@
     mCurrentParent = layer;
 }
 
-void Layer::clearSyncPoints() {
-    for (const auto& child : mCurrentChildren) {
-        child->clearSyncPoints();
-    }
-
-    Mutex::Autolock lock(mLocalSyncPointMutex);
-    for (auto& point : mLocalSyncPoints) {
-        point->setFrameAvailable();
-    }
-    mLocalSyncPoints.clear();
-}
-
 int32_t Layer::getZ() const {
     return mDrawingState.z;
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 046482c..1afb917 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -210,6 +210,7 @@
         // The deque of callback handles for this frame. The back of the deque contains the most
         // recent callback handle.
         std::deque<sp<CallbackHandle>> callbackHandles;
+        bool colorSpaceAgnostic;
     };
 
     explicit Layer(const LayerCreationArgs& args);
@@ -297,6 +298,7 @@
     virtual bool setColorTransform(const mat4& matrix);
     virtual mat4 getColorTransform() const;
     virtual bool hasColorTransform() const;
+    virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
 
     // Used only to set BufferStateLayer state
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -315,6 +317,7 @@
         return false;
     };
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
+    virtual bool setColorSpaceAgnostic(const bool agnostic);
 
     ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
 
@@ -450,7 +453,8 @@
     bool getForceClientComposition(const sp<DisplayDevice>& display);
     virtual void setPerFrameData(const sp<const DisplayDevice>& display,
                                  const ui::Transform& transform, const Rect& viewport,
-                                 int32_t supportedPerFrameMetadata) = 0;
+                                 int32_t supportedPerFrameMetadata,
+                                 const ui::Dataspace targetDataspace) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
@@ -750,8 +754,6 @@
     virtual bool applyPendingStates(State* stateToCommit);
     virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
 
-    void clearSyncPoints();
-
     // Returns mCurrentScaling mode (originating from the
     // Client) or mOverrideScalingMode mode (originating from
     // the Surface Controller) if set.
@@ -899,6 +901,8 @@
 
     // Layer bounds in screen space.
     FloatRect mScreenBounds;
+
+    void setZOrderRelativeOf(const wp<Layer>& relativeOf);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index ab1f460..7e2b03d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -76,13 +76,13 @@
     mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
 
     mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
-                                                                  : highFpsLateAppOffsetNs,
+                                                                  : highFpsLateSfOffsetNs,
                                      highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
-                                                                   : highFpsLateSfOffsetNs};
+                                                                   : highFpsLateAppOffsetNs};
     mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
-                                                                      : highFpsLateAppOffsetNs,
+                                                                      : highFpsLateSfOffsetNs,
                                        highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
-                                                                       : highFpsLateSfOffsetNs};
+                                                                       : highFpsLateAppOffsetNs};
     mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
 }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 026f7c7..cbcc031 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -28,7 +28,7 @@
 namespace scheduler {
 
 /**
- * This class is used to encapsulate configuration for refresh rates. It holds infomation
+ * This class is used to encapsulate configuration for refresh rates. It holds information
  * about available refresh rates on the device, and the mapping between the numbers and human
  * readable names.
  */
@@ -40,8 +40,6 @@
     enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
 
     struct RefreshRate {
-        // Type of the refresh rate.
-        RefreshRateType type;
         // This config ID corresponds to the position of the config in the vector that is stored
         // on the device.
         int configId;
@@ -59,13 +57,16 @@
     }
     ~RefreshRateConfigs() = default;
 
-    const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; }
+    const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
+        return mRefreshRates;
+    }
+    const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; }
 
 private:
     void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
         // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
-        mRefreshRates.push_back(
-                RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+        mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
+                              RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
 
         if (configs.size() < 1) {
             ALOGE("Device does not have valid configs. Config size is 0.");
@@ -88,9 +89,10 @@
         nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
-            mRefreshRates.push_back(
-                    RefreshRate{RefreshRateType::DEFAULT, configIdToVsyncPeriod[0].first,
-                                base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+            mRefreshRates.emplace(RefreshRateType::DEFAULT,
+                                  RefreshRate{configIdToVsyncPeriod[0].first,
+                                              base::StringPrintf("%2.ffps", fps),
+                                              static_cast<uint32_t>(fps)});
         }
 
         if (configs.size() < 2) {
@@ -102,13 +104,14 @@
         vsyncPeriod = configIdToVsyncPeriod[1].second;
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
-            mRefreshRates.push_back(
-                    RefreshRate{RefreshRateType::PERFORMANCE, configIdToVsyncPeriod[1].first,
-                                base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+            mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
+                                  RefreshRate{configIdToVsyncPeriod[1].first,
+                                              base::StringPrintf("%2.ffps", fps),
+                                              static_cast<uint32_t>(fps)});
         }
     }
 
-    std::vector<RefreshRate> mRefreshRates;
+    std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index dcb2988..2491081 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,10 +41,9 @@
     static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
 
 public:
-    explicit RefreshRateStats(
-            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
-            const std::shared_ptr<TimeStats>& timeStats)
-          : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+    explicit RefreshRateStats(const std::shared_ptr<RefreshRateConfigs>& refreshRateConfigs,
+                              const std::shared_ptr<TimeStats>& timeStats)
+          : mRefreshRateConfigs(refreshRateConfigs),
             mTimeStats(timeStats),
             mPreviousRecordedTime(systemTime()) {}
     ~RefreshRateStats() = default;
@@ -84,7 +83,7 @@
         flushTime();
 
         std::unordered_map<std::string, int64_t> totalTime;
-        for (auto config : mRefreshRateConfigs->getRefreshRates()) {
+        for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
             int64_t totalTimeForConfig = 0;
             if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
                 totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
@@ -124,7 +123,7 @@
         mPreviousRecordedTime = currentTime;
 
         mConfigModesTotalTime[mode] += timeElapsedMs;
-        for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
+        for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
             if (config.configId == mode) {
                 mTimeStats->recordRefreshRate(config.fps, timeElapsed);
             }
@@ -143,7 +142,7 @@
     }
 
     // Keeps information about refresh rate configs that device has.
-    std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+    std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
 
     // Aggregate refresh rate statistics for telemetry.
     std::shared_ptr<TimeStats> mTimeStats;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e50dd08..b90bd53 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -201,9 +201,6 @@
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sDump("android.permission.DUMP");
 
-constexpr float kDefaultRefreshRate = 60.f;
-constexpr float kPerformanceRefreshRate = 90.f;
-
 // ---------------------------------------------------------------------------
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -712,9 +709,11 @@
             setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
         });
     }
-    mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
-                                                                              *display->getId()),
-                                                                      mTimeStats);
+    mRefreshRateConfigs[*display->getId()] = std::make_shared<scheduler::RefreshRateConfigs>(
+            getHwComposer().getConfigs(*display->getId()));
+    mRefreshRateStats =
+            std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()],
+                                                          mTimeStats);
 
     ALOGV("Done initializing");
 }
@@ -921,14 +920,6 @@
                                             ConfigEvent event) {
     ATRACE_CALL();
 
-    Vector<DisplayInfo> configs;
-    // Lock is acquired by setRefreshRateTo.
-    getDisplayConfigsLocked(displayToken, &configs);
-    if (mode < 0 || mode >= static_cast<int>(configs.size())) {
-        ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
-        return;
-    }
-
     // Lock is acquired by setRefreshRateTo.
     const auto display = getDisplayDeviceLocked(displayToken);
     if (!display) {
@@ -1426,6 +1417,8 @@
 }
 
 void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
+    ATRACE_CALL();
+
     mPhaseOffsets->setRefreshRateType(refreshRate);
 
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
@@ -1435,47 +1428,23 @@
         return;
     }
 
-    // TODO(b/113612090): There should be a message queue flush here. Because this esentially
-    // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
-    // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
-    // refresh cycle.
-
     // Don't do any updating if the current fps is the same as the new one.
-    const nsecs_t currentVsyncPeriod = getVsyncPeriod();
-    if (currentVsyncPeriod == 0) {
-        return;
-    }
-
-    // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
-    // floating numbers.
-    const float currentFps = 1e9 / currentVsyncPeriod;
-    const float newFps = refreshRate == RefreshRateType::PERFORMANCE ? kPerformanceRefreshRate
-                                                                     : kDefaultRefreshRate;
-    if (std::abs(currentFps - newFps) <= 1) {
-        return;
-    }
-
     const auto displayId = getInternalDisplayIdLocked();
     LOG_ALWAYS_FATAL_IF(!displayId);
+    const auto displayToken = getInternalDisplayTokenLocked();
 
-    auto configs = getHwComposer().getConfigs(*displayId);
-    for (int i = 0; i < configs.size(); i++) {
-        if (!isConfigAllowed(*displayId, i)) {
-            ALOGV("Skipping config %d as it is not part of allowed configs", i);
-            continue;
-        }
-
-        const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
-        if (vsyncPeriod == 0) {
-            continue;
-        }
-        const float fps = 1e9 / vsyncPeriod;
-        // TODO(b/113612090): There should be a better way at determining which config
-        // has the right refresh rate.
-        if (std::abs(fps - newFps) <= 1) {
-            setDesiredActiveConfig(getInternalDisplayTokenLocked(), i, event);
-        }
+    auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (desiredConfigId == display->getActiveConfig()) {
+        return;
     }
+
+    if (!isConfigAllowed(*displayId, desiredConfigId)) {
+        ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
+        return;
+    }
+
+    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1789,6 +1758,13 @@
         if (mDrawingState.colorMatrixChanged) {
             display->setColorTransform(mDrawingState.colorMatrix);
         }
+        Dataspace targetDataspace = Dataspace::UNKNOWN;
+        if (useColorManagement) {
+            ColorMode colorMode;
+            RenderIntent renderIntent;
+            pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
+            display->setColorMode(colorMode, targetDataspace, renderIntent);
+        }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
                 layer->forceClientComposition(displayDevice);
@@ -1820,15 +1796,7 @@
 
             const auto& displayState = display->getState();
             layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
-                                   displayDevice->getSupportedPerFrameMetadata());
-        }
-
-        if (useColorManagement) {
-            ColorMode  colorMode;
-            Dataspace dataSpace;
-            RenderIntent renderIntent;
-            pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
-            display->setColorMode(colorMode, dataSpace, renderIntent);
+                                   displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
         }
     }
 
@@ -3364,6 +3332,16 @@
     // Perform some cleanup steps if we used client composition.
     if (hasClientComposition) {
         clientCompositionDisplay.clearRegion = clearRegion;
+
+        // We boost GPU frequency here because there will be color spaces conversion
+        // and it's expensive. We boost the GPU frequency so that GPU composition can
+        // finish in time. We must reset GPU frequency afterwards, because high frequency
+        // consumes extra battery.
+        const bool expensiveRenderingExpected =
+                clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
+        if (expensiveRenderingExpected && displayId) {
+            mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
+        }
         if (!debugRegion.isEmpty()) {
             Region::const_iterator it = debugRegion.begin();
             Region::const_iterator end = debugRegion.end();
@@ -3379,6 +3357,9 @@
         }
         renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
                                 buf->getNativeBuffer(), std::move(fd), readyFence);
+        if (expensiveRenderingExpected && displayId) {
+            mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
+        }
     }
     return true;
 }
@@ -3906,6 +3887,11 @@
     if (what & layer_state_t::eMetadataChanged) {
         if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eColorSpaceAgnosticChanged) {
+        if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     std::vector<sp<CallbackHandle>> callbackHandles;
     if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
         mTransactionCompletedThread.run();
@@ -5664,17 +5650,13 @@
     // make sure that the current config is still allowed
     int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
     if (!isConfigAllowed(*displayId, currentConfigIndex)) {
-        // TODO(b/122906558): stop querying HWC for the available configs and instead use the cached
-        // configs queried on boot
-        auto configs = getHwComposer().getConfigs(*displayId);
-
-        for (int i = 0; i < configs.size(); i++) {
-            if (isConfigAllowed(*displayId, i)) {
+        for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
+            if (isConfigAllowed(*displayId, config.configId)) {
                 // TODO: we switch to the first allowed config. In the future
                 // we may want to enhance this logic to pick a similar config
                 // to the current one
-                ALOGV("Old config is not allowed - switching to config %d", i);
-                setDesiredActiveConfig(displayToken, i, ConfigEvent::Changed);
+                ALOGV("Old config is not allowed - switching to config %d", config.configId);
+                setDesiredActiveConfig(displayToken, config.configId, ConfigEvent::Changed);
                 break;
             }
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3eaaaea..75947ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -53,6 +53,7 @@
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
 #include "Effects/Daltonizer.h"
 #include "FrameTracker.h"
 #include "LayerStats.h"
@@ -1115,6 +1116,9 @@
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
+    std::unordered_map<DisplayId, std::shared_ptr<scheduler::RefreshRateConfigs>>
+            mRefreshRateConfigs;
+
     std::mutex mAllowedConfigsLock;
     std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
             GUARDED_BY(mAllowedConfigsLock);
@@ -1150,11 +1154,11 @@
     InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
     // Should only be accessed by the main thread.
     InputWindowCommands mInputWindowCommands;
-
     ui::DisplayPrimaries mInternalDisplayPrimaries;
 
     sp<SetInputWindowsListener> mSetInputWindowsListener;
     bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
+    Hwc2::impl::PowerAdvisor mPowerAdvisor;
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 3d887ea..4342dc9 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -45,6 +45,7 @@
 
     std::unique_ptr<RefreshRateStats> mRefreshRateStats;
     std::shared_ptr<android::mock::TimeStats> mTimeStats;
+    std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -61,7 +62,8 @@
 
 void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
     mTimeStats = std::make_shared<android::mock::TimeStats>();
-    mRefreshRateStats = std::make_unique<RefreshRateStats>(configs, mTimeStats);
+    mRefreshRateConfigs = std::make_shared<RefreshRateConfigs>(configs);
+    mRefreshRateStats = std::make_unique<RefreshRateStats>(mRefreshRateConfigs, mTimeStats);
 }
 
 namespace {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d61973e..79b5ca0 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -324,6 +324,7 @@
     auto& mutableTexturePool() { return mFlinger->mTexturePool; }
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
+    auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
 
     auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
     auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
@@ -352,18 +353,11 @@
      * Wrapper classes for Read-write access to private data to set up
      * preconditions and assert post-conditions.
      */
-    class FakePowerAdvisor : public Hwc2::PowerAdvisor {
-    public:
-        FakePowerAdvisor() = default;
-        ~FakePowerAdvisor() override = default;
-        void setExpensiveRenderingExpected(hwc2_display_t, bool) override {}
-    };
-
     struct HWC2Display : public HWC2::impl::Display {
-        HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
+        HWC2Display(Hwc2::Composer& composer,
                     const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
                     HWC2::DisplayType type)
-              : HWC2::impl::Display(composer, advisor, capabilities, id, type) {}
+              : HWC2::impl::Display(composer, capabilities, id, type) {}
         ~HWC2Display() {
             // Prevents a call to disable vsyncs.
             mType = HWC2::DisplayType::Invalid;
@@ -427,14 +421,7 @@
             return *this;
         }
 
-        auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
-            mPowerAdvisor = powerAdvisor;
-            return *this;
-        }
-
         void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
-            static FakePowerAdvisor defaultPowerAdvisor;
-            if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor;
             static const std::unordered_set<HWC2::Capability> defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
 
@@ -442,8 +429,8 @@
             // not refer to an instance owned by FakeHwcDisplayInjector. This
             // class has temporary lifetime, while the constructed HWC2::Display
             // is much longer lived.
-            auto display = std::make_unique<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities,
-                                                         mHwcDisplayId, mHwcDisplayType);
+            auto display = std::make_unique<HWC2Display>(*composer, *mCapabilities, mHwcDisplayId,
+                                                         mHwcDisplayType);
 
             auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
             config.setWidth(mWidth);
@@ -478,7 +465,6 @@
         int32_t mDpiY = DEFAULT_DPI;
         int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
         const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
-        Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
     };
 
     class FakeDisplayDeviceInjector {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index dc6d83b..7c65f95 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -29,7 +29,7 @@
     PowerAdvisor();
     ~PowerAdvisor() override;
 
-    MOCK_METHOD2(setExpensiveRenderingExpected, void(hwc2_display_t displayId, bool expected));
+    MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
 };
 
 } // namespace mock