Merge "add the OMX_VIDEO_CodingAV1 in the OMX_VIDEO_CODINGTYPE"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 254e142..c5bfb42 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -154,6 +154,7 @@
 #define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
 #define WLUTIL "/vendor/xbin/wlutil"
 #define WMTRACE_DATA_DIR "/data/misc/wmtrace"
+#define OTA_METADATA_DIR "/metadata/ota"
 
 // TODO(narayan): Since this information has to be kept in sync
 // with tombstoned, we should just put it in a common header.
@@ -253,7 +254,7 @@
         MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
         return 0L;
     }
-    MYLOGD("Module metadata package name: %s", package_name.c_str());
+    MYLOGD("Module metadata package name: %s\n", package_name.c_str());
     int64_t version_code;
     status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
                                                        &version_code);
@@ -300,12 +301,10 @@
  * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
  * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
  * is set, the vector only contains files that were written in the last 30 minutes.
- * If |limit_by_count| is set, the vector only contains the ten latest files.
  */
 static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
                                         const std::string& file_prefix,
-                                        bool limit_by_mtime,
-                                        bool limit_by_count = true) {
+                                        bool limit_by_mtime) {
     const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
 
     std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
@@ -349,15 +348,6 @@
         dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
     }
 
-    // Sort in descending modification time so that we only keep the newest
-    // reports if |limit_by_count| is true.
-    std::sort(dump_data.begin(), dump_data.end(),
-              [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
-
-    if (limit_by_count && dump_data.size() > 10) {
-        dump_data.erase(dump_data.begin() + 10, dump_data.end());
-    }
-
     return dump_data;
 }
 
@@ -887,6 +877,17 @@
         CommandOptions::WithTimeoutInMs(timeout_ms).Build());
 }
 
+static void DoSystemLogcat(time_t since) {
+    char since_str[80];
+    strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
+
+    unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
+    RunCommand("SYSTEM LOG",
+               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
+                since_str},
+               CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+}
+
 static void DoLogcat() {
     unsigned long timeout_ms;
     // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -918,6 +919,31 @@
                                "-v", "uid", "-d", "*:v"});
 }
 
+static void DumpIncidentReport() {
+    if (!ds.IsZipping()) {
+        MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
+        return;
+    }
+    DurationReporter duration_reporter("INCIDENT REPORT");
+    const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
+    auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
+                O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+    if (fd < 0) {
+        MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
+        return;
+    }
+    RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
+    bool empty = 0 == lseek(fd, 0, SEEK_END);
+    if (!empty) {
+        // Use a different name from "incident.proto"
+        // /proto/incident.proto is reserved for incident service dump
+        // i.e. metadata for debugging.
+        ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
+    }
+    unlink(path.c_str());
+}
+
 static void DumpIpTablesAsRoot() {
     RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
     RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
@@ -935,6 +961,7 @@
     }
 
     RunCommand("LPDUMP", {"lpdump", "--all"});
+    RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
 }
 
 static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
@@ -1057,7 +1084,7 @@
         std::string path(title);
         path.append(" - ").append(String8(service).c_str());
         size_t bytes_written = 0;
-        status_t status = dumpsys.startDumpThread(service, args);
+        status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
         if (status == OK) {
             dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
             std::chrono::duration<double> elapsed_seconds;
@@ -1129,7 +1156,7 @@
             path.append("_HIGH");
         }
         path.append(kProtoExt);
-        status_t status = dumpsys.startDumpThread(service, args);
+        status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
         if (status == OK) {
             status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
             bool dumpTerminated = (status == OK);
@@ -1351,8 +1378,6 @@
         ds.TakeScreenshot();
     }
 
-    DoLogcat();
-
     AddAnrTraceFiles();
 
     // NOTE: tombstones are always added as separate entries in the zip archive
@@ -1490,6 +1515,9 @@
     printf("========================================================\n");
     // This differs from the usual dumpsys stats, which is the stats report data.
     RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
+
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
+
     return Dumpstate::RunStatus::OK;
 }
 
@@ -1506,6 +1534,12 @@
     // keep the system stats as close to its initial state as possible.
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
 
+    // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
+    // buffer.
+    DoLogcat();
+    // Capture timestamp after first logcat to use in next logcat
+    time_t logcat_ts = time(nullptr);
+
     /* collect stack traces from Dalvik and native processes (needs root) */
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
 
@@ -1524,6 +1558,7 @@
     add_mountinfo();
     DumpIpTablesAsRoot();
     DumpDynamicPartitionInfo();
+    ds.AddDir(OTA_METADATA_DIR, true);
 
     // Capture any IPSec policies in play. No keys are exposed here.
     RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
@@ -1543,12 +1578,19 @@
         RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
     }
 
+    DumpFile("PSI cpu", "/proc/pressure/cpu");
+    DumpFile("PSI memory", "/proc/pressure/memory");
+    DumpFile("PSI io", "/proc/pressure/io");
+
     if (!DropRootUser()) {
         return Dumpstate::RunStatus::ERROR;
     }
 
     RETURN_IF_USER_DENIED_CONSENT();
-    return dumpstate();
+    Dumpstate::RunStatus status = dumpstate();
+    // Capture logcat since the last time we did it.
+    DoSystemLogcat(logcat_ts);
+    return status;
 }
 
 // This method collects common dumpsys for telephony and wifi
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 181046a..7e6f6f5 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -216,8 +216,8 @@
         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
     }
 
-    static const char* getZipFilePath() {
-        return ds.GetPath(".zip").c_str();
+    static const std::string getZipFilePath() {
+        return ds.GetPath(".zip");
     }
 };
 std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
@@ -226,12 +226,12 @@
 std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
 
 TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
-    EXPECT_EQ(access(getZipFilePath(), F_OK), 0);
+    EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
 }
 
 TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
     struct stat st;
-    EXPECT_EQ(stat(getZipFilePath(), &st), 0);
+    EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
     EXPECT_GE(st.st_size, 3000000 /* 3MB */);
     EXPECT_LE(st.st_size, 30000000 /* 30MB */);
 }
@@ -250,7 +250,7 @@
   public:
     ZipArchiveHandle handle;
     void SetUp() {
-        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0);
+        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath().c_str(), &handle), 0);
     }
     void TearDown() {
         CloseArchive(handle);
@@ -314,7 +314,7 @@
 class BugreportSectionTest : public Test {
   public:
     static void SetUpTestCase() {
-        ParseSections(ZippedBugreportGenerationTest::getZipFilePath(),
+        ParseSections(ZippedBugreportGenerationTest::getZipFilePath().c_str(),
                       ZippedBugreportGenerationTest::sections.get());
     }
 
diff --git a/cmds/dumpsys/TEST_MAPPING b/cmds/dumpsys/TEST_MAPPING
new file mode 100644
index 0000000..dc88ada
--- /dev/null
+++ b/cmds/dumpsys/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "presubmit": [
+    {
+      // small test which assumes the output format of dumpsys, however
+      // there are many other parts of Android that expect the output
+      // to be a specific way (see b/141728094)
+      "name": "timezone_data_e2e_tests"
+    },
+    {
+      "name": "dumpsys_test"
+    }
+  ]
+}
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 9f65425..abdf168 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -59,12 +59,13 @@
             "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
-            "SERVICE [ARGS]]\n"
+            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES "
+            "| SERVICE [ARGS]]\n"
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
             "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
             "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
+            "         --pid: dump PID instead of usual dump\n"
             "         --proto: filter services that support dumping data in proto format. Dumps\n"
             "               will be in proto format.\n"
             "         --priority LEVEL: filter services based on specified priority\n"
@@ -120,9 +121,11 @@
     bool showListOnly = false;
     bool skipServices = false;
     bool asProto = false;
+    Type type = Type::DUMP;
     int timeoutArgMs = 10000;
     int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
-    static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+    static struct option longOptions[] = {{"pid", no_argument, 0, 0},
+                                          {"priority", required_argument, 0, 0},
                                           {"proto", no_argument, 0, 0},
                                           {"skip", no_argument, 0, 0},
                                           {"help", no_argument, 0, 0},
@@ -157,6 +160,8 @@
                     usage();
                     return -1;
                 }
+            } else if (!strcmp(longOptions[optionIndex].name, "pid")) {
+                type = Type::PID;
             }
             break;
 
@@ -246,7 +251,7 @@
         const String16& serviceName = services[i];
         if (IsSkipped(skippedServices, serviceName)) continue;
 
-        if (startDumpThread(serviceName, args) == OK) {
+        if (startDumpThread(type, serviceName, args) == OK) {
             bool addSeparator = (N > 1);
             if (addSeparator) {
                 writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
@@ -313,7 +318,18 @@
     }
 }
 
-status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector<String16>& args) {
+static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) {
+     pid_t pid;
+     status_t status = service->getDebugPid(&pid);
+     if (status != OK) {
+         return status;
+     }
+     WriteStringToFd(std::to_string(pid) + "\n", fd.get());
+     return OK;
+}
+
+status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
+                                  const Vector<String16>& args) {
     sp<IBinder> service = sm_->checkService(serviceName);
     if (service == nullptr) {
         aerr << "Can't find service: " << serviceName << endl;
@@ -333,16 +349,22 @@
 
     // dump blocks until completion, so spawn a thread..
     activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
-        int err = service->dump(remote_end.get(), args);
+        status_t err = 0;
 
-        // It'd be nice to be able to close the remote end of the socketpair before the dump
-        // call returns, to terminate our reads if the other end closes their copy of the
-        // file descriptor, but then hangs for some reason. There doesn't seem to be a good
-        // way to do this, though.
-        remote_end.reset();
+        switch (type) {
+        case Type::DUMP:
+            err = service->dump(remote_end.get(), args);
+            break;
+        case Type::PID:
+            err = dumpPidToFd(service, remote_end);
+            break;
+        default:
+            aerr << "Unknown dump type" << static_cast<int>(type) << endl;
+            return;
+        }
 
-        if (err != 0) {
-            aerr << "Error dumping service info: (" << strerror(err) << ") "
+        if (err != OK) {
+            aerr << "Error dumping service info status_t: (" << err << ") "
                  << serviceName << endl;
         }
     });
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index c48a1e9..929c55c 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -51,6 +51,11 @@
      */
     static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
 
+    enum class Type {
+        DUMP,  // dump using `dump` function
+        PID,   // dump pid of server only
+    };
+
     /**
      * Starts a thread to connect to a service and get its dump output. The thread redirects
      * the output to a pipe. Thread must be stopped by a subsequent callto {@code
@@ -61,7 +66,8 @@
      *         {@code NAME_NOT_FOUND} service could not be found.
      *         {@code != OK} error
      */
-    status_t startDumpThread(const String16& serviceName, const Vector<String16>& args);
+    status_t startDumpThread(Type type, const String16& serviceName,
+                             const Vector<String16>& args);
 
     /**
      * Writes a section header to a file descriptor.
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index cbac839..b9395ba 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -54,6 +54,7 @@
     MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
     MOCK_METHOD1(listServices, Vector<String16>(int));
     MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
+    MOCK_METHOD1(isDeclared, bool(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
@@ -194,7 +195,7 @@
         CaptureStdout();
         CaptureStderr();
         dump_.setServiceArgs(args, supportsProto, priorityFlags);
-        status_t status = dump_.startDumpThread(serviceName, args);
+        status_t status = dump_.startDumpThread(Dumpsys::Type::DUMP, serviceName, args);
         EXPECT_THAT(status, Eq(0));
         status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
                                  elapsedDuration, bytesWritten);
@@ -539,6 +540,27 @@
     AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
 }
 
+// Tests 'dumpsys --pid'
+TEST_F(DumpsysTest, ListAllServicesWithPid) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"--pid"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+    AssertOutputContains(std::to_string(getpid()));
+}
+
+// Tests 'dumpsys --pid service_name'
+TEST_F(DumpsysTest, ListServiceWithPid) {
+    ExpectCheckService("Locksmith");
+
+    CallMain({"--pid", "Locksmith"});
+
+    AssertOutput(std::to_string(getpid()) + "\n");
+}
+
 TEST_F(DumpsysTest, GetBytesWritten) {
     const char* serviceName = "service2";
     const char* dumpContents = "dump1";
@@ -563,4 +585,4 @@
         dump_.writeDump(STDOUT_FILENO, String16("service"), std::chrono::milliseconds(500),
                         /* as_proto = */ false, elapsedDuration, bytesWritten);
     EXPECT_THAT(status, Eq(INVALID_OPERATION));
-}
\ No newline at end of file
+}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 7eee749..838d11d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -303,6 +303,9 @@
 // Location of the apex image.
 static const char* kApexImage = "/system/framework/apex.art";
 
+// Phenotype property name for enabling profiling the boot class path.
+static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
+
 class RunDex2Oat : public ExecVHelper {
   public:
     RunDex2Oat(int zip_fd,
@@ -402,7 +405,15 @@
             server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                                  ENABLE_APEX_IMAGE,
                                                                  /*default_value=*/ "");
-        if (use_apex_image == "true") {
+
+        std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
+        profile_boot_class_path =
+            server_configurable_flags::GetServerConfigurableFlag(
+                RUNTIME_NATIVE_BOOT_NAMESPACE,
+                PROFILE_BOOT_CLASS_PATH,
+                /*default_value=*/ profile_boot_class_path);
+
+        if (use_apex_image == "true" || profile_boot_class_path == "true") {
           boot_image = StringPrintf("-Ximage:%s", kApexImage);
         } else {
           boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
@@ -709,8 +720,7 @@
                   const unique_fd& reference_profile_fd,
                   const std::vector<unique_fd>& apk_fds,
                   const std::vector<std::string>& dex_locations,
-                  bool copy_and_update,
-                  bool store_aggregation_counters) {
+                  bool copy_and_update) {
 
         // 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
@@ -742,10 +752,6 @@
             AddArg("--copy-and-update-profile-key");
         }
 
-        if (store_aggregation_counters) {
-            AddArg("--store-aggregation-counters");
-        }
-
         // Do not add after dex2oat_flags, they should override others for debugging.
         PrepareArgs(profman_bin);
     }
@@ -753,14 +759,12 @@
     void SetupMerge(const std::vector<unique_fd>& profiles_fd,
                     const unique_fd& reference_profile_fd,
                     const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
-                    const std::vector<std::string>& dex_locations = std::vector<std::string>(),
-                    bool store_aggregation_counters = false) {
+                    const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
         SetupArgs(profiles_fd,
                   reference_profile_fd,
                   apk_fds,
                   dex_locations,
-                  /*copy_and_update=*/false,
-                  store_aggregation_counters);
+                  /*copy_and_update=*/false);
     }
 
     void SetupCopyAndUpdate(unique_fd&& profile_fd,
@@ -777,8 +781,7 @@
                   reference_profile_fd_,
                   apk_fds_,
                   dex_locations,
-                  /*copy_and_update=*/true,
-                  /*store_aggregation_counters=*/false);
+                  /*copy_and_update=*/true);
     }
 
     void SetupDump(const std::vector<unique_fd>& profiles_fd,
@@ -792,8 +795,7 @@
                   reference_profile_fd,
                   apk_fds,
                   dex_locations,
-                  /*copy_and_update=*/false,
-                  /*store_aggregation_counters=*/false);
+                  /*copy_and_update=*/false);
     }
 
     void Exec() {
@@ -2828,8 +2830,7 @@
         args.SetupMerge(profiles_fd,
                         snapshot_fd,
                         apk_fds,
-                        dex_locations,
-                        /*store_aggregation_counters=*/true);
+                        dex_locations);
         pid_t pid = fork();
         if (pid == 0) {
             /* child -- drop privileges before continuing */
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index db09070..5a5cb53 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -67,29 +67,29 @@
 }
 
 static void mkdir(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::mkdir(fullPath, 0755);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    ::mkdir(fullPath.c_str(), 0755);
 }
 
 static void touch(const char* path, int len, int time) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    int fd = ::open(fullPath.c_str(), O_RDWR | O_CREAT, 0644);
     ::fallocate(fd, 0, 0, len);
     ::close(fd);
     struct utimbuf times;
     times.actime = times.modtime = std::time(0) + time;
-    ::utime(fullPath, &times);
+    ::utime(fullPath.c_str(), &times);
 }
 
 static int exists(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    return ::access(fullPath, F_OK);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    return ::access(fullPath.c_str(), F_OK);
 }
 
 static int64_t size(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
     struct stat buf;
-    if (!stat(fullPath, &buf)) {
+    if (!stat(fullPath.c_str(), &buf)) {
         return buf.st_size;
     } else {
         return -1;
@@ -107,8 +107,8 @@
 }
 
 static void setxattr(const char* path, const char* key) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::setxattr(fullPath, key, "", 0, 0);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    ::setxattr(fullPath.c_str(), key, "", 0, 0);
 }
 
 class CacheTest : public testing::Test {
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index 606477f..b7e520f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -137,7 +137,7 @@
 
 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
     char *tctx = nullptr;
-    if (selabel_lookup(getSehandle(), &tctx, name.c_str(), 0) != 0) {
+    if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
         LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
         return false;
     }
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 9344368..861401c 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -34,11 +34,7 @@
 namespace android {
 
 #ifndef VENDORSERVICEMANAGER
-static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
-    if (!Stability::requiresVintfDeclaration(binder)) {
-        return true;
-    }
-
+static bool isVintfDeclared(const std::string& name) {
     size_t firstSlash = name.find('/');
     size_t lastDot = name.rfind('.', firstSlash);
     if (firstSlash == std::string::npos || lastDot == std::string::npos) {
@@ -54,7 +50,7 @@
             vintf::VintfObject::GetDeviceHalManifest(),
             vintf::VintfObject::GetFrameworkHalManifest()
         }) {
-        if (manifest->hasAidlInstance(package, iface, instance)) {
+        if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) {
             return true;
         }
     }
@@ -62,6 +58,14 @@
                << " in the VINTF manifest.";
     return false;
 }
+
+static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
+    if (!Stability::requiresVintfDeclaration(binder)) {
+        return true;
+    }
+
+    return isVintfDeclared(name);
+}
 #endif  // !VENDORSERVICEMANAGER
 
 ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
@@ -165,7 +169,7 @@
 #endif  // !VENDORSERVICEMANAGER
 
     // implicitly unlinked when the binder is removed
-    if (OK != binder->linkToDeath(this)) {
+    if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) {
         LOG(ERROR) << "Could not linkToDeath when adding " << name;
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
     }
@@ -270,6 +274,21 @@
     return Status::ok();
 }
 
+Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    if (!mAccess->canFind(ctx, name)) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    *outReturn = false;
+
+#ifndef VENDORSERVICEMANAGER
+    *outReturn = isVintfDeclared(name);
+#endif
+    return Status::ok();
+}
+
 void ServiceManager::removeCallback(const wp<IBinder>& who,
                                     CallbackMap::iterator* it,
                                     bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 006e519..7dcdaa4 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -40,6 +40,7 @@
                                             const sp<IServiceCallback>& callback) override;
     binder::Status unregisterForNotifications(const std::string& name,
                                               const sp<IServiceCallback>& callback) override;
+    binder::Status isDeclared(const std::string& name, bool* outReturn) override;
 
     void binderDied(const wp<IBinder>& who) override;
 
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 11d43a6..4b12fc6 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -23,11 +23,12 @@
 #include "Access.h"
 #include "ServiceManager.h"
 
-using ::android::sp;
-using ::android::ProcessState;
-using ::android::IPCThreadState;
-using ::android::ServiceManager;
 using ::android::Access;
+using ::android::IPCThreadState;
+using ::android::ProcessState;
+using ::android::ServiceManager;
+using ::android::os::IServiceManager;
+using ::android::sp;
 
 int main(int argc, char** argv) {
     if (argc > 2) {
@@ -41,6 +42,10 @@
     ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
 
     sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());
+    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
+        LOG(ERROR) << "Could not self register servicemanager";
+    }
+
     IPCThreadState::self()->setTheContextObject(manager);
     ps->becomeContextManager(nullptr, nullptr);
 
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 44883cc..346861f 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -59,6 +59,8 @@
 /**
  * Get the AChoreographer instance for the current thread. This must be called
  * on an ALooper thread.
+ *
+ * Available since API level 24.
  */
 AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24);
 
@@ -82,6 +84,8 @@
 /**
  * Power a callback to be run on the next frame.  The data pointer provided will
  * be passed to the callback function when it's called.
+ *
+ * Available since API level 29.
  */
 void AChoreographer_postFrameCallback64(AChoreographer* chroreographer,
                 AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
@@ -90,6 +94,8 @@
  * Post a callback to be run on the frame following the specified delay.  The
  * data pointer provided will be passed to the callback function when it's
  * called.
+ *
+ * Available since API level 29.
  */
 void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
                 AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29);
diff --git a/include/android/configuration.h b/include/android/configuration.h
index ef6c5a2..3310722 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -675,50 +675,52 @@
  */
 void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
 
-#if __ANDROID_API__ >= 13
 /**
  * Return the current configuration screen width in dp units, or
  * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
+int32_t AConfiguration_getScreenWidthDp(AConfiguration* config);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
+void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value);
 
 /**
  * Return the current configuration screen height in dp units, or
  * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenHeightDp(AConfiguration* config) __INTRODUCED_IN(13);
+int32_t AConfiguration_getScreenHeightDp(AConfiguration* config);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
+void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value);
 
 /**
  * Return the configuration's smallest screen width in dp units, or
  * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
+int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config);
 
 /**
  * Set the configuration's smallest screen width in dp units.
  */
-void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
-#endif /* __ANDROID_API__ >= 13 */
+void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
 
 #if __ANDROID_API__ >= 17
 /**
  * Return the configuration's layout direction, or
  * ACONFIGURATION_LAYOUTDIR_ANY if not set.
+ *
+ * Available since API level 17.
  */
 int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_IN(17);
 
 /**
  * Set the configuration's layout direction.
+ *
+ * Available since API level 17.
  */
 void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17);
 #endif /* __ANDROID_API__ >= 17 */
diff --git a/include/android/font.h b/include/android/font.h
index 8001ee1..1618096 100644
--- a/include/android/font.h
+++ b/include/android/font.h
@@ -96,6 +96,8 @@
 /**
  * Close an AFont.
  *
+ * Available since API level 29.
+ *
  * \param font a font returned by ASystemFontIterator_next or AFontMatchert_match.
  *        Do nothing if NULL is passed.
  */
@@ -116,6 +118,8 @@
  * The font file returned is guaranteed to be opend with O_RDONLY.
  * Note that the returned pointer is valid until AFont_close() is called for the given font.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a string of the font file path.
  */
@@ -184,6 +188,8 @@
  *
  * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
  */
@@ -192,6 +198,8 @@
 /**
  * Return true if the current font is italic, otherwise returns false.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return true if italic, otherwise false.
  */
@@ -204,6 +212,8 @@
  *
  * Note that the returned pointer is valid until AFont_close() is called.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a IETF BCP47 compliant language tag or nullptr if not available.
  */
@@ -216,6 +226,8 @@
  * returns a non-negative value as an font offset in the collection. This
  * always returns 0 if the target font file is a regular font.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a font collection index.
  */
@@ -247,6 +259,8 @@
  *
  * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a number of font variation settings.
  */
@@ -258,6 +272,8 @@
  *
  * See AFont_getAxisCount for more details.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \param axisIndex an index to the font variation settings. Passing value larger than or
  *        equal to {@link AFont_getAxisCount} is not allowed.
@@ -271,6 +287,8 @@
  *
  * See AFont_getAxisCount for more details.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \param axisIndex an index to the font variation settings. Passing value larger than or
  *         equal to {@link ASYstemFont_getAxisCount} is not allwed.
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
index 0b8f892..d4bd892 100644
--- a/include/android/font_matcher.h
+++ b/include/android/font_matcher.h
@@ -130,13 +130,17 @@
  */
 
 /**
- * Creates a new AFontMatcher object
+ * Creates a new AFontMatcher object.
+ *
+ * Available since API level 29.
  */
 AFontMatcher* _Nonnull AFontMatcher_create() __INTRODUCED_IN(29);
 
 /**
  * Destroy the matcher object.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  */
 void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29);
@@ -147,6 +151,8 @@
  * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL}
  * with non-italic style.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param weight a font weight value. Only from 0 to 1000 value is valid
  * \param italic true if italic, otherwise false.
@@ -161,6 +167,8 @@
  *
  * If this function is not called, the matcher performs with empty locale list.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
  *                     tags.
@@ -174,6 +182,8 @@
  *
  * If this function is not called, the matcher performs with {@link AFAMILY_VARIANT_DEFAULT}.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param familyVariant Must be one of {@link AFAMILY_VARIANT_DEFAULT},
  *                      {@link AFAMILY_VARIANT_COMPACT} or {@link AFAMILY_VARIANT_ELEGANT} is valid.
@@ -190,6 +200,8 @@
  * Even if no font can render the given text, this function will return a non-null result for
  * drawing Tofu character.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param familyName a null character terminated font family name
  * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string.
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
index aedf369..293e5ac 100644
--- a/include/android/hardware_buffer_jni.h
+++ b/include/android/hardware_buffer_jni.h
@@ -42,6 +42,8 @@
  * that is returned. To keep the AHardwareBuffer live after the Java
  * HardwareBuffer object got garbage collected, be sure to use AHardwareBuffer_acquire()
  * to acquire an additional reference.
+ *
+ * Available since API level 26.
  */
 AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
         jobject hardwareBufferObj) __INTRODUCED_IN(26);
@@ -49,6 +51,8 @@
 /**
  * Return a new Java HardwareBuffer object that wraps the passed native
  * AHardwareBuffer object.
+ *
+ * Available since API level 26.
  */
 jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env,
         AHardwareBuffer* hardwareBuffer) __INTRODUCED_IN(26);
diff --git a/include/android/input.h b/include/android/input.h
index cfade6c..ce439c6 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -986,10 +986,8 @@
  */
 int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
 
-#if __ANDROID_API__ >= 14
 /** Get the button state of all buttons that are pressed. */
-int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) __INTRODUCED_IN(14);
-#endif
+int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
 
 /**
  * Get a bitfield indicating which edges, if any, were touched by this motion event.
@@ -1054,14 +1052,12 @@
  */
 int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
 
-#if __ANDROID_API__ >= 14
 /**
  * Get the tool type of a pointer for the given pointer index.
  * The tool type indicates the type of tool used to make contact such as a
  * finger or stylus, if known.
  */
-int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) __INTRODUCED_IN(14);
-#endif
+int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
 
 /**
  * Get the original raw X coordinate of this event.
@@ -1151,11 +1147,9 @@
  */
 float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
 
-#if __ANDROID_API__ >= 13
 /** Get the value of the request axis for the given pointer index. */
 float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index) __INTRODUCED_IN(13);
-#endif
+        int32_t axis, size_t pointer_index);
 
 /**
  * Get the number of historical points in this event.  These are movements that
@@ -1286,14 +1280,12 @@
 float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
-#if __ANDROID_API__ >= 13
 /**
  * Get the historical value of the request axis for the given pointer index
  * that occurred between this event and the previous motion event.
  */
 float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index, size_t history_index) __INTRODUCED_IN(13);
-#endif
+        int32_t axis, size_t pointer_index, size_t history_index);
 
 
 struct AInputQueue;
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index d31d1f1..59b1deb 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -69,6 +69,7 @@
  *
  * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket))
  *
+ * Available since API level 23.
  */
 int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23);
 
@@ -86,6 +87,7 @@
  *
  * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
  *
+ * Available since API level 23.
  */
 int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23);
 
@@ -103,6 +105,7 @@
  *
  * This is the equivalent of: [android.net.Network#getAllByName()](https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String))
  *
+ * Available since API level 23.
  */
 int android_getaddrinfofornetwork(net_handle_t network,
         const char *node, const char *service,
@@ -144,6 +147,8 @@
  *
  * Returns a file descriptor to watch for read events, or a negative
  * POSIX error code (see errno.h) if an immediate error occurs.
+ *
+ * Available since API level 29.
  */
 int android_res_nquery(net_handle_t network,
         const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
@@ -155,6 +160,8 @@
  *
  * Returns a file descriptor to watch for read events, or a negative
  * POSIX error code (see errno.h) if an immediate error occurs.
+ *
+ * Available since API level 29.
  */
 int android_res_nsend(net_handle_t network,
         const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
@@ -163,6 +170,8 @@
  * Read a result for the query associated with the |fd| descriptor.
  * Closes |fd| before returning.
  *
+ * Available since 29.
+ *
  * Returns:
  *     < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
  *     >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain)
@@ -173,6 +182,8 @@
 /**
  * Attempts to cancel the in-progress query associated with the |nsend_fd|
  * descriptor.
+ *
+ * Available since API level 29.
  */
 void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
 
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 0c196b9..3a77ffe 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -51,6 +51,8 @@
  * the ANativeWindow; maintains it through general Java object's life cycle;
  * and will automatically release the reference when the Java object gets garbage
  * collected.
+ *
+ * Available since API level 26.
  */
 jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26);
 #endif
diff --git a/include/android/sensor.h b/include/android/sensor.h
index e9d5c16..3ebe79f 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -564,6 +564,7 @@
  *
  *     ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
  *
+ * Available since API level 26.
  */
 ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
 #endif
@@ -583,6 +584,8 @@
 /**
  * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
  * of this type and wakeUp properties exists.
+ *
+ * Available since API level 21.
  */
 ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21);
 #endif
@@ -609,6 +612,8 @@
  * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} to be used
  * for configuring sensor direct report.
  *
+ * Available since API level 26.
+ *
  * \param manager the {@link ASensorManager} instance obtained from
  *                {@link ASensorManager_getInstanceForPackage}.
  * \param fd      file descriptor representing a shared memory created by
@@ -627,6 +632,8 @@
  * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER} type to be used
  * for configuring sensor direct report.
  *
+ * Available since API level 26.
+ *
  * \param manager the {@link ASensorManager} instance obtained from
  *                {@link ASensorManager_getInstanceForPackage}.
  * \param buffer  {@link AHardwareBuffer} instance created by {@link AHardwareBuffer_allocate}.
@@ -646,6 +653,8 @@
  * The buffer used for creating direct channel does not get destroyed with
  * {@link ASensorManager_destroy} and has to be close or released separately.
  *
+ * Available since API level 26.
+ *
  * \param manager the {@link ASensorManager} instance obtained from
  *                {@link ASensorManager_getInstanceForPackage}.
  * \param channelId channel id (a positive integer) returned from
@@ -678,6 +687,8 @@
  *
  *     ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
  *
+ * Available since API level 26.
+ *
  * \param manager   the {@link ASensorManager} instance obtained from
  *                  {@link ASensorManager_getInstanceForPackage}.
  * \param sensor    a {@link ASensor} to denote which sensor to be operate. It can be NULL if rate
@@ -780,7 +791,7 @@
  */
 ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
 
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 /**
  * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on
  * the given {@link ASensorEventQueue}.
@@ -796,13 +807,15 @@
  * {@link AAdditionalInfoEvent#type}, as new values may be defined in the future
  * and may delivered to the client.
  *
+ * Available since API level 29.
+ *
  * \param queue {@link ASensorEventQueue} to configure
  * \param enable true to request {@link ASENSOR_TYPE_ADDITIONAL_INFO} events,
  *        false to stop receiving events
  * \return 0 on success or a negative error code on failure
  */
-int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable);
-#endif /* __ANDROID_API__ >= __ANDRDOID_API_Q__ */
+int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) __INTRODUCED_IN(29);
+#endif /* __ANDROID_API__ >= 29 */
 
 /*****************************************************************************/
 
@@ -837,26 +850,36 @@
 /**
  * Returns the maximum size of batches for this sensor. Batches will often be
  * smaller, as the hardware fifo might be used for other sensors.
+ *
+ * Available since API level 21.
  */
 int ASensor_getFifoMaxEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the hardware batch fifo size reserved to this sensor.
+ *
+ * Available since API level 21.
  */
 int ASensor_getFifoReservedEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns this sensor's string type.
+ *
+ * Available since API level 21.
  */
 const char* ASensor_getStringType(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants.
+ *
+ * Available since API level 21.
  */
 int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns true if this is a wake up sensor, false otherwise.
+ *
+ * Available since API level 21.
  */
 bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21);
 #endif /* __ANDROID_API__ >= 21 */
@@ -865,6 +888,8 @@
 /**
  * Test if sensor supports a certain type of direct channel.
  *
+ * Available since API level 26.
+ *
  * \param sensor  a {@link ASensor} to denote the sensor to be checked.
  * \param channelType  Channel type constant, either
  *                     {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY}
@@ -874,7 +899,9 @@
 bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType) __INTRODUCED_IN(26);
 
 /**
- * Get the highest direct rate level that a sensor support.
+ * Get the highest direct rate level that a sensor supports.
+ *
+ * Available since API level 26.
  *
  * \param sensor  a {@link ASensor} to denote the sensor to be checked.
  *
@@ -885,7 +912,7 @@
 int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
 #endif /* __ANDROID_API__ >= 26 */
 
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 /**
  * Returns the sensor's handle.
  *
@@ -899,9 +926,11 @@
  * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
  * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
  * between the values.
+ *
+ * Available since API level 29.
  */
-int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__);
-#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */
+int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(29);
+#endif /* __ANDROID_API__ >= 29 */
 
 #ifdef __cplusplus
 };
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index ef2ad99..90e5653 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -46,7 +46,7 @@
  */
 typedef struct ASurfaceControl ASurfaceControl;
 
-/*
+/**
  * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent.
  * |debug_name| is a debug name associated with this surface. It can be used to
  * identify this surface in the SurfaceFlinger's layer tree. It must not be
@@ -54,10 +54,17 @@
  *
  * The caller takes ownership of the ASurfaceControl returned and must release it
  * using ASurfaceControl_release below.
+ *
+ * Available since API level 29.
  */
 ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
                                                   __INTRODUCED_IN(29);
 
+/**
+ * See ASurfaceControl_createFromWindow.
+ *
+ * Available since API level 29.
+ */
 ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
                                         __INTRODUCED_IN(29);
 
@@ -65,6 +72,8 @@
  * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer
  * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
  * as their parent remains on display.
+ *
+ * Available since API level 29.
  */
 void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
 
@@ -79,11 +88,15 @@
 /**
  * The caller takes ownership of the transaction and must release it using
  * ASurfaceControl_delete below.
+ *
+ * Available since API level 29.
  */
 ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
 
 /**
  * Destroys the |transaction| object.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
 
@@ -93,6 +106,8 @@
  * Note that the transaction is guaranteed to be applied atomically. The
  * transactions which are applied on the same thread are also guaranteed to be
  * applied in order.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
 
@@ -116,6 +131,8 @@
  *
  * THREADING
  * The transaction completed callback can be invoked on any thread.
+ *
+ * Available since API level 29.
  */
 typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
                                                __INTRODUCED_IN(29);
@@ -123,6 +140,8 @@
 /**
  * Returns the timestamp of when the frame was latched by the framework. Once a frame is
  * latched by the framework, it is presented at the following hardware vsync.
+ *
+ * Available since API level 29.
  */
 int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats)
                                               __INTRODUCED_IN(29);
@@ -131,6 +150,8 @@
  * Returns a sync fence that signals when the transaction has been presented.
  * The recipient of the callback takes ownership of the fence and is responsible for closing
  * it.
+ *
+ * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
                                                __INTRODUCED_IN(29);
@@ -141,6 +162,8 @@
  * When the client is done using the array, it must release it by calling
  * ASurfaceTransactionStats_releaseASurfaceControls.
  *
+ * Available since API level 29.
+ *
  * |outASurfaceControlsSize| returns the size of the ASurfaceControls array.
  */
 void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats,
@@ -150,6 +173,8 @@
 /**
  * Releases the array of ASurfaceControls that were returned by
  * ASurfaceTransactionStats_getASurfaceControls.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls)
                                                       __INTRODUCED_IN(29);
@@ -158,6 +183,8 @@
  * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered
  * acquired when its acquire_fence_fd has signaled. A buffer cannot be latched or presented until
  * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1.
+ *
+ * Available since API level 29.
  */
 int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats,
                                                 ASurfaceControl* surface_control)
@@ -180,6 +207,8 @@
  *
  * The client must ensure that all pending refs on a buffer are released before attempting to reuse
  * this buffer, otherwise synchronization errors may occur.
+ *
+ * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
                                                 ASurfaceTransactionStats* surface_transaction_stats,
@@ -190,6 +219,8 @@
  * Sets the callback that will be invoked when the updates from this transaction
  * are presented. For details on the callback semantics and data, see the
  * comments on the ASurfaceTransaction_OnComplete declaration above.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
                                        ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
@@ -199,6 +230,8 @@
  * Any children of the* reparented |surface_control| will remain children of the |surface_control|.
  *
  * The |new_parent| can be null. Surface controls with a null parent do not appear on the display.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction,
                                   ASurfaceControl* surface_control, ASurfaceControl* new_parent)
@@ -213,6 +246,8 @@
  * Updates the visibility of |surface_control|. If show is set to
  * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will
  * be hidden.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
                                        ASurfaceControl* surface_control, int8_t visibility)
@@ -224,6 +259,8 @@
  * the same z order is undefined.
  *
  * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
                                    ASurfaceControl* surface_control, int32_t z_order)
@@ -236,6 +273,8 @@
  *
  * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible
  * for closing it.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
                                    ASurfaceControl* surface_control, AHardwareBuffer* buffer,
@@ -246,6 +285,8 @@
  * ASurfaceControl visible in transparent regions of the surface.  Colors |r|, |g|,
  * and |b| must be within the range that is valid for |dataspace|.  |dataspace| and |alpha|
  * will be the dataspace and alpha set for the background color layer.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction,
                                   ASurfaceControl* surface_control, float r, float g, float b,
@@ -264,6 +305,8 @@
  * |transform| the transform applied after the source rect is applied to the buffer. This parameter
  * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
  * enum.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
                                      ASurfaceControl* surface_control, const ARect& source,
@@ -281,6 +324,8 @@
  * Updates whether the content for the buffer associated with this surface is
  * completely opaque. If true, every pixel of content inside the buffer must be
  * opaque or visual errors can occur.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
                                                ASurfaceControl* surface_control,
@@ -290,6 +335,8 @@
 /**
  * Updates the region for the content on this surface updated in this
  * transaction. If unspecified, the complete surface is assumed to be damaged.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
                                          ASurfaceControl* surface_control, const ARect rects[],
@@ -304,6 +351,8 @@
  *
  * If an earlier transaction has a desired present time of x, and a later transaction has a desired
  * present time that is before x, the later transaction will not preempt the earlier transaction.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction,
                                                int64_t desiredPresentTime) __INTRODUCED_IN(29);
@@ -312,6 +361,8 @@
  * Sets the alpha for the buffer. It uses a premultiplied blending.
  *
  * The |alpha| must be between 0.0 and 1.0.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction,
                                         ASurfaceControl* surface_control, float alpha)
@@ -321,6 +372,8 @@
  * Sets the data space of the surface_control's buffers.
  *
  * If no data space is set, the surface control defaults to ADATASPACE_SRGB.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction,
                                             ASurfaceControl* surface_control, ADataSpace data_space)
@@ -331,6 +384,8 @@
  *
  * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering
  * the surface's buffer.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction,
                                                   ASurfaceControl* surface_control,
@@ -342,6 +397,8 @@
  *
  * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering
  * the surface's buffer.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction,
                                                  ASurfaceControl* surface_control,
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index 540d23a..dde7eaa 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -65,6 +65,9 @@
  * Release the reference to the native ASurfaceTexture acquired with
  * ASurfaceTexture_fromSurfaceTexture().
  * Failing to do so will result in leaked memory and graphic resources.
+ *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
 void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28);
@@ -73,6 +76,8 @@
  * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
  * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture);
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed
  * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
@@ -90,6 +95,8 @@
  * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
  * context at a time.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \param texName The name of the OpenGL ES texture that will be created.  This texture name
  * must be unusued in the OpenGL ES context that is current on the calling thread.
@@ -108,6 +115,8 @@
  * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
  * context at a time.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
@@ -118,6 +127,8 @@
  * called while the OpenGL ES context that owns the texture is current on the calling thread.
  * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
@@ -135,6 +146,8 @@
  * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via
  * the glLoadMatrixf or glUniformMatrix4fv functions.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \param mtx the array into which the 4x4 matrix will be stored.  The array must have exactly
  *     16 elements.
@@ -156,6 +169,8 @@
  * For EGL/Vulkan producers, this timestamp is the desired present time set with the
  * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
 int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28);
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
index b0e1edd..2266d54 100644
--- a/include/android/surface_texture_jni.h
+++ b/include/android/surface_texture_jni.h
@@ -32,6 +32,8 @@
 
 __BEGIN_DECLS
 
+#if __ANDROID_API__ >= 28
+
 /**
  * Get a reference to the native ASurfaceTexture from the corresponding java object.
  *
@@ -40,13 +42,17 @@
  * properly once the Java object gets finalized.
  * However, this will not result in program termination.
  *
+ * Available since API level 28.
+ *
  * \param env JNI environment
  * \param surfacetexture Instance of Java SurfaceTexture object
  * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture.
  *         The returned reference MUST BE released when it's no longer needed using
  *         ASurfaceTexture_release().
  */
-ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) __INTRODUCED_IN(28);
+
+#endif
 
 __END_DECLS
 
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index f0485a1..6fd7d2c 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -102,6 +102,8 @@
  *
  * Use ASystemFont_close() to close the iterator.
  *
+ * Available since API level 29.
+ *
  * \return a pointer for a newly allocated iterator, nullptr on failure.
  */
 ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29);
@@ -109,6 +111,8 @@
 /**
  * Close an opened system font iterator, freeing any related resources.
  *
+ * Available since API level 29.
+ *
  * \param iterator a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
  */
 void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
@@ -116,6 +120,8 @@
 /**
  * Move to the next system font.
  *
+ * Available since API level 29.
+ *
  * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
  * \return a font. If no more font is available, returns nullptr. You need to release the returned
  *         font by ASystemFont_close when it is no longer needed.
diff --git a/include/android/trace.h b/include/android/trace.h
index bb7ff28..d59690a 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -74,7 +74,7 @@
 
 #endif /* __ANDROID_API__ >= 23 */
 
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 /**
  * Writes a trace message to indicate that a given section of code has
@@ -83,6 +83,8 @@
  * asynchronous events do not need to be nested. The name and cookie used to
  * begin an event must be used to end it.
  *
+ * Available since API level 29.
+ *
  * \param sectionName The method name to appear in the trace.
  * \param cookie Unique identifier for distinguishing simultaneous events
  */
@@ -93,6 +95,8 @@
  * Must be called exactly once for each call to {@link ATrace_beginAsyncSection}
  * using the same name and cookie.
  *
+ * Available since API level 29.
+ *
  * \param methodName The method name to appear in the trace.
  * \param cookie Unique identifier for distinguishing simultaneous events
  */
@@ -101,6 +105,8 @@
 /**
  * Writes trace message to indicate the value of a given counter.
  *
+ * Available since API level 29.
+ *
  * \param counterName The counter name to appear in the trace.
  * \param counterValue The counter value.
  */
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index 2d6292c..09a5f39 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -52,10 +52,6 @@
         "libutils",
     ],
 
-    required: [
-        "libandroid_runtime",
-    ],
-
     export_include_dirs: [
         "include",
     ],
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 296e3f6..7ee4882 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,7 +71,13 @@
     // libbinder does not offer a stable wire protocol.
     // if a second copy of it is installed, then it may break after security
     // or dessert updates. Instead, apex users should use libbinder_ndk.
-    no_apex: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.vndk.current",
+        // TODO(b/139016109) remove these three
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 
     srcs: [
         "Binder.cpp",
@@ -159,3 +165,16 @@
     ],
     path: "aidl",
 }
+
+aidl_interface {
+    name: "libbinder_aidl_test_stub",
+    local_include_dir: "aidl",
+    srcs: [":libbinder_aidl"],
+    visibility: [":__subpackages__"],
+    vendor_available: true,
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 50c7053..238c9dc 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -214,16 +214,21 @@
 {
     // Once a binder has died, it will never come back to life.
     if (mAlive) {
+        bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
+        // don't send userspace flags to the kernel
+        flags = flags & ~FLAG_PRIVATE_VENDOR;
+
         // user transactions require a given stability level
         if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
             using android::internal::Stability;
 
             auto stability = Stability::get(this);
+            auto required = privateVendor ? Stability::VENDOR : Stability::kLocalStability;
 
-            if (CC_UNLIKELY(!Stability::check(stability, Stability::kLocalStability))) {
+            if (CC_UNLIKELY(!Stability::check(stability, required))) {
                 ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
                     Stability::stabilityString(stability).c_str(),
-                    Stability::stabilityString(Stability::kLocalStability).c_str());
+                    Stability::stabilityString(required).c_str());
                 return BAD_TYPE;
             }
         }
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 094f89f..222b32c 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -149,6 +149,10 @@
     return static_cast<char*>(base) + offset;
 }
 
+void* IMemory::unsecurePointer() const {
+    return pointer();
+}
+
 void* IMemory::pointer() const {
     ssize_t offset;
     sp<IMemoryHeap> heap = getMemory(&offset);
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ee637e2..4f47db1 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -43,6 +43,48 @@
 using AidlServiceManager = android::os::IServiceManager;
 using android::binder::Status;
 
+// libbinder's IServiceManager.h can't rely on the values generated by AIDL
+// because many places use its headers via include_dirs (meaning, without
+// declaring the dependency in the build system). So, for now, we can just check
+// the values here.
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_CRITICAL == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_HIGH == IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_NORMAL == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_DEFAULT == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_ALL == IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+static_assert(AidlServiceManager::DUMP_FLAG_PROTO == IServiceManager::DUMP_FLAG_PROTO);
+
+const String16& IServiceManager::getInterfaceDescriptor() const {
+    return AidlServiceManager::descriptor;
+}
+IServiceManager::IServiceManager() {}
+IServiceManager::~IServiceManager() {}
+
+// From the old libbinder IServiceManager interface to IServiceManager.
+class ServiceManagerShim : public IServiceManager
+{
+public:
+    explicit ServiceManagerShim (const sp<AidlServiceManager>& impl);
+
+    sp<IBinder> getService(const String16& name) const override;
+    sp<IBinder> checkService(const String16& name) const override;
+    status_t addService(const String16& name, const sp<IBinder>& service,
+                        bool allowIsolated, int dumpsysPriority) override;
+    Vector<String16> listServices(int dumpsysPriority) override;
+    sp<IBinder> waitForService(const String16& name16) override;
+    bool isDeclared(const String16& name) override;
+
+    // for legacy ABI
+    const String16& getInterfaceDescriptor() const override {
+        return mTheRealServiceManager->getInterfaceDescriptor();
+    }
+    IBinder* onAsBinder() override {
+        return IInterface::asBinder(mTheRealServiceManager).get();
+    }
+private:
+    sp<AidlServiceManager> mTheRealServiceManager;
+};
+
 sp<IServiceManager> defaultServiceManager()
 {
     static Mutex gDefaultServiceManagerLock;
@@ -53,8 +95,9 @@
     {
         AutoMutex _l(gDefaultServiceManagerLock);
         while (gDefaultServiceManager == nullptr) {
-            gDefaultServiceManager = interface_cast<IServiceManager>(
-                ProcessState::self()->getContextObject(nullptr));
+            gDefaultServiceManager = new ServiceManagerShim(
+                interface_cast<AidlServiceManager>(
+                    ProcessState::self()->getContextObject(nullptr)));
             if (gDefaultServiceManager == nullptr)
                 sleep(1);
         }
@@ -147,142 +190,144 @@
 
 // ----------------------------------------------------------------------
 
-class BpServiceManager : public BpInterface<IServiceManager>
-{
-public:
-    explicit BpServiceManager(const sp<IBinder>& impl)
-        : BpInterface<IServiceManager>(impl),
-          mTheRealServiceManager(interface_cast<AidlServiceManager>(impl))
-    {
-    }
+ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
+ : mTheRealServiceManager(impl)
+{}
 
-    sp<IBinder> getService(const String16& name) const override
-    {
-        static bool gSystemBootCompleted = false;
+sp<IBinder> ServiceManagerShim::getService(const String16& name) const
+{
+    static bool gSystemBootCompleted = false;
+
+    sp<IBinder> svc = checkService(name);
+    if (svc != nullptr) return svc;
+
+    const bool isVendorService =
+        strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+    const long timeout = uptimeMillis() + 5000;
+    // Vendor code can't access system properties
+    if (!gSystemBootCompleted && !isVendorService) {
+#ifdef __ANDROID__
+        char bootCompleted[PROPERTY_VALUE_MAX];
+        property_get("sys.boot_completed", bootCompleted, "0");
+        gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
+#else
+        gSystemBootCompleted = true;
+#endif
+    }
+    // retry interval in millisecond; note that vendor services stay at 100ms
+    const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+    int n = 0;
+    while (uptimeMillis() < timeout) {
+        n++;
+        ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+            ProcessState::self()->getDriverName().c_str());
+        usleep(1000*sleepTime);
 
         sp<IBinder> svc = checkService(name);
         if (svc != nullptr) return svc;
+    }
+    ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+    return nullptr;
+}
 
-        const bool isVendorService =
-            strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
-        const long timeout = uptimeMillis() + 5000;
-        // Vendor code can't access system properties
-        if (!gSystemBootCompleted && !isVendorService) {
-#ifdef __ANDROID__
-            char bootCompleted[PROPERTY_VALUE_MAX];
-            property_get("sys.boot_completed", bootCompleted, "0");
-            gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
-#else
-            gSystemBootCompleted = true;
-#endif
+sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
+{
+    sp<IBinder> ret;
+    if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
+        return nullptr;
+    }
+    return ret;
+}
+
+status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
+                                        bool allowIsolated, int dumpsysPriority)
+{
+    Status status = mTheRealServiceManager->addService(
+        String8(name).c_str(), service, allowIsolated, dumpsysPriority);
+    return status.exceptionCode();
+}
+
+Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
+{
+    std::vector<std::string> ret;
+    if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
+        return {};
+    }
+
+    Vector<String16> res;
+    res.setCapacity(ret.size());
+    for (const std::string& name : ret) {
+        res.push(String16(name.c_str()));
+    }
+    return res;
+}
+
+sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
+{
+    class Waiter : public android::os::BnServiceCallback {
+        Status onRegistration(const std::string& /*name*/,
+                              const sp<IBinder>& binder) override {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mBinder = binder;
+            lock.unlock();
+            mCv.notify_one();
+            return Status::ok();
         }
-        // retry interval in millisecond; note that vendor services stay at 100ms
-        const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+    public:
+        sp<IBinder> mBinder;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+    };
 
-        int n = 0;
-        while (uptimeMillis() < timeout) {
-            n++;
-            ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
-                ProcessState::self()->getDriverName().c_str());
-            usleep(1000*sleepTime);
+    const std::string name = String8(name16).c_str();
 
-            sp<IBinder> svc = checkService(name);
-            if (svc != nullptr) return svc;
-        }
-        ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+    sp<IBinder> out;
+    if (!mTheRealServiceManager->getService(name, &out).isOk()) {
+        return nullptr;
+    }
+    if(out != nullptr) return out;
+
+    sp<Waiter> waiter = new Waiter;
+    if (!mTheRealServiceManager->registerForNotifications(
+            name, waiter).isOk()) {
         return nullptr;
     }
 
-    sp<IBinder> checkService(const String16& name) const override {
-        sp<IBinder> ret;
-        if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
-            return nullptr;
-        }
-        return ret;
-    }
-
-    status_t addService(const String16& name, const sp<IBinder>& service,
-                        bool allowIsolated, int dumpsysPriority) override {
-        Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority);
-        return status.exceptionCode();
-    }
-
-    virtual Vector<String16> listServices(int dumpsysPriority) {
-        std::vector<std::string> ret;
-        if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
-            return {};
+    while(true) {
+        {
+            std::unique_lock<std::mutex> lock(waiter->mMutex);
+            using std::literals::chrono_literals::operator""s;
+            waiter->mCv.wait_for(lock, 1s, [&] {
+                return waiter->mBinder != nullptr;
+            });
+            if (waiter->mBinder != nullptr) return waiter->mBinder;
         }
 
-        Vector<String16> res;
-        res.setCapacity(ret.size());
-        for (const std::string& name : ret) {
-            res.push(String16(name.c_str()));
-        }
-        return res;
-    }
-
-    sp<IBinder> waitForService(const String16& name16) override {
-        class Waiter : public android::os::BnServiceCallback {
-            Status onRegistration(const std::string& /*name*/,
-                                  const sp<IBinder>& binder) override {
-                std::unique_lock<std::mutex> lock(mMutex);
-                mBinder = binder;
-                lock.unlock();
-                mCv.notify_one();
-                return Status::ok();
-            }
-        public:
-            sp<IBinder> mBinder;
-            std::mutex mMutex;
-            std::condition_variable mCv;
-        };
-
-        const std::string name = String8(name16).c_str();
-
-        sp<IBinder> out;
+        // Handle race condition for lazy services. Here is what can happen:
+        // - the service dies (not processed by init yet).
+        // - sm processes death notification.
+        // - sm gets getService and calls init to start service.
+        // - init gets the start signal, but the service already appears
+        //   started, so it does nothing.
+        // - init gets death signal, but doesn't know it needs to restart
+        //   the service
+        // - we need to request service again to get it to start
         if (!mTheRealServiceManager->getService(name, &out).isOk()) {
             return nullptr;
         }
         if(out != nullptr) return out;
 
-        sp<Waiter> waiter = new Waiter;
-        if (!mTheRealServiceManager->registerForNotifications(
-                name, waiter).isOk()) {
-            return nullptr;
-        }
-
-        while(true) {
-            {
-                std::unique_lock<std::mutex> lock(waiter->mMutex);
-                using std::literals::chrono_literals::operator""s;
-                waiter->mCv.wait_for(lock, 1s, [&] {
-                    return waiter->mBinder != nullptr;
-                });
-                if (waiter->mBinder != nullptr) return waiter->mBinder;
-            }
-
-            // Handle race condition for lazy services. Here is what can happen:
-            // - the service dies (not processed by init yet).
-            // - sm processes death notification.
-            // - sm gets getService and calls init to start service.
-            // - init gets the start signal, but the service already appears
-            //   started, so it does nothing.
-            // - init gets death signal, but doesn't know it needs to restart
-            //   the service
-            // - we need to request service again to get it to start
-            if (!mTheRealServiceManager->getService(name, &out).isOk()) {
-                return nullptr;
-            }
-            if(out != nullptr) return out;
-
-            ALOGW("Waited one second for %s", name.c_str());
-        }
+        ALOGW("Waited one second for %s", name.c_str());
     }
+}
 
-private:
-    sp<AidlServiceManager> mTheRealServiceManager;
-};
-
-IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+bool ServiceManagerShim::isDeclared(const String16& name) {
+    bool declared;
+    if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) {
+        return false;
+    }
+    return declared;
+}
 
 } // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 93e6c5f..9be06cd 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -50,10 +50,6 @@
 #include <private/binder/binder_module.h>
 #include "Static.h"
 
-#ifndef INT32_MAX
-#define INT32_MAX ((int32_t)(2147483647))
-#endif
-
 #define LOG_REFS(...)
 //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #define LOG_ALLOC(...)
@@ -509,7 +505,7 @@
     }
 }
 
-#ifdef __ANDROID_VNDK__
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
 constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
 #else
 constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
@@ -750,61 +746,37 @@
   return writeUtf8AsUtf16(*str);
 }
 
-namespace {
-
-template<typename T>
-status_t writeByteVectorInternal(Parcel* parcel, const std::vector<T>& val)
-{
-    status_t status;
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        status = BAD_VALUE;
-        return status;
+status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) {
+    if (size > std::numeric_limits<int32_t>::max()) {
+        return BAD_VALUE;
     }
 
-    status = parcel->writeInt32(val.size());
+    status_t status = writeInt32(size);
     if (status != OK) {
         return status;
     }
 
-    void* data = parcel->writeInplace(val.size());
-    if (!data) {
-        status = BAD_VALUE;
-        return status;
-    }
-
-    memcpy(data, val.data(), val.size());
-    return status;
+    return write(data, size);
 }
 
-template<typename T>
-status_t writeByteVectorInternalPtr(Parcel* parcel,
-                                    const std::unique_ptr<std::vector<T>>& val)
-{
-    if (!val) {
-        return parcel->writeInt32(-1);
-    }
-
-    return writeByteVectorInternal(parcel, *val);
-}
-
-}  // namespace
-
 status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
-    return writeByteVectorInternal(this, val);
+    return writeByteVectorInternal(val.data(), val.size());
 }
 
 status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
 {
-    return writeByteVectorInternalPtr(this, val);
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(val->data(), val->size());
 }
 
 status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) {
-    return writeByteVectorInternal(this, val);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
 }
 
 status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
 {
-    return writeByteVectorInternalPtr(this, val);
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
 }
 
 status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
@@ -1477,81 +1449,38 @@
     return err;
 }
 
-namespace {
-
-template<typename T>
-status_t readByteVectorInternal(const Parcel* parcel,
-                                std::vector<T>* val) {
-    val->clear();
-
-    int32_t size;
-    status_t status = parcel->readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        status = UNEXPECTED_NULL;
-        return status;
-    }
-    if (size_t(size) > parcel->dataAvail()) {
-        status = BAD_VALUE;
-        return status;
-    }
-
-    T* data = const_cast<T*>(reinterpret_cast<const T*>(parcel->readInplace(size)));
-    if (!data) {
-        status = BAD_VALUE;
-        return status;
-    }
-    val->reserve(size);
-    val->insert(val->end(), data, data + size);
-
-    return status;
-}
-
-template<typename T>
-status_t readByteVectorInternalPtr(
-        const Parcel* parcel,
-        std::unique_ptr<std::vector<T>>* val) {
-    const int32_t start = parcel->dataPosition();
-    int32_t size;
-    status_t status = parcel->readInt32(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    parcel->setDataPosition(start);
-    val->reset(new (std::nothrow) std::vector<T>());
-
-    status = readByteVectorInternal(parcel, val->get());
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-}  // namespace
-
 status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
-    return readByteVectorInternal(this, val);
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    return readByteVectorInternal(val, size);
 }
 
 status_t Parcel::readByteVector(std::vector<uint8_t>* val) const {
-    return readByteVectorInternal(this, val);
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    return readByteVectorInternal(val, size);
 }
 
 status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
-    return readByteVectorInternalPtr(this, val);
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    if (val->get() == nullptr) {
+        // reserveOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null byte vector.
+        return OK;
+    }
+    return readByteVectorInternal(val->get(), size);
 }
 
 status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
-    return readByteVectorInternalPtr(this, val);
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    if (val->get() == nullptr) {
+        // reserveOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null byte vector.
+        return OK;
+    }
+    return readByteVectorInternal(val->get(), size);
 }
 
 status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 0336d3e..ea61dc5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -188,6 +188,30 @@
     return count;
 }
 
+// Queries the driver for the current strong reference count of the node
+// that the handle points to. Can only be used by the servicemanager.
+//
+// Returns -1 in case of failure, otherwise the strong reference count.
+ssize_t ProcessState::getStrongRefCountForNodeByHandle(int32_t handle) {
+    binder_node_info_for_ref info;
+    memset(&info, 0, sizeof(binder_node_info_for_ref));
+
+    info.handle = handle;
+
+    status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
+
+    if (result != OK) {
+        static bool logged = false;
+        if (!logged) {
+          ALOGW("Kernel does not support BINDER_GET_NODE_INFO_FOR_REF.");
+          logged = true;
+        }
+        return -1;
+    }
+
+    return info.strong_count;
+}
+
 void ProcessState::setCallRestriction(CallRestriction restriction) {
     LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull() != nullptr,
         "Call restrictions must be set before the threadpool is started.");
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 136bdb0..b3afd81 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -4,6 +4,9 @@
       "name": "binderSafeInterfaceTest"
     },
     {
+      "name": "binderVendorDoubleLoadTest"
+    },
+    {
       "name": "binderDriverInterfaceTest"
     },
     {
@@ -14,6 +17,9 @@
     },
     {
       "name": "binderStabilityTest"
+    },
+    {
+      "name": "CtsNdkBinderTestCases"
     }
   ]
 }
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 60c2cce..8c7ebba 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -31,22 +31,22 @@
      * Must update values in IServiceManager.h
      */
     /* Allows services to dump sections according to priorities. */
-    const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0
-    const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1
-    const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2
+    const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+    const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+    const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
     /**
      * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
      * same priority as NORMAL priority but the services are not called with dump priority
      * arguments.
      */
-    const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3
+    const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
 
     const int DUMP_FLAG_PRIORITY_ALL = 15;
              // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
              // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
 
     /* Allows services to dump sections in protobuf format. */
-    const int DUMP_FLAG_PROTO = 16; // 1 << 4
+    const int DUMP_FLAG_PROTO = 1 << 4;
 
     /**
      * Retrieve an existing service called @a name from the
@@ -89,4 +89,11 @@
      * Unregisters all requests for notifications for a specific callback.
      */
     void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
+
+    /**
+     * Returns whether a given interface is declared on the device, even if it
+     * is not started yet. For instance, this could be a service declared in the VINTF
+     * manifest.
+     */
+    boolean isDeclared(@utf8InCpp String name);
 }
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 64f3052..64604b7 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -62,7 +62,11 @@
         DEBUG_PID_TRANSACTION   = B_PACK_CHARS('_', 'P', 'I', 'D'),
 
         // Corresponds to TF_ONE_WAY -- an asynchronous call.
-        FLAG_ONEWAY             = 0x00000001
+        FLAG_ONEWAY             = 0x00000001,
+
+        // Private userspace flag for transaction which is being requested from
+        // a vendor context.
+        FLAG_PRIVATE_VENDOR     = 0x10000000,
     };
 
                           IBinder();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 5793a1c..28ffa48 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -88,8 +88,12 @@
 public:                                                                 \
 
 
+#define __IINTF_CONCAT(x, y) (x ## y)
 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
-    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
+    const ::android::StaticString16                                     \
+        I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
+    const ::android::String16 I##INTERFACE::descriptor(                 \
+        I##INTERFACE##_descriptor_static_str16);                        \
     const ::android::String16&                                          \
             I##INTERFACE::getInterfaceDescriptor() const {              \
         return I##INTERFACE::descriptor;                                \
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 3728029..98e92c4 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -76,6 +76,8 @@
     // NOLINTNEXTLINE(google-default-arguments)
     virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0;
 
+    void* unsecurePointer() const;
+
     // helpers
     void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
     void* pointer() const;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index def1bea..bd77567 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -26,12 +26,22 @@
 
 // ----------------------------------------------------------------------
 
+/**
+ * Service manager for C++ services.
+ *
+ * IInterface is only for legacy ABI compatibility
+ */
 class IServiceManager : public IInterface
 {
 public:
-    DECLARE_META_INTERFACE(ServiceManager)
+    // for ABI compatibility
+    virtual const String16& getInterfaceDescriptor() const;
+
+    IServiceManager();
+    virtual ~IServiceManager();
+
     /**
-     * Must match values in IServiceManager.java
+     * Must match values in IServiceManager.aidl
      */
     /* Allows services to dump sections according to priorities. */
     static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
@@ -78,6 +88,14 @@
      * Returns nullptr only for permission problem or fatal error.
      */
     virtual sp<IBinder> waitForService(const String16& name) = 0;
+
+    /**
+     * Check if a service is declared (e.g. VINTF manifest).
+     *
+     * If this returns true, waitForService should always be able to return the
+     * service.
+     */
+    virtual bool isDeclared(const String16& name) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
@@ -89,6 +107,20 @@
 }
 
 template<typename INTERFACE>
+sp<INTERFACE> waitForDeclaredService(const String16& name) {
+    const sp<IServiceManager> sm = defaultServiceManager();
+    if (!sm->isDeclared(name)) return nullptr;
+    return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
+sp<INTERFACE> waitForVintfService(
+        const String16& instance = String16("default")) {
+    return waitForDeclaredService<INTERFACE>(
+        INTERFACE::descriptor + String16("/") + instance);
+}
+
+template<typename INTERFACE>
 status_t getService(const String16& name, sp<INTERFACE>* outService)
 {
     const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 8726681..d4bb85b 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -19,6 +19,7 @@
 
 #include <map> // for legacy reasons
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include <android-base/unique_fd.h>
@@ -157,6 +158,18 @@
     status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val);
     status_t            writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
 
+    // Write an Enum vector with underlying type int8_t.
+    // Does not use padding; each byte is contiguous.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::vector<T>& val);
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+    // Write an Enum vector with underlying type != int8_t.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::vector<T>& val);
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+
     template<typename T>
     status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val);
     template<typename T>
@@ -275,6 +288,19 @@
     status_t            readStrongBinder(sp<IBinder>* val) const;
     status_t            readNullableStrongBinder(sp<IBinder>* val) const;
 
+
+    // Read an Enum vector with underlying type int8_t.
+    // Does not use padding; each byte is contiguous.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::vector<T>* val) const;
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+    // Read an Enum vector with underlying type != int8_t.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::vector<T>* val) const;
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+
     template<typename T>
     status_t            readParcelableVector(
                             std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const;
@@ -330,6 +356,11 @@
     status_t            resizeOutVector(std::vector<T>* val) const;
     template<typename T>
     status_t            resizeOutVector(std::unique_ptr<std::vector<T>>* val) const;
+    template<typename T>
+    status_t            reserveOutVector(std::vector<T>* val, size_t* size) const;
+    template<typename T>
+    status_t            reserveOutVector(std::unique_ptr<std::vector<T>>* val,
+                                         size_t* size) const;
 
     // Like Parcel.java's readExceptionCode().  Reads the first int32
     // off of a Parcel's header, returning 0 or the negative error
@@ -438,6 +469,20 @@
     status_t            writeRawNullableParcelable(const Parcelable*
                                                    parcelable);
 
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
+    status_t            writeEnum(const T& val);
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
+    status_t            writeEnum(const T& val);
+
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
+    status_t            readEnum(T* pArg) const;
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
+    status_t            readEnum(T* pArg) const;
+
+    status_t writeByteVectorInternal(const int8_t* data, size_t size);
+    template<typename T>
+    status_t readByteVectorInternal(std::vector<T>* val, size_t size) const;
+
     template<typename T, typename U>
     status_t            unsafeReadTypedVector(std::vector<T>* val,
                                               status_t(Parcel::*read_func)(U*) const) const;
@@ -681,6 +726,42 @@
 }
 
 template<typename T>
+status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const {
+    int32_t read_size;
+    status_t err = readInt32(&read_size);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (read_size < 0) {
+        return UNEXPECTED_NULL;
+    }
+    *size = static_cast<size_t>(read_size);
+    val->reserve(*size);
+    return OK;
+}
+
+template<typename T>
+status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val,
+                                  size_t* size) const {
+    int32_t read_size;
+    status_t err = readInt32(&read_size);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (read_size >= 0) {
+        *size = static_cast<size_t>(read_size);
+        val->reset(new std::vector<T>());
+        (*val)->reserve(*size);
+    } else {
+        val->reset();
+    }
+
+    return OK;
+}
+
+template<typename T>
 status_t Parcel::readStrongBinder(sp<T>* val) const {
     sp<IBinder> tmp;
     status_t ret = readStrongBinder(&tmp);
@@ -913,6 +994,79 @@
     return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
 }
 
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
+status_t Parcel::writeEnum(const T& val) {
+    return writeInt32(static_cast<int32_t>(val));
+}
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
+status_t Parcel::writeEnum(const T& val) {
+    return writeInt64(static_cast<int64_t>(val));
+}
+
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::vector<T>& val) {
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::vector<T>& val) {
+    return writeTypedVector(val, &Parcel::writeEnum);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
+    return writeNullableTypedVector(val, &Parcel::writeEnum);
+}
+
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
+status_t Parcel::readEnum(T* pArg) const {
+    return readInt32(reinterpret_cast<int32_t *>(pArg));
+}
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
+status_t Parcel::readEnum(T* pArg) const {
+    return readInt64(reinterpret_cast<int64_t *>(pArg));
+}
+
+template<typename T>
+inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const {
+  // readByteVectorInternal expects a vector that has been reserved (but not
+  // resized) to have the provided size.
+  const T* data = reinterpret_cast<const T*>(readInplace(size));
+  if (!data) return BAD_VALUE;
+  val->clear();
+  val->insert(val->begin(), data, data+size);
+  return NO_ERROR;
+}
+
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::vector<T>* val) const {
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    return readByteVectorInternal(val, size);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    if (val->get() == nullptr) {
+        // reserveOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null Enum vector.
+        return OK;
+    }
+    return readByteVectorInternal(val->get(), size);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::vector<T>* val) const {
+    return readTypedVector(val, &Parcel::readEnum);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readEnum);
+}
+
 // ---------------------------------------------------------------------------
 
 inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index f7c38f4..e57ff1c 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -69,6 +69,14 @@
 
             ssize_t             getKernelReferences(size_t count, uintptr_t* buf);
 
+                                // Only usable by the context manager.
+                                // This refcount includes:
+                                // 1. Strong references to the node by this and other processes
+                                // 2. Temporary strong references held by the kernel during a
+                                //    transaction on the node.
+                                // It does NOT include local strong references to the node
+            ssize_t             getStrongRefCountForNodeByHandle(int32_t handle);
+
             enum class CallRestriction {
                 // all calls okay
                 NONE,
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index b84657a..b2f51d3 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
         VINTF = 0b111111,
     };
 
-#ifdef __ANDROID_VNDK__
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
     static constexpr Level kLocalStability = Level::VENDOR;
 #else
     static constexpr Level kLocalStability = Level::SYSTEM;
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 62a0f9f..c0ea6d7 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -22,6 +22,8 @@
             cflags: [
                 "-D__INTRODUCED_IN(n)=",
                 "-D__assert(a,b,c)=",
+                // We want all the APIs to be available on the host.
+                "-D__ANDROID_API__=10000",
             ],
         },
     },
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index b06ca86..e752c45 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -17,6 +17,7 @@
 #include <android/binder_ibinder.h>
 #include "ibinder_internal.h"
 
+#include <android/binder_stability.h>
 #include <android/binder_status.h>
 #include "parcel_internal.h"
 #include "status_internal.h"
@@ -542,7 +543,8 @@
         return STATUS_UNKNOWN_TRANSACTION;
     }
 
-    if ((flags & ~FLAG_ONEWAY) != 0) {
+    constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY;
+    if ((flags & ~kAllFlags) != 0) {
         LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags;
         return STATUS_BAD_VALUE;
     }
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index c6868b0..8f37c5e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -21,7 +21,7 @@
 
 /**
  * @file binder_auto_utils.h
- * @brief These objects provide a more C++-like thin interface to the .
+ * @brief These objects provide a more C++-like thin interface to the binder.
  */
 
 #pragma once
@@ -201,12 +201,49 @@
     /**
      * See AStatus_isOk.
      */
-    bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+    bool isOk() const { return get() != nullptr && AStatus_isOk(get()); }
 
     /**
-     * Convenience method for okay status.
+     * See AStatus_getExceptionCode
+     */
+    binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); }
+
+    /**
+     * See AStatus_getServiceSpecificError
+     */
+    int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); }
+
+    /**
+     * See AStatus_getStatus
+     */
+    binder_status_t getStatus() const { return AStatus_getStatus(get()); }
+
+    /**
+     * See AStatus_getMessage
+     */
+    const char* getMessage() const { return AStatus_getMessage(get()); }
+
+    /**
+     * Convenience methods for creating scoped statuses.
      */
     static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
+    static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
+        return ScopedAStatus(AStatus_fromExceptionCode(exception));
+    }
+    static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
+                                                      const char* message) {
+        return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message));
+    }
+    static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
+        return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific));
+    }
+    static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
+                                                             const char* message) {
+        return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message));
+    }
+    static ScopedAStatus fromStatus(binder_status_t status) {
+        return ScopedAStatus(AStatus_fromStatus(status));
+    }
 };
 
 /**
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 160739b..4d5c044 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -34,7 +34,7 @@
 #include <android/binder_status.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 // Also see TF_* in kernel's binder.h
 typedef uint32_t binder_flags_t;
@@ -165,6 +165,8 @@
  *
  * None of these parameters can be null.
  *
+ * Available since API level 29.
+ *
  * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
  * sanity checks on transactions.
  * \param onCreate see AIBinder_Class_onCreate.
@@ -199,6 +201,8 @@
  * If this isn't set, nothing will be dumped when dump is called (for instance with
  * android.os.Binder#dump). Must be called before any instance of the class is created.
  *
+ * Available since API level 29.
+ *
  * \param dump function to call when an instance of this binder class is being dumped.
  */
 void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
@@ -220,6 +224,8 @@
  * these two objects are actually equal using the AIBinder pointer alone (which they should be able
  * to do). Also see the suggested memory ownership model suggested above.
  *
+ * Available since API level 29.
+ *
  * \param clazz the type of the object to be created.
  * \param args the args to pass to AIBinder_onCreate for that class.
  *
@@ -231,6 +237,8 @@
 /**
  * If this is hosted in a process other than the current one.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder being queried.
  *
  * \return true if the AIBinder represents an object in another process.
@@ -244,6 +252,8 @@
  * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
  * based on the results of bookkeeping or other transactions made internally.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder being queried.
  *
  * \return true if the binder is alive.
@@ -255,6 +265,8 @@
  * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
  * sanity check.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder being queried.
  *
  * \return STATUS_OK if the ping succeeds.
@@ -264,7 +276,9 @@
 /**
  * Built-in transaction for all binder objects. This dumps information about a given binder.
  *
- * See also AIBinder_Class_setOnDump, AIBinder_onDump
+ * See also AIBinder_Class_setOnDump, AIBinder_onDump.
+ *
+ * Available since API level 29.
  *
  * \param binder the binder to dump information about
  * \param fd where information should be dumped to
@@ -287,6 +301,8 @@
  *
  * If binder is local, this will return STATUS_INVALID_OPERATION.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object you want to receive death notifications from.
  * \param recipient the callback that will receive notifications when/if the binder dies.
  * \param cookie the value that will be passed to the death recipient on death.
@@ -306,6 +322,8 @@
  * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
  * automatically unlinked.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to remove a previously linked death recipient from.
  * \param recipient the callback to remove.
  * \param cookie the cookie used to link to death.
@@ -322,9 +340,11 @@
  * This can be used with higher-level system services to determine the caller's identity and check
  * permissions.
  *
+ * Available since API level 29.
+ *
  * \return calling uid or the current process's UID if this thread isn't processing a transaction.
  */
-uid_t AIBinder_getCallingUid();
+uid_t AIBinder_getCallingUid() __INTRODUCED_IN(29);
 
 /**
  * This returns the calling PID assuming that this thread is called from a thread that is processing
@@ -335,14 +355,18 @@
  * calling process dies and is replaced with another process with elevated permissions and the same
  * PID.
  *
+ * Available since API level 29.
+ *
  * \return calling pid or the current process's PID if this thread isn't processing a transaction.
  * If the transaction being processed is a oneway transaction, then this method will return 0.
  */
-pid_t AIBinder_getCallingPid();
+pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29);
 
 /**
  * This can only be called if a strong reference to this object already exists in process.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to add a refcount to.
  */
 void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
@@ -350,6 +374,8 @@
 /**
  * This will delete the object and call onDestroy once the refcount reaches zero.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to remove a refcount from.
  */
 void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
@@ -357,6 +383,8 @@
 /**
  * For debugging only!
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to retrieve the refcount of.
  *
  * \return the number of strong-refs on this binder in this process. If binder is null, this will be
@@ -373,6 +401,8 @@
  * This returns true if the class association succeeds. If it fails, no change is made to the
  * binder object.
  *
+ * Available since API level 29.
+ *
  * \param binder the object to attach the class to.
  * \param clazz the clazz to attach to binder.
  *
@@ -383,6 +413,8 @@
 /**
  * Returns the class that this binder was constructed with or associated with.
  *
+ * Available since API level 29.
+ *
  * \param binder the object that is being queried.
  *
  * \return the class that this binder is associated with. If this binder wasn't created with
@@ -394,6 +426,8 @@
  * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
  * null), this also returns null. For a remote binder, this will always return null.
  *
+ * Available since API level 29.
+ *
  * \param binder the object that is being queried.
  *
  * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
@@ -422,6 +456,8 @@
  * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
  * deleted with AParcel_delete.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to start a transaction on.
  * \param in out parameter for input data to the transaction.
  *
@@ -442,6 +478,8 @@
  * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
  * and must be released with AParcel_delete when finished reading.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to transact on.
  * \param code the implementation-specific code representing which transaction should be taken.
  * \param in the implementation-specific input data to this transaction.
@@ -459,6 +497,8 @@
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
  *
+ * Available since API level 29.
+ *
  * \param binder object to create a weak pointer to.
  *
  * \return object representing a weak pointer to binder (or null if binder is null).
@@ -469,6 +509,8 @@
 /**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
  *
+ * Available since API level 29.
+ *
  * \param weakBinder object created with AIBinder_Weak_new.
  */
 void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
@@ -477,6 +519,8 @@
  * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
  * null.
  *
+ * Available since API level 29.
+ *
  * \param weakBinder weak pointer to attempt retrieving the original object from.
  *
  * \return an AIBinder object with one refcount given to the caller or null.
@@ -487,6 +531,8 @@
 /**
  * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
  *
+ * Available since API level 29.
+ *
  * \param cookie the cookie passed to AIBinder_linkToDeath.
  */
 typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
@@ -494,6 +540,8 @@
 /**
  * Creates a new binder death recipient. This can be attached to multiple different binder objects.
  *
+ * Available since API level 29.
+ *
  * \param onBinderDied the callback to call when this death recipient is invoked.
  *
  * \return the newly constructed object (or null if onBinderDied is null).
@@ -505,19 +553,23 @@
  * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
  * calling this as these will all be automatically unlinked.
  *
+ * Available since API level 29.
+ *
  * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
  */
 void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 
-#if __ANDROID_API__ >= __ANDROID_API_R__
+#if __ANDROID_API__ >= 30
 
 /**
  * Gets the extension registered with AIBinder_setExtension.
  *
  * See AIBinder_setExtension.
  *
+ * Available since API level 30.
+ *
  * \param binder the object to get the extension of.
  * \param outExt the returned extension object. Will be null if there is no extension set or
  * non-null with one strong ref count.
@@ -570,6 +622,8 @@
  *         // if bar is null, then there is no extension or a different
  *         // type of extension
  *
+ * Available since API level 30.
+ *
  * \param binder the object to get the extension on. Must be local.
  * \param ext the extension to set (binder will hold a strong reference to this)
  *
@@ -578,7 +632,7 @@
  */
 binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODUCED_IN(30);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_R__
+#endif  //__ANDROID_API__ >= 30
 
 __END_DECLS
 
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 124f36c..be3029c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -31,7 +31,7 @@
 #include <jni.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 /**
  * Converts an android.os.IBinder object into an AIBinder* object.
@@ -40,6 +40,8 @@
  * AIBinder object, the original object is returned. The returned object has one refcount
  * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
  *
+ * Available since API level 29.
+ *
  * \param env Java environment.
  * \param binder android.os.IBinder java object.
  *
@@ -55,6 +57,8 @@
  * If either env or the binder is null, null is returned. If this binder object was originally an
  * IBinder object, the original java object will be returned.
  *
+ * Available since API level 29.
+ *
  * \param env Java environment.
  * \param binder the object to convert.
  *
@@ -63,7 +67,7 @@
 __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
         __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 8c41707..86b75b8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -35,7 +35,7 @@
 typedef struct AIBinder AIBinder;
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 /**
  * This object represents a package of data that can be sent between processes. When transacting, an
@@ -49,6 +49,8 @@
 /**
  * Cleans up a parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
  * transaction is being aborted.
  */
@@ -57,6 +59,8 @@
 /**
  * Sets the position within the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel The parcel of which to set the position.
  * \param position Position of the parcel to set. This must be a value returned by
  * AParcel_getDataPosition. Positions are constant for a given parcel between processes.
@@ -69,6 +73,8 @@
 /**
  * Gets the current position within the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel The parcel of which to get the position.
  *
  * \return The size of the parcel. This will always be greater than 0. The values returned by this
@@ -389,6 +395,8 @@
  * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
  * refcounts of ownership of the binder from the client.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param binder the value to write to the parcel.
  *
@@ -400,6 +408,8 @@
  * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership
  * is passed to the caller of this function.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param binder the out parameter for what is read from the parcel. This may be null.
  *
@@ -414,12 +424,14 @@
  *
  * This corresponds to the SDK's android.os.ParcelFileDescriptor.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor).
  *
  * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) __INTRODUCED_IN(29);
 
 /**
  * Reads an int from the next location in a non-null parcel.
@@ -428,13 +440,16 @@
  *
  * This corresponds to the SDK's android.os.ParcelFileDescriptor.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param fd the out parameter for what is read from the parcel (or -1 to represent a null
  * ParcelFileDescriptor)
  *
  * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd)
+        __INTRODUCED_IN(29);
 
 /**
  * Writes an AStatus object to the next location in a non-null parcel.
@@ -445,6 +460,8 @@
  * this happens or if writing the status object itself fails, the return value from this function
  * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param status the value to write to the parcel.
  *
@@ -457,6 +474,8 @@
  * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
  * of this function.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param status the out parameter for what is read from the parcel.
  *
@@ -470,6 +489,8 @@
  *
  * If length is -1, and string is nullptr, this will write a 'null' string to the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param string the null-terminated string to write to the parcel, at least of size 'length'.
  * \param length the length of the string to be written.
@@ -487,6 +508,8 @@
  * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator
  * will be called with length -1.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param stringData some external representation of a string.
  * \param allocator allocator that will be called once the size of the string is known.
@@ -504,6 +527,8 @@
  * returned from this function will be used to fill out the data from the parcel. If length is -1,
  * this will write a 'null' string array to the binder buffer.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData some external representation of an array.
  * \param length the length of the array to be written.
@@ -526,6 +551,8 @@
  * the contents of the string that is read. If the string array being read is 'null', this will
  * instead just pass -1 to AParcel_stringArrayAllocator.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called with arrayData once the size of the output
@@ -543,6 +570,8 @@
 /**
  * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -562,6 +591,8 @@
  * length is greater than zero, elementReader will be called for every index to read the
  * corresponding parcelable.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -578,6 +609,8 @@
 /**
  * Writes int32_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -588,6 +621,8 @@
 /**
  * Writes uint32_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -598,6 +633,8 @@
 /**
  * Writes int64_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -608,6 +645,8 @@
 /**
  * Writes uint64_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -618,6 +657,8 @@
 /**
  * Writes float value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -628,6 +669,8 @@
 /**
  * Writes double value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -638,6 +681,8 @@
 /**
  * Writes bool value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -648,6 +693,8 @@
 /**
  * Writes char16_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -658,6 +705,8 @@
 /**
  * Writes int8_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -668,6 +717,8 @@
 /**
  * Reads into int32_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -678,6 +729,8 @@
 /**
  * Reads into uint32_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -688,6 +741,8 @@
 /**
  * Reads into int64_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -698,6 +753,8 @@
 /**
  * Reads into uint64_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -708,6 +765,8 @@
 /**
  * Reads into float value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -718,6 +777,8 @@
 /**
  * Reads into double value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -728,6 +789,8 @@
 /**
  * Reads into bool value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -738,6 +801,8 @@
 /**
  * Reads into char16_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -748,6 +813,8 @@
 /**
  * Reads into int8_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -758,6 +825,8 @@
 /**
  * Writes an array of int32_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -770,6 +839,8 @@
 /**
  * Writes an array of uint32_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -782,6 +853,8 @@
 /**
  * Writes an array of int64_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -794,6 +867,8 @@
 /**
  * Writes an array of uint64_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -806,6 +881,8 @@
 /**
  * Writes an array of float to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -818,6 +895,8 @@
 /**
  * Writes an array of double to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -833,6 +912,8 @@
  * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
  * values to write to the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData some external representation of an array.
  * \param length the length of arrayData (or -1 if this represents a null array).
@@ -846,6 +927,8 @@
 /**
  * Writes an array of char16_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -858,6 +941,8 @@
 /**
  * Writes an array of int8_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -874,6 +959,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -890,6 +977,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -906,6 +995,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -922,6 +1013,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -938,6 +1031,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -954,6 +1049,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -969,6 +1066,8 @@
  * First, allocator will be called with the length of the array. Then, for every i in [0, length),
  * setter(arrayData, i, x) will be called where x is the value at the associated index.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -988,6 +1087,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -1004,6 +1105,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -1015,7 +1118,7 @@
 
 // @END-PRIMITIVE-READ-WRITE
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 2671b9b..78d70f8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -30,7 +30,7 @@
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 enum {
     STATUS_OK = 0,
@@ -105,6 +105,8 @@
 /**
  * New status which is considered a success.
  *
+ * Available since API level 29.
+ *
  * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
@@ -112,6 +114,8 @@
 /**
  * New status with exception code.
  *
+ * Available since API level 29.
+ *
  * \param exception the code that this status should represent. If this is EX_NONE, then this
  * constructs an non-error status object.
  *
@@ -123,6 +127,8 @@
 /**
  * New status with exception code and message.
  *
+ * Available since API level 29.
+ *
  * \param exception the code that this status should represent. If this is EX_NONE, then this
  * constructs an non-error status object.
  * \param message the error message to associate with this status object.
@@ -137,6 +143,8 @@
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
  *
+ * Available since API level 29.
+ *
  * \param serviceSpecific an implementation defined error code.
  *
  * \return a newly constructed status object that the caller owns.
@@ -149,6 +157,8 @@
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
  *
+ * Available since API level 29.
+ *
  * \param serviceSpecific an implementation defined error code.
  * \param message the error message to associate with this status object.
  *
@@ -162,6 +172,8 @@
  * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
  * an AStatus instance.
  *
+ * Available since API level 29.
+ *
  * \param a low-level error to associate with this status object.
  *
  * \return a newly constructed status object that the caller owns.
@@ -173,6 +185,8 @@
  * Whether this object represents a successful transaction. If this function returns true, then
  * AStatus_getExceptionCode will return EX_NONE.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return whether the status represents a successful transaction. For more details, see below.
@@ -182,6 +196,8 @@
 /**
  * The exception that this status object represents.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the exception code that this object represents.
@@ -194,6 +210,8 @@
  * 0, the status object may still represent a different exception or status. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
@@ -206,6 +224,8 @@
  * object may represent a different exception or a service specific error. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
@@ -218,6 +238,8 @@
  *
  * The returned string has the lifetime of the status object passed into this function.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the message associated with this error.
@@ -227,11 +249,13 @@
 /**
  * Deletes memory associated with the status instance.
  *
+ * Available since API level 29.
+ *
  * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
  */
 void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index e6aeb04..2a4ded8 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -20,7 +20,22 @@
 
 __BEGIN_DECLS
 
-#ifdef __ANDROID_VNDK__
+/**
+ * Private addition to binder_flag_t.
+ */
+enum {
+    /**
+     * Indicates that this transaction is coupled w/ vendor.img
+     */
+    FLAG_PRIVATE_VENDOR = 0x10000000,
+};
+
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \
+        (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+
+enum {
+    FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
+};
 
 /**
  * This interface has the stability of the vendor image.
@@ -31,7 +46,12 @@
     AIBinder_markVendorStability(binder);
 }
 
-#else  // ndef defined __ANDROID_VNDK__
+#else  // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
+       // !defined(__ANDROID_APEX__))
+
+enum {
+    FLAG_PRIVATE_LOCAL = 0,
+};
 
 /**
  * This interface has the stability of the system image.
@@ -42,7 +62,8 @@
     AIBinder_markSystemStability(binder);
 }
 
-#endif  // ifdef __ANDROID_VNDK__
+#endif  // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
+        // !defined(__ANDROID_APEX__))
 
 /**
  * This interface has system<->vendor stability
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index ae2276e..f18e118 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -50,7 +50,7 @@
     if (length < -1) return STATUS_BAD_VALUE;
 
     if (!isNullArray && length < 0) {
-        LOG(ERROR) << __func__ << ": null array must be used with length == -1.";
+        LOG(ERROR) << __func__ << ": non-null array but length is " << length;
         return STATUS_BAD_VALUE;
     }
     if (isNullArray && length > 0) {
diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh
deleted file mode 100755
index 698d291..0000000
--- a/libs/binder/ndk/scripts/format.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (C) 2018 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.
-
-set -e
-
-echo "Formatting code"
-
-bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp")
-clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\))
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index bb1fe2f..ebd08b2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -67,3 +67,32 @@
     srcs: ["main_server.cpp"],
     gtest: false,
 }
+
+cc_test {
+    name: "binderVendorDoubleLoadTest",
+    vendor: true,
+    srcs: [
+        "binderVendorDoubleLoadTest.cpp",
+    ],
+    static_libs: [
+        "IBinderVendorDoubleLoadTest-cpp",
+        "IBinderVendorDoubleLoadTest-ndk_platform",
+        "libbinder_aidl_test_stub-ndk_platform",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libbinder_ndk",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+}
+
+aidl_interface {
+    name: "IBinderVendorDoubleLoadTest",
+    // TODO(b/119771576): only vendor is needed
+    vendor_available: true,
+    srcs: [
+        "IBinderVendorDoubleLoadTest.aidl",
+    ],
+}
diff --git a/libs/binder/ndk/test/AndroidTest.xml b/libs/binder/ndk/test/AndroidTest.xml
new file mode 100644
index 0000000..89646f7
--- /dev/null
+++ b/libs/binder/ndk/test/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Runs binderVendorDoubleLoadTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="binderVendorDoubleLoadTest->/data/nativetest/vendor/binderVendorDoubleLoadTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/nativetest/vendor" />
+        <option name="module-name" value="binderVendorDoubleLoadTest" />
+    </test>
+</configuration>
+
diff --git a/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
new file mode 100644
index 0000000..3a5bd9c
--- /dev/null
+++ b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+interface IBinderVendorDoubleLoadTest {
+    @utf8InCpp String RepeatString(@utf8InCpp String toRepeat);
+}
diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
new file mode 100644
index 0000000..d3ccdc2
--- /dev/null
+++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 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 <BnBinderVendorDoubleLoadTest.h>
+#include <aidl/BnBinderVendorDoubleLoadTest.h>
+#include <aidl/android/os/IServiceManager.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Stability.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+using namespace android;
+using ::android::base::EndsWith;
+using ::android::base::GetProperty;
+using ::android::base::Split;
+using ::android::binder::Status;
+using ::android::internal::Stability;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::ndk::SpAIBinder;
+
+static const std::string kLocalNdkServerName = "NdkServer-local-IBinderVendorDoubleLoadTest";
+static const std::string kRemoteNdkServerName = "NdkServer-remote-IBinderVendorDoubleLoadTest";
+
+class NdkServer : public aidl::BnBinderVendorDoubleLoadTest {
+    ScopedAStatus RepeatString(const std::string& in, std::string* out) override {
+        *out = in;
+        return ScopedAStatus::ok();
+    }
+};
+class CppServer : public BnBinderVendorDoubleLoadTest {
+    Status RepeatString(const std::string& in, std::string* out) override {
+        *out = in;
+        return Status::ok();
+    }
+};
+
+TEST(DoubleBinder, VendorCppCantCallIntoSystem) {
+    Vector<String16> services = defaultServiceManager()->listServices();
+    EXPECT_TRUE(services.empty());
+}
+
+TEST(DoubleBinder, VendorCppCantRegisterService) {
+    sp<CppServer> cppServer = new CppServer;
+    status_t status = defaultServiceManager()->addService(String16("anything"), cppServer);
+    EXPECT_EQ(EX_TRANSACTION_FAILED, status);
+}
+
+TEST(DoubleBinder, CppVendorCantManuallyMarkVintfStability) {
+    // this test also implies that stability logic is turned on in vendor
+    ASSERT_DEATH(
+            {
+                sp<IBinder> binder = new CppServer();
+                Stability::markVintf(binder.get());
+            },
+            "Should only mark known object.");
+}
+
+TEST(DoubleBinder, NdkVendorCantManuallyMarkVintfStability) {
+    // this test also implies that stability logic is turned on in vendor
+    ASSERT_DEATH(
+            {
+                std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+                AIBinder_markVintfStability(ndkServer->asBinder().get());
+            },
+            "Should only mark known object.");
+}
+
+TEST(DoubleBinder, CallIntoNdk) {
+    for (const std::string& serviceName : {kLocalNdkServerName, kRemoteNdkServerName}) {
+        SpAIBinder binder = SpAIBinder(AServiceManager_checkService(serviceName.c_str()));
+        ASSERT_NE(nullptr, binder.get()) << serviceName;
+        EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())) << serviceName;
+
+        std::shared_ptr<aidl::IBinderVendorDoubleLoadTest> server =
+                aidl::IBinderVendorDoubleLoadTest::fromBinder(binder);
+
+        ASSERT_NE(nullptr, server.get()) << serviceName;
+
+        EXPECT_EQ(STATUS_OK, AIBinder_ping(server->asBinder().get()));
+
+        std::string outString;
+        ScopedAStatus status = server->RepeatString("foo", &outString);
+        EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get())) << serviceName;
+        EXPECT_EQ("foo", outString) << serviceName;
+    }
+}
+
+TEST(DoubleBinder, CallIntoSystemStabilityNdk) {
+    // picking an arbitrary system service
+    SpAIBinder binder = SpAIBinder(AServiceManager_checkService("manager"));
+    ASSERT_NE(nullptr, binder.get());
+
+    // can make stable transaction to system server
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+
+    using aidl::android::os::IServiceManager;
+    std::shared_ptr<IServiceManager> manager = IServiceManager::fromBinder(binder);
+    ASSERT_NE(nullptr, manager.get());
+
+    std::vector<std::string> services;
+    ASSERT_EQ(
+            STATUS_BAD_TYPE,
+            manager->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &services).getStatus());
+}
+
+void initDrivers() {
+    // Explicitly instantiated with the same driver that system would use.
+    // __ANDROID_VNDK__ right now uses /dev/vndbinder by default.
+    ProcessState::initWithDriver("/dev/binder");
+    ProcessState::self()->startThreadPool();
+    ABinderProcess_startThreadPool();
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        // child process
+
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+        initDrivers();
+
+        // REMOTE SERVERS
+        std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+        CHECK(STATUS_OK == AServiceManager_addService(ndkServer->asBinder().get(),
+                                                      kRemoteNdkServerName.c_str()));
+
+        // OR sleep forever or whatever, it doesn't matter
+        IPCThreadState::self()->joinThreadPool(true);
+        exit(1);  // should not reach
+    }
+
+    sleep(1);
+
+    initDrivers();
+
+    // LOCAL SERVERS
+    std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+    AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str());
+
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
deleted file mode 100755
index 1eba892..0000000
--- a/libs/binder/ndk/update.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (C) 2018 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.
-
-
-set -ex
-
-# This script makes sure that the source code is in sync with the various scripts
-./scripts/gen_parcel_helper.py
-./scripts/format.sh
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 0bee56c..1f2779a 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -134,18 +134,15 @@
 TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
     sp<IBinder> vintfServer = BadStableBinder::vintf();
 
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("."), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("/"), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("/."), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("a.d.IFoo"), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("foo"), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("a.d.IFoo/foo"), vintfServer));
+    for (const char* instance8 : {
+        ".", "/", "/.", "a.d.IFoo", "foo", "a.d.IFoo/foo"
+    }) {
+        String16 instance (instance8);
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+            android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
+        EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+    }
 }
 
 TEST(BinderStability, CantCallVendorBinderInSystemContext) {
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 40f6b43..8e762f1 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -46,6 +46,7 @@
 static const char* hal_interfaces_to_dump[] {
         "android.hardware.audio@2.0::IDevicesFactory",
         "android.hardware.audio@4.0::IDevicesFactory",
+        "android.hardware.biometrics.face@1.0::IBiometricsFace",
         "android.hardware.bluetooth@1.0::IBluetoothHci",
         "android.hardware.camera.provider@2.4::ICameraProvider",
         "android.hardware.drm@1.0::IDrmFactory",
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 24b6c2d..4a39069 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -213,7 +213,8 @@
         case GraphicsEnv::Driver::GL:
         case GraphicsEnv::Driver::GL_UPDATED:
         case GraphicsEnv::Driver::ANGLE: {
-            if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) {
+            if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE ||
+                mGpuStats.glDriverToLoad == GraphicsEnv::Driver::GL) {
                 mGpuStats.glDriverToLoad = driver;
                 break;
             }
@@ -225,7 +226,8 @@
         }
         case Driver::VULKAN:
         case Driver::VULKAN_UPDATED: {
-            if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) {
+            if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE ||
+                mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::VULKAN) {
                 mGpuStats.vkDriverToLoad = driver;
                 break;
             }
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 59cb8e0..166775b 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -15,6 +15,18 @@
     name: "libgui_headers",
     vendor_available: true,
     export_include_dirs: ["include"],
+
+    // we must build this module to get the required header as that is generated
+    export_shared_lib_headers: [
+        "android.hidl.token@1.0-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+    ],
+    shared_libs: [
+        "android.hidl.token@1.0-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+    ],
 }
 
 cc_library_shared {
@@ -34,6 +46,7 @@
         "BufferItemConsumer.cpp",
         "ConsumerBase.cpp",
         "CpuConsumer.cpp",
+        "DebugEGLImageTracker.cpp",
         "DisplayEventReceiver.cpp",
         "GLConsumer.cpp",
         "GuiConfig.cpp",
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9c311a3..92ab410 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -936,6 +936,15 @@
                     }
                 }
 
+                // Make sure to merge the damage rect from the frame we're about
+                // to drop into the new frame's damage rect.
+                if (last.mSurfaceDamage.bounds() == Rect::INVALID_RECT ||
+                    item.mSurfaceDamage.bounds() == Rect::INVALID_RECT) {
+                    item.mSurfaceDamage = Region::INVALID_REGION;
+                } else {
+                    item.mSurfaceDamage |= last.mSurfaceDamage;
+                }
+
                 // Overwrite the droppable buffer with the incoming one
                 mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
                 frameReplacedListener = mCore->mConsumerListener;
diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp
new file mode 100644
index 0000000..ab6f364
--- /dev/null
+++ b/libs/gui/DebugEGLImageTracker.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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 <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gui/DebugEGLImageTracker.h>
+
+#include <cinttypes>
+#include <unordered_map>
+
+using android::base::StringAppendF;
+
+std::mutex DebugEGLImageTracker::mInstanceLock;
+std::atomic<DebugEGLImageTracker *> DebugEGLImageTracker::mInstance;
+
+class DebugEGLImageTrackerNoOp : public DebugEGLImageTracker {
+public:
+    DebugEGLImageTrackerNoOp() = default;
+    ~DebugEGLImageTrackerNoOp() override = default;
+    void create(const char * /*from*/) override {}
+    void destroy(const char * /*from*/) override {}
+
+    void dump(std::string & /*result*/) override {}
+};
+
+class DebugEGLImageTrackerImpl : public DebugEGLImageTracker {
+public:
+    DebugEGLImageTrackerImpl() = default;
+    ~DebugEGLImageTrackerImpl() override = default;
+    void create(const char * /*from*/) override;
+    void destroy(const char * /*from*/) override;
+
+    void dump(std::string & /*result*/) override;
+
+private:
+    std::mutex mLock;
+    std::unordered_map<std::string, int64_t> mCreateTracker;
+    std::unordered_map<std::string, int64_t> mDestroyTracker;
+
+    int64_t mTotalCreated = 0;
+    int64_t mTotalDestroyed = 0;
+};
+
+DebugEGLImageTracker *DebugEGLImageTracker::getInstance() {
+    std::lock_guard lock(mInstanceLock);
+    if (mInstance == nullptr) {
+        char value[PROPERTY_VALUE_MAX];
+        property_get("debug.sf.enable_egl_image_tracker", value, "0");
+        const bool enabled = static_cast<bool>(atoi(value));
+
+        if (enabled) {
+            mInstance = new DebugEGLImageTrackerImpl();
+        } else {
+            mInstance = new DebugEGLImageTrackerNoOp();
+        }
+    }
+
+    return mInstance;
+}
+
+void DebugEGLImageTrackerImpl::create(const char *from) {
+    std::lock_guard lock(mLock);
+    mCreateTracker[from]++;
+    mTotalCreated++;
+}
+
+void DebugEGLImageTrackerImpl::destroy(const char *from) {
+    std::lock_guard lock(mLock);
+    mDestroyTracker[from]++;
+    mTotalDestroyed++;
+}
+
+void DebugEGLImageTrackerImpl::dump(std::string &result) {
+    std::lock_guard lock(mLock);
+    StringAppendF(&result, "Live EGL Image objects: %" PRIi64 "\n",
+                  mTotalCreated - mTotalDestroyed);
+    StringAppendF(&result, "Total EGL Image created: %" PRIi64 "\n", mTotalCreated);
+    for (const auto &[from, count] : mCreateTracker) {
+        StringAppendF(&result, "\t%s: %" PRIi64 "\n", from.c_str(), count);
+    }
+    StringAppendF(&result, "Total EGL Image destroyed: %" PRIi64 "\n", mTotalDestroyed);
+    for (const auto &[from, count] : mDestroyTracker) {
+        StringAppendF(&result, "\t%s: %" PRIi64 "\n", from.c_str(), count);
+    }
+}
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index f5cf1c4..b8faa2d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -32,10 +32,11 @@
 
 // ---------------------------------------------------------------------------
 
-DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
+DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
+                                           ISurfaceComposer::ConfigChanged configChanged) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     if (sf != nullptr) {
-        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
+        mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
         if (mEventConnection != nullptr) {
             mDataChannel = std::make_unique<gui::BitTube>();
             mEventConnection->stealReceiveChannel(mDataChannel.get());
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 8d66154..8199c98 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -34,6 +34,7 @@
 #include <math/mat4.h>
 
 #include <gui/BufferItem.h>
+#include <gui/DebugEGLImageTracker.h>
 #include <gui/GLConsumer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
@@ -944,6 +945,7 @@
         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
            ALOGE("~EglImage: eglDestroyImageKHR failed");
         }
+        DEBUG_EGL_IMAGE_TRACKER_DESTROY();
         eglTerminate(mEglDisplay);
     }
 }
@@ -957,6 +959,7 @@
         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
         }
+        DEBUG_EGL_IMAGE_TRACKER_DESTROY();
         eglTerminate(mEglDisplay);
         mEglImage = EGL_NO_IMAGE_KHR;
         mEglDisplay = EGL_NO_DISPLAY;
@@ -1006,7 +1009,10 @@
         EGLint error = eglGetError();
         ALOGE("error creating EGLImage: %#x", error);
         eglTerminate(dpy);
+    } else {
+        DEBUG_EGL_IMAGE_TRACKER_CREATE();
     }
+
     return image;
 }
 
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 9590df7..12deaf0 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -278,8 +278,8 @@
         return NO_ERROR;
     }
 
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
-    {
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource,
+                                                                     ConfigChanged configChanged) {
         Parcel data, reply;
         sp<IDisplayEventConnection> result;
         int err = data.writeInterfaceToken(
@@ -288,6 +288,7 @@
             return result;
         }
         data.writeInt32(static_cast<int32_t>(vsyncSource));
+        data.writeInt32(static_cast<int32_t>(configChanged));
         err = remote()->transact(
                 BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
                 data, &reply);
@@ -1155,8 +1156,11 @@
         }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IDisplayEventConnection> connection(createDisplayEventConnection(
-                    static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
+            auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
+            auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32());
+
+            sp<IDisplayEventConnection> connection(
+                    createDisplayEventConnection(vsyncSource, configChanged));
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e6eb327..9fe5de8 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1920,7 +1920,8 @@
     return OK;
 }
 
-status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) {
+status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer,
+                                                    Dataspace dataspace) {
     if (buffer == nullptr) {
         return BAD_VALUE;
     }
@@ -1929,6 +1930,11 @@
     if (err != OK) {
         return err;
     }
+    ui::Dataspace tmpDataspace = surface->getBuffersDataSpace();
+    err = surface->setBuffersDataSpace(dataspace);
+    if (err != OK) {
+        return err;
+    }
     err = surface->attachBuffer(buffer->getNativeBuffer());
     if (err != OK) {
         return err;
@@ -1937,6 +1943,10 @@
     if (err != OK) {
         return err;
     }
+    err = surface->setBuffersDataSpace(tmpDataspace);
+    if (err != OK) {
+        return err;
+    }
     err = surface->disconnect(NATIVE_WINDOW_API_CPU);
     return err;
 }
diff --git a/libs/gui/include/gui/DebugEGLImageTracker.h b/libs/gui/include/gui/DebugEGLImageTracker.h
new file mode 100644
index 0000000..5d369c9
--- /dev/null
+++ b/libs/gui/include/gui/DebugEGLImageTracker.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <mutex>
+#include <string>
+
+class DebugEGLImageTracker {
+public:
+    static DebugEGLImageTracker *getInstance();
+
+    virtual void create(const char *from) = 0;
+    virtual void destroy(const char *from) = 0;
+
+    virtual void dump(std::string &result) = 0;
+
+protected:
+    DebugEGLImageTracker() = default;
+    virtual ~DebugEGLImageTracker() = default;
+    DebugEGLImageTracker(const DebugEGLImageTracker &) = delete;
+
+    static std::mutex mInstanceLock;
+    static std::atomic<DebugEGLImageTracker *> mInstance;
+};
+
+#define DEBUG_EGL_IMAGE_TRACKER_CREATE() \
+    (DebugEGLImageTracker::getInstance()->create(__PRETTY_FUNCTION__))
+#define DEBUG_EGL_IMAGE_TRACKER_DESTROY() \
+    (DebugEGLImageTracker::getInstance()->destroy(__PRETTY_FUNCTION__))
\ No newline at end of file
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 22de751..a558cf9 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -88,10 +88,13 @@
      * DisplayEventReceiver creates and registers an event connection with
      * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
      * or requestNextVsync to receive them.
+     * To receive Config Changed events specify this in the constructor.
      * Other events start being delivered immediately.
      */
     explicit DisplayEventReceiver(
-            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
+            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
+            ISurfaceComposer::ConfigChanged configChanged =
+                    ISurfaceComposer::eConfigChangedSuppress);
 
     /*
      * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e2f7736..c84910b 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -90,6 +90,8 @@
         eVsyncSourceSurfaceFlinger = 1
     };
 
+    enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 };
+
     /*
      * Create a connection with SurfaceFlinger.
      */
@@ -97,7 +99,8 @@
 
     /* return an IDisplayEventConnection */
     virtual sp<IDisplayEventConnection> createDisplayEventConnection(
-            VsyncSource vsyncSource = eVsyncSourceApp) = 0;
+            VsyncSource vsyncSource = eVsyncSourceApp,
+            ConfigChanged configChanged = eConfigChangedSuppress) = 0;
 
     /* create a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0c471bb..5c6a1ee 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -292,7 +292,8 @@
 
     ui::Dataspace getBuffersDataSpace();
 
-    static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer);
+    static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer,
+                                                      ui::Dataspace dataspace);
 
 protected:
     enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 960cf18..d370858 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -548,8 +548,8 @@
     }
 
     sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
-    sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
-            override {
+    sp<IDisplayEventConnection> createDisplayEventConnection(
+            ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override {
         return nullptr;
     }
     sp<IBinder> createDisplay(const String8& /*displayName*/,
diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h
index 1936a2b..07573c5 100644
--- a/libs/math/include/math/quat.h
+++ b/libs/math/include/math/quat.h
@@ -109,7 +109,7 @@
 
     // initialize from 4 values to w + xi + yj + zk
     template<typename A, typename B, typename C, typename D>
-    constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) { }
+    constexpr TQuaternion(A w, B x, C y, D z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)), w(static_cast<T>(w)) { }
 
     // initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w
     template<typename A, typename B>
diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h
index a347633..e0adb7f 100644
--- a/libs/math/include/math/vec2.h
+++ b/libs/math/include/math/vec2.h
@@ -89,7 +89,7 @@
     constexpr TVec2(A v) : x(v), y(v) { }
 
     template<typename A, typename B>
-    constexpr TVec2(A x, B y) : x(x), y(y) { }
+    constexpr TVec2(A x, B y) : x(static_cast<T>(x)), y(static_cast<T>(y)) { }
 
     template<typename A>
     explicit
diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h
index 009fd84..21fb684 100644
--- a/libs/math/include/math/vec3.h
+++ b/libs/math/include/math/vec3.h
@@ -86,13 +86,13 @@
 
     // handles implicit conversion to a tvec4. must not be explicit.
     template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type>
-    constexpr TVec3(A v) : x(v), y(v), z(v) { }
+    constexpr TVec3(A v) : x(static_cast<T>(v)), y(static_cast<T>(v)), z(static_cast<T>(v)) { }
 
     template<typename A, typename B, typename C>
-    constexpr TVec3(A x, B y, C z) : x(x), y(y), z(z) { }
+    constexpr TVec3(A x, B y, C z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)) { }
 
     template<typename A, typename B>
-    constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(z) { }
+    constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(static_cast<T>(z)) { }
 
     template<typename A>
     explicit
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 9bd3095..1ec73ce 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -266,10 +266,10 @@
 
     char buf[CMSG_SPACE(kFdBufferSize)];
     struct msghdr msg = {
-            .msg_control = buf,
-            .msg_controllen = sizeof(buf),
             .msg_iov = &iov[0],
             .msg_iovlen = 1,
+            .msg_control = buf,
+            .msg_controllen = sizeof(buf),
     };
 
     struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
@@ -306,10 +306,10 @@
     iov[0].iov_len = kMessageBufferSize;
 
     struct msghdr msg = {
-            .msg_control = fdBuf,
-            .msg_controllen = sizeof(fdBuf),
             .msg_iov = &iov[0],
             .msg_iovlen = 1,
+            .msg_control = fdBuf,
+            .msg_controllen = sizeof(fdBuf),
     };
 
     int result;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index da959e3..ae5e47b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -342,6 +342,8 @@
  * not compatible with its usage flags, the results are undefined and
  * may include program termination.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success, or an error number of the allocation fails for
  * any reason. The returned buffer has a reference count of 1.
  */
@@ -352,18 +354,24 @@
  *
  * This prevents the object from being deleted until the last reference
  * is removed.
+ *
+ * Available since API level 26.
  */
 void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with
  * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
+ *
+ * Available since API level 26.
  */
 void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Return a description of the AHardwareBuffer in the passed
  * AHardwareBuffer_Desc struct.
+ *
+ * Available since API level 26.
  */
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
         AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
@@ -413,6 +421,8 @@
  * simultaneously, and the contents of the buffer behave like shared
  * memory.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
  * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
  * has more than one layer. Error number if the lock fails for any other
@@ -441,6 +451,8 @@
  *
  * See the AHardwareBuffer_lock documentation for all other locking semantics.
  *
+ * Available since API level 29.
+ *
  * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
  * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
  * has more than one layer. Error number if the lock fails for any other
@@ -462,6 +474,8 @@
  * completed before the function returned and no further operations are
  * necessary.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
  * the unlock fails for any reason.
  */
@@ -470,6 +484,8 @@
 /**
  * Send the AHardwareBuffer to an AF_UNIX socket.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
  * number if the operation fails for any reason.
  */
@@ -478,6 +494,8 @@
 /**
  * Receive an AHardwareBuffer from an AF_UNIX socket.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
  * number if the operation fails for any reason.
  */
@@ -501,6 +519,8 @@
  * some implementations have implementation-defined limits on texture
  * size and layer count.
  *
+ * Available since API level 29.
+ *
  * \return 1 if the format and usage flag combination is allocatable,
  *     0 otherwise.
  */
@@ -514,6 +534,8 @@
  * of the locked buffer.  If the bytes per pixel or bytes per stride are unknown
  * or variable, or if the underlying mapper implementation does not support returning
  * additional information, then this call will fail with INVALID_OPERATION
+ *
+ * Available since API level 29.
  */
 int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress,
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6730596..3e436e3 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -189,6 +189,8 @@
 /**
  * Set a transform that will be applied to future buffers posted to the window.
  *
+ * Available since API level 26.
+ *
  * \param transform combination of {@link ANativeWindowTransform} flags
  * \return 0 for success, or -EINVAL if \p transform is invalid
  */
@@ -208,6 +210,8 @@
  * measurement data instead of color images. The default dataSpace is 0,
  * ADATASPACE_UNKNOWN, unless it has been overridden by the producer.
  *
+ * Available since API level 28.
+ *
  * \param dataSpace data space of all buffers queued after this call.
  * \return 0 for success, -EINVAL if window is invalid or the dataspace is not
  * supported.
@@ -216,6 +220,9 @@
 
 /**
  * Get the dataspace of the buffers in window.
+ *
+ * Available since API level 28.
+ *
  * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if
  * dataspace is unknown, or -EINVAL if window is invalid.
  */
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 36211ca..cc252d6 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -26,6 +26,7 @@
         "libgui",
         "liblog",
         "libnativewindow",
+        "libprocessgroup",
         "libsync",
         "libui",
         "libutils",
@@ -51,6 +52,7 @@
         "gl/GLExtensions.cpp",
         "gl/GLFramebuffer.cpp",
         "gl/GLImage.cpp",
+        "gl/ImageManager.cpp",
         "gl/Program.cpp",
         "gl/ProgramCache.cpp",
     ],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 46a8e9e..d2a7525 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -19,9 +19,8 @@
 #define LOG_TAG "RenderEngine"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "GLESRenderEngine.h"
-
-#include <math.h>
+#include <sched.h>
+#include <cmath>
 #include <fstream>
 #include <sstream>
 #include <unordered_set>
@@ -31,6 +30,7 @@
 #include <android-base/stringprintf.h>
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
+#include <gui/DebugEGLImageTracker.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/Texture.h>
 #include <renderengine/private/Description.h>
@@ -42,6 +42,7 @@
 #include <ui/Region.h>
 #include <utils/KeyedVector.h>
 #include <utils/Trace.h>
+#include "GLESRenderEngine.h"
 #include "GLExtensions.h"
 #include "GLFramebuffer.h"
 #include "GLImage.h"
@@ -422,10 +423,13 @@
         mTraceGpuCompletion = true;
         mFlushTracer = std::make_unique<FlushTracer>(this);
     }
+    mImageManager = std::make_unique<ImageManager>(this);
     mDrawingBuffer = createFramebuffer();
 }
 
 GLESRenderEngine::~GLESRenderEngine() {
+    // Destroy the image manager first.
+    mImageManager = nullptr;
     std::lock_guard<std::mutex> lock(mRenderingMutex);
     unbindFrameBuffer(mDrawingBuffer.get());
     mDrawingBuffer = nullptr;
@@ -433,6 +437,7 @@
         EGLImageKHR expired = mFramebufferImageCache.front().second;
         mFramebufferImageCache.pop_front();
         eglDestroyImageKHR(mEGLDisplay, expired);
+        DEBUG_EGL_IMAGE_TRACKER_DESTROY();
     }
     mImageCache.clear();
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -614,64 +619,51 @@
     }
 }
 
-status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    return cacheExternalTextureBufferLocked(buffer);
-}
-
 status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
                                                      const sp<GraphicBuffer>& buffer,
                                                      const sp<Fence>& bufferFence) {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    return bindExternalTextureBufferLocked(texName, buffer, bufferFence);
-}
-
-status_t GLESRenderEngine::cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) {
     if (buffer == nullptr) {
         return BAD_VALUE;
     }
 
     ATRACE_CALL();
 
-    if (mImageCache.count(buffer->getId()) > 0) {
-        return NO_ERROR;
+    bool found = false;
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        auto cachedImage = mImageCache.find(buffer->getId());
+        found = (cachedImage != mImageCache.end());
     }
 
-    std::unique_ptr<Image> newImage = createImage();
-
-    bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
-                                                   buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-    if (!created) {
-        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
-              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
-              buffer->getPixelFormat());
-        return NO_INIT;
-    }
-    mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
-
-    return NO_ERROR;
-}
-
-status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
-                                                           const sp<GraphicBuffer>& buffer,
-                                                           const sp<Fence>& bufferFence) {
-    ATRACE_CALL();
-    status_t cacheResult = cacheExternalTextureBufferLocked(buffer);
-
-    if (cacheResult != NO_ERROR) {
-        return cacheResult;
+    // If we couldn't find the image in the cache at this time, then either
+    // SurfaceFlinger messed up registering the buffer ahead of time or we got
+    // backed up creating other EGLImages.
+    if (!found) {
+        status_t cacheResult = mImageManager->cache(buffer);
+        if (cacheResult != NO_ERROR) {
+            return cacheResult;
+        }
     }
 
-    auto cachedImage = mImageCache.find(buffer->getId());
+    // Whether or not we needed to cache, re-check mImageCache to make sure that
+    // there's an EGLImage. The current threading model guarantees that we don't
+    // destroy a cached image until it's really not needed anymore (i.e. this
+    // function should not be called), so the only possibility is that something
+    // terrible went wrong and we should just bind something and move on.
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        auto cachedImage = mImageCache.find(buffer->getId());
 
-    if (cachedImage == mImageCache.end()) {
-        // We failed creating the image if we got here, so bail out.
-        bindExternalTextureImage(texName, *createImage());
-        return NO_INIT;
+        if (cachedImage == mImageCache.end()) {
+            // We failed creating the image if we got here, so bail out.
+            ALOGE("Failed to create an EGLImage when rendering");
+            bindExternalTextureImage(texName, *createImage());
+            return NO_INIT;
+        }
+
+        bindExternalTextureImage(texName, *cachedImage->second);
     }
 
-    bindExternalTextureImage(texName, *cachedImage->second);
-
     // Wait for the new buffer to be ready.
     if (bufferFence != nullptr && bufferFence->isValid()) {
         if (GLExtensions::getInstance().hasWaitSync()) {
@@ -696,13 +688,81 @@
     return NO_ERROR;
 }
 
+void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+    mImageManager->cacheAsync(buffer, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting(
+        const sp<GraphicBuffer>& buffer) {
+    auto barrier = std::make_shared<ImageManager::Barrier>();
+    mImageManager->cacheAsync(buffer, barrier);
+    return barrier;
+}
+
+status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) {
+    if (buffer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        if (mImageCache.count(buffer->getId()) > 0) {
+            // If there's already an image then fail fast here.
+            return NO_ERROR;
+        }
+    }
+    ATRACE_CALL();
+
+    // Create the image without holding a lock so that we don't block anything.
+    std::unique_ptr<Image> newImage = createImage();
+
+    bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
+                                                   buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    if (!created) {
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
+              buffer->getPixelFormat());
+        return NO_INIT;
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        if (mImageCache.count(buffer->getId()) > 0) {
+            // In theory it's possible for another thread to recache the image,
+            // so bail out if another thread won.
+            return NO_ERROR;
+        }
+        mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
+    }
+
+    return NO_ERROR;
+}
+
 void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    const auto& cachedImage = mImageCache.find(bufferId);
-    if (cachedImage != mImageCache.end()) {
-        ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
-        mImageCache.erase(bufferId);
-        return;
+    mImageManager->releaseAsync(bufferId, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting(
+        uint64_t bufferId) {
+    auto barrier = std::make_shared<ImageManager::Barrier>();
+    mImageManager->releaseAsync(bufferId, barrier);
+    return barrier;
+}
+
+void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) {
+    std::unique_ptr<Image> image;
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        const auto& cachedImage = mImageCache.find(bufferId);
+
+        if (cachedImage != mImageCache.end()) {
+            ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+            // Move the buffer out of cache first, so that we can destroy
+            // without holding the cache's lock.
+            image = std::move(cachedImage->second);
+            mImageCache.erase(bufferId);
+            return;
+        }
     }
     ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
 }
@@ -842,6 +902,7 @@
                                                              bool useFramebufferCache) {
     sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
     if (useFramebufferCache) {
+        std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
         for (const auto& image : mFramebufferImageCache) {
             if (image.first == graphicBuffer->getId()) {
                 return image.second;
@@ -857,14 +918,20 @@
                                           nativeBuffer, attributes);
     if (useFramebufferCache) {
         if (image != EGL_NO_IMAGE_KHR) {
+            std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
             if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
                 EGLImageKHR expired = mFramebufferImageCache.front().second;
                 mFramebufferImageCache.pop_front();
                 eglDestroyImageKHR(mEGLDisplay, expired);
+                DEBUG_EGL_IMAGE_TRACKER_DESTROY();
             }
             mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
         }
     }
+
+    if (image != EGL_NO_IMAGE_KHR) {
+        DEBUG_EGL_IMAGE_TRACKER_CREATE();
+    }
     return image;
 }
 
@@ -889,127 +956,123 @@
         return BAD_VALUE;
     }
 
-    {
-        std::lock_guard<std::mutex> lock(mRenderingMutex);
+    BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
 
-        BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
-
-        if (fbo.getStatus() != NO_ERROR) {
-            ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
-                  buffer->handle);
-            checkErrors();
-            return fbo.getStatus();
-        }
-
-        // clear the entire buffer, sometimes when we reuse buffers we'd persist
-        // ghost images otherwise.
-        // we also require a full transparent framebuffer for overlays. This is
-        // probably not quite efficient on all GPUs, since we could filter out
-        // opaque layers.
-        clearWithColor(0.0, 0.0, 0.0, 0.0);
-
-        setViewportAndProjection(display.physicalDisplay, display.clip);
-
-        setOutputDataSpace(display.outputDataspace);
-        setDisplayMaxLuminance(display.maxLuminance);
-
-        mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
-        mState.projectionMatrix = projectionMatrix;
-        if (!display.clearRegion.isEmpty()) {
-            glDisable(GL_BLEND);
-            fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
-        }
-
-        Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
-        for (auto layer : layers) {
-            mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
-
-            const FloatRect bounds = layer.geometry.boundaries;
-            Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-            position[0] = vec2(bounds.left, bounds.top);
-            position[1] = vec2(bounds.left, bounds.bottom);
-            position[2] = vec2(bounds.right, bounds.bottom);
-            position[3] = vec2(bounds.right, bounds.top);
-
-            setupLayerCropping(layer, mesh);
-            setColorTransform(display.colorTransform * layer.colorTransform);
-
-            bool usePremultipliedAlpha = true;
-            bool disableTexture = true;
-            bool isOpaque = false;
-
-            if (layer.source.buffer.buffer != nullptr) {
-                disableTexture = false;
-                isOpaque = layer.source.buffer.isOpaque;
-
-                sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
-                bindExternalTextureBufferLocked(layer.source.buffer.textureName, gBuf,
-                                                layer.source.buffer.fence);
-
-                usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
-                Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
-                mat4 texMatrix = layer.source.buffer.textureTransform;
-
-                texture.setMatrix(texMatrix.asArray());
-                texture.setFiltering(layer.source.buffer.useTextureFiltering);
-
-                texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
-                setSourceY410BT2020(layer.source.buffer.isY410BT2020);
-
-                renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
-                texCoords[0] = vec2(0.0, 0.0);
-                texCoords[1] = vec2(0.0, 1.0);
-                texCoords[2] = vec2(1.0, 1.0);
-                texCoords[3] = vec2(1.0, 0.0);
-                setupLayerTexturing(texture);
-            }
-
-            const half3 solidColor = layer.source.solidColor;
-            const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
-            // Buffer sources will have a black solid color ignored in the shader,
-            // so in that scenario the solid color passed here is arbitrary.
-            setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
-                               layer.geometry.roundedCornersRadius);
-            if (layer.disableBlending) {
-                glDisable(GL_BLEND);
-            }
-            setSourceDataSpace(layer.sourceDataspace);
-
-            // We only want to do a special handling for rounded corners when having rounded corners
-            // is the only reason it needs to turn on blending, otherwise, we handle it like the
-            // usual way since it needs to turn on blending anyway.
-            if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
-                handleRoundedCorners(display, layer, mesh);
-            } else {
-                drawMesh(mesh);
-            }
-
-            // Cleanup if there's a buffer source
-            if (layer.source.buffer.buffer != nullptr) {
-                disableBlending();
-                setSourceY410BT2020(false);
-                disableTexturing();
-            }
-        }
-
-        if (drawFence != nullptr) {
-            *drawFence = flush();
-        }
-        // If flush failed or we don't support native fences, we need to force the
-        // gl command stream to be executed.
-        if (drawFence == nullptr || drawFence->get() < 0) {
-            bool success = finish();
-            if (!success) {
-                ALOGE("Failed to flush RenderEngine commands");
-                checkErrors();
-                // Chances are, something illegal happened (either the caller passed
-                // us bad parameters, or we messed up our shader generation).
-                return INVALID_OPERATION;
-            }
-        }
-
+    if (fbo.getStatus() != NO_ERROR) {
+        ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+              buffer->handle);
         checkErrors();
+        return fbo.getStatus();
     }
+
+    // clear the entire buffer, sometimes when we reuse buffers we'd persist
+    // ghost images otherwise.
+    // we also require a full transparent framebuffer for overlays. This is
+    // probably not quite efficient on all GPUs, since we could filter out
+    // opaque layers.
+    clearWithColor(0.0, 0.0, 0.0, 0.0);
+
+    setViewportAndProjection(display.physicalDisplay, display.clip);
+
+    setOutputDataSpace(display.outputDataspace);
+    setDisplayMaxLuminance(display.maxLuminance);
+
+    mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
+    mState.projectionMatrix = projectionMatrix;
+    if (!display.clearRegion.isEmpty()) {
+        glDisable(GL_BLEND);
+        fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
+    }
+
+    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
+    for (auto layer : layers) {
+        mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+
+        const FloatRect bounds = layer.geometry.boundaries;
+        Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+        position[0] = vec2(bounds.left, bounds.top);
+        position[1] = vec2(bounds.left, bounds.bottom);
+        position[2] = vec2(bounds.right, bounds.bottom);
+        position[3] = vec2(bounds.right, bounds.top);
+
+        setupLayerCropping(layer, mesh);
+        setColorTransform(display.colorTransform * layer.colorTransform);
+
+        bool usePremultipliedAlpha = true;
+        bool disableTexture = true;
+        bool isOpaque = false;
+
+        if (layer.source.buffer.buffer != nullptr) {
+            disableTexture = false;
+            isOpaque = layer.source.buffer.isOpaque;
+
+            sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
+            bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
+                                      layer.source.buffer.fence);
+
+            usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
+            Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
+            mat4 texMatrix = layer.source.buffer.textureTransform;
+
+            texture.setMatrix(texMatrix.asArray());
+            texture.setFiltering(layer.source.buffer.useTextureFiltering);
+
+            texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
+            setSourceY410BT2020(layer.source.buffer.isY410BT2020);
+
+            renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
+            texCoords[0] = vec2(0.0, 0.0);
+            texCoords[1] = vec2(0.0, 1.0);
+            texCoords[2] = vec2(1.0, 1.0);
+            texCoords[3] = vec2(1.0, 0.0);
+            setupLayerTexturing(texture);
+        }
+
+        const half3 solidColor = layer.source.solidColor;
+        const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+        // Buffer sources will have a black solid color ignored in the shader,
+        // so in that scenario the solid color passed here is arbitrary.
+        setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
+                           layer.geometry.roundedCornersRadius);
+        if (layer.disableBlending) {
+            glDisable(GL_BLEND);
+        }
+        setSourceDataSpace(layer.sourceDataspace);
+
+        // We only want to do a special handling for rounded corners when having rounded corners
+        // is the only reason it needs to turn on blending, otherwise, we handle it like the
+        // usual way since it needs to turn on blending anyway.
+        if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+            handleRoundedCorners(display, layer, mesh);
+        } else {
+            drawMesh(mesh);
+        }
+
+        // Cleanup if there's a buffer source
+        if (layer.source.buffer.buffer != nullptr) {
+            disableBlending();
+            setSourceY410BT2020(false);
+            disableTexturing();
+        }
+    }
+
+    if (drawFence != nullptr) {
+        *drawFence = flush();
+    }
+    // If flush failed or we don't support native fences, we need to force the
+    // gl command stream to be executed.
+    if (drawFence == nullptr || drawFence->get() < 0) {
+        bool success = finish();
+        if (!success) {
+            ALOGE("Failed to flush RenderEngine commands");
+            checkErrors();
+            // Chances are, something illegal happened (either the caller passed
+            // us bad parameters, or we messed up our shader generation).
+            return INVALID_OPERATION;
+        }
+    }
+
+    checkErrors();
     return NO_ERROR;
 }
 
@@ -1306,6 +1369,23 @@
     StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n",
                   dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
                   dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size());
+        StringAppendF(&result, "Dumping buffer ids...\n");
+        for (const auto& [id, unused] : mImageCache) {
+            StringAppendF(&result, "0x%" PRIx64 "\n", id);
+        }
+    }
+    {
+        std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
+        StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n",
+                      mFramebufferImageCache.size());
+        StringAppendF(&result, "Dumping buffer ids...\n");
+        for (const auto& [id, unused] : mFramebufferImageCache) {
+            StringAppendF(&result, "0x%" PRIx64 "\n", id);
+        }
+    }
 }
 
 GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) {
@@ -1432,7 +1512,7 @@
 }
 
 bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
     return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(),
                        [=](std::pair<uint64_t, EGLImageKHR> image) {
                            return image.first == bufferId;
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index de793c2..dd60e50 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -17,9 +17,7 @@
 #ifndef SF_GLESRENDERENGINE_H_
 #define SF_GLESRENDERENGINE_H_
 
-#include <android-base/thread_annotations.h>
 #include <stdint.h>
-#include <sys/types.h>
 #include <condition_variable>
 #include <deque>
 #include <mutex>
@@ -30,8 +28,11 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
+#include <android-base/thread_annotations.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
+#include <sys/types.h>
+#include "ImageManager.h"
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -74,7 +75,7 @@
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
     status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
                                        const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
-    status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
+    void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
     void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
     status_t bindFrameBuffer(Framebuffer* framebuffer) override;
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
@@ -85,25 +86,32 @@
     bool useProtectedContext(bool useProtectedContext) override;
     status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
                         ANativeWindowBuffer* buffer, const bool useFramebufferCache,
-                        base::unique_fd&& bufferFence, base::unique_fd* drawFence)
-            EXCLUDES(mRenderingMutex) override;
+                        base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
 
     // internal to RenderEngine
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     EGLConfig getEGLConfig() const { return mEGLConfig; }
     // Creates an output image for rendering to
     EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected,
-                                               bool useFramebufferCache);
+                                               bool useFramebufferCache)
+            EXCLUDES(mFramebufferImageCacheMutex);
 
     // Test-only methods
     // Returns true iff mImageCache contains an image keyed by bufferId
     bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex);
     // Returns true iff mFramebufferImageCache contains an image keyed by bufferId
-    bool isFramebufferImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex);
+    bool isFramebufferImageCachedForTesting(uint64_t bufferId)
+            EXCLUDES(mFramebufferImageCacheMutex);
+    // These are wrappers around public methods above, but exposing Barrier
+    // objects so that tests can block.
+    std::shared_ptr<ImageManager::Barrier> cacheExternalTextureBufferForTesting(
+            const sp<GraphicBuffer>& buffer);
+    std::shared_ptr<ImageManager::Barrier> unbindExternalTextureBufferForTesting(uint64_t bufferId);
 
 protected:
     Framebuffer* getFramebufferForDrawing() override;
-    void dump(std::string& result) override;
+    void dump(std::string& result) override EXCLUDES(mRenderingMutex)
+            EXCLUDES(mFramebufferImageCacheMutex);
     void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                   ui::Transform::orientation_flags rotation) override;
     void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
@@ -145,6 +153,9 @@
     void setScissor(const Rect& region);
     void disableScissor();
     bool waitSync(EGLSyncKHR sync, EGLint flags);
+    status_t cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer)
+            EXCLUDES(mRenderingMutex);
+    void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex);
 
     // A data space is considered HDR data space if it has BT2020 color space
     // with PQ or HLG transfer function.
@@ -200,7 +211,11 @@
     uint32_t mFramebufferImageCacheSize = 0;
 
     // Cache of output images, keyed by corresponding GraphicBuffer ID.
-    std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache;
+    std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache
+            GUARDED_BY(mFramebufferImageCacheMutex);
+    // The only reason why we have this mutex is so that we don't segfault when
+    // dumping info.
+    std::mutex mFramebufferImageCacheMutex;
 
     // Current dataspace of layer being rendered
     ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
@@ -220,15 +235,6 @@
     // multiple threads is guaranteed thread-safe.
     std::mutex mRenderingMutex;
 
-    // See bindExternalTextureBuffer above, but requiring that mRenderingMutex
-    // is held.
-    status_t bindExternalTextureBufferLocked(uint32_t texName, const sp<GraphicBuffer>& buffer,
-                                             const sp<Fence>& fence) REQUIRES(mRenderingMutex);
-    // See cacheExternalTextureBuffer above, but requiring that mRenderingMutex
-    // is held.
-    status_t cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer)
-            REQUIRES(mRenderingMutex);
-
     std::unique_ptr<Framebuffer> mDrawingBuffer;
 
     class FlushTracer {
@@ -253,7 +259,9 @@
         bool mRunning = true;
     };
     friend class FlushTracer;
+    friend class ImageManager;
     std::unique_ptr<FlushTracer> mFlushTracer;
+    std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
 };
 
 } // namespace gl
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index dacf8d3..5fbb5ba 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -22,6 +22,7 @@
 #include <GLES/glext.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <gui/DebugEGLImageTracker.h>
 #include <nativebase/nativebase.h>
 #include <utils/Trace.h>
 #include "GLESRenderEngine.h"
@@ -47,6 +48,7 @@
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         if (!usingFramebufferCache) {
             eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+            DEBUG_EGL_IMAGE_TRACKER_DESTROY();
         }
         mEGLImage = EGL_NO_IMAGE_KHR;
         mBufferWidth = 0;
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
index 77e648e..8497721 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -20,6 +20,7 @@
 
 #include <vector>
 
+#include <gui/DebugEGLImageTracker.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 #include "GLESRenderEngine.h"
@@ -58,6 +59,7 @@
         if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
             ALOGE("failed to destroy image: %#x", eglGetError());
         }
+        DEBUG_EGL_IMAGE_TRACKER_DESTROY();
         mEGLImage = EGL_NO_IMAGE_KHR;
     }
 
@@ -69,6 +71,7 @@
             ALOGE("failed to create EGLImage: %#x", eglGetError());
             return false;
         }
+        DEBUG_EGL_IMAGE_TRACKER_CREATE();
         mProtected = isProtected;
     }
 
diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp
new file mode 100644
index 0000000..5af0e4f
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <pthread.h>
+
+#include <processgroup/sched_policy.h>
+#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
+#include "ImageManager.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {
+    pthread_setname_np(mThread.native_handle(), "ImageManager");
+    // Use SCHED_FIFO to minimize jitter
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for ImageManager");
+    }
+}
+
+ImageManager::~ImageManager() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mRunning = false;
+    }
+    mCondition.notify_all();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer,
+                              const std::shared_ptr<Barrier>& barrier) {
+    if (buffer == nullptr) {
+        {
+            std::lock_guard<std::mutex> lock(barrier->mutex);
+            barrier->isOpen = true;
+            barrier->result = BAD_VALUE;
+        }
+        barrier->condition.notify_one();
+        return;
+    }
+    ATRACE_CALL();
+    QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier};
+    queueOperation(std::move(entry));
+}
+
+status_t ImageManager::cache(const sp<GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+    auto barrier = std::make_shared<Barrier>();
+    cacheAsync(buffer, barrier);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    barrier->condition.wait(barrier->mutex,
+                            [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; });
+    return barrier->result;
+}
+
+void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) {
+    ATRACE_CALL();
+    QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier};
+    queueOperation(std::move(entry));
+}
+
+void ImageManager::queueOperation(const QueueEntry&& entry) {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mQueue.emplace(entry);
+        ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+    }
+    mCondition.notify_one();
+}
+
+void ImageManager::threadMain() {
+    set_sched_policy(0, SP_FOREGROUND);
+    bool run;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        run = mRunning;
+    }
+    while (run) {
+        QueueEntry entry;
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mCondition.wait(mMutex,
+                            [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
+            run = mRunning;
+
+            if (!mRunning) {
+                // if mRunning is false, then ImageManager is being destroyed, so
+                // bail out now.
+                break;
+            }
+
+            entry = mQueue.front();
+            mQueue.pop();
+            ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+        }
+
+        status_t result = NO_ERROR;
+        switch (entry.op) {
+            case QueueEntry::Operation::Delete:
+                mEngine->unbindExternalTextureBufferInternal(entry.bufferId);
+                break;
+            case QueueEntry::Operation::Insert:
+                result = mEngine->cacheExternalTextureBufferInternal(entry.buffer);
+                break;
+        }
+        if (entry.barrier != nullptr) {
+            {
+                std::lock_guard<std::mutex> entryLock(entry.barrier->mutex);
+                entry.barrier->result = result;
+                entry.barrier->isOpen = true;
+            }
+            entry.barrier->condition.notify_one();
+        }
+    }
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h
new file mode 100644
index 0000000..b5ba554
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLESRenderEngine;
+
+class ImageManager {
+public:
+    struct Barrier {
+        std::mutex mutex;
+        std::condition_variable_any condition;
+        bool isOpen GUARDED_BY(mutex) = false;
+        status_t result GUARDED_BY(mutex) = NO_ERROR;
+    };
+    ImageManager(GLESRenderEngine* engine);
+    ~ImageManager();
+    void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier)
+            EXCLUDES(mMutex);
+    status_t cache(const sp<GraphicBuffer>& buffer);
+    void releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex);
+
+private:
+    struct QueueEntry {
+        enum class Operation { Delete, Insert };
+
+        Operation op = Operation::Delete;
+        sp<GraphicBuffer> buffer = nullptr;
+        uint64_t bufferId = 0;
+        std::shared_ptr<Barrier> barrier = nullptr;
+    };
+
+    void queueOperation(const QueueEntry&& entry);
+    void threadMain();
+    GLESRenderEngine* const mEngine;
+    std::thread mThread = std::thread([this]() { threadMain(); });
+    std::condition_variable_any mCondition;
+    std::mutex mMutex;
+    std::queue<QueueEntry> mQueue GUARDED_BY(mMutex);
+
+    bool mRunning GUARDED_BY(mMutex) = true;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e707004..c6a7bd8 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -116,10 +116,20 @@
                                                const sp<Fence>& fence) = 0;
     // Caches Image resources for this buffer, but does not bind the buffer to
     // a particular texture.
-    virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
+    // Note that work is deferred to an additional thread, i.e. this call
+    // is made asynchronously, but the caller can expect that cache/unbind calls
+    // are performed in a manner that's conflict serializable, i.e. unbinding
+    // a buffer should never occur before binding the buffer if the caller
+    // called {bind, cache}ExternalTextureBuffer before calling unbind.
+    virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
     // Removes internal resources referenced by the bufferId. This method should be
     // invoked when the caller will no longer hold a reference to a GraphicBuffer
     // and needs to clean up its resources.
+    // Note that work is deferred to an additional thread, i.e. this call
+    // is made asynchronously, but the caller can expect that cache/unbind calls
+    // are performed in a manner that's conflict serializable, i.e. unbinding
+    // a buffer should never occur before binding the buffer if the caller
+    // called {bind, cache}ExternalTextureBuffer before calling unbind.
     virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
     // When binding a native buffer, it must be done before setViewportAndProjection
     // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
@@ -176,6 +186,17 @@
     // should be called for every display that needs to be rendered via the GPU.
     // @param display The display-wide settings that should be applied prior to
     // drawing any layers.
+    //
+    // Assumptions when calling this method:
+    // 1. There is exactly one caller - i.e. multi-threading is not supported.
+    // 2. Additional threads may be calling the {bind,cache}ExternalTexture
+    // methods above. But the main thread is responsible for holding resources
+    // such that Image destruction does not occur while this method is called.
+    //
+    // TODO(b/136806342): This should behavior should ideally be fixed since
+    // the above two assumptions are brittle, as conditional thread safetyness
+    // may be insufficient when maximizing rendering performance in the future.
+    //
     // @param layers The layers to draw onto the display, in Z-order.
     // @param buffer The buffer which will be drawn to. This buffer will be
     // ready once drawFence fires.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index e33bcfd..b4d3ef2 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -51,7 +51,7 @@
     MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
     MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
     MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
-    MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+    MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&));
     MOCK_METHOD3(bindExternalTextureBuffer,
                  status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
     MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 9b483ef..e98babc 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -31,6 +31,7 @@
         "libgui",
         "liblog",
         "libnativewindow",
+        "libprocessgroup",
         "libsync",
         "libui",
         "libutils",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7acaecf..f47c7fd 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#include <chrono>
+#include <condition_variable>
 
+#include <gtest/gtest.h>
 #include <renderengine/RenderEngine.h>
 #include <sync/sync.h>
 #include <ui/PixelFormat.h>
@@ -1001,8 +1003,15 @@
     invokeDraw(settings, layers, mBuffer);
     uint64_t bufferId = layer.source.buffer.buffer->getId();
     EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
-    sRE->unbindExternalTextureBuffer(bufferId);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->unbindExternalTextureBufferForTesting(bufferId);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                            [&]() REQUIRES(barrier->mutex) {
+                                                return barrier->isOpen;
+                                            }));
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+    EXPECT_EQ(NO_ERROR, barrier->result);
 }
 
 TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
@@ -1019,21 +1028,52 @@
     sRE->bindExternalTextureBuffer(texName, buf, nullptr);
     uint64_t bufferId = buf->getId();
     EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
-    sRE->unbindExternalTextureBuffer(bufferId);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->unbindExternalTextureBufferForTesting(bufferId);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                            [&]() REQUIRES(barrier->mutex) {
+                                                return barrier->isOpen;
+                                            }));
+    EXPECT_EQ(NO_ERROR, barrier->result);
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
 }
 
 TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
-    status_t result = sRE->cacheExternalTextureBuffer(nullptr);
-    ASSERT_EQ(BAD_VALUE, result);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->cacheExternalTextureBufferForTesting(nullptr);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                            [&]() REQUIRES(barrier->mutex) {
+                                                return barrier->isOpen;
+                                            }));
+    EXPECT_TRUE(barrier->isOpen);
+    EXPECT_EQ(BAD_VALUE, barrier->result);
 }
 
 TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
     sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
     uint64_t bufferId = buf->getId();
-    sRE->cacheExternalTextureBuffer(buf);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->cacheExternalTextureBufferForTesting(buf);
+    {
+        std::lock_guard<std::mutex> lock(barrier->mutex);
+        ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                                [&]() REQUIRES(barrier->mutex) {
+                                                    return barrier->isOpen;
+                                                }));
+        EXPECT_EQ(NO_ERROR, barrier->result);
+    }
     EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
-    sRE->unbindExternalTextureBuffer(bufferId);
+    barrier = sRE->unbindExternalTextureBufferForTesting(bufferId);
+    {
+        std::lock_guard<std::mutex> lock(barrier->mutex);
+        ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                                [&]() REQUIRES(barrier->mutex) {
+                                                    return barrier->isOpen;
+                                                }));
+        EXPECT_EQ(NO_ERROR, barrier->result);
+    }
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
 }
 
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 7a14af1..df390e2 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -364,7 +364,11 @@
     for (uint32_t z = 0; z < size; z++) {
         for (int32_t y = int32_t(size - 1); y >= 0; y--) {
             for (uint32_t x = 0; x < size; x++) {
-                *data++ = connector.transform({x * m, y * m, z * m});
+                *data++ = connector.transform({
+                    static_cast<float>(x) * m,
+                    static_cast<float>(y) * m,
+                    static_cast<float>(z) * m,
+                });
             }
         }
     }
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 0861a1f..f1aa89c 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -20,6 +20,7 @@
 
 #include <ui/GraphicBufferAllocator.h>
 
+#include <limits.h>
 #include <stdio.h>
 
 #include <grallocusage/GrallocUsageConversion.h>
@@ -80,7 +81,7 @@
         if (rec.size) {
             StringAppendF(&result,
                           "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
-                          list.keyAt(i), rec.size / 1024.0, rec.width, rec.stride, rec.height,
+                          list.keyAt(i), static_cast<double>(rec.size) / 1024.0, rec.width, rec.stride, rec.height,
                           rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str());
         } else {
             StringAppendF(&result,
@@ -90,7 +91,7 @@
         }
         total += rec.size;
     }
-    StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", total / 1024.0);
+    StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", static_cast<double>(total) / 1024.0);
 
     result.append(mAllocator->dumpDebugInfo());
 }
@@ -114,6 +115,14 @@
     if (!width || !height)
         width = height = 1;
 
+    const uint32_t bpp = bytesPerPixel(format);
+    if (std::numeric_limits<size_t>::max() / width / height < static_cast<size_t>(bpp)) {
+        ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
+              "usage %" PRIx64 ": Requesting too large a buffer size",
+              width, height, layerCount, format, usage);
+        return BAD_VALUE;
+    }
+
     // Ensure that layerCount is valid.
     if (layerCount < 1)
         layerCount = 1;
@@ -126,7 +135,6 @@
     if (error == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
-        uint32_t bpp = bytesPerPixel(format);
         alloc_rec_t rec;
         rec.width = width;
         rec.height = height;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 55e3b99..1222cd6 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -339,10 +339,10 @@
     size_t count = mStorage.size();
     Rect* rects = mStorage.editArray();
     while (count) {
-        rects->left = static_cast<int32_t>(rects->left * sx + 0.5f);
-        rects->right = static_cast<int32_t>(rects->right * sx + 0.5f);
-        rects->top = static_cast<int32_t>(rects->top * sy + 0.5f);
-        rects->bottom = static_cast<int32_t>(rects->bottom * sy + 0.5f);
+        rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
+        rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
+        rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f);
+        rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f);
         rects++;
         count--;
     }
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
index c39d8af..d9b713d 100644
--- a/libs/ui/include/ui/Size.h
+++ b/libs/ui/include/ui/Size.h
@@ -132,7 +132,7 @@
         // Otherwise we leverage implicit conversion to safely compare values of
         // different types, to ensure we return a value clamped to the range of
         // ToType.
-        return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+        return v < toLowest ? toLowest : (static_cast<ToType>(v) > toHighest ? toHighest : static_cast<ToType>(v));
     }
 };
 
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index a7c248c..127f7ee 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -35,6 +35,22 @@
 
 class GraphicBufferTest : public testing::Test {};
 
+TEST_F(GraphicBufferTest, AllocateNoError) {
+    PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+    sp<GraphicBuffer> gb(new GraphicBuffer(kTestWidth, kTestHeight, format, kTestLayerCount,
+                                           kTestUsage, std::string("test")));
+    ASSERT_EQ(NO_ERROR, gb->initCheck());
+}
+
+TEST_F(GraphicBufferTest, AllocateBadDimensions) {
+    PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+    uint32_t width, height;
+    width = height = std::numeric_limits<uint32_t>::max();
+    sp<GraphicBuffer> gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
+                                           std::string("test")));
+    ASSERT_EQ(BAD_VALUE, gb->initCheck());
+}
+
 TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) {
     std::unique_ptr<BufferHubBuffer> b1 =
             BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 6d202ae..2fcee7b 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -29,11 +29,9 @@
 sharedLibraries = [
     "libbase",
     "libcutils",
-    "libhardware",
     "liblog",
     "libui",
     "libutils",
-    "libnativewindow",
     "libpdx_default_transport",
 ]
 
diff --git a/opengl/libagl/Android.bp b/opengl/libagl/Android.bp
index 6ec24b3..f5bf015 100644
--- a/opengl/libagl/Android.bp
+++ b/opengl/libagl/Android.bp
@@ -25,8 +25,9 @@
         "libnativewindow",
     ],
 
-    // we need to access the private Bionic header <bionic_tls.h>
-    include_dirs: ["bionic/libc/private"],
+    header_libs: [
+        "bionic_libc_platform_headers",
+    ],
 
     arch: {
         arm: {
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
index 18ef7d5..6e77a23 100644
--- a/opengl/libagl/context.h
+++ b/opengl/libagl/context.h
@@ -22,7 +22,7 @@
 #include <sys/types.h>
 #include <pthread.h>
 #ifdef __ANDROID__
-#include <bionic_tls.h>
+#include <bionic/tls.h>
 #endif
 
 #include <private/pixelflinger/ggl_context.h>
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 342fb59..eb90c8b 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -72,15 +72,13 @@
         "libarect",
     ],
     header_libs: [
+        "bionic_libc_platform_headers",
         "gl_headers",
         "libsystem_headers",
         "libhardware_headers",
         "libnativebase_headers",
     ],
     export_header_lib_headers: ["gl_headers"],
-
-    // we need to access the private Bionic header <bionic_tls.h>
-    include_dirs: ["bionic/libc/private"],
 }
 
 //##############################################################################
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 63a0e14..86fec21 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -46,7 +46,7 @@
 #define MAX_NUMBER_OF_GL_EXTENSIONS 256
 
 
-#include <bionic_tls.h>  /* special private C library header */
+#include <bionic/tls.h>  /* special private C library header */
 
 // ----------------------------------------------------------------------------
 namespace android {
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index 19c8b37..8bfe517 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -28,9 +28,11 @@
     ],
 
     include_dirs: [
-        "bionic/libc/private",
         "frameworks/native/opengl/libs",
         "frameworks/native/opengl/libs/EGL",
     ],
 
+    header_libs: [
+        "bionic_libc_platform_headers",
+    ],
 }
diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp
index fefedc0..613f1c6 100644
--- a/opengl/tests/gl_perf/fill_common.cpp
+++ b/opengl/tests/gl_perf/fill_common.cpp
@@ -191,10 +191,10 @@
 static void randUniform(int pgm, const char *var) {
     GLint loc = glGetUniformLocation(pgm, var);
     if (loc >= 0) {
-        float x = ((float)rand()) / RAND_MAX;
-        float y = ((float)rand()) / RAND_MAX;
-        float z = ((float)rand()) / RAND_MAX;
-        float w = ((float)rand()) / RAND_MAX;
+        float x = ((float)rand()) / (float)RAND_MAX;
+        float y = ((float)rand()) / (float)RAND_MAX;
+        float z = ((float)rand()) / (float)RAND_MAX;
+        float w = ((float)rand()) / (float)RAND_MAX;
         glUniform4f(loc, x, y, z, w);
     }
 }
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index ef1a224..6a7f279 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -82,7 +82,7 @@
 // Check if the "deep touch" feature is on.
 static bool deepPressEnabled() {
     std::string flag_value = server_configurable_flags::GetServerConfigurableFlag(
-            INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true");
+            INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "false");
     std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower);
     if (flag_value == "1" || flag_value == "true") {
         ALOGI("Deep press feature enabled.");
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 2f046c3..683c05d 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -127,10 +127,10 @@
             input_bus_t bus, const char* uniqueId) {
     auto identifier = new ::input_device_identifier {
         .name = name,
-        .productId = productId,
-        .vendorId = vendorId,
-        .bus = bus,
         .uniqueId = uniqueId,
+        .bus = bus,
+        .vendorId = vendorId,
+        .productId = productId,
     };
     // TODO: store this identifier somewhere
     return identifier;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5f07bec..cda982a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -149,9 +149,10 @@
         "Scheduler/LayerHistory.cpp",
         "Scheduler/LayerInfo.cpp",
         "Scheduler/MessageQueue.cpp",
+        "Scheduler/PhaseOffsets.cpp",
         "Scheduler/Scheduler.cpp",
         "Scheduler/SchedulerUtils.cpp",
-        "Scheduler/PhaseOffsets.cpp",
+        "Scheduler/VSyncModulator.cpp",
         "StartPropertySetThread.cpp",
         "SurfaceFlinger.cpp",
         "SurfaceInterceptor.cpp",
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b679380..46a62ed 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -48,7 +48,7 @@
 class BufferLayer : public Layer {
 public:
     explicit BufferLayer(const LayerCreationArgs& args);
-    ~BufferLayer() override;
+    virtual ~BufferLayer() override;
 
     // -----------------------------------------------------------------------
     // Overriden from Layer
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6709fb4..414814a 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -369,6 +369,15 @@
     return mCurrentSurfaceDamage;
 }
 
+void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) {
+    if (damage.bounds() == Rect::INVALID_RECT ||
+        mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) {
+        mCurrentSurfaceDamage = Region::INVALID_REGION;
+    } else {
+        mCurrentSurfaceDamage |= damage;
+    }
+}
+
 int BufferLayerConsumer::getCurrentApi() const {
     Mutex::Autolock lock(mMutex);
     return mCurrentApi;
@@ -485,7 +494,6 @@
         if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
             oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
             mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
-            mRE.cacheExternalTextureBuffer(item.mGraphicBuffer);
         }
     }
 }
@@ -522,6 +530,12 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
+BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
+                                  renderengine::RenderEngine& engine)
+      : mGraphicBuffer(graphicBuffer), mRE(engine) {
+    mRE.cacheExternalTextureBuffer(mGraphicBuffer);
+}
+
 BufferLayerConsumer::Image::~Image() {
     if (mGraphicBuffer != nullptr) {
         ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e3f6100..617b1c2 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -140,6 +140,9 @@
     // must be called from SF main thread
     const Region& getSurfaceDamage() const;
 
+    // Merge the given damage region into the current damage region value.
+    void mergeSurfaceDamage(const Region& damage);
+
     // getCurrentApi retrieves the API which queues the current buffer.
     int getCurrentApi() const;
 
@@ -220,8 +223,7 @@
     // Utility class for managing GraphicBuffer references into renderengine
     class Image {
     public:
-        Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine)
-              : mGraphicBuffer(graphicBuffer), mRE(engine) {}
+        Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine);
         virtual ~Image();
         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ab7b8ba..cbb9d65 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -317,6 +317,7 @@
         // and return early
         if (queuedBuffer) {
             Mutex::Autolock lock(mQueueItemLock);
+            mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
             mQueueItems.removeAt(0);
             mQueuedFrames--;
@@ -352,6 +353,7 @@
         // Remove any stale buffers that have been dropped during
         // updateTexImage
         while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+            mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
             mQueueItems.removeAt(0);
             mQueuedFrames--;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 203bd72..63a07c3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -50,8 +50,12 @@
     mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
     mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
 }
+
 BufferStateLayer::~BufferStateLayer() {
     if (mActiveBuffer != nullptr) {
+        // Ensure that mActiveBuffer is uncached from RenderEngine here, as
+        // RenderEngine may have been using the buffer as an external texture
+        // after the client uncached the buffer.
         auto& engine(mFlinger->getRenderEngine());
         engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
     }
@@ -571,11 +575,6 @@
         return BAD_VALUE;
     }
 
-    if (mActiveBuffer != nullptr) {
-        // todo: get this to work with BufferStateLayerCache
-        auto& engine(mFlinger->getRenderEngine());
-        engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
-    }
     mActiveBuffer = s.buffer;
     mActiveBufferFence = s.acquireFence;
     auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 4e2bc45..97e24cb 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -34,6 +34,7 @@
 class BufferStateLayer : public BufferLayer {
 public:
     explicit BufferStateLayer(const LayerCreationArgs&);
+
     ~BufferStateLayer() override;
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 77f2f57..16fe27c 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -55,16 +55,16 @@
     return true;
 }
 
-void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
+bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
     auto& [processToken, id] = cacheId;
     if (processToken == nullptr) {
         ALOGE("failed to cache buffer: invalid process token");
-        return;
+        return false;
     }
 
     if (!buffer) {
         ALOGE("failed to cache buffer: invalid buffer");
-        return;
+        return false;
     }
 
     std::lock_guard lock(mMutex);
@@ -77,13 +77,13 @@
         token = processToken.promote();
         if (!token) {
             ALOGE("failed to cache buffer: invalid token");
-            return;
+            return false;
         }
 
         status_t err = token->linkToDeath(mDeathRecipient);
         if (err != NO_ERROR) {
             ALOGE("failed to cache buffer: could not link to death");
-            return;
+            return false;
         }
         auto [itr, success] =
                 mBuffers.emplace(processToken, std::unordered_map<uint64_t, ClientCacheBuffer>());
@@ -95,10 +95,11 @@
 
     if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
         ALOGE("failed to cache buffer: cache is full");
-        return;
+        return false;
     }
 
     processBuffers[id].buffer = buffer;
+    return true;
 }
 
 void ClientCache::erase(const client_cache_t& cacheId) {
@@ -139,16 +140,17 @@
     return buf->buffer;
 }
 
-void ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
+bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
                                           const wp<ErasedRecipient>& recipient) {
     std::lock_guard lock(mMutex);
 
     ClientCacheBuffer* buf = nullptr;
     if (!getBuffer(cacheId, &buf)) {
         ALOGE("failed to register erased recipient, could not retrieve buffer");
-        return;
+        return false;
     }
     buf->recipients.insert(recipient);
+    return true;
 }
 
 void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
index 9f057c4..aa6c80d 100644
--- a/services/surfaceflinger/ClientCache.h
+++ b/services/surfaceflinger/ClientCache.h
@@ -36,7 +36,7 @@
 public:
     ClientCache();
 
-    void add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
+    bool add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
     void erase(const client_cache_t& cacheId);
 
     sp<GraphicBuffer> get(const client_cache_t& cacheId);
@@ -48,7 +48,7 @@
         virtual void bufferErased(const client_cache_t& clientCacheId) = 0;
     };
 
-    void registerErasedRecipient(const client_cache_t& cacheId,
+    bool registerErasedRecipient(const client_cache_t& cacheId,
                                  const wp<ErasedRecipient>& recipient);
     void unregisterErasedRecipient(const client_cache_t& cacheId,
                                    const wp<ErasedRecipient>& recipient);
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index cc5a5b5..7f47a2e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -24,6 +24,7 @@
 
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <gui/BufferQueue.h>
+#include <hidl/HidlTransportSupport.h>
 #include <hidl/HidlTransportUtils.h>
 
 namespace android {
@@ -229,6 +230,7 @@
 
 void Composer::registerCallback(const sp<IComposerCallback>& callback)
 {
+    android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
     auto ret = mClient->registerCallback(callback);
     if (!ret.isOk()) {
         ALOGE("failed to register IComposerCallback");
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f4284fe..edbfeb0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2036,6 +2036,13 @@
     return mRemovedFromCurrentState;
 }
 
+// Debug helper for b/137560795
+#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2))
+
+#define RECT_BOUNDS_INVALID(rect)                                               \
+    (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \
+     INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top))
+
 InputWindowInfo Layer::fillInputInfo() {
     InputWindowInfo info = mDrawingState.inputInfo;
 
@@ -2065,6 +2072,26 @@
         layerBounds = getCroppedBufferSize(getDrawingState());
     }
     layerBounds = t.transform(layerBounds);
+
+    // debug check for b/137560795
+    {
+        if (RECT_BOUNDS_INVALID(layerBounds)) {
+            ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32
+                  ")",
+                  mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right,
+                  layerBounds.bottom);
+            std::string out;
+            getTransform().dump(out, "Transform");
+            ALOGE("%s", out.c_str());
+            layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0;
+        }
+
+        if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) {
+            ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(),
+                  int32_t(xSurfaceInset), int32_t(ySurfaceInset));
+            xSurfaceInset = ySurfaceInset = 0;
+        }
+    }
     layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
 
     // Input coordinate should match the layer bounds.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 132b4cf..3b4d873 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,8 +17,6 @@
 #ifndef ANDROID_LAYER_H
 #define ANDROID_LAYER_H
 
-#include <sys/types.h>
-
 #include <compositionengine/LayerFE.h>
 #include <gui/BufferQueue.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -28,6 +26,7 @@
 #include <math/vec4.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/Texture.h>
+#include <sys/types.h>
 #include <ui/FloatRect.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
@@ -44,16 +43,16 @@
 #include <vector>
 
 #include "Client.h"
+#include "ClientCache.h"
+#include "DisplayHardware/ComposerHal.h"
+#include "DisplayHardware/HWComposer.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
+#include "RenderArea.h"
 #include "SurfaceFlinger.h"
 #include "TransactionCompletedThread.h"
 
-#include "DisplayHardware/ComposerHal.h"
-#include "DisplayHardware/HWComposer.h"
-#include "RenderArea.h"
-
 using namespace android::surfaceflinger;
 
 namespace android {
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 66906e9..07fdead 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -44,11 +44,14 @@
 enum class samplingStep {
     noWorkNeeded,
     idleTimerWaiting,
+    waitForQuietFrame,
     waitForZeroPhase,
     waitForSamplePhase,
     sample
 };
 
+constexpr auto timeForRegionSampling = 5000000ns;
+constexpr auto maxRegionSamplingSkips = 10;
 constexpr auto defaultRegionSamplingOffset = -3ms;
 constexpr auto defaultRegionSamplingPeriod = 100ms;
 constexpr auto defaultRegionSamplingTimerTimeout = 100ms;
@@ -215,9 +218,9 @@
 void RegionSamplingThread::checkForStaleLuma() {
     std::lock_guard lock(mThreadControlMutex);
 
-    if (mDiscardedFrames) {
+    if (mDiscardedFrames > 0) {
         ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase));
-        mDiscardedFrames = false;
+        mDiscardedFrames = 0;
         mPhaseCallback->startVsyncListener();
     }
 }
@@ -235,13 +238,25 @@
     auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC));
     if (lastSampleTime + mTunables.mSamplingPeriod > now) {
         ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting));
-        mDiscardedFrames = true;
+        if (mDiscardedFrames == 0) mDiscardedFrames++;
         return;
     }
+    if (mDiscardedFrames < maxRegionSamplingSkips) {
+        // If there is relatively little time left for surfaceflinger
+        // until the next vsync deadline, defer this sampling work
+        // to a later frame, when hopefully there will be more time.
+        DisplayStatInfo stats;
+        mScheduler.getDisplayStatInfo(&stats);
+        if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) {
+            ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForQuietFrame));
+            mDiscardedFrames++;
+            return;
+        }
+    }
 
     ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample));
 
-    mDiscardedFrames = false;
+    mDiscardedFrames = 0;
     lastSampleTime = now;
 
     mIdleTimer.reset();
@@ -258,7 +273,7 @@
 
 namespace {
 // Using Rec. 709 primaries
-float getLuma(float r, float g, float b) {
+inline float getLuma(float r, float g, float b) {
     constexpr auto rec709_red_primary = 0.2126f;
     constexpr auto rec709_green_primary = 0.7152f;
     constexpr auto rec709_blue_primary = 0.0722f;
@@ -293,10 +308,10 @@
         const uint32_t* rowBase = data + row * stride;
         for (int32_t column = area.left; column < area.right; ++column) {
             uint32_t pixel = rowBase[column];
-            const float r = (pixel & 0xFF) / 255.0f;
-            const float g = ((pixel >> 8) & 0xFF) / 255.0f;
-            const float b = ((pixel >> 16) & 0xFF) / 255.0f;
-            const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f);
+            const float r = pixel & 0xFF;
+            const float g = (pixel >> 8) & 0xFF;
+            const float b = (pixel >> 16) & 0xFF;
+            const uint8_t luma = std::round(getLuma(r, g, b));
             ++brightnessBuckets[luma];
             if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f;
         }
@@ -342,9 +357,19 @@
     }
 
     const auto device = mFlinger.getDefaultDisplayDevice();
-    const auto display = device->getCompositionDisplay();
-    const auto state = display->getState();
-    const auto orientation = static_cast<ui::Transform::orientation_flags>(state.orientation);
+    const auto orientation = [](uint32_t orientation) {
+        switch (orientation) {
+            default:
+            case DisplayState::eOrientationDefault:
+                return ui::Transform::ROT_0;
+            case DisplayState::eOrientation90:
+                return ui::Transform::ROT_90;
+            case DisplayState::eOrientation180:
+                return ui::Transform::ROT_180;
+            case DisplayState::eOrientation270:
+                return ui::Transform::ROT_270;
+        }
+    }(device->getOrientation());
 
     std::vector<RegionSamplingThread::Descriptor> descriptors;
     Region sampleRegion;
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 3c6fcf3..96ffe20 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -117,7 +117,7 @@
     std::condition_variable_any mCondition;
     bool mRunning GUARDED_BY(mThreadControlMutex) = true;
     bool mSampleRequested GUARDED_BY(mThreadControlMutex) = false;
-    bool mDiscardedFrames GUARDED_BY(mThreadControlMutex) = false;
+    uint32_t mDiscardedFrames GUARDED_BY(mThreadControlMutex) = 0;
     std::chrono::nanoseconds lastSampleTime GUARDED_BY(mThreadControlMutex);
 
     std::mutex mSamplingMutex;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 95ff9d0..0c94052 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -92,9 +92,12 @@
         mPeriod = period;
         if (!mModelLocked && referenceTimeChanged) {
             for (auto& eventListener : mEventListeners) {
-                eventListener.mHasFired = false;
-                eventListener.mLastEventTime =
-                        mReferenceTime - mPeriod + mPhase + eventListener.mPhase;
+                eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase;
+                // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets
+                // are used) we treat it as like it happened in previous period.
+                if (eventListener.mLastEventTime > mReferenceTime) {
+                    eventListener.mLastEventTime -= mPeriod;
+                }
             }
         }
         if (mTraceDetailedInfo) {
@@ -123,13 +126,6 @@
 
     void unlockModel() {
         Mutex::Autolock lock(mMutex);
-        if (mModelLocked) {
-            for (auto& eventListener : mEventListeners) {
-                if (eventListener.mLastEventTime > mReferenceTime) {
-                    eventListener.mHasFired = true;
-                }
-            }
-        }
         mModelLocked = false;
         ATRACE_INT("DispSync:ModelLocked", mModelLocked);
     }
@@ -259,10 +255,6 @@
             listener.mLastCallbackTime = lastCallbackTime;
         }
 
-        if (!mModelLocked && listener.mLastEventTime > mReferenceTime) {
-            listener.mHasFired = true;
-        }
-
         mEventListeners.push_back(listener);
 
         mCond.signal();
@@ -300,12 +292,8 @@
                 // new offset to allow for a seamless offset change without double-firing or
                 // skipping.
                 nsecs_t diff = oldPhase - phase;
-                if (diff > mPeriod / 2) {
-                    diff -= mPeriod;
-                } else if (diff < -mPeriod / 2) {
-                    diff += mPeriod;
-                }
                 eventListener.mLastEventTime -= diff;
+                eventListener.mLastCallbackTime -= diff;
                 mCond.signal();
                 return NO_ERROR;
             }
@@ -320,7 +308,6 @@
         nsecs_t mLastEventTime;
         nsecs_t mLastCallbackTime;
         DispSync::Callback* mCallback;
-        bool mHasFired = false;
     };
 
     struct CallbackInvocation {
@@ -368,12 +355,7 @@
                           eventListener.mName);
                     continue;
                 }
-                if (eventListener.mHasFired && !mModelLocked) {
-                    eventListener.mLastEventTime = t;
-                    ALOGV("[%s] [%s] Skipping event due to already firing", mName,
-                          eventListener.mName);
-                    continue;
-                }
+
                 CallbackInvocation ci;
                 ci.mCallback = eventListener.mCallback;
                 ci.mEventTime = t;
@@ -382,7 +364,6 @@
                 callbackInvocations.push_back(ci);
                 eventListener.mLastEventTime = t;
                 eventListener.mLastCallbackTime = now;
-                eventListener.mHasFired = true;
             }
         }
 
@@ -687,7 +668,13 @@
         nsecs_t durationSum = 0;
         nsecs_t minDuration = INT64_MAX;
         nsecs_t maxDuration = 0;
-        for (size_t i = 1; i < mNumResyncSamples; i++) {
+        // We skip the first 2 samples because the first vsync duration on some
+        // devices may be much more inaccurate than on other devices, e.g. due
+        // to delays in ramping up from a power collapse. By doing so this
+        // actually increases the accuracy of the DispSync model even though
+        // we're effectively relying on fewer sample points.
+        static constexpr size_t numSamplesSkipped = 2;
+        for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
             size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
             nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
@@ -698,15 +685,14 @@
 
         // Exclude the min and max from the average
         durationSum -= minDuration + maxDuration;
-        mPeriod = durationSum / (mNumResyncSamples - 3);
+        mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2);
 
         ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
 
         double sampleAvgX = 0;
         double sampleAvgY = 0;
         double scale = 2.0 * M_PI / double(mPeriod);
-        // Intentionally skip the first sample
-        for (size_t i = 1; i < mNumResyncSamples; i++) {
+        for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
             nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
             double samplePhase = double(sample % mPeriod) * scale;
@@ -714,8 +700,8 @@
             sampleAvgY += sin(samplePhase);
         }
 
-        sampleAvgX /= double(mNumResyncSamples - 1);
-        sampleAvgY /= double(mNumResyncSamples - 1);
+        sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped);
+        sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped);
 
         mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
 
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 00948ae..5faf46e 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -27,18 +27,23 @@
 
 namespace android {
 
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
+                               nsecs_t offsetThresholdForNextVsync, bool traceVsync,
                                const char* name)
       : mName(name),
         mTraceVsync(traceVsync),
         mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
         mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
+        mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
+        mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
         mDispSync(dispSync),
-        mPhaseOffset(phaseOffset) {}
+        mPhaseOffset(phaseOffset),
+        mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
 
 void DispSyncSource::setVSyncEnabled(bool enable) {
     std::lock_guard lock(mVsyncMutex);
     if (enable) {
+        tracePhaseOffset();
         status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
                                                    static_cast<DispSync::Callback*>(this),
                                                    mLastCallbackTime);
@@ -64,16 +69,21 @@
 
 void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
     std::lock_guard lock(mVsyncMutex);
-
-    // Normalize phaseOffset to [0, period)
-    auto period = mDispSync->getPeriod();
-    phaseOffset %= period;
-    if (phaseOffset < 0) {
-        // If we're here, then phaseOffset is in (-period, 0). After this
-        // operation, it will be in (0, period)
-        phaseOffset += period;
+    const nsecs_t period = mDispSync->getPeriod();
+    // Check if offset should be handled as negative
+    if (phaseOffset >= mOffsetThresholdForNextVsync) {
+        phaseOffset -= period;
     }
+
+    // Normalize phaseOffset to [-period, period)
+    const int numPeriods = phaseOffset / period;
+    phaseOffset -= numPeriods * period;
+    if (mPhaseOffset == phaseOffset) {
+        return;
+    }
+
     mPhaseOffset = phaseOffset;
+    tracePhaseOffset();
 
     // If we're not enabled, we don't need to mess with the listeners
     if (!mEnabled) {
@@ -92,11 +102,11 @@
     {
         std::lock_guard lock(mCallbackMutex);
         callback = mCallback;
+    }
 
-        if (mTraceVsync) {
-            mValue = (mValue + 1) % 2;
-            ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
-        }
+    if (mTraceVsync) {
+        mValue = (mValue + 1) % 2;
+        ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
     }
 
     if (callback != nullptr) {
@@ -104,4 +114,14 @@
     }
 }
 
-} // namespace android
\ No newline at end of file
+void DispSyncSource::tracePhaseOffset() {
+    if (mPhaseOffset > 0) {
+        ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
+        ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
+    } else {
+        ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
+        ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 4759699..50560a5 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -25,7 +25,8 @@
 
 class DispSyncSource final : public VSyncSource, private DispSync::Callback {
 public:
-    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync,
+                   bool traceVsync, const char* name);
 
     ~DispSyncSource() override = default;
 
@@ -38,12 +39,16 @@
     // The following method is the implementation of the DispSync::Callback.
     virtual void onDispSyncEvent(nsecs_t when);
 
+    void tracePhaseOffset() REQUIRES(mVsyncMutex);
+
     const char* const mName;
     int mValue = 0;
 
     const bool mTraceVsync;
     const std::string mVsyncOnLabel;
     const std::string mVsyncEventLabel;
+    const std::string mVsyncOffsetLabel;
+    const std::string mVsyncNegativeOffsetLabel;
     nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
 
     DispSync* mDispSync;
@@ -53,7 +58,8 @@
 
     std::mutex mVsyncMutex;
     nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+    const nsecs_t mOffsetThresholdForNextVsync;
     bool mEnabled GUARDED_BY(mVsyncMutex) = false;
 };
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 05bad4d..9d1f777 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -76,6 +76,10 @@
             return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
                                 ", count=%u}",
                                 event.header.displayId, event.vsync.count);
+        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+            return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+                                ", configId=%u}",
+                                event.header.displayId, event.config.configId);
         default:
             return "Event{}";
     }
@@ -107,8 +111,10 @@
 } // namespace
 
 EventThreadConnection::EventThreadConnection(EventThread* eventThread,
-                                             ResyncCallback resyncCallback)
+                                             ResyncCallback resyncCallback,
+                                             ISurfaceComposer::ConfigChanged configChanged)
       : resyncCallback(std::move(resyncCallback)),
+        configChanged(configChanged),
         mEventThread(eventThread),
         mChannel(gui::BitTube::DefaultSize) {}
 
@@ -203,8 +209,10 @@
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
-sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
-    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
+sp<EventThreadConnection> EventThread::createEventConnection(
+        ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
+    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
+                                     configChanged);
 }
 
 status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -398,9 +406,11 @@
                                      const sp<EventThreadConnection>& connection) const {
     switch (event.header.type) {
         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
-        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
             return true;
 
+        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+            return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch;
+
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
             switch (connection->vsyncRequest) {
                 case VSyncRequest::None:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 61530c6..dd23b88 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -69,7 +69,8 @@
 
 class EventThreadConnection : public BnDisplayEventConnection {
 public:
-    EventThreadConnection(EventThread*, ResyncCallback);
+    EventThreadConnection(EventThread*, ResyncCallback,
+                          ISurfaceComposer::ConfigChanged configChanged);
     virtual ~EventThreadConnection();
 
     virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -82,6 +83,7 @@
     const ResyncCallback resyncCallback;
 
     VSyncRequest vsyncRequest = VSyncRequest::None;
+    const ISurfaceComposer::ConfigChanged configChanged;
 
 private:
     virtual void onFirstRef();
@@ -93,7 +95,8 @@
 public:
     virtual ~EventThread();
 
-    virtual sp<EventThreadConnection> createEventConnection(ResyncCallback) const = 0;
+    virtual sp<EventThreadConnection> createEventConnection(
+            ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0;
 
     // called before the screen is turned off from main thread
     virtual void onScreenReleased() = 0;
@@ -128,7 +131,8 @@
     EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
     ~EventThread();
 
-    sp<EventThreadConnection> createEventConnection(ResyncCallback) const override;
+    sp<EventThreadConnection> createEventConnection(
+            ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override;
 
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 1db43a3..f80c233 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -46,11 +46,13 @@
 LayerHistory::~LayerHistory() = default;
 
 std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name,
+                                                                     float minRefreshRate,
                                                                      float maxRefreshRate) {
     const int64_t id = sNextId++;
 
     std::lock_guard lock(mLock);
-    mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate));
+    mInactiveLayerInfos.emplace(id,
+                                std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate));
     return std::make_unique<LayerHistory::LayerHandle>(*this, id);
 }
 
@@ -173,5 +175,18 @@
     }
 }
 
+void LayerHistory::clearHistory() {
+    std::lock_guard lock(mLock);
+
+    auto it = mActiveLayerInfos.begin();
+    while (it != mActiveLayerInfos.end()) {
+        auto id = it->first;
+        auto layerInfo = it->second;
+        layerInfo->clearHistory();
+        mInactiveLayerInfos.insert({id, layerInfo});
+        it = mActiveLayerInfos.erase(it);
+    }
+}
+
 } // namespace scheduler
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index adc5ce5..5598cc1 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -53,7 +53,8 @@
     ~LayerHistory();
 
     // When the layer is first created, register it.
-    std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate);
+    std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate,
+                                             float maxRefreshRate);
 
     // Method for inserting layers and their requested present time into the unordered map.
     void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr);
@@ -64,6 +65,9 @@
     // layers. See go/content-fps-detection-in-scheduler for more information.
     std::pair<float, bool> getDesiredRefreshRateAndHDR();
 
+    // Clears all layer history.
+    void clearHistory();
+
     // Removes the handle and the object from the map.
     void destroyLayer(const int64_t id);
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 95d7d31..723d71f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -24,9 +24,10 @@
 namespace android {
 namespace scheduler {
 
-LayerInfo::LayerInfo(const std::string name, float maxRefreshRate)
+LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate)
       : mName(name),
         mMinRefreshDuration(1e9f / maxRefreshRate),
+        mLowActivityRefreshDuration(1e9f / minRefreshRate),
         mRefreshRateHistory(mMinRefreshDuration) {}
 
 LayerInfo::~LayerInfo() = default;
@@ -38,12 +39,19 @@
     mLastUpdatedTime = std::max(lastPresentTime, systemTime());
     mPresentTimeHistory.insertPresentTime(mLastUpdatedTime);
 
+    if (mLastPresentTime == 0) {
+        // First frame
+        mLastPresentTime = lastPresentTime;
+        return;
+    }
+
     const nsecs_t timeDiff = lastPresentTime - mLastPresentTime;
     mLastPresentTime = lastPresentTime;
     // Ignore time diff that are too high - those are stale values
-    if (timeDiff > TIME_EPSILON_NS.count()) return;
-    const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
-    mRefreshRateHistory.insertRefreshRate(refreshDuration);
+    if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
+    const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration);
+    const int fps = 1e9f / refreshDuration;
+    mRefreshRateHistory.insertRefreshRate(fps);
 }
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 02b6aef..a733781 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -46,7 +46,7 @@
     public:
         explicit RefreshRateHistory(nsecs_t minRefreshDuration)
               : mMinRefreshDuration(minRefreshDuration) {}
-        void insertRefreshRate(nsecs_t refreshRate) {
+        void insertRefreshRate(int refreshRate) {
             mElements.push_back(refreshRate);
             if (mElements.size() > HISTORY_SIZE) {
                 mElements.pop_front();
@@ -54,13 +54,13 @@
         }
 
         float getRefreshRateAvg() const {
-            nsecs_t refreshDuration = mMinRefreshDuration;
-            if (mElements.size() == HISTORY_SIZE) {
-                refreshDuration = scheduler::calculate_mean(mElements);
+            if (mElements.empty()) {
+                return 1e9f / mMinRefreshDuration;
             }
 
-            return 1e9f / refreshDuration;
+            return scheduler::calculate_mean(mElements);
         }
+
         void clearHistory() { mElements.clear(); }
 
     private:
@@ -86,13 +86,42 @@
         // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
         // certain threshold: TIME_EPSILON_NS.
         bool isRelevant() const {
-            const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count();
-            // The layer had to publish at least HISTORY_SIZE of updates, and the first
-            // update should not be older than TIME_EPSILON_NS nanoseconds.
-            if (mElements.size() == HISTORY_SIZE &&
-                mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) {
+            if (mElements.size() < 2) {
+                return false;
+            }
+
+            // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
+            if (mElements.size() != HISTORY_SIZE &&
+                mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
+                return false;
+            }
+
+            // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
+            const int64_t obsoleteEpsilon =
+                    systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
+            if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
+                return false;
+            }
+
+            return true;
+        }
+
+        bool isLowActivityLayer() const {
+            // We want to make sure that we received more than two frames from the layer
+            // in order to check low activity.
+            if (mElements.size() < 2) {
+                return false;
+            }
+
+            const int64_t obsoleteEpsilon =
+                    systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
+            // Check the frame before last to determine whether there is low activity.
+            // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
+            // infrequent updates.
+            if (mElements.at(mElements.size() - 2) < obsoleteEpsilon) {
                 return true;
             }
+
             return false;
         }
 
@@ -100,11 +129,12 @@
 
     private:
         std::deque<nsecs_t> mElements;
-        static constexpr size_t HISTORY_SIZE = 10;
+        static constexpr size_t HISTORY_SIZE = 90;
+        static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
     };
 
 public:
-    LayerInfo(const std::string name, float maxRefreshRate);
+    LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
     ~LayerInfo();
 
     LayerInfo(const LayerInfo&) = delete;
@@ -134,6 +164,10 @@
     // Calculate the average refresh rate.
     float getDesiredRefreshRate() const {
         std::lock_guard lock(mLock);
+
+        if (mPresentTimeHistory.isLowActivityLayer()) {
+            return 1e9f / mLowActivityRefreshDuration;
+        }
         return mRefreshRateHistory.getRefreshRateAvg();
     }
 
@@ -165,6 +199,7 @@
 private:
     const std::string mName;
     const nsecs_t mMinRefreshDuration;
+    const nsecs_t mLowActivityRefreshDuration;
     mutable std::mutex mLock;
     nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
     nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index baf900d..fcb307f 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -96,7 +96,8 @@
     }
 
     mEventThread = eventThread;
-    mEvents = eventThread->createEventConnection(std::move(resyncCallback));
+    mEvents = eventThread->createEventConnection(std::move(resyncCallback),
+                                                 ISurfaceComposer::eConfigChangedSuppress);
     mEvents->stealReceiveChannel(&mEventTube);
     mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
                    this);
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 276bce1..8a2604f 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -25,6 +25,7 @@
 
 namespace scheduler {
 
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
 PhaseOffsets::~PhaseOffsets() = default;
 
 namespace impl {
@@ -72,25 +73,32 @@
     property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
     const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
 
-    mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
-                                                              : sfVsyncPhaseOffsetNs,
-                                        earlyAppOffsetNs != -1 ? earlyAppOffsetNs
-                                                               : vsyncPhaseOffsetNs};
-    mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
-                                                                  : sfVsyncPhaseOffsetNs,
-                                          earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
-                                                                   : vsyncPhaseOffsetNs};
-    mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+    Offsets defaultOffsets;
+    Offsets highFpsOffsets;
+    defaultOffsets.early = {RefreshRateType::DEFAULT,
+                            earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
+                            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
+    defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
+                              earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
+                              earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
+    defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
 
-    mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
-                                                                  : highFpsLateSfOffsetNs,
-                                     highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
-                                                                   : highFpsLateAppOffsetNs};
-    mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
-                                                                      : highFpsLateSfOffsetNs,
-                                       highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
-                                                                       : highFpsLateAppOffsetNs};
-    mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
+    highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
+                            highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
+                                                         : highFpsLateSfOffsetNs,
+                            highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
+                                                          : highFpsLateAppOffsetNs};
+    highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
+                              highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
+                                                             : highFpsLateSfOffsetNs,
+                              highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
+                                                              : highFpsLateAppOffsetNs};
+    highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
+                           highFpsLateAppOffsetNs};
+
+    mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
+    mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
+    mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
 
     mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
             ? phaseOffsetThresholdForNextVsyncNs
@@ -99,12 +107,7 @@
 
 PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
         android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
-    switch (refreshRateType) {
-        case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
-            return mHighRefreshRateOffsets;
-        default:
-            return mDefaultRefreshRateOffsets;
-    }
+    return mOffsets.at(refreshRateType);
 }
 
 void PhaseOffsets::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index dc71e6e..2b5c2f1 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cinttypes>
+#include <unordered_map>
 
 #include "RefreshRateConfigs.h"
 #include "VSyncModulator.h"
@@ -79,14 +80,10 @@
     void dump(std::string& result) const override;
 
 private:
-    Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
-    Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
-
     std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
             RefreshRateConfigs::RefreshRateType::DEFAULT;
 
-    Offsets mDefaultRefreshRateOffsets;
-    Offsets mHighRefreshRateOffsets;
+    std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
     nsecs_t mOffsetThresholdForNextVsync;
 };
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 1d899df..a194106 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -76,6 +76,7 @@
     mSupportKernelTimer = support_kernel_idle_timer(false);
 
     mSetTouchTimerMs = set_touch_timer_ms(0);
+    mSetDisplayPowerTimerMs = set_display_power_timer_ms(0);
 
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.set_idle_timer_ms", value, "0");
@@ -110,26 +111,40 @@
                                                        [this] { expiredTouchTimerCallback(); });
         mTouchTimer->start();
     }
+
+    if (mSetDisplayPowerTimerMs > 0) {
+        mDisplayPowerTimer =
+                std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
+                                                               mSetDisplayPowerTimerMs),
+                                                       [this] { resetDisplayPowerTimerCallback(); },
+                                                       [this] {
+                                                           expiredDisplayPowerTimerCallback();
+                                                       });
+        mDisplayPowerTimer->start();
+    }
 }
 
 Scheduler::~Scheduler() {
     // Ensure the IdleTimer thread is joined before we start destroying state.
+    mDisplayPowerTimer.reset();
     mTouchTimer.reset();
     mIdleTimer.reset();
 }
 
 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
-        const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+        const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
+        ResyncCallback resyncCallback,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     const int64_t id = sNextId++;
     ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
 
     std::unique_ptr<EventThread> eventThread =
             makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
-                            std::move(interceptCallback));
+                            offsetThresholdForNextVsync, std::move(interceptCallback));
 
     auto eventThreadConnection =
-            createConnectionInternal(eventThread.get(), std::move(resyncCallback));
+            createConnectionInternal(eventThread.get(), std::move(resyncCallback),
+                                     ISurfaceComposer::eConfigChangedSuppress);
     mConnections.emplace(id,
                          std::make_unique<Connection>(new ConnectionHandle(id),
                                                       eventThreadConnection,
@@ -138,24 +153,28 @@
 }
 
 std::unique_ptr<EventThread> Scheduler::makeEventThread(
-        const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+        const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+        nsecs_t offsetThresholdForNextVsync,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     std::unique_ptr<VSyncSource> eventThreadSource =
-            std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+            std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
+                                             true, connectionName);
     return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
                                                std::move(interceptCallback), connectionName);
 }
 
-sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
-                                                              ResyncCallback&& resyncCallback) {
-    return eventThread->createEventConnection(std::move(resyncCallback));
+sp<EventThreadConnection> Scheduler::createConnectionInternal(
+        EventThread* eventThread, ResyncCallback&& resyncCallback,
+        ISurfaceComposer::ConfigChanged configChanged) {
+    return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
 }
 
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
-        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
+        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
+        ISurfaceComposer::ConfigChanged configChanged) {
     RETURN_VALUE_IF_INVALID(nullptr);
     return createConnectionInternal(mConnections[handle->id]->thread.get(),
-                                    std::move(resyncCallback));
+                                    std::move(resyncCallback), configChanged);
 }
 
 EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -324,8 +343,11 @@
             : RefreshRateType::PERFORMANCE;
 
     const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
-    const uint32_t fps = (refreshRate) ? refreshRate->fps : 0;
-    return mLayerHistory.createLayer(name, fps);
+    const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
+
+    const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
+    const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
+    return mLayerHistory.createLayer(name, defaultFps, performanceFps);
 }
 
 void Scheduler::addLayerPresentTimeAndHDR(
@@ -371,11 +393,17 @@
 }
 
 void Scheduler::setChangeRefreshRateCallback(
-        const ChangeRefreshRateCallback& changeRefreshRateCallback) {
+        const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
     std::lock_guard<std::mutex> lock(mCallbackLock);
     mChangeRefreshRateCallback = changeRefreshRateCallback;
 }
 
+void Scheduler::setGetCurrentRefreshRateTypeCallback(
+        const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
+}
+
 void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
     std::lock_guard<std::mutex> lock(mCallbackLock);
     mGetVsyncPeriod = getVsyncPeriod;
@@ -404,43 +432,81 @@
     if (mSupportKernelTimer) {
         resetIdleTimer();
     }
+
+    // Touch event will boost the refresh rate to performance.
+    // Clear Layer History to get fresh FPS detection
+    mLayerHistory.clearHistory();
+}
+
+void Scheduler::setDisplayPowerState(bool normal) {
+    {
+        std::lock_guard<std::mutex> lock(mFeatureStateLock);
+        mIsDisplayPowerStateNormal = normal;
+    }
+
+    if (mDisplayPowerTimer) {
+        mDisplayPowerTimer->reset();
+    }
+
+    // Display Power event will boost the refresh rate to performance.
+    // Clear Layer History to get fresh FPS detection
+    mLayerHistory.clearHistory();
 }
 
 void Scheduler::resetTimerCallback() {
-    timerChangeRefreshRate(IdleTimerState::RESET);
+    handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false);
     ATRACE_INT("ExpiredIdleTimer", 0);
 }
 
 void Scheduler::resetKernelTimerCallback() {
     ATRACE_INT("ExpiredKernelIdleTimer", 0);
     std::lock_guard<std::mutex> lock(mCallbackLock);
-    if (mGetVsyncPeriod) {
-        resyncToHardwareVsync(true, mGetVsyncPeriod());
+    if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
+        // If we're not in performance mode then the kernel timer shouldn't do
+        // anything, as the refresh rate during DPU power collapse will be the
+        // same.
+        if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
+            resyncToHardwareVsync(true, mGetVsyncPeriod());
+        }
     }
 }
 
 void Scheduler::expiredTimerCallback() {
-    timerChangeRefreshRate(IdleTimerState::EXPIRED);
+    handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false);
     ATRACE_INT("ExpiredIdleTimer", 1);
 }
 
 void Scheduler::resetTouchTimerCallback() {
-    // We do not notify the applications about config changes when idle timer is reset.
-    touchChangeRefreshRate(TouchState::ACTIVE);
+    handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true);
     ATRACE_INT("TouchState", 1);
 }
 
 void Scheduler::expiredTouchTimerCallback() {
-    // We do not notify the applications about config changes when idle timer expires.
-    touchChangeRefreshRate(TouchState::INACTIVE);
+    handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true);
     ATRACE_INT("TouchState", 0);
 }
 
+void Scheduler::resetDisplayPowerTimerCallback() {
+    handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true);
+    ATRACE_INT("ExpiredDisplayPowerTimer", 0);
+}
+
+void Scheduler::expiredDisplayPowerTimerCallback() {
+    handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true);
+    ATRACE_INT("ExpiredDisplayPowerTimer", 1);
+}
+
 void Scheduler::expiredKernelTimerCallback() {
+    std::lock_guard<std::mutex> lock(mCallbackLock);
     ATRACE_INT("ExpiredKernelIdleTimer", 1);
-    // Disable HW Vsync if the timer expired, as we don't need it
-    // enabled if we're not pushing frames.
-    disableHardwareVsync(false);
+    if (mGetCurrentRefreshRateTypeCallback) {
+        if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
+            // Disable HW Vsync if the timer expired, as we don't need it
+            // enabled if we're not pushing frames, and if we're in PERFORMANCE
+            // mode then we'll need to re-update the DispSync model anyways.
+            disableHardwareVsync(false);
+        }
+    }
 }
 
 std::string Scheduler::doDump() {
@@ -450,39 +516,23 @@
     return stream.str();
 }
 
-void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) {
-    RefreshRateType newRefreshRateType;
-    {
-        std::lock_guard<std::mutex> lock(mFeatureStateLock);
-        if (mCurrentIdleTimerState == idleTimerState) {
-            return;
-        }
-        mCurrentIdleTimerState = idleTimerState;
-        newRefreshRateType = calculateRefreshRateType();
-        if (mRefreshRateType == newRefreshRateType) {
-            return;
-        }
-        mRefreshRateType = newRefreshRateType;
-    }
-    changeRefreshRate(newRefreshRateType, ConfigEvent::None);
-}
-
-void Scheduler::touchChangeRefreshRate(TouchState touchState) {
+template <class T>
+void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
     ConfigEvent event = ConfigEvent::None;
     RefreshRateType newRefreshRateType;
     {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
-        if (mCurrentTouchState == touchState) {
+        if (*currentState == newState) {
             return;
         }
-        mCurrentTouchState = touchState;
+        *currentState = newState;
         newRefreshRateType = calculateRefreshRateType();
         if (mRefreshRateType == newRefreshRateType) {
             return;
         }
         mRefreshRateType = newRefreshRateType;
-        // Send an event in case that content detection is on as touch has a higher priority
-        if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
+        if (eventOnContentDetection &&
+            mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
             event = ConfigEvent::Changed;
         }
     }
@@ -495,6 +545,12 @@
         return RefreshRateType::DEFAULT;
     }
 
+    // If Display Power is not in normal operation we want to be in performance mode.
+    // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+    if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) {
+        return RefreshRateType::PERFORMANCE;
+    }
+
     // As long as touch is active we want to be in performance mode
     if (mCurrentTouchState == TouchState::ACTIVE) {
         return RefreshRateType::PERFORMANCE;
@@ -510,22 +566,19 @@
         return RefreshRateType::PERFORMANCE;
     }
 
-    // Content detection is on, find the appropriate refresh rate
-    // Start with the smallest refresh rate which is within a margin of the content
-    RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE;
-    constexpr float MARGIN = 0.05f;
-    auto iter = mRefreshRateConfigs.getRefreshRates().cbegin();
-    while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
-        if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) {
-            currRefreshRateType = iter->first;
-            break;
-        }
-        ++iter;
-    }
+    // Content detection is on, find the appropriate refresh rate with minimal error
+    auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
+                            mRefreshRateConfigs.getRefreshRates().cend(),
+                            [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
+                                return std::abs(l.second->fps - static_cast<float>(rate)) <
+                                        std::abs(r.second->fps - static_cast<float>(rate));
+                            });
+    RefreshRateType currRefreshRateType = iter->first;
 
     // Some content aligns better on higher refresh rate. For example for 45fps we should choose
     // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
     // align well with both
+    constexpr float MARGIN = 0.05f;
     float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
             float(mContentRefreshRate);
     if (std::abs(std::round(ratio) - ratio) > MARGIN) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a32bd41..5d8bb4c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -49,6 +49,7 @@
     }
 
     using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+    using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>;
     using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
     using GetVsyncPeriod = std::function<nsecs_t()>;
 
@@ -96,12 +97,13 @@
     virtual ~Scheduler();
 
     /** Creates an EventThread connection. */
-    sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
-                                          ResyncCallback,
+    sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+                                          nsecs_t offsetThresholdForNextVsync, ResyncCallback,
                                           impl::EventThread::InterceptVSyncsCallback);
 
-    sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
-                                                             ResyncCallback);
+    sp<IDisplayEventConnection> createDisplayEventConnection(
+            const sp<ConnectionHandle>& handle, ResyncCallback,
+            ISurfaceComposer::ConfigChanged configChanged);
 
     // Getter methods.
     EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -164,7 +166,9 @@
     // Updates FPS based on the most content presented.
     void updateFpsBasedOnContent();
     // Callback that gets invoked when Scheduler wants to change the refresh rate.
-    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
+    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback);
+    void setGetCurrentRefreshRateTypeCallback(
+            const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType);
     void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod);
 
     // Returns whether idle timer is enabled or not
@@ -176,6 +180,9 @@
     // Function that resets the touch timer.
     void notifyTouchEvent();
 
+    // Function that sets whether display power mode is normal or not.
+    void setDisplayPowerState(bool normal);
+
     // Returns relevant information about Scheduler for dumpsys purposes.
     std::string doDump();
 
@@ -184,7 +191,8 @@
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
-            const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+            const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+            nsecs_t offsetThresholdForNextVsync,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
 private:
@@ -195,9 +203,11 @@
     enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
     enum class IdleTimerState { EXPIRED, RESET };
     enum class TouchState { INACTIVE, ACTIVE };
+    enum class DisplayPowerTimerState { EXPIRED, RESET };
 
     // Creates a connection on the given EventThread and forwards the given callbacks.
-    sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
+    sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+                                                       ISurfaceComposer::ConfigChanged);
 
     nsecs_t calculateAverage() const;
     void updateFrameSkipping(const int64_t skipCount);
@@ -218,12 +228,15 @@
     void resetTouchTimerCallback();
     // Function that is called when the touch timer expires.
     void expiredTouchTimerCallback();
+    // Function that is called when the display power timer resets.
+    void resetDisplayPowerTimerCallback();
+    // Function that is called when the display power timer expires.
+    void expiredDisplayPowerTimerCallback();
     // Sets vsync period.
     void setVsyncPeriod(const nsecs_t period);
-    // Idle timer feature's function to change the refresh rate.
-    void timerChangeRefreshRate(IdleTimerState idleTimerState);
-    // Touch timer feature's function to change the refresh rate.
-    void touchChangeRefreshRate(TouchState touchState);
+    // handles various timer features to change the refresh rate.
+    template <class T>
+    void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
     // Calculate the new refresh rate type
     RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
     // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
@@ -279,7 +292,12 @@
     int64_t mSetTouchTimerMs = 0;
     std::unique_ptr<scheduler::IdleTimer> mTouchTimer;
 
+    // Timer used to monitor display power mode.
+    int64_t mSetDisplayPowerTimerMs = 0;
+    std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer;
+
     std::mutex mCallbackLock;
+    GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock);
     ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
     GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock);
 
@@ -290,14 +308,17 @@
             ContentFeatureState::CONTENT_DETECTION_OFF;
     IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
     TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE;
+    DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) =
+            DisplayPowerTimerState::EXPIRED;
     uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
     RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
     bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
+    bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true;
 
     const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
 
     // Global config to force HDR content to work on DEFAULT refreshRate
-    static constexpr bool mForceHDRContentToDefaultRefreshRate = true;
+    static constexpr bool mForceHDRContentToDefaultRefreshRate = false;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 3bf3922..ced1899 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -36,13 +36,16 @@
 static constexpr int SCREEN_OFF_CONFIG_ID = -1;
 static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff;
 
-// This number is used when we try to determine how long does a given layer stay relevant.
-// Currently it is set to 100ms, because that would indicate 10Hz rendering.
-static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms;
-
 // This number is used when we try to determine how long do we keep layer information around
-// before we remove it. Currently it is set to 100ms.
-static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms;
+// before we remove it. It is also used to determine how long the layer stays relevant.
+// This time period captures infrequent updates when playing YouTube video with static image,
+// or waiting idle in messaging app, when cursor is blinking.
+static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms;
+
+// Layer is considered low activity if the buffers come more than LOW_ACTIVITY_EPSILON_NS
+// apart. This is helping SF to vote for lower refresh rates when there is not activity
+// in screen.
+static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms;
 
 // Calculates the statistical mean (average) in the data structure (array, vector). The
 // function does not modify the contents of the array.
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
new file mode 100644
index 0000000..7a3bf8e
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "VSyncModulator.h"
+
+#include <cutils/properties.h>
+#include <utils/Trace.h>
+
+#include <cinttypes>
+#include <mutex>
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+VSyncModulator::VSyncModulator() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.vsync_trace_detailed_info", value, "0");
+    mTraceDetailedInfo = atoi(value);
+    // Populate the offset map with some default offsets.
+    const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
+    setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
+}
+
+void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
+                                     nsecs_t thresholdForNextVsync) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mOffsetMap.insert_or_assign(OffsetType::Early, early);
+    mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
+    mOffsetMap.insert_or_assign(OffsetType::Late, late);
+    mThresholdForNextVsync = thresholdForNextVsync;
+    updateOffsetsLocked();
+}
+
+void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
+    if (transactionStart == Scheduler::TransactionStart::EARLY) {
+        mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
+    }
+
+    // An early transaction stays an early transaction.
+    if (transactionStart == mTransactionStart ||
+        mTransactionStart == Scheduler::TransactionStart::EARLY) {
+        return;
+    }
+    mTransactionStart = transactionStart;
+    updateOffsets();
+}
+
+void VSyncModulator::onTransactionHandled() {
+    if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
+    mTransactionStart = Scheduler::TransactionStart::NORMAL;
+    updateOffsets();
+}
+
+void VSyncModulator::onRefreshRateChangeInitiated() {
+    if (mRefreshRateChangePending) {
+        return;
+    }
+    mRefreshRateChangePending = true;
+    updateOffsets();
+}
+
+void VSyncModulator::onRefreshRateChangeCompleted() {
+    if (!mRefreshRateChangePending) {
+        return;
+    }
+    mRefreshRateChangePending = false;
+    updateOffsets();
+}
+
+void VSyncModulator::onRefreshed(bool usedRenderEngine) {
+    bool updateOffsetsNeeded = false;
+    if (mRemainingEarlyFrameCount > 0) {
+        mRemainingEarlyFrameCount--;
+        updateOffsetsNeeded = true;
+    }
+    if (usedRenderEngine) {
+        mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION;
+        updateOffsetsNeeded = true;
+    } else if (mRemainingRenderEngineUsageCount > 0) {
+        mRemainingRenderEngineUsageCount--;
+        updateOffsetsNeeded = true;
+    }
+    if (updateOffsetsNeeded) {
+        updateOffsets();
+    }
+}
+
+VSyncModulator::Offsets VSyncModulator::getOffsets() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mOffsets;
+}
+
+VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
+    return mOffsetMap.at(getNextOffsetType());
+}
+
+VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
+    // Early offsets are used if we're in the middle of a refresh rate
+    // change, or if we recently begin a transaction.
+    if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
+        mRefreshRateChangePending) {
+        return OffsetType::Early;
+    } else if (mRemainingRenderEngineUsageCount > 0) {
+        return OffsetType::EarlyGl;
+    } else {
+        return OffsetType::Late;
+    }
+}
+
+void VSyncModulator::updateOffsets() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    updateOffsetsLocked();
+}
+
+void VSyncModulator::updateOffsetsLocked() {
+    const Offsets desired = getNextOffsets();
+
+    if (mSfConnectionHandle != nullptr) {
+        mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
+    }
+
+    if (mAppConnectionHandle != nullptr) {
+        mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
+    }
+
+    flushOffsets();
+}
+
+void VSyncModulator::flushOffsets() {
+    OffsetType type = getNextOffsetType();
+    mOffsets = mOffsetMap.at(type);
+    if (!mTraceDetailedInfo) {
+        return;
+    }
+    ATRACE_INT("Vsync-EarlyOffsetsOn",
+               mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
+    ATRACE_INT("Vsync-EarlyGLOffsetsOn",
+               mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
+    ATRACE_INT("Vsync-LateOffsetsOn",
+               mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
+    ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
+               mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
+    ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
+               mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
+    ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
+               mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 21dad12..ddbd221 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -16,8 +16,6 @@
 
 #pragma once
 
-#include <utils/Errors.h>
-
 #include <cinttypes>
 #include <mutex>
 
@@ -35,12 +33,28 @@
     // sending new transactions.
     const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
 
+    // Number of frames we'll keep the early gl phase offsets once they are activated.
+    // This acts as a low-pass filter to avoid scenarios where we rapidly
+    // switch in and out of gl composition.
+    const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+
 public:
+    VSyncModulator();
+
+    // Wrapper for a collection of surfaceflinger/app offsets for a particular
+    // configuration .
     struct Offsets {
+        scheduler::RefreshRateConfigs::RefreshRateType fpsMode;
         nsecs_t sf;
         nsecs_t app;
     };
 
+    enum class OffsetType {
+        Early,
+        EarlyGl,
+        Late,
+    };
+
     // Sets the phase offsets
     //
     // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
@@ -51,31 +65,10 @@
     // appEarly: Like sfEarly, but for the app-vsync
     // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
     // appLate: The regular app vsync phase offset.
-    void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
-        mEarlyOffsets = early;
-        mEarlyGlOffsets = earlyGl;
-        mLateOffsets = late;
+    void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
+                         nsecs_t thresholdForNextVsync) EXCLUDES(mMutex);
 
-        if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
-            mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
-        }
-
-        if (mAppConnectionHandle && late.app != mOffsets.load().app) {
-            mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
-        }
-
-        mOffsets = late;
-    }
-
-    Offsets getEarlyOffsets() const { return mEarlyOffsets; }
-
-    Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; }
-
-    void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
-        mSfEventThread = sfEventThread;
-        mAppEventThread = appEventThread;
-    }
-
+    // Sets the scheduler and vsync connection handlers.
     void setSchedulerAndHandles(Scheduler* scheduler,
                                 Scheduler::ConnectionHandle* appConnectionHandle,
                                 Scheduler::ConnectionHandle* sfConnectionHandle) {
@@ -84,120 +77,57 @@
         mSfConnectionHandle = sfConnectionHandle;
     }
 
-    void setTransactionStart(Scheduler::TransactionStart transactionStart) {
-        if (transactionStart == Scheduler::TransactionStart::EARLY) {
-            mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
-        }
+    // Signals that a transaction has started, and changes offsets accordingly.
+    void setTransactionStart(Scheduler::TransactionStart transactionStart);
 
-        // An early transaction stays an early transaction.
-        if (transactionStart == mTransactionStart ||
-            mTransactionStart == Scheduler::TransactionStart::EARLY) {
-            return;
-        }
-        mTransactionStart = transactionStart;
-        updateOffsets();
-    }
-
-    void onTransactionHandled() {
-        if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
-        mTransactionStart = Scheduler::TransactionStart::NORMAL;
-        updateOffsets();
-    }
+    // Signals that a transaction has been completed, so that we can finish
+    // special handling for a transaction.
+    void onTransactionHandled();
 
     // Called when we send a refresh rate change to hardware composer, so that
     // we can move into early offsets.
-    void onRefreshRateChangeInitiated() {
-        if (mRefreshRateChangePending) {
-            return;
-        }
-        mRefreshRateChangePending = true;
-        updateOffsets();
-    }
+    void onRefreshRateChangeInitiated();
 
     // Called when we detect from vsync signals that the refresh rate changed.
     // This way we can move out of early offsets if no longer necessary.
-    void onRefreshRateChangeCompleted() {
-        if (!mRefreshRateChangePending) {
-            return;
-        }
-        mRefreshRateChangePending = false;
-        updateOffsets();
-    }
+    void onRefreshRateChangeCompleted();
 
-    void onRefreshed(bool usedRenderEngine) {
-        bool updateOffsetsNeeded = false;
-        if (mRemainingEarlyFrameCount > 0) {
-            mRemainingEarlyFrameCount--;
-            updateOffsetsNeeded = true;
-        }
-        if (usedRenderEngine != mLastFrameUsedRenderEngine) {
-            mLastFrameUsedRenderEngine = usedRenderEngine;
-            updateOffsetsNeeded = true;
-        }
-        if (updateOffsetsNeeded) {
-            updateOffsets();
-        }
-    }
+    // Called when the display is presenting a new frame. usedRenderEngine
+    // should be set to true if RenderEngine was involved with composing the new
+    // frame.
+    void onRefreshed(bool usedRenderEngine);
 
-    Offsets getOffsets() {
-        // Early offsets are used if we're in the middle of a refresh rate
-        // change, or if we recently begin a transaction.
-        if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
-            mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
-            return mEarlyOffsets;
-        } else if (mLastFrameUsedRenderEngine) {
-            return mEarlyGlOffsets;
-        } else {
-            return mLateOffsets;
-        }
-    }
+    // Returns the offsets that we are currently using
+    Offsets getOffsets() EXCLUDES(mMutex);
 
 private:
-    void updateOffsets() {
-        const Offsets desired = getOffsets();
-        const Offsets current = mOffsets;
+    // Returns the next offsets that we should be using
+    Offsets getNextOffsets() REQUIRES(mMutex);
+    // Returns the next offset type that we should use.
+    OffsetType getNextOffsetType();
+    // Updates offsets and persists them into the scheduler framework.
+    void updateOffsets() EXCLUDES(mMutex);
+    void updateOffsetsLocked() REQUIRES(mMutex);
+    // Updates the internal offsets and offset type.
+    void flushOffsets() REQUIRES(mMutex);
 
-        bool changed = false;
-        if (desired.sf != current.sf) {
-            if (mSfConnectionHandle != nullptr) {
-                mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
-            } else {
-                mSfEventThread->setPhaseOffset(desired.sf);
-            }
-            changed = true;
-        }
-        if (desired.app != current.app) {
-            if (mAppConnectionHandle != nullptr) {
-                mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
-            } else {
-                mAppEventThread->setPhaseOffset(desired.app);
-            }
-            changed = true;
-        }
-
-        if (changed) {
-            mOffsets = desired;
-        }
-    }
-
-    Offsets mLateOffsets;
-    Offsets mEarlyOffsets;
-    Offsets mEarlyGlOffsets;
-
-    EventThread* mSfEventThread = nullptr;
-    EventThread* mAppEventThread = nullptr;
+    mutable std::mutex mMutex;
+    std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex);
+    nsecs_t mThresholdForNextVsync;
 
     Scheduler* mScheduler = nullptr;
     Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
     Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
 
-    std::atomic<Offsets> mOffsets;
+    Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0};
 
     std::atomic<Scheduler::TransactionStart> mTransactionStart =
             Scheduler::TransactionStart::NORMAL;
-    std::atomic<bool> mLastFrameUsedRenderEngine = false;
     std::atomic<bool> mRefreshRateChangePending = false;
     std::atomic<int> mRemainingEarlyFrameCount = 0;
+    std::atomic<int> mRemainingRenderEngineUsageCount = 0;
+
+    bool mTraceDetailedInfo = false;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a15cf4a..3057ed1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -48,6 +48,8 @@
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <dvr/vr_flinger.h>
 #include <gui/BufferQueue.h>
+#include <gui/DebugEGLImageTracker.h>
+
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IProducerListener.h>
@@ -311,6 +313,9 @@
     wideColorGamutCompositionPixelFormat =
             static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888));
 
+    mColorSpaceAgnosticDataspace =
+            static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN));
+
     useContextPriority = use_context_priority(true);
 
     auto tmpPrimaryDisplayOrientation = primary_display_orientation(
@@ -382,7 +387,8 @@
     mLumaSampling = atoi(value);
 
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
-    mVsyncModulator.setPhaseOffsets(early, gl, late);
+    mVsyncModulator.setPhaseOffsets(early, gl, late,
+                                    mPhaseOffsets->getOffsetThresholdForNextVsync());
 
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
@@ -621,13 +627,16 @@
             mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
 
     mAppConnectionHandle =
-            mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+            mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+                                         mPhaseOffsets->getOffsetThresholdForNextVsync(),
                                          resyncCallback,
                                          impl::EventThread::InterceptVSyncsCallback());
-    mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
-                                                       resyncCallback, [this](nsecs_t timestamp) {
-                                                           mInterceptor->saveVSyncEvent(timestamp);
-                                                       });
+    mSfConnectionHandle =
+            mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+                                         mPhaseOffsets->getOffsetThresholdForNextVsync(),
+                                         resyncCallback, [this](nsecs_t timestamp) {
+                                             mInterceptor->saveVSyncEvent(timestamp);
+                                         });
 
     mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
     mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
@@ -711,6 +720,24 @@
                 Mutex::Autolock lock(mStateLock);
                 setRefreshRateTo(type, event);
             });
+    mScheduler->setGetCurrentRefreshRateTypeCallback([this] {
+        Mutex::Autolock lock(mStateLock);
+        const auto display = getDefaultDisplayDeviceLocked();
+        if (!display) {
+            // If we don't have a default display the fallback to the default
+            // refresh rate type
+            return RefreshRateType::DEFAULT;
+        }
+
+        const int configId = display->getActiveConfig();
+        for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) {
+            if (refresh && refresh->configId == configId) {
+                return type;
+            }
+        }
+        // This should never happen, but just gracefully fallback to default.
+        return RefreshRateType::DEFAULT;
+    });
     mScheduler->setGetVsyncPeriodCallback([this] {
         Mutex::Autolock lock(mStateLock);
         return getVsyncPeriod();
@@ -940,15 +967,13 @@
         // Start receiving vsync samples now, so that we can detect a period
         // switch.
         mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
-        // We should only move to early offsets when we know that the refresh
-        // rate will change. Otherwise, we may be stuck in early offsets
-        // forever, as onRefreshRateChangeDetected will not be called.
-        if (mDesiredActiveConfig.event == Scheduler::ConfigEvent::Changed) {
-            mVsyncModulator.onRefreshRateChangeInitiated();
-        }
+        // As we called to set period, we will call to onRefreshRateChangeCompleted once
+        // DispSync model is locked.
+        mVsyncModulator.onRefreshRateChangeInitiated();
         mPhaseOffsets->setRefreshRateType(info.type);
         const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
-        mVsyncModulator.setPhaseOffsets(early, gl, late);
+        mVsyncModulator.setPhaseOffsets(early, gl, late,
+                                        mPhaseOffsets->getOffsetThresholdForNextVsync());
     }
     mDesiredActiveConfigChanged = true;
     ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
@@ -980,10 +1005,10 @@
 
     display->setActiveConfig(mUpcomingActiveConfig.configId);
 
-    mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
     mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
-    mVsyncModulator.setPhaseOffsets(early, gl, late);
+    mVsyncModulator.setPhaseOffsets(early, gl, late,
+                                    mPhaseOffsets->getOffsetThresholdForNextVsync());
     ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
 
     if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -992,6 +1017,19 @@
     }
 }
 
+void SurfaceFlinger::desiredActiveConfigChangeDone() {
+    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+    mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
+    mDesiredActiveConfigChanged = false;
+    ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+
+    mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+    mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
+    const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+    mVsyncModulator.setPhaseOffsets(early, gl, late,
+                                    mPhaseOffsets->getOffsetThresholdForNextVsync());
+}
+
 bool SurfaceFlinger::performSetActiveConfig() {
     ATRACE_CALL();
     if (mCheckPendingFence) {
@@ -1021,14 +1059,7 @@
     if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
         // display is not valid or we are already in the requested mode
         // on both cases there is nothing left to do
-        std::lock_guard<std::mutex> lock(mActiveConfigLock);
-        mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
-        mDesiredActiveConfigChanged = false;
-        // Update scheduler with the correct vsync period as a no-op.
-        // Otherwise, there exists a race condition where we get stuck in the
-        // incorrect vsync period.
-        mScheduler->resyncToHardwareVsync(false, getVsyncPeriod());
-        ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+        desiredActiveConfigChangeDone();
         return false;
     }
 
@@ -1036,17 +1067,10 @@
     // allowed configs might have change by the time we process the refresh.
     // Make sure the desired config is still allowed
     if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) {
-        std::lock_guard<std::mutex> lock(mActiveConfigLock);
-        mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
-        mDesiredActiveConfig.configId = display->getActiveConfig();
-        mDesiredActiveConfigChanged = false;
-        // Update scheduler with the current vsync period as a no-op.
-        // Otherwise, there exists a race condition where we get stuck in the
-        // incorrect vsync period.
-        mScheduler->resyncToHardwareVsync(false, getVsyncPeriod());
-        ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+        desiredActiveConfigChangeDone();
         return false;
     }
+
     mUpcomingActiveConfig = desiredActiveConfig;
     const auto displayId = display->getId();
     LOG_ALWAYS_FATAL_IF(!displayId);
@@ -1384,7 +1408,7 @@
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
-        ISurfaceComposer::VsyncSource vsyncSource) {
+        ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
     auto resyncCallback = mScheduler->makeResyncCallback([this] {
         Mutex::Autolock lock(mStateLock);
         return getVsyncPeriod();
@@ -1393,7 +1417,8 @@
     const auto& handle =
             vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
 
-    return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
+    return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
+                                                    configChanged);
 }
 
 // ----------------------------------------------------------------------------
@@ -1542,10 +1567,23 @@
 
 void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mStateLock);
+
+    // Enable / Disable HWVsync from the main thread to avoid race conditions with
+    // display power state.
+    postMessageAsync(new LambdaMessage(
+            [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
+}
+
+void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
+    ATRACE_CALL();
+
+    mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable;
+
     if (const auto displayId = getInternalDisplayIdLocked()) {
-        getHwComposer().setVsyncEnabled(*displayId,
-                                        enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+        sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
+        if (display && display->isPoweredOn()) {
+            setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+        }
     }
 }
 
@@ -1655,22 +1693,26 @@
     return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
 }
 
-nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::populateExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
     DisplayStatInfo stats;
     mScheduler->getDisplayStatInfo(&stats);
     const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
     // Inflate the expected present time if we're targetting the next vsync.
-    const nsecs_t correctedTime =
+    mExpectedPresentTime =
             mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
             ? presentTime
             : presentTime + stats.vsyncPeriod;
-    return correctedTime;
 }
 
 void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
+            // calculate the expected present time once and use the cached
+            // value throughout this frame to make sure all layers are
+            // seeing this same value.
+            populateExpectedPresentTime();
+
             bool frameMissed = previousFrameMissed();
             bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
             bool gpuFrameMissed = mHadClientComposition && frameMissed;
@@ -1873,7 +1915,14 @@
             RenderIntent renderIntent;
             pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
             display->setColorMode(colorMode, targetDataspace, renderIntent);
+
+            if (isHdrColorMode(colorMode)) {
+                targetDataspace = Dataspace::UNKNOWN;
+            } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) {
+                targetDataspace = mColorSpaceAgnosticDataspace;
+            }
         }
+
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
                 layer->forceClientComposition(displayDevice);
@@ -1900,9 +1949,7 @@
 
             const auto& displayState = display->getState();
             layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
-                                   displayDevice->getSupportedPerFrameMetadata(),
-                                   isHdrColorMode(displayState.colorMode) ? Dataspace::UNKNOWN
-                                                                          : targetDataspace);
+                                   displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
         }
     }
 
@@ -3798,6 +3845,7 @@
 
     if (uncacheBuffer.isValid()) {
         ClientCache::getInstance().erase(uncacheBuffer);
+        getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id);
     }
 
     // If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -4152,9 +4200,18 @@
     bool bufferChanged = what & layer_state_t::eBufferChanged;
     bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
     sp<GraphicBuffer> buffer;
-    if (bufferChanged && cacheIdChanged) {
-        ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+    if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
         buffer = s.buffer;
+        bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+        if (success) {
+            getRenderEngine().cacheExternalTextureBuffer(s.buffer);
+            success = ClientCache::getInstance()
+                              .registerErasedRecipient(s.cachedBuffer,
+                                                       wp<ClientCache::ErasedRecipient>(this));
+            if (!success) {
+                getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId());
+            }
+        }
     } else if (cacheIdChanged) {
         buffer = ClientCache::getInstance().get(s.cachedBuffer);
     } else if (bufferChanged) {
@@ -4437,6 +4494,13 @@
             new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
 }
 
+void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) {
+    if (mHWCVsyncState != enabled) {
+        getHwComposer().setVsyncEnabled(displayId, enabled);
+        mHWCVsyncState = enabled;
+    }
+}
+
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
     if (display->isVirtual()) {
         ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4463,6 +4527,7 @@
         // Turn on the display
         getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+            setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
         }
@@ -4488,6 +4553,9 @@
             mScheduler->onScreenReleased(mAppConnectionHandle);
         }
 
+        // Make sure HWVsync is disabled before turning off the display
+        setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable);
+
         getHwComposer().setPowerMode(*displayId, mode);
         mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing on this display
@@ -4514,6 +4582,7 @@
     if (display->isPrimary()) {
         mTimeStats->setPowerMode(mode);
         mRefreshRateStats.setPowerMode(mode);
+        mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL);
     }
 
     ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
@@ -4682,6 +4751,16 @@
     StringAppendF(&result, "Scheduler enabled.");
     StringAppendF(&result, "+  Smart 90 for video detection: %s\n\n",
                   mUseSmart90ForVideo ? "on" : "off");
+    StringAppendF(&result, "Allowed Display Configs: ");
+    for (int32_t configId : mAllowedDisplayConfigs) {
+        for (auto refresh : mRefreshRateConfigs.getRefreshRates()) {
+            if (refresh.second && refresh.second->configId == configId) {
+                StringAppendF(&result, "%dHz, ", refresh.second->fps);
+            }
+        }
+    }
+    StringAppendF(&result, "(config override by backdoor: %s)\n\n",
+                  mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
     mScheduler->dump(mAppConnectionHandle, result);
 }
 
@@ -4964,6 +5043,8 @@
 
     getRenderEngine().dump(result);
 
+    DebugEGLImageTracker::getInstance()->dump(result);
+
     if (const auto display = getDefaultDisplayDeviceLocked()) {
         display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
                                                                           "undefinedRegion");
@@ -5377,7 +5458,12 @@
                 return NO_ERROR;
             }
             case 1023: { // Set native mode
+                int32_t colorMode;
+
                 mDisplayColorSetting = static_cast<DisplayColorSetting>(data.readInt32());
+                if (data.readInt32(&colorMode) == NO_ERROR) {
+                    mForceColorMode = static_cast<ColorMode>(colorMode);
+                }
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
@@ -6173,6 +6259,10 @@
     return nullptr;
 }
 
+void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) {
+    getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 49a048c..8049b61 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -170,9 +170,9 @@
 
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
+                       public ClientCache::ErasedRecipient,
                        private IBinder::DeathRecipient,
-                       private HWC2::ComposerCallback
-{
+                       private HWC2::ComposerCallback {
 public:
     SurfaceFlingerBE& getBE() { return mBE; }
     const SurfaceFlingerBE& getBE() const { return mBE; }
@@ -294,15 +294,19 @@
     // TODO: this should be made accessible only to EventThread
     void setPrimaryVsyncEnabled(bool enabled);
 
+    // main thread function to enable/disable h/w composer event
+    void setPrimaryVsyncEnabledInternal(bool enabled);
+
     // called on the main thread by MessageQueue when an internal message
     // is received
     // TODO: this should be made accessible only to MessageQueue
     void onMessageReceived(int32_t what);
 
-    // Returns the expected present time for this frame.
+    // populates the expected present time for this frame.
     // When we are in negative offsets, we perform a correction so that the
     // predicted vsync for the *next* frame is used instead.
-    nsecs_t getExpectedPresentTime();
+    void populateExpectedPresentTime();
+    nsecs_t getExpectedPresentTime() const { return mExpectedPresentTime; }
 
     // for debugging only
     // TODO: this should be made accessible only to HWComposer
@@ -325,6 +329,9 @@
 
     sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
 
+    // Inherit from ClientCache::ErasedRecipient
+    void bufferErased(const client_cache_t& clientCacheId) override;
+
 private:
     friend class BufferLayer;
     friend class BufferQueueLayer;
@@ -405,7 +412,9 @@
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
     status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
     sp<IDisplayEventConnection> createDisplayEventConnection(
-            ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
+            ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
+            ISurfaceComposer::ConfigChanged configChanged =
+                    ISurfaceComposer::eConfigChangedSuppress) override;
     status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
             bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
             const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
@@ -514,13 +523,15 @@
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
     void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
     // Once HWC has returned the present fence, this sets the active config and a new refresh
-    // rate in SF. It also triggers HWC vsync.
+    // rate in SF.
     void setActiveConfigInternal() REQUIRES(mStateLock);
     // Active config is updated on INVALIDATE call in a state machine-like manner. When the
     // desired config was set, HWC needs to update the panel on the next refresh, and when
     // we receive the fence back, we know that the process was complete. It returns whether
     // we need to wait for the next invalidate
     bool performSetActiveConfig() REQUIRES(mStateLock);
+    // Called when active config is no longer is progress
+    void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
     // called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
 
@@ -839,6 +850,7 @@
     }
 
     bool previousFrameMissed();
+    void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
 
     /*
      * Debugging & dumpsys
@@ -1113,6 +1125,7 @@
 
     ui::Dataspace mDefaultCompositionDataspace;
     ui::Dataspace mWideColorGamutCompositionDataspace;
+    ui::Dataspace mColorSpaceAgnosticDataspace;
 
     SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
@@ -1177,6 +1190,12 @@
     // The Layer pointer is removed from the set when the destructor is called so there shouldn't
     // be any issues with a raw pointer referencing an invalid object.
     std::unordered_set<Layer*> mOffscreenLayers;
+
+    // Flags to capture the state of Vsync in HWC
+    HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
+    HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
+
+    nsecs_t mExpectedPresentTime;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 2b33ba1..768074a 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -218,6 +218,14 @@
     return static_cast<int32_t>(defaultValue);
 }
 
+int64_t color_space_agnostic_dataspace(Dataspace defaultValue) {
+    auto temp = SurfaceFlingerProperties::color_space_agnostic_dataspace();
+    if (temp.has_value()) {
+        return *temp;
+    }
+    return static_cast<int64_t>(defaultValue);
+}
+
 int32_t set_idle_timer_ms(int32_t defaultValue) {
     auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
     if (temp.has_value()) {
@@ -234,6 +242,14 @@
     return defaultValue;
 }
 
+int32_t set_display_power_timer_ms(int32_t defaultValue) {
+    auto temp = SurfaceFlingerProperties::set_display_power_timer_ms();
+    if (temp.has_value()) {
+        return *temp;
+    }
+    return defaultValue;
+}
+
 bool use_smart_90_for_video(bool defaultValue) {
     auto temp = SurfaceFlingerProperties::use_smart_90_for_video();
     if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 1964ccd..5f88322 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -70,10 +70,15 @@
 int32_t wcg_composition_pixel_format(
         android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
 
+int64_t color_space_agnostic_dataspace(
+        android::hardware::graphics::common::V1_2::Dataspace defaultValue);
+
 int32_t set_idle_timer_ms(int32_t defaultValue);
 
 int32_t set_touch_timer_ms(int32_t defaultValue);
 
+int32_t set_display_power_timer_ms(int32_t defaultValue);
+
 bool use_smart_90_for_video(bool defaultValue);
 
 bool enable_protected_contents(bool defaultValue);
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
index ac02d12..1441f91 100644
--- a/services/surfaceflinger/TimeStats/OWNERS
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -1 +1,2 @@
-zzyiwei@google.com
\ No newline at end of file
+alecmouri@google.com
+zzyiwei@google.com
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index a8ec764..56ab4e3 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -251,6 +251,20 @@
     prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
 }
 
+# colorSpaceAgnosticDataspace specifies the data space that
+# SurfaceFlinger expects for surfaces which are color space agnostic.
+# The variable works only when useColorManagement is specified. If
+# unspecified, the data space follows what SurfaceFlinger expects for
+# surfaces when useColorManagement is specified.
+
+prop {
+    api_name: "color_space_agnostic_dataspace"
+    type: Long
+    scope: System
+    access: Readonly
+    prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
+}
+
 # Return the native panel primary data. The data includes red, green,
 # blue and white. The primary format is CIE 1931 XYZ color space.
 # If unspecified, the primaries is sRGB gamut by default.
@@ -309,6 +323,18 @@
     prop_name: "ro.surface_flinger.set_touch_timer_ms"
 }
 
+# setDisplayPowerTimerMs indicates what is considered a timeout in milliseconds for Scheduler.
+# This value is used by the Scheduler to trigger display power inactivity callbacks that will
+# keep the display in peak refresh rate as long as display power is not in normal mode.
+# Setting this property to 0 means there is no timer.
+prop {
+    api_name: "set_display_power_timer_ms"
+    type: Integer
+    scope: System
+    access: Readonly
+    prop_name: "ro.surface_flinger.set_display_power_timer_ms"
+}
+
 # useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the
 # screen refresh rate based on that.
 prop {
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 0611684..b66e56e 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -1,6 +1,11 @@
 props {
   module: "android.sysprop.SurfaceFlingerProperties"
   prop {
+    api_name: "color_space_agnostic_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
+  }
+  prop {
     api_name: "default_composition_dataspace"
     type: Long
     prop_name: "ro.surface_flinger.default_composition_dataspace"
@@ -72,6 +77,11 @@
     prop_name: "ro.surface_flinger.running_without_sync_framework"
   }
   prop {
+    api_name: "set_display_power_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_display_power_timer_ms"
+  }
+  prop {
     api_name: "set_idle_timer_ms"
     type: Integer
     prop_name: "ro.surface_flinger.set_idle_timer_ms"
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index d5f6534..c93e15e 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -28,6 +28,7 @@
 
 #include <binder/ProcessState.h>
 #include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
@@ -6059,4 +6060,97 @@
     }
 }
 
+// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
+// the dropped buffer's damage region into the next buffer's damage region. If
+// we don't do this, we'll report an incorrect damage region to hardware
+// composer, resulting in broken rendering. This test checks the BufferQueue
+// case.
+//
+// Unfortunately, we don't currently have a way to inspect the damage region
+// SurfaceFlinger sends to hardware composer from a test, so this test requires
+// the dev to manually watch the device's screen during the test to spot broken
+// rendering. Because the results can't be automatically verified, this test is
+// marked disabled.
+TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
+    const int width = mDisplayWidth;
+    const int height = mDisplayHeight;
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+    const auto producer = layer->getIGraphicBufferProducer();
+    const sp<IProducerListener> dummyListener(new DummyProducerListener);
+    IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
+    ASSERT_EQ(OK,
+              producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+
+    std::map<int, sp<GraphicBuffer>> slotMap;
+    auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
+        ASSERT_NE(nullptr, buf);
+        const auto iter = slotMap.find(slot);
+        ASSERT_NE(slotMap.end(), iter);
+        *buf = iter->second;
+    };
+
+    auto dequeue = [&](int* outSlot) {
+        ASSERT_NE(nullptr, outSlot);
+        *outSlot = -1;
+        int slot;
+        sp<Fence> fence;
+        uint64_t age;
+        FrameEventHistoryDelta timestamps;
+        const status_t dequeueResult =
+                producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
+                                        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                        &age, &timestamps);
+        if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            sp<GraphicBuffer> newBuf;
+            ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
+            ASSERT_NE(nullptr, newBuf.get());
+            slotMap[slot] = newBuf;
+        } else {
+            ASSERT_EQ(OK, dequeueResult);
+        }
+        *outSlot = slot;
+    };
+
+    auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
+        IGraphicBufferProducer::QueueBufferInput input(
+                /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
+                /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+                /*transform=*/0, Fence::NO_FENCE);
+        input.setSurfaceDamage(damage);
+        IGraphicBufferProducer::QueueBufferOutput output;
+        ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
+    };
+
+    auto fillAndPostBuffers = [&](const Color& color) {
+        int slot1;
+        ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
+        int slot2;
+        ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
+
+        sp<GraphicBuffer> buf1;
+        ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
+        sp<GraphicBuffer> buf2;
+        ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
+        fillGraphicBufferColor(buf1, Rect(width, height), color);
+        fillGraphicBufferColor(buf2, Rect(width, height), color);
+
+        const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
+        ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
+        ASSERT_NO_FATAL_FAILURE(
+                queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
+                      displayTime));
+    };
+
+    const auto startTime = systemTime();
+    const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
+    int colorIndex = 0;
+    while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
+        ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
+        std::this_thread::sleep_for(1s);
+    }
+
+    ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 2e705da..0aa8cf5 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -51,6 +51,7 @@
     AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
 
     static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+    static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
     static constexpr int mIterations = 100;
 };
 
@@ -78,7 +79,8 @@
 
 void DispSyncSourceTest::createDispSyncSource() {
     createDispSync();
-    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
+    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
+                                                       mOffsetThresholdForNextVsync.count(), true,
                                                        "DispSyncSourceTest");
     mDispSyncSource->setCallback(this);
 }
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ea908a9..dbd9b84 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -55,8 +55,9 @@
     class MockEventThreadConnection : public EventThreadConnection {
     public:
         MockEventThreadConnection(android::impl::EventThread* eventThread,
-                                  ResyncCallback&& resyncCallback)
-              : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
+                                  ResyncCallback&& resyncCallback,
+                                  ISurfaceComposer::ConfigChanged configChanged)
+              : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {}
         MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
     };
 
@@ -67,7 +68,8 @@
     ~EventThreadTest() override;
 
     void createThread();
-    sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder);
+    sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
+                                                   ISurfaceComposer::ConfigChanged configChanged);
 
     void expectVSyncSetEnabledCallReceived(bool expectedState);
     void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
@@ -110,7 +112,8 @@
             .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
 
     createThread();
-    mConnection = createConnection(mConnectionEventCallRecorder);
+    mConnection = createConnection(mConnectionEventCallRecorder,
+                                   ISurfaceComposer::eConfigChangedDispatch);
 
     // A display must be connected for VSYNC events to be delivered.
     mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
@@ -138,9 +141,10 @@
 }
 
 sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
-        ConnectionEventRecorder& recorder) {
+        ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) {
     sp<MockEventThreadConnection> connection =
-            new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
+            new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(),
+                                          configChanged);
     EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
     return connection;
 }
@@ -267,7 +271,9 @@
 TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
     // Create a first connection, register it, and request a vsync rate of zero.
     ConnectionEventRecorder firstConnectionEventRecorder{0};
-    sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder);
+    sp<MockEventThreadConnection> firstConnection =
+            createConnection(firstConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
     mThread->setVsyncRate(0, firstConnection);
 
     // By itself, this should not enable vsync events
@@ -277,7 +283,8 @@
     // However if there is another connection which wants events at a nonzero rate.....
     ConnectionEventRecorder secondConnectionEventRecorder{0};
     sp<MockEventThreadConnection> secondConnection =
-            createConnection(secondConnectionEventRecorder);
+            createConnection(secondConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
     mThread->setVsyncRate(1, secondConnection);
 
     // EventThread should enable vsync callbacks.
@@ -363,7 +370,9 @@
 
 TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
     ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
-    sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+    sp<MockEventThreadConnection> errorConnection =
+            createConnection(errorConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
     mThread->setVsyncRate(1, errorConnection);
 
     // EventThread should enable vsync callbacks.
@@ -387,7 +396,9 @@
 
 TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
     ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
-    sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+    sp<MockEventThreadConnection> errorConnection =
+            createConnection(errorConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
     mThread->setVsyncRate(1, errorConnection);
 
     // EventThread should enable vsync callbacks.
@@ -449,5 +460,18 @@
     expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
 }
 
+TEST_F(EventThreadTest, suppressConfigChanged) {
+    ConnectionEventRecorder suppressConnectionEventRecorder{0};
+    sp<MockEventThreadConnection> suppressConnection =
+            createConnection(suppressConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
+
+    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9);
+    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+
+    auto args = suppressConnectionEventRecorder.waitForCall();
+    ASSERT_FALSE(args.has_value());
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 96121bb..1d75011 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -23,6 +23,8 @@
 namespace android {
 namespace scheduler {
 
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+
 class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
     nsecs_t FAKE_PHASE_OFFSET_NS = 0;
 
@@ -34,20 +36,20 @@
     nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
 
     PhaseOffsets::Offsets getOffsetsForRefreshRate(
-            RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override {
+            RefreshRateType /*refreshRateType*/) const override {
         return getCurrentOffsets();
     }
 
     // Returns early, early GL, and late offsets for Apps and SF.
     PhaseOffsets::Offsets getCurrentOffsets() const override {
-        return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
-                       {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
-                       {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+        return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                       {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                       {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
     }
 
     // This function should be called when the device is switching between different
     // refresh rates, to properly update the offsets.
-    void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+    void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
 
     nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
 
@@ -56,4 +58,4 @@
 };
 
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 2b1dfa8..8e7440c 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -25,7 +25,17 @@
 protected:
     std::unique_ptr<LayerHistory> mLayerHistory;
 
+    static constexpr float MIN_REFRESH_RATE = 30.f;
     static constexpr float MAX_REFRESH_RATE = 90.f;
+    static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u;
+    static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333;
+
+    void forceRelevancy(const std::unique_ptr<LayerHistory::LayerHandle>& testLayer) {
+        mLayerHistory->setVisibility(testLayer, true);
+        for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
+            mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+        }
+    };
 };
 
 LayerHistoryTest::LayerHistoryTest() {
@@ -36,31 +46,25 @@
 namespace {
 TEST_F(LayerHistoryTest, oneLayer) {
     std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
+            mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
     mLayerHistory->setVisibility(testLayer, true);
+    for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
+        EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    }
 
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    // This is still 0, because the layer is not considered recently active if it
-    // has been present in less than 10 frames.
-    EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-    // This should be MAX_REFRESH_RATE as we have more than 10 samples
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+    // Add a few more. This time we should get MAX refresh rate as the layer
+    // becomes relevant
+    static constexpr auto A_FEW = 10;
+    for (auto i = 0u; i < A_FEW; i++) {
+        EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    }
 }
 
 TEST_F(LayerHistoryTest, oneHDRLayer) {
     std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestHDRLayer", MAX_REFRESH_RATE);
+            mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
     mLayerHistory->setVisibility(testLayer, true);
 
     mLayerHistory->insert(testLayer, 0, true /*isHDR*/);
@@ -74,12 +78,13 @@
 
 TEST_F(LayerHistoryTest, explicitTimestamp) {
     std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
-            mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
+            mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
     mLayerHistory->setVisibility(test30FpsLayer, true);
 
     nsecs_t startTime = systemTime();
-    for (int i = 0; i < 31; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/);
+    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
+        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
+                              false /*isHDR*/);
     }
 
     EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
@@ -87,29 +92,31 @@
 
 TEST_F(LayerHistoryTest, multipleLayers) {
     std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
+            mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
     mLayerHistory->setVisibility(testLayer, true);
     std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
-            mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
+            mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
     mLayerHistory->setVisibility(test30FpsLayer, true);
     std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
-            mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE);
+            mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
     mLayerHistory->setVisibility(testLayer2, true);
 
     nsecs_t startTime = systemTime();
-    for (int i = 0; i < 10; i++) {
+    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
         mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
     }
     EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
     startTime = systemTime();
-    for (int i = 0; i < 10; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/);
+    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
+        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
+                              false /*isHDR*/);
     }
     EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    for (int i = 10; i < 30; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/);
+    for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) {
+        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
+                              false /*isHDR*/);
     }
     EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
@@ -119,10 +126,12 @@
         mLayerHistory->insert(testLayer2, 0, false /*isHDR*/);
     }
     EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    // After 100 ms frames become obsolete.
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    // Insert the 31st frame.
-    mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333), false /*isHDR*/);
+    // After 1200 ms frames become obsolete.
+    std::this_thread::sleep_for(std::chrono::milliseconds(1500));
+
+    mLayerHistory->insert(test30FpsLayer,
+                          startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL),
+                          false /*isHDR*/);
     EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 }
 
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1f8b111..740115e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -25,7 +25,8 @@
     class MockEventThreadConnection : public android::EventThreadConnection {
     public:
         explicit MockEventThreadConnection(EventThread* eventThread)
-              : EventThreadConnection(eventThread, ResyncCallback()) {}
+              : EventThreadConnection(eventThread, ResyncCallback(),
+                                      ISurfaceComposer::eConfigChangedSuppress) {}
         ~MockEventThreadConnection() = default;
 
         MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -47,7 +48,7 @@
 
         std::unique_ptr<EventThread> makeEventThread(
                 const char* /* connectionName */, DispSync* /* dispSync */,
-                nsecs_t /* phaseOffsetNs */,
+                nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
                 impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
             return std::move(mEventThread);
         }
@@ -81,10 +82,10 @@
 
     // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
     // sure that call gets executed and returns an EventThread::Connection object.
-    EXPECT_CALL(*mEventThread, createEventConnection(_))
+    EXPECT_CALL(*mEventThread, createEventConnection(_, _))
             .WillRepeatedly(Return(mEventThreadConnection));
 
-    mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+    mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(),
                                                      impl::EventThread::InterceptVSyncsCallback());
     EXPECT_TRUE(mConnectionHandle != nullptr);
 }
@@ -105,7 +106,10 @@
     // exceptions, just gracefully continues.
     sp<IDisplayEventConnection> returnedValue;
     ASSERT_NO_FATAL_FAILURE(
-            returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
+            returnedValue =
+                    mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
+                                                             ISurfaceComposer::
+                                                                     eConfigChangedSuppress));
     EXPECT_TRUE(returnedValue == nullptr);
     EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
     EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -126,7 +130,9 @@
     sp<IDisplayEventConnection> returnedValue;
     ASSERT_NO_FATAL_FAILURE(
             returnedValue =
-                    mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
+                    mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
+                                                             ISurfaceComposer::
+                                                                     eConfigChangedSuppress));
     EXPECT_TRUE(returnedValue == nullptr);
     EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
     EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -155,7 +161,9 @@
     sp<IDisplayEventConnection> returnedValue;
     ASSERT_NO_FATAL_FAILURE(
             returnedValue =
-                    mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
+                    mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
+                                                             ISurfaceComposer::
+                                                                     eConfigChangedSuppress));
     EXPECT_TRUE(returnedValue != nullptr);
     ASSERT_EQ(returnedValue, mEventThreadConnection);
 
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index c3d2b8d..cb6980e 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <gmock/gmock.h>
+#include <gui/ISurfaceComposer.h>
 
 #include "Scheduler/EventThread.h"
 #include "Scheduler/RefreshRateConfigs.h"
@@ -34,7 +35,8 @@
     // Scheduler::Connection. This allows plugging in mock::EventThread.
     sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
         sp<EventThreadConnection> eventThreadConnection =
-                new EventThreadConnection(eventThread.get(), ResyncCallback());
+                new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                          ISurfaceComposer::eConfigChangedSuppress);
         const int64_t id = sNextId++;
         mConnections.emplace(id,
                              std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 5b5f8e7..ed35ebf 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,7 +28,8 @@
     EventThread();
     ~EventThread() override;
 
-    MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
+    MOCK_CONST_METHOD2(createEventConnection,
+                       sp<EventThreadConnection>(ResyncCallback, ISurfaceComposer::ConfigChanged));
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 71048db..3d56656 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -519,7 +519,11 @@
       get_device_proc_addr_(nullptr),
       driver_extensions_(nullptr),
       driver_extension_count_(0) {
-    enabled_extensions_.set(driver::ProcHook::EXTENSION_CORE);
+    // advertise the loader supported core Vulkan API version at vulkan::api
+    for (uint32_t i = driver::ProcHook::EXTENSION_CORE_1_0;
+         i != driver::ProcHook::EXTENSION_COUNT; ++i) {
+        enabled_extensions_.set(i);
+    }
 }
 
 LayerChain::~LayerChain() {
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index bdd3573..a5a0405 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -765,6 +765,19 @@
 {{end}}
 
 
+
+{{/*
+------------------------------------------------------------------------------
+  Emits the ProcHook enum for core Vulkan API verions.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.GetProcHookEnum"}}
+  {{if GetAnnotation $ "vulkan1_1"}}ProcHook::EXTENSION_CORE_1_1
+  {{else}}ProcHook::EXTENSION_CORE_1_0
+  {{end}}
+{{end}}
+
+
 {{/*
 ------------------------------------------------------------------------------
   Emits true if a function needs a ProcHook stub.
@@ -778,6 +791,8 @@
     {{if $ext}}
       {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}}
     {{end}}
+
+    {{if GetAnnotation $ "vulkan1_1"}}true{{end}}
   {{end}}
 {{end}}
 
@@ -801,7 +816,8 @@
           {{TrimPrefix "VK_" $e}},
         {{end}}

-        EXTENSION_CORE, // valid bit
+        EXTENSION_CORE_1_0,
+        EXTENSION_CORE_1_1,
         EXTENSION_COUNT,
         EXTENSION_UNKNOWN,
       };
@@ -838,14 +854,21 @@
   {{AssertType $ "Function"}}
 
   {{if (Macro "driver.NeedProcHookStub" $)}}
+    {{$ext_name := Strings ("")}}
+    {{$ext_hook := Strings ("")}}
     {{$ext := GetAnnotation $ "extension"}}
-    {{$ext_name := index $ext.Arguments 0}}
+    {{if $ext}}
+      {{$ext_name = index $ext.Arguments 0}}
+      {{$ext_hook = Strings ("ProcHook::") (Macro "BaseName" $ext)}}
+    {{else}}
+      {{$ext_name = Strings ("VK_VERSION_1_0")}}
+      {{$ext_hook = (Macro "driver.GetProcHookEnum" $)}}
+    {{end}}
 
     {{$base := (Macro "BaseName" $)}}
 
     VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) {
       {{$p0 := index $.CallParameters 0}}
-      {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}}
 
       if (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) {
         {{if not (IsVoid $.Return.Type)}}return §{{end}}
@@ -878,7 +901,7 @@
   {
     "{{$.Name}}",
     ProcHook::GLOBAL,
-    ProcHook::EXTENSION_CORE,
+    {{Macro "driver.GetProcHookEnum" $}},
     reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
     nullptr,
   },
@@ -911,7 +934,7 @@
         nullptr,
       {{end}}
     {{else}}
-      ProcHook::EXTENSION_CORE,
+      {{Macro "driver.GetProcHookEnum" $}},
       reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
       nullptr,
     {{end}}
@@ -934,18 +957,23 @@
     ProcHook::DEVICE,
 
     {{$ext := GetAnnotation $ "extension"}}
-    {{if $ext}}
-      ProcHook::{{Macro "BaseName" $ext}},
-
-      {{if (Macro "IsExtensionInternal" $ext)}}
-        nullptr,
-        nullptr,
+    {{if or $ext (GetAnnotation $ "vulkan1_1")}}
+      {{if $ext}}
+        ProcHook::{{Macro "BaseName" $ext}},
+        {{if Macro "IsExtensionInternal" $ext}}
+          nullptr,
+          nullptr,
+        {{else}}
+          reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+          reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
+        {{end}}
       {{else}}
+        {{Macro "driver.GetProcHookEnum" $}},
         reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
         reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
       {{end}}
     {{else}}
-      ProcHook::EXTENSION_CORE,
+      {{Macro "driver.GetProcHookEnum" $}},
       reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
       nullptr,
     {{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 23506ba..85e1c92 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -24,7 +24,10 @@
 #include <dlfcn.h>
 #include <algorithm>
 #include <array>
+#include <climits>
 #include <new>
+#include <sstream>
+#include <string>
 
 #include <log/log.h>
 
@@ -104,6 +107,7 @@
 
     VkResult Validate();
     void DowngradeApiVersion();
+    void UpgradeDeviceCoreApiVersion(uint32_t api_version);
 
     const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
     const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
@@ -152,15 +156,12 @@
 Hal Hal::hal_;
 
 void* LoadLibrary(const android_dlextinfo& dlextinfo,
-                  const char* subname,
-                  int subname_len) {
+                  const std::string_view subname) {
     ATRACE_CALL();
 
-    const char kLibFormat[] = "vulkan.%*s.so";
-    char* name = static_cast<char*>(
-        alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
-    sprintf(name, kLibFormat, subname_len, subname);
-    return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+    std::stringstream ss;
+    ss << "vulkan." << subname << ".so";
+    return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
 }
 
 const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
@@ -180,8 +181,9 @@
     char prop[PROPERTY_VALUE_MAX];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
         int prop_len = property_get(key, prop, nullptr);
-        if (prop_len > 0) {
-            so = LoadLibrary(dlextinfo, prop, prop_len);
+        if (prop_len > 0 && prop_len <= UINT_MAX) {
+            std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
+            so = LoadLibrary(dlextinfo, lib_name);
             if (so)
                 break;
         }
@@ -333,8 +335,12 @@
       physical_dev_(VK_NULL_HANDLE),
       instance_info_(create_info),
       extension_filter_() {
-    hook_extensions_.set(ProcHook::EXTENSION_CORE);
-    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+    // instance core versions need to match the loader api version
+    for (uint32_t i = ProcHook::EXTENSION_CORE_1_0;
+         i != ProcHook::EXTENSION_COUNT; ++i) {
+        hook_extensions_.set(i);
+        hal_extensions_.set(i);
+    }
 }
 
 CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
@@ -345,8 +351,9 @@
       physical_dev_(physical_dev),
       dev_info_(create_info),
       extension_filter_() {
-    hook_extensions_.set(ProcHook::EXTENSION_CORE);
-    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+    // initialize with baseline core API version
+    hook_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
 }
 
 CreateInfoWrapper::~CreateInfoWrapper() {
@@ -545,7 +552,8 @@
             case ProcHook::ANDROID_external_memory_android_hardware_buffer:
             case ProcHook::ANDROID_native_buffer:
             case ProcHook::GOOGLE_display_timing:
-            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_CORE_1_0:
+            case ProcHook::EXTENSION_CORE_1_1:
             case ProcHook::EXTENSION_COUNT:
                 // Device and meta extensions. If we ever get here it's a bug in
                 // our code. But enumerating them lets us avoid having a default
@@ -593,7 +601,8 @@
             case ProcHook::EXT_debug_report:
             case ProcHook::EXT_swapchain_colorspace:
             case ProcHook::ANDROID_native_buffer:
-            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_CORE_1_0:
+            case ProcHook::EXTENSION_CORE_1_1:
             case ProcHook::EXTENSION_COUNT:
                 // Instance and meta extensions. If we ever get here it's a bug
                 // in our code. But enumerating them lets us avoid having a
@@ -641,6 +650,28 @@
     }
 }
 
+void CreateInfoWrapper::UpgradeDeviceCoreApiVersion(uint32_t api_version) {
+    ALOG_ASSERT(!is_instance_, "Device only API called by instance wrapper.");
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+    api_version ^= VK_VERSION_PATCH(api_version);
+#pragma clang diagnostic pop
+    // cap the API version to the loader supported highest version
+    if (api_version > VK_API_VERSION_1_1)
+        api_version = VK_API_VERSION_1_1;
+    switch (api_version) {
+        case VK_API_VERSION_1_1:
+            hook_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+            hal_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+            [[clang::fallthrough]];
+        case VK_API_VERSION_1_0:
+            break;
+        default:
+            ALOGD("Unknown upgrade API version[%u]", api_version);
+            break;
+    }
+}
+
 VKAPI_ATTR void* DefaultAllocate(void*,
                                  size_t size,
                                  size_t alignment,
@@ -776,7 +807,7 @@
                        : nullptr;
             break;
         case ProcHook::DEVICE:
-            proc = (hook->extension == ProcHook::EXTENSION_CORE)
+            proc = (hook->extension == ProcHook::EXTENSION_CORE_1_0)
                        ? hook->proc
                        : hook->checked_proc;
             break;
@@ -1124,6 +1155,13 @@
     if (!data)
         return VK_ERROR_OUT_OF_HOST_MEMORY;
 
+    VkPhysicalDeviceProperties properties;
+    ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
+    instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
+                                                     &properties);
+    ATRACE_END();
+
+    wrapper.UpgradeDeviceCoreApiVersion(properties.apiVersion);
     data->hook_extensions |= wrapper.GetHookExtensions();
 
     // call into the driver
@@ -1168,12 +1206,6 @@
         return VK_ERROR_INCOMPATIBLE_DRIVER;
     }
 
-    VkPhysicalDeviceProperties properties;
-    ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
-    instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
-                                                     &properties);
-    ATRACE_END();
-
     if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
         // Log that the app is hitting software Vulkan implementation
         android::GraphicsEnv::getInstance().setCpuVulkanInUse();
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 57c956d..047a27a 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -67,9 +67,7 @@
         : opaque_api_data(),
           allocator(alloc),
           driver(),
-          get_device_proc_addr(nullptr) {
-        hook_extensions.set(ProcHook::EXTENSION_CORE);
-    }
+          get_device_proc_addr(nullptr) {}
 
     api::InstanceData opaque_api_data;
 
@@ -89,9 +87,7 @@
         : opaque_api_data(),
           allocator(alloc),
           debug_report_callbacks(debug_report_callbacks_),
-          driver() {
-        hook_extensions.set(ProcHook::EXTENSION_CORE);
-    }
+          driver() {}
 
     api::DeviceData opaque_api_data;
 
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 574c327..aa31735 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -31,6 +31,23 @@
 
 // clang-format off
 
+VKAPI_ATTR VkResult checkedBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+    if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) {
+        return BindImageMemory2(device, bindInfoCount, pBindInfos);
+    } else {
+        Logger(device).Err(device, "VK_VERSION_1_0 not enabled. vkBindImageMemory2 not executed.");
+        return VK_SUCCESS;
+    }
+}
+
+VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+    if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) {
+        GetDeviceQueue2(device, pQueueInfo, pQueue);
+    } else {
+        Logger(device).Err(device, "VK_VERSION_1_0 not enabled. vkGetDeviceQueue2 not executed.");
+    }
+}
+
 VKAPI_ATTR VkResult checkedCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) {
     if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
         return CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
@@ -174,16 +191,16 @@
     {
         "vkAllocateCommandBuffers",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers),
         nullptr,
     },
     {
         "vkBindImageMemory2",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_1,
         reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2),
-        nullptr,
+        reinterpret_cast<PFN_vkVoidFunction>(checkedBindImageMemory2),
     },
     {
         "vkBindImageMemory2KHR",
@@ -209,14 +226,14 @@
     {
         "vkCreateDevice",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(CreateDevice),
         nullptr,
     },
     {
         "vkCreateInstance",
         ProcHook::GLOBAL,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(CreateInstance),
         nullptr,
     },
@@ -244,14 +261,14 @@
     {
         "vkDestroyDevice",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice),
         nullptr,
     },
     {
         "vkDestroyInstance",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance),
         nullptr,
     },
@@ -272,28 +289,28 @@
     {
         "vkEnumerateDeviceExtensionProperties",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties),
         nullptr,
     },
     {
         "vkEnumerateInstanceExtensionProperties",
         ProcHook::GLOBAL,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties),
         nullptr,
     },
     {
         "vkEnumeratePhysicalDeviceGroups",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_1,
         reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups),
         nullptr,
     },
     {
         "vkEnumeratePhysicalDevices",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices),
         nullptr,
     },
@@ -314,28 +331,28 @@
     {
         "vkGetDeviceProcAddr",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr),
         nullptr,
     },
     {
         "vkGetDeviceQueue",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue),
         nullptr,
     },
     {
         "vkGetDeviceQueue2",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_1,
         reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2),
-        nullptr,
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceQueue2),
     },
     {
         "vkGetInstanceProcAddr",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr),
         nullptr,
     },
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 3faf6c0..831efb7 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -48,7 +48,8 @@
         ANDROID_external_memory_android_hardware_buffer,
         KHR_bind_memory2,
 
-        EXTENSION_CORE,  // valid bit
+        EXTENSION_CORE_1_0,
+        EXTENSION_CORE_1_1,
         EXTENSION_COUNT,
         EXTENSION_UNKNOWN,
     };
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 5679412..dd91739 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <sys/prctl.h>
 
+#include <memory>
 #include <mutex>
 #include <string>
 #include <vector>
@@ -101,9 +102,7 @@
     bool EnumerateLayers(size_t library_idx,
                          std::vector<Layer>& instance_layers) const;
 
-    void* GetGPA(const Layer& layer,
-                 const char* gpa_name,
-                 size_t gpa_name_len) const;
+    void* GetGPA(const Layer& layer, const std::string_view gpa_name) const;
 
     const std::string GetFilename() { return filename_; }
 
@@ -226,17 +225,10 @@
     }
 
     // get layer properties
-    VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
-        (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
-    result = enumerate_instance_layers(&num_instance_layers, properties);
-    if (result != VK_SUCCESS) {
-        ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
-              path_.c_str(), result);
-        return false;
-    }
+    auto properties = std::make_unique<VkLayerProperties[]>(num_instance_layers + num_device_layers);
     if (num_device_layers > 0) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
-                                         properties + num_instance_layers);
+                                         properties.get() + num_instance_layers);
         if (result != VK_SUCCESS) {
             ALOGE(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
@@ -321,21 +313,11 @@
     return true;
 }
 
-void* LayerLibrary::GetGPA(const Layer& layer,
-                           const char* gpa_name,
-                           size_t gpa_name_len) const {
-    void* gpa;
-    size_t layer_name_len =
-        std::max(size_t{2}, strlen(layer.properties.layerName));
-    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
-    strcpy(name, layer.properties.layerName);
-    strcpy(name + layer_name_len, gpa_name);
-    if (!(gpa = GetTrampoline(name))) {
-        strcpy(name, "vk");
-        strcpy(name + 2, gpa_name);
-        gpa = GetTrampoline(name);
-    }
-    return gpa;
+void* LayerLibrary::GetGPA(const Layer& layer, const std::string_view gpa_name) const {
+    std::string layer_name { layer.properties.layerName };
+    if (void* gpa = GetTrampoline((layer_name.append(gpa_name).c_str())))
+        return gpa;
+    return GetTrampoline((std::string {"vk"}.append(gpa_name)).c_str());
 }
 
 // ----------------------------------------------------------------------------
@@ -470,10 +452,9 @@
 }
 
 void* GetLayerGetProcAddr(const Layer& layer,
-                          const char* gpa_name,
-                          size_t gpa_name_len) {
+                          const std::string_view gpa_name) {
     const LayerLibrary& library = g_layer_libraries[layer.library_idx];
-    return library.GetGPA(layer, gpa_name, gpa_name_len);
+    return library.GetGPA(layer, gpa_name);
 }
 
 }  // anonymous namespace
@@ -556,13 +537,13 @@
 
 PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
     return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
-                        GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
+                        GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr"))
                   : nullptr;
 }
 
 PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
     return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
-                        GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
+                        GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr"))
                   : nullptr;
 }
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5f4c6b1..fbf6d0d 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -718,8 +718,6 @@
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
     };
     const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
     uint32_t total_num_formats = kNumFormats;
@@ -1280,6 +1278,7 @@
     VkImageCreateInfo image_create = {
         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
         .pNext = &image_native_buffer,
+        .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
         .imageType = VK_IMAGE_TYPE_2D,
         .format = create_info->imageFormat,
         .extent = {0, 0, 1},
@@ -1288,7 +1287,6 @@
         .samples = VK_SAMPLE_COUNT_1_BIT,
         .tiling = VK_IMAGE_TILING_OPTIMAL,
         .usage = create_info->imageUsage,
-        .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
         .sharingMode = create_info->imageSharingMode,
         .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index 89bc926..f9e4916 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -195,10 +195,10 @@
         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
         .queueCreateInfoCount = 1,
         .pQueueCreateInfos = &queue_create_info,
-        .enabledExtensionCount = num_extensions,
-        .ppEnabledExtensionNames = extensions,
         .enabledLayerCount = (options.validate) ? num_layers : 0,
         .ppEnabledLayerNames = kValidationLayers,
+        .enabledExtensionCount = num_extensions,
+        .ppEnabledExtensionNames = extensions,
         .pEnabledFeatures = &info.features,
     };
     result = vkCreateDevice(gpu, &create_info, nullptr, &device);
@@ -272,10 +272,10 @@
     const VkInstanceCreateInfo create_info = {
         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
         .pApplicationInfo = &application_info,
-        .enabledExtensionCount = num_extensions,
-        .ppEnabledExtensionNames = extensions,
         .enabledLayerCount = (options.validate) ? num_layers : 0,
         .ppEnabledLayerNames = kValidationLayers,
+        .enabledExtensionCount = num_extensions,
+        .ppEnabledExtensionNames = extensions,
     };
     VkInstance instance;
     result = vkCreateInstance(&create_info, nullptr, &instance);