Merge "Fix dumpsys SurfaceFlinger --frame-events"
diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp
index e5c52d8..f81994b 100644
--- a/cmds/bugreport/bugreport.cpp
+++ b/cmds/bugreport/bugreport.cpp
@@ -14,91 +14,19 @@
  * limitations under the License.
  */
 
-#include <errno.h>
 #include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
 
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
+// Only prints a warning redirecting to bugreportz.
+int main() {
+    fprintf(stderr,
+            "=============================================================================\n");
+    fprintf(stderr, "WARNING: Flat (text file, non-zipped) bugreports are deprecated.\n");
+    fprintf(stderr, "WARNING: Please generate zipped bugreports instead.\n");
+    fprintf(stderr, "WARNING: On the host use: adb bugreport filename.zip\n");
+    fprintf(stderr, "WARNING: On the device use: bugreportz\n");
+    fprintf(stderr, "WARNING: bugreportz will output the filename to use with adb pull.\n");
+    fprintf(stderr,
+            "=============================================================================\n\n\n");
 
-// This program will trigger the dumpstate service to start a call to
-// dumpstate, then connect to the dumpstate local client to read the
-// output. All of the dumpstate output is written to stdout, including
-// any errors encountered while reading/writing the output.
-int main(int argc, char* /*argv*/[]) {
-  fprintf(stderr, "=============================================================================\n");
-  fprintf(stderr, "WARNING: Flat (text file, non-zipped) bugreports are deprecated.\n");
-  fprintf(stderr, "WARNING: Please generate zipped bugreports instead.\n");
-  fprintf(stderr, "WARNING: On the host use: adb bugreport filename.zip\n");
-  fprintf(stderr, "WARNING: On the device use: bugreportz\n");
-  fprintf(stderr, "WARNING: bugreportz will output the filename to use with adb pull.\n");
-  fprintf(stderr, "=============================================================================\n\n\n");
-
-  if (argc != 1) {
-    fprintf(stderr, "usage: bugreport\n");
-    exit(1);
-  }
-
-  // Start the dumpstate service.
-  property_set("ctl.start", "dumpstate");
-
-  // Socket will not be available until service starts.
-  int s = -1;
-  for (int i = 0; i < 20; i++) {
-    s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                            SOCK_STREAM);
-    if (s >= 0)
-      break;
-    // Try again in 1 second.
-    sleep(1);
-  }
-
-  if (s == -1) {
-    printf("Failed to connect to dumpstate service: %s\n", strerror(errno));
-    return 1;
-  }
-
-  // Set a timeout so that if nothing is read in 3 minutes, we'll stop
-  // reading and quit. No timeout in dumpstate is longer than 60 seconds,
-  // so this gives lots of leeway in case of unforeseen time outs.
-  struct timeval tv;
-  tv.tv_sec = 3 * 60;
-  tv.tv_usec = 0;
-  if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
-    printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno));
-  }
-
-  while (1) {
-    char buffer[65536];
-    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
-    if (bytes_read == 0) {
-      break;
-    } else if (bytes_read == -1) {
-      // EAGAIN really means time out, so change the errno.
-      if (errno == EAGAIN) {
-        errno = ETIMEDOUT;
-      }
-      printf("\nBugreport read terminated abnormally (%s).\n", strerror(errno));
-      break;
-    }
-
-    ssize_t bytes_to_send = bytes_read;
-    ssize_t bytes_written;
-    do {
-      bytes_written = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
-                                               buffer + bytes_read - bytes_to_send,
-                                               bytes_to_send));
-      if (bytes_written == -1) {
-        printf("Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
-               bytes_read, bytes_to_send, strerror(errno));
-        return 1;
-      }
-      bytes_to_send -= bytes_written;
-    } while (bytes_written != 0 && bytes_to_send > 0);
-  }
-
-  close(s);
-  return 0;
+    return 0;
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index a5e6c68..85e6969 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -72,5 +72,5 @@
     /**
      * Called when ui intensive bugreport dumps are finished.
      */
-    oneway void onUiIntensiveBugreportDumpsFinished(String callingPackage);
+    oneway void onUiIntensiveBugreportDumpsFinished();
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 67527b2..9c5b883 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -227,7 +227,6 @@
 static const std::string DUMP_HALS_TASK = "DUMP HALS";
 static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
 static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
-static const std::string DUMP_APP_INFOS_TASK = "DUMP APP INFOS";
 
 namespace android {
 namespace os {
@@ -1576,7 +1575,6 @@
         ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
         ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
         ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
-        ds.dump_pool_->enqueueTaskWithFd(DUMP_APP_INFOS_TASK, &DumpAppInfos, _1);
     }
 
     // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
@@ -1729,11 +1727,7 @@
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
     }
 
-    if (ds.dump_pool_) {
-        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_APP_INFOS_TASK, ds.dump_pool_);
-    } else {
-        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_APP_INFOS_TASK, DumpAppInfos);
-    }
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpAppInfos);
 
     printf("========================================================\n");
     printf("== Dropbox crashes\n");
@@ -2863,31 +2857,23 @@
     // duration is logged into MYLOG instead.
     PrintHeader();
 
-    // TODO(b/158737089) reduce code repetition in if branches
-    if (options_->telephony_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateTelephonyOnly(calling_package);
-    } else if (options_->wifi_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateWifiOnly();
-    } else if (options_->limited_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateLimitedOnly();
-    } else {
+    bool is_dumpstate_restricted = options_->telephony_only
+                                   || options_->wifi_only
+                                   || options_->limited_only;
+    if (!is_dumpstate_restricted) {
         // Invoke critical dumpsys first to preserve system state, before doing anything else.
         RunDumpsysCritical();
-
-        // Take screenshot and get consent only after critical dumpsys has finished.
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-
+    }
+    MaybeTakeEarlyScreenshot();
+    onUiIntensiveBugreportDumpsFinished(calling_uid);
+    MaybeCheckUserConsent(calling_uid, calling_package);
+    if (options_->telephony_only) {
+        DumpstateTelephonyOnly(calling_package);
+    } else if (options_->wifi_only) {
+        DumpstateWifiOnly();
+    } else if (options_->limited_only) {
+        DumpstateLimitedOnly();
+    } else {
         // Dump state for the default case. This also drops root.
         RunStatus s = DumpstateDefaultAfterCritical();
         if (s != RunStatus::OK) {
@@ -2969,16 +2955,14 @@
     TakeScreenshot();
 }
 
-void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
-                                                    const std::string& calling_package) {
+void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
     if (calling_uid == AID_SHELL || !CalledByApi()) {
         return;
     }
     if (listener_ != nullptr) {
         // Let listener know ui intensive bugreport dumps are finished, then it can do event
         // handling if required.
-        android::String16 package(calling_package.c_str());
-        listener_->onUiIntensiveBugreportDumpsFinished(package);
+        listener_->onUiIntensiveBugreportDumpsFinished();
     }
 }
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index efe06dc..255243f 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -544,8 +544,7 @@
 
     void MaybeTakeEarlyScreenshot();
 
-    void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
-                                             const std::string& calling_package);
+    void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid);
 
     void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package);
 
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 23c0d95..fe6a34a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -173,12 +173,9 @@
         return binder::Status::ok();
     }
 
-    binder::Status onUiIntensiveBugreportDumpsFinished(const android::String16& callingpackage)
-        override {
+    binder::Status onUiIntensiveBugreportDumpsFinished() override {
         std::lock_guard <std::mutex> lock(lock_);
-        std::string callingpackageUtf8 = std::string(String8(callingpackage).string());
-        dprintf(out_fd_, "\rCalling package of ui intensive bugreport dumps finished: %s",
-                callingpackageUtf8.c_str());
+        dprintf(out_fd_, "\rUi intensive bugreport dumps finished");
         return binder::Status::ok();
     }
 
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 306069f..b2518ad 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -70,8 +70,7 @@
     MOCK_METHOD1(onError, binder::Status(int32_t error_code));
     MOCK_METHOD0(onFinished, binder::Status());
     MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success));
-    MOCK_METHOD1(onUiIntensiveBugreportDumpsFinished,
-        binder::Status(const android::String16& callingpackage));
+    MOCK_METHOD0(onUiIntensiveBugreportDumpsFinished, binder::Status());
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 1327cfd..a017246 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -427,7 +427,7 @@
                  << strerror(errno) << std::endl;
             status = -errno;
             break;
-        } else if (rc == 0) {
+        } else if (rc == 0 || time_left_ms() == 0) {
             status = TIMED_OUT;
             break;
         }
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 6001a58..c55fc6a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -398,6 +398,10 @@
         PLOG(ERROR) << "Failed to prepare " << profile_dir;
         return false;
     }
+    if (selinux_android_restorecon(profile_dir.c_str(), 0)) {
+        PLOG(ERROR) << "Failed to restorecon " << profile_dir;
+        return false;
+    }
 
     const std::string ref_profile_path =
             create_primary_reference_profile_package_dir_path(packageName);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 594880a..65fc46e 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1818,10 +1818,13 @@
 
     pid_t pid = fork();
     if (pid == 0) {
+        // Need to set schedpolicy before dropping privileges
+        // for cgroup migration. See details at b/175178520.
+        SetDex2OatScheduling(boot_complete);
+
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
-        SetDex2OatScheduling(boot_complete);
         if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat.path() << ") failed";
             _exit(DexoptReturnCodes::kFlock);
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 6459805..72c03bf 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -68,15 +68,15 @@
                                        apex::kApexPackageVendorDir};
     for (const auto& dir : apex_dirs) {
         // Cast call to void to suppress warn_unused_result.
-        static_cast<void>(apex::scanPackagesDirAndActivate(dir));
+        static_cast<void>(apex::ScanPackagesDirAndActivate(dir));
     }
-    return apex::getActivePackages();
+    return apex::GetActivePackages();
 }
 
 static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
     for (const apex::ApexFile& apex_file : active_packages) {
         const std::string& package_path = apex_file.GetPath();
-        base::Result<void> status = apex::deactivatePackage(package_path);
+        base::Result<void> status = apex::DeactivatePackage(package_path);
         if (!status.ok()) {
             LOG(ERROR) << "Failed to deactivate " << package_path << ": "
                        << status.error();
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 987adaf..0cbb80f 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -16,6 +16,7 @@
     name: "liblshal",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -47,6 +48,7 @@
     name: "lshal_defaults",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -72,15 +74,18 @@
 cc_test {
     name: "lshal_test",
     test_suites: ["device-tests"],
-    defaults: ["lshal_defaults"],
+    defaults: [
+        "libvintf_static_user_defaults",
+        "lshal_defaults"
+    ],
     gtest: true,
     static_libs: [
         "android.hardware.tests.inheritance@1.0",
         "libgmock",
+        "libvintf",
     ],
     shared_libs: [
         "libhidlbase",
-        "libvintf",
     ],
     srcs: [
         "test.cpp"
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 92958d9..22268ac 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -29,7 +29,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl-hash/Hash.h>
 #include <hidl-util/FQName.h>
@@ -203,97 +202,14 @@
             lshal::getVintfInfo(getFrameworkMatrix(), fqInstance, ta, FRAMEWORK_MATRIX);
 }
 
-static bool scanBinderContext(pid_t pid,
-        const std::string &contextName,
-        std::function<void(const std::string&)> eachLine) {
-    std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
-    if (!ifs.is_open()) {
-        ifs.open("/d/binder/proc/" + std::to_string(pid));
-        if (!ifs.is_open()) {
-            return false;
-        }
-    }
-
-    static const std::regex kContextLine("^context (\\w+)$");
-
-    bool isDesiredContext = false;
-    std::string line;
-    std::smatch match;
-    while(getline(ifs, line)) {
-        if (std::regex_search(line, match, kContextLine)) {
-            isDesiredContext = match.str(1) == contextName;
-            continue;
-        }
-
-        if (!isDesiredContext) {
-            continue;
-        }
-
-        eachLine(line);
-    }
-    return true;
-}
-
 bool ListCommand::getPidInfo(
-        pid_t serverPid, PidInfo *pidInfo) const {
-    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
-    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
-
-    std::smatch match;
-    return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
-        if (std::regex_search(line, match, kReferencePrefix)) {
-            const std::string &ptrString = "0x" + match.str(2); // use number after c
-            uint64_t ptr;
-            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
-                // Should not reach here, but just be tolerant.
-                err() << "Could not parse number " << ptrString << std::endl;
-                return;
-            }
-            const std::string proc = " proc ";
-            auto pos = line.rfind(proc);
-            if (pos != std::string::npos) {
-                for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
-                    int32_t pid;
-                    if (!::android::base::ParseInt(pidStr, &pid)) {
-                        err() << "Could not parse number " << pidStr << std::endl;
-                        return;
-                    }
-                    pidInfo->refPids[ptr].push_back(pid);
-                }
-            }
-
-            return;
-        }
-
-        if (std::regex_search(line, match, kThreadPrefix)) {
-            // "1" is waiting in binder driver
-            // "2" is poll. It's impossible to tell if these are in use.
-            //     and HIDL default code doesn't use it.
-            bool isInUse = match.str(1) != "1";
-            // "0" is a thread that has called into binder
-            // "1" is looper thread
-            // "2" is main looper thread
-            bool isHwbinderThread = match.str(2) != "0";
-
-            if (!isHwbinderThread) {
-                return;
-            }
-
-            if (isInUse) {
-                pidInfo->threadUsage++;
-            }
-
-            pidInfo->threadCount++;
-            return;
-        }
-
-        // not reference or thread line
-        return;
-    });
+        pid_t serverPid, BinderPidInfo *pidInfo) const {
+    const auto& status = getBinderPidInfo(BinderDebugContext::HWBINDER, serverPid, pidInfo);
+    return status == OK;
 }
 
-const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
-    auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
+const BinderPidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
+    auto pair = mCachedPidInfos.insert({serverPid, BinderPidInfo{}});
     if (pair.second /* did insertion take place? */) {
         if (!getPidInfo(serverPid, &pair.first->second)) {
             return nullptr;
@@ -727,7 +643,7 @@
         entry->arch = fromBaseArchitecture(debugInfo.arch);
 
         if (debugInfo.pid != NO_PID) {
-            const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
+            const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
             if (pidInfo == nullptr) {
                 handleError(IO_ERROR,
                             "no information for PID " + std::to_string(debugInfo.pid) +
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 412aadd..561f9cb 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -25,6 +25,7 @@
 
 #include <android-base/macros.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binderdebug/BinderDebug.h>
 #include <hidl-util/FqInstance.h>
 #include <vintf/HalManifest.h>
 #include <vintf/VintfObject.h>
@@ -40,12 +41,6 @@
 
 class Lshal;
 
-struct PidInfo {
-    std::map<uint64_t, Pids> refPids; // pids that are referenced
-    uint32_t threadUsage; // number of threads in use
-    uint32_t threadCount; // number of threads total
-};
-
 enum class HalType {
     BINDERIZED_SERVICES = 0,
     PASSTHROUGH_CLIENTS,
@@ -110,9 +105,9 @@
     // Get relevant information for a PID by parsing files under
     // /dev/binderfs/binder_logs or /d/binder.
     // It is a virtual member function so that it can be mocked.
-    virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+    virtual bool getPidInfo(pid_t serverPid, BinderPidInfo *info) const;
     // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
-    const PidInfo* getPidInfoCached(pid_t serverPid);
+    const BinderPidInfo* getPidInfoCached(pid_t serverPid);
 
     void dumpTable(const NullableOStream<std::ostream>& out) const;
     void dumpVintf(const NullableOStream<std::ostream>& out) const;
@@ -191,7 +186,7 @@
     std::map<pid_t, std::string> mCmdlines;
 
     // Cache for getPidInfo.
-    std::map<pid_t, PidInfo> mCachedPidInfos;
+    std::map<pid_t, BinderPidInfo> mCachedPidInfos;
 
     // Cache for getPartition.
     std::map<pid_t, Partition> mPartitions;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 3c36813..476aa04 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -32,7 +32,7 @@
 namespace lshal {
 
 using android::procpartition::Partition;
-using Pids = std::vector<int32_t>;
+using Pids = std::vector<pid_t>;
 
 enum class TableColumnType : unsigned int {
     INTERFACE_NAME = 0,
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index ba6cdf1..b6ff28d 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -233,12 +233,12 @@
         return ListCommand::dumpVintf(out);
     }
     void internalPostprocess() { ListCommand::postprocess(); }
-    const PidInfo* getPidInfoCached(pid_t serverPid) {
+    const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
         return ListCommand::getPidInfoCached(serverPid);
     }
 
     MOCK_METHOD0(postprocess, void());
-    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
+    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
     MOCK_METHOD1(getPartition, Partition(pid_t));
 
@@ -299,8 +299,8 @@
 static std::vector<pid_t> getClients(pid_t serverId) {
     return {serverId + 1, serverId + 3};
 }
-static PidInfo getPidInfoFromId(pid_t serverId) {
-    PidInfo info;
+static BinderPidInfo getPidInfoFromId(pid_t serverId) {
+    BinderPidInfo info;
     info.refPids[getPtr(serverId)] = getClients(serverId);
     info.threadUsage = 10 + serverId;
     info.threadCount = 20 + serverId;
@@ -363,7 +363,7 @@
     void initMockList() {
         mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
         ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
-            [](pid_t serverPid, PidInfo* info) {
+            [](pid_t serverPid, BinderPidInfo* info) {
                 *info = getPidInfoFromId(serverPid);
                 return true;
             }));
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 7aac7da..b21010d 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -494,7 +494,7 @@
     sp<BpBinder> bpBinder = binder->remoteBinder();
     if (bpBinder == nullptr) return -1;
 
-    return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle());
+    return ProcessState::self()->getStrongRefCountForNode(bpBinder);
 }
 
 void ServiceManager::handleClientCallbacks() {
diff --git a/data/etc/android.software.opengles.deqp.level-2020-03-01.xml b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
new file mode 100644
index 0000000..f11e0bb
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+     dEQP tests associated with date 2020-03-01 (0x07E40301). -->
+<permissions>
+    <feature name="android.software.opengles.deqp.level" version="132383489" />
+</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2021-03-01.xml b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..b60697d
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+     dEQP tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+    <feature name="android.software.opengles.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
index 9c67d4a..d3ad45a 100644
--- a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
      tests associated with date 2019-03-01 (0x07E30301). -->
 <permissions>
     <feature name="android.software.vulkan.deqp.level" version="132317953" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
index 19b269b..84ba389 100644
--- a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
      tests associated with date 2020-03-01 (0x07E40301). -->
 <permissions>
     <feature name="android.software.vulkan.deqp.level" version="132383489" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..ae26269
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+     tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+    <feature name="android.software.vulkan.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 50f117d..6ffb947 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -38,7 +38,6 @@
     <!-- basic system services -->
     <feature name="android.software.connectionservice" />
     <feature name="android.software.voice_recognizers" notLowRam="true" />
-    <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
new file mode 100644
index 0000000..c62da0a
--- /dev/null
+++ b/data/etc/pc_core_hardware.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<!-- These are the hardware components that all handheld devices
+     must include. Devices with optional hardware must also include extra
+     hardware files, per the comments below.
+
+     Handheld devices include phones, mobile Internet devices (MIDs),
+     Personal Media Players (PMPs), small tablets (7" or less), and similar
+     devices.
+-->
+<permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
+    <feature name="android.hardware.audio.output" />
+    <feature name="android.hardware.bluetooth" />
+    <feature name="android.hardware.microphone" />
+    <feature name="android.hardware.screen.portrait" />
+    <feature name="android.hardware.screen.landscape" />
+    <feature name="android.hardware.location" />
+    <feature name="android.hardware.location.network" />
+
+    <!-- basic system services -->
+    <feature name="android.software.app_widgets" />
+    <feature name="android.software.voice_recognizers" />
+    <feature name="android.software.backup" />
+    <feature name="android.software.home_screen" />
+    <feature name="android.software.input_methods" />
+    <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
+    <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
+
+    <!-- Feature to specify if the device supports adding device admins. -->
+    <feature name="android.software.device_admin" />
+
+    <!-- Feature to specify if the device support managed users. -->
+    <feature name="android.software.managed_users" />
+
+    <!-- Feature to specify if the device supports controls. -->
+    <feature name="android.software.controls" />
+
+    <!-- Feature to specify if the device supports freeform. -->
+    <feature name="android.software.freeform_window_management" />
+    <feature name="android.hardware.type.pc" />
+</permissions>
\ No newline at end of file
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index dae6eeb..15bd5c3 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -282,9 +282,8 @@
             LOG(FATAL) << "adbd_auth: unhandled packet type?";
         }
 
-        output_queue_.pop_front();
-
         ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
+        output_queue_.pop_front();
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
             ReplaceFrameworkFd(unique_fd());
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index ee0259d..08b984e 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -182,6 +182,14 @@
     ],
     tidy_checks_as_errors: [
         "*",
+        "-clang-analyzer-core.CallAndMessage",
+        "-clang-analyzer-core.uninitialized.Assign",
+        "-clang-analyzer-unix.Malloc,",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.cplusplus.UninitializedObject",
+        "-misc-no-recursion",
+        "-misc-redundant-expression",
+        "-misc-unused-using-decls",
     ],
 }
 
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index f2d223d..d964d25 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -133,6 +133,7 @@
 public:
     // unlocked objects
     bool mRequestingSid = false;
+    bool mInheritRt = false;
     sp<IBinder> mExtension;
     int mPolicy = SCHED_NORMAL;
     int mPriority = 0;
@@ -327,6 +328,27 @@
     return e->mPriority;
 }
 
+bool BBinder::isInheritRt() {
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    return e && e->mInheritRt;
+}
+
+void BBinder::setInheritRt(bool inheritRt) {
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    if (!e) {
+        if (!inheritRt) {
+            return;
+        }
+
+        e = getOrCreateExtras();
+        if (!e) return; // out of memory
+    }
+
+    e->mInheritRt = inheritRt;
+}
+
 pid_t BBinder::getDebugPid() {
     return getpid();
 }
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 8cf6097..88c85bf 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -18,7 +18,6 @@
 #include <binder/Debug.h>
 
 #include <cutils/atomic.h>
-#include <cutils/threads.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
@@ -91,22 +90,6 @@
 
 static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
 
-static thread_store_t   tls;
-
-BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
-{
-    ThreadState*  ts = (ThreadState*) thread_store_get( &tls );
-    if (ts) return ts;
-    ts = new ThreadState;
-    thread_store_set( &tls, ts, threadDestructor );
-    return ts;
-}
-
-void BufferedTextOutput::threadDestructor(void *st)
-{
-    delete ((ThreadState*)st);
-}
-
 static volatile int32_t gSequence = 0;
 
 static volatile int32_t gFreeBufferIndex = -1;
@@ -266,16 +249,14 @@
 BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
 {
     if ((mFlags&MULTITHREADED) != 0) {
-        ThreadState* ts = getThreadState();
-        if (ts) {
-            while (ts->states.size() <= (size_t)mIndex) ts->states.add(nullptr);
-            BufferState* bs = ts->states[mIndex].get();
-            if (bs != nullptr && bs->seq == mSeq) return bs;
-            
-            ts->states.editItemAt(mIndex) = new BufferState(mIndex);
-            bs = ts->states[mIndex].get();
-            if (bs != nullptr) return bs;
-        }
+        thread_local ThreadState ts;
+        while (ts.states.size() <= (size_t)mIndex) ts.states.add(nullptr);
+        BufferState* bs = ts.states[mIndex].get();
+        if (bs != nullptr && bs->seq == mSeq) return bs;
+
+        ts.states.editItemAt(mIndex) = new BufferState(mIndex);
+        bs = ts.states[mIndex].get();
+        if (bs != nullptr) return bs;
     }
     
     return mGlobalState;
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index 1b27bb2..fdd532a 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -47,10 +47,7 @@
 private:
     struct BufferState;
     struct ThreadState;
-    
-    static  ThreadState*getThreadState();
-    static  void        threadDestructor(void *st);
-    
+
             BufferState*getBuffer() const;
             
     uint32_t            mFlags;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index d4c7acf..7d01e0b 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1248,10 +1248,22 @@
                 constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
                 sendReply(reply, (tr.flags & kForwardReplyFlags));
             } else {
-                if (error != OK || reply.dataSize() != 0) {
-                    alog << "oneway function results will be dropped but finished with status "
-                         << statusToString(error)
-                         << " and parcel size " << reply.dataSize() << endl;
+                if (error != OK) {
+                    alog << "oneway function results for code " << tr.code
+                         << " on binder at "
+                         << reinterpret_cast<void*>(tr.target.ptr)
+                         << " will be dropped but finished with status "
+                         << statusToString(error);
+
+                    // ideally we could log this even when error == OK, but it
+                    // causes too much logspam because some manually-written
+                    // interfaces have clients that call methods which always
+                    // write results, sometimes as oneway methods.
+                    if (reply.dataSize() != 0) {
+                         alog << " and reply parcel size " << reply.dataSize();
+                    }
+
+                    alog << endl;
                 }
                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
             }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 7737d53..9bba369 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -164,12 +164,8 @@
     ALOGE("Invalid object type 0x%08x", obj.hdr.type);
 }
 
-status_t Parcel::finishFlattenBinder(
-    const sp<IBinder>& binder, const flat_binder_object& flat)
+status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
 {
-    status_t status = writeObject(flat, false);
-    if (status != OK) return status;
-
     internal::Stability::tryMarkCompilationUnit(binder.get());
     auto category = internal::Stability::getCategory(binder.get());
     return writeInt32(category.repr());
@@ -210,7 +206,7 @@
             if (proxy == nullptr) {
                 ALOGE("null proxy");
             }
-            const int32_t handle = proxy ? proxy->handle() : 0;
+            const int32_t handle = proxy ? proxy->getPrivateAccessorForHandle().handle() : 0;
             obj.hdr.type = BINDER_TYPE_HANDLE;
             obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
             obj.handle = handle;
@@ -226,6 +222,9 @@
             if (local->isRequestingSid()) {
                 obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
             }
+            if (local->isInheritRt()) {
+                obj.flags |= FLAT_BINDER_FLAG_INHERIT_RT;
+            }
             obj.hdr.type = BINDER_TYPE_BINDER;
             obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
             obj.cookie = reinterpret_cast<uintptr_t>(local);
@@ -238,7 +237,10 @@
 
     obj.flags |= schedBits;
 
-    return finishFlattenBinder(binder, obj);
+    status_t status = writeObject(obj, false);
+    if (status != OK) return status;
+
+    return finishFlattenBinder(binder);
 }
 
 status_t Parcel::unflattenBinder(sp<IBinder>* out) const
@@ -2501,19 +2503,15 @@
 void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
     const binder_size_t* objects, size_t objectsCount, release_func relFunc)
 {
-    binder_size_t minOffset = 0;
-    freeDataNoInit();
-    mError = NO_ERROR;
+    freeData();
+
     mData = const_cast<uint8_t*>(data);
     mDataSize = mDataCapacity = dataSize;
-    //ALOGI("setDataReference Setting data size of %p to %lu (pid=%d)", this, mDataSize, getpid());
-    mDataPos = 0;
-    ALOGV("setDataReference Setting data pos of %p to %zu", this, mDataPos);
     mObjects = const_cast<binder_size_t*>(objects);
     mObjectsSize = mObjectsCapacity = objectsCount;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
     mOwner = relFunc;
+
+    binder_size_t minOffset = 0;
     for (size_t i = 0; i < mObjectsSize; i++) {
         binder_size_t offset = mObjects[i];
         if (offset < minOffset) {
@@ -2683,7 +2681,7 @@
 
     releaseObjects();
 
-    if (data) {
+    if (data || desired == 0) {
         LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired);
         if (mDataCapacity > desired) {
             gParcelGlobalAllocSize -= (mDataCapacity - desired);
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 9aedf28..b5e4dfe 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -124,14 +124,14 @@
 {
     sp<IBinder> context = getStrongProxyForHandle(0);
 
-    if (context == nullptr) {
-       ALOGW("Not able to get context object on %s.", mDriverName.c_str());
+    if (context) {
+        // The root object is special since we get it directly from the driver, it is never
+        // written by Parcell::writeStrongBinder.
+        internal::Stability::markCompilationUnit(context.get());
+    } else {
+        ALOGW("Not able to get context object on %s.", mDriverName.c_str());
     }
 
-    // The root object is special since we get it directly from the driver, it is never
-    // written by Parcell::writeStrongBinder.
-    internal::Stability::markCompilationUnit(context.get());
-
     return context;
 }
 
@@ -204,11 +204,11 @@
 // 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) {
+ssize_t ProcessState::getStrongRefCountForNode(const sp<BpBinder>& binder) {
     binder_node_info_for_ref info;
     memset(&info, 0, sizeof(binder_node_info_for_ref));
 
-    info.handle = handle;
+    info.handle = binder->getPrivateAccessorForHandle().handle();
 
     status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
 
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 4375818..97e282e 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -38,6 +38,9 @@
       "name": "aidl_lazy_test"
     },
     {
+      "name": "aidl_integration_test"
+    },
+    {
       "name": "libbinderthreadstateutils_test"
     },
     {
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 18a8a98..35c697e 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -132,7 +132,11 @@
         OP_DEPRECATED_1 = 96,
         OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97,
         OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98,
-        _NUM_OP = 99
+        OP_NO_ISOLATED_STORAGE = 99,
+        OP_PHONE_CALL_MICROPHONE = 100,
+        OP_PHONE_CALL_CAMERA = 101,
+        OP_RECORD_AUDIO_HOTWORD = 102,
+        _NUM_OP = 103
     };
 
     AppOpsManager();
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index d6da397..7079544 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -87,6 +87,11 @@
     int                 getMinSchedulerPolicy();
     int                 getMinSchedulerPriority();
 
+    // Whether realtime scheduling policies are inherited.
+    bool                isInheritRt();
+    // This must be called before the object is sent to another process. Not thread safe.
+    void                setInheritRt(bool inheritRt);
+
     pid_t               getDebugPid();
 
 protected:
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 2735315..22300ac 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -29,6 +29,7 @@
 namespace internal {
 class Stability;
 }
+class ProcessState;
 
 using binder_proxy_limit_callback = void(*)(int);
 
@@ -37,8 +38,6 @@
 public:
     static BpBinder*    create(int32_t handle);
 
-    int32_t             handle() const;
-
     virtual const String16&    getInterfaceDescriptor() const;
     virtual bool        isBinderAlive() const;
     virtual status_t    pingBinder();
@@ -109,7 +108,23 @@
         KeyedVector<const void*, entry_t> mObjects;
     };
 
+    class PrivateAccessorForHandle {
+    private:
+        friend BpBinder;
+        friend ::android::Parcel;
+        friend ::android::ProcessState;
+        explicit PrivateAccessorForHandle(const BpBinder* binder) : mBinder(binder) {}
+        int32_t handle() const { return mBinder->handle(); }
+        const BpBinder* mBinder;
+    };
+    const PrivateAccessorForHandle getPrivateAccessorForHandle() const {
+        return PrivateAccessorForHandle(this);
+    }
+
 private:
+    friend PrivateAccessorForHandle;
+
+    int32_t             handle() const;
                         BpBinder(int32_t handle,int32_t trackedUid);
     virtual             ~BpBinder();
     virtual void        onFirstRef();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index cfe1f3a..b49951b 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -504,9 +504,6 @@
                                             const binder_size_t* objects, size_t objectsCount,
                                             release_func relFunc);
 
-                        Parcel(const Parcel& o);
-    Parcel&             operator=(const Parcel& o);
-    
     status_t            finishWrite(size_t len);
     void                releaseObjects();
     void                acquireObjects();
@@ -522,8 +519,7 @@
     status_t            validateReadData(size_t len) const;
     void                updateWorkSourceRequestHeaderPosition() const;
 
-    status_t            finishFlattenBinder(const sp<IBinder>& binder,
-                                            const flat_binder_object& flat);
+    status_t            finishFlattenBinder(const sp<IBinder>& binder);
     status_t            finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
     status_t            flattenBinder(const sp<IBinder>& binder);
     status_t            unflattenBinder(sp<IBinder>* out) const;
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index ce5027e..ff0a686 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -52,80 +52,80 @@
     }
 
     template <typename T>
-    bool setParcelable(T&& p) {
+    status_t setParcelable(T&& p) {
         using Tt = typename std::decay<T>::type;
         return setParcelable<Tt>(std::make_shared<Tt>(std::forward<T>(p)));
     }
 
     template <typename T>
-    bool setParcelable(std::shared_ptr<T> p) {
+    status_t setParcelable(std::shared_ptr<T> p) {
         static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
         if (p && this->getStability() > p->getStability()) {
-            return false;
+            return android::BAD_VALUE;
         }
         this->mParcelable = p;
         this->mParcelableName = T::getParcelableDescriptor();
         this->mParcelPtr = nullptr;
-        return true;
+        return android::OK;
     }
 
     template <typename T>
-    std::shared_ptr<T> getParcelable() const {
+    status_t getParcelable(std::shared_ptr<T>* ret) const {
         static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
         const std::string& parcelableDesc = T::getParcelableDescriptor();
         if (!this->mParcelPtr) {
             if (!this->mParcelable || !this->mParcelableName) {
                 ALOGD("empty ParcelableHolder");
-                return nullptr;
+                *ret = nullptr;
+                return android::OK;
             } else if (parcelableDesc != *mParcelableName) {
                 ALOGD("extension class name mismatch expected:%s actual:%s",
                       mParcelableName->c_str(), parcelableDesc.c_str());
-                return nullptr;
+                *ret = nullptr;
+                return android::BAD_VALUE;
             }
-            return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            return android::OK;
         }
         this->mParcelPtr->setDataPosition(0);
         status_t status = this->mParcelPtr->readUtf8FromUtf16(&this->mParcelableName);
         if (status != android::OK || parcelableDesc != this->mParcelableName) {
             this->mParcelableName = std::nullopt;
-            return nullptr;
+            *ret = nullptr;
+            return status;
         }
         this->mParcelable = std::make_shared<T>();
         status = mParcelable.get()->readFromParcel(this->mParcelPtr.get());
         if (status != android::OK) {
             this->mParcelableName = std::nullopt;
             this->mParcelable = nullptr;
-            return nullptr;
+            *ret = nullptr;
+            return status;
         }
         this->mParcelPtr = nullptr;
-        return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        return android::OK;
     }
 
     Stability getStability() const override { return mStability; }
 
     inline bool operator!=(const ParcelableHolder& rhs) const {
-        return std::tie(mParcelable, mParcelPtr, mStability) !=
-                std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+        return this != &rhs;
     }
     inline bool operator<(const ParcelableHolder& rhs) const {
-        return std::tie(mParcelable, mParcelPtr, mStability) <
-                std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+        return this < &rhs;
     }
     inline bool operator<=(const ParcelableHolder& rhs) const {
-        return std::tie(mParcelable, mParcelPtr, mStability) <=
-                std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+        return this <= &rhs;
     }
     inline bool operator==(const ParcelableHolder& rhs) const {
-        return std::tie(mParcelable, mParcelPtr, mStability) ==
-                std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+        return this == &rhs;
     }
     inline bool operator>(const ParcelableHolder& rhs) const {
-        return std::tie(mParcelable, mParcelPtr, mStability) >
-                std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+        return this > &rhs;
     }
     inline bool operator>=(const ParcelableHolder& rhs) const {
-        return std::tie(mParcelable, mParcelPtr, mStability) >=
-                std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+        return this >= &rhs;
     }
 
 private:
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 46457cd..bab6469 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -70,7 +70,7 @@
                                 // 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);
+            ssize_t             getStrongRefCountForNode(const sp<BpBinder>& binder);
 
             enum class CallRestriction {
                 // all calls okay
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index a57beee..bdb74dc 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -105,6 +105,14 @@
     ],
     tidy_checks_as_errors: [
         "*",
+        "-clang-analyzer-core.CallAndMessage",
+        "-clang-analyzer-core.uninitialized.Assign",
+        "-clang-analyzer-unix.Malloc,",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.cplusplus.UninitializedObject",
+        "-misc-no-recursion",
+        "-misc-redundant-expression",
+        "-misc-unused-using-decls",
     ],
 }
 
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 2d85f90..53871f2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -27,6 +27,7 @@
 #pragma once
 
 #include <android/binder_ibinder.h>
+#include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 #include <android/binder_status.h>
 
@@ -114,6 +115,13 @@
      */
     AIBinder** getR() { return &mBinder; }
 
+    bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
+    bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
+    bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
+
    private:
     AIBinder* mBinder = nullptr;
 };
@@ -123,7 +131,7 @@
 /**
  * This baseclass owns a single object, used to make various classes RAII.
  */
-template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
+template <typename T, void (*Destroy)(T), T DEFAULT>
 class ScopedAResource {
    public:
     /**
@@ -191,7 +199,7 @@
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public impl::ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+class ScopedAParcel : public impl::ScopedAResource<AParcel*, AParcel_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -200,12 +208,19 @@
     ~ScopedAParcel() {}
     ScopedAParcel(ScopedAParcel&&) = default;
     ScopedAParcel& operator=(ScopedAParcel&&) = default;
+
+    bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
+    bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
+    bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
 };
 
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -277,7 +292,7 @@
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-    : public impl::ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+    : public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete,
                                    nullptr> {
    public:
     /**
@@ -294,7 +309,7 @@
  * Convenience wrapper. See AIBinder_Weak.
  */
 class ScopedAIBinder_Weak
-    : public impl::ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+    : public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -310,10 +325,22 @@
     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
 };
 
+namespace internal {
+
+static void closeWithError(int fd) {
+    if (fd == -1) return;
+    int ret = close(fd);
+    if (ret != 0) {
+        syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
+    }
+}
+
+}  // namespace internal
+
 /**
  * Convenience wrapper for a file descriptor.
  */
-class ScopedFileDescriptor : public impl::ScopedAResource<int, int, close, -1> {
+class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> {
    public:
     /**
      * Takes ownership of a.
@@ -323,6 +350,13 @@
     ~ScopedFileDescriptor() {}
     ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
     ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
+
+    bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
+    bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
+    bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
 };
 
 }  // namespace ndk
diff --git a/libs/binder/ndk/include_cpp/android/binder_internal_logging.h b/libs/binder/ndk/include_cpp/android/binder_internal_logging.h
new file mode 100644
index 0000000..88c6443
--- /dev/null
+++ b/libs/binder/ndk/include_cpp/android/binder_internal_logging.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_internal_logging.h
+ * @brief This provides the ability to use syslog from binder headers, since
+ * other logging functionality might be inaccessable.
+ */
+
+#pragma once
+
+// defined differently by liblog
+#pragma push_macro("LOG_PRI")
+#ifdef LOG_PRI
+#undef LOG_PRI
+#endif
+#include <syslog.h>
+#pragma pop_macro("LOG_PRI")
+
+/** @} */
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 054aebe..83190aa 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -27,6 +27,7 @@
 #pragma once
 
 #include <android/binder_auto_utils.h>
+#include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 
 #include <optional>
@@ -179,6 +180,7 @@
 static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel,
                                                                 const SpAIBinder& binder) {
     if (binder.get() == nullptr) {
+        syslog(LOG_ERR, "Passing null binder object as non-@nullable AIDL IBinder");
         return STATUS_UNEXPECTED_NULL;
     }
     return AParcel_writeStrongBinder(parcel, binder.get());
@@ -228,6 +230,7 @@
 static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor(
         AParcel* parcel, const ScopedFileDescriptor& fd) {
     if (fd.get() < 0) {
+        syslog(LOG_ERR, "Passing -1 file descriptor as non-@nullable AIDL ParcelFileDescriptor");
         return STATUS_UNEXPECTED_NULL;
     }
     return AParcel_writeParcelFileDescriptor(parcel, fd.get());
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 4858514..6636a41 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -82,38 +82,48 @@
     }
 
     template <typename T>
-    bool setParcelable(const T& p) {
+    binder_status_t setParcelable(const T& p) {
         if (this->mStability > T::_aidl_stability) {
-            return false;
+            return STATUS_BAD_VALUE;
         }
         AParcel_reset(mParcel.get());
         AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
         p.writeToParcel(mParcel.get());
-        return true;
+        return STATUS_OK;
     }
 
     template <typename T>
-    std::unique_ptr<T> getParcelable() const {
+    binder_status_t getParcelable(std::optional<T>* ret) const {
         const std::string parcelableDesc(T::descriptor);
         AParcel_setDataPosition(mParcel.get(), 0);
         if (AParcel_getDataSize(mParcel.get()) == 0) {
-            return nullptr;
+            *ret = std::nullopt;
+            return STATUS_OK;
         }
         std::string parcelableDescInParcel;
         binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
         if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
-            return nullptr;
+            *ret = std::nullopt;
+            return status;
         }
-        std::unique_ptr<T> ret = std::make_unique<T>();
-        status = ret->readFromParcel(this->mParcel.get());
+        *ret = std::make_optional<T>();
+        status = (*ret)->readFromParcel(this->mParcel.get());
         if (status != STATUS_OK) {
-            return nullptr;
+            *ret = std::nullopt;
+            return status;
         }
-        return std::move(ret);
+        return STATUS_OK;
     }
 
     void reset() { AParcel_reset(mParcel.get()); }
 
+    inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
+    inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
+    inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; }
+    inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
+    inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
+    inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
+
    private:
     mutable ndk::ScopedAParcel mParcel;
     parcelable_stability_t mStability;
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 386c70b..78606cc 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -20,12 +20,16 @@
 #include "hwbinder.h"
 #include "util.h"
 
+#include <iostream>
+
 #include <android-base/logging.h>
 #include <fuzzbinder/random_parcel.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
 #include <cstdlib>
 #include <ctime>
+#include <sys/resource.h>
+#include <sys/time.h>
 
 using android::fillRandomParcel;
 
@@ -77,7 +81,25 @@
     }
 }
 
+size_t getHardMemoryLimit() {
+    struct rlimit limit;
+    CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
+    return limit.rlim_max;
+}
+
+void setMemoryLimit(size_t cur, size_t max) {
+    const struct rlimit kLimit = {
+       .rlim_cur = cur,
+       .rlim_max = max,
+    };
+    CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+}
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    static constexpr size_t kMemLimit = 1 * 1024 * 1024;
+    size_t hardLimit = getHardMemoryLimit();
+    setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
+
     if (size <= 1) return 0;  // no use
 
     // avoid timeouts, see b/142617274, b/142473153
@@ -102,5 +124,7 @@
 
     provider.PickValueInArray(fuzzBackend)(std::move(provider));
 
+    setMemoryLimit(hardLimit, hardLimit);
+
     return 0;
 }
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index b558f27..ed3b9ec 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -592,7 +592,9 @@
                         // pointer.
                         return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
                     }
-                } else if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
+                }
+
+                if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
                     let service: $crate::Result<$crate::Binder<$native>> =
                         std::convert::TryFrom::try_from(ibinder.clone());
                     if let Ok(service) = service {
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 8ee6a62..edfb56a 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -122,7 +122,7 @@
     pub use super::parcel::ParcelFileDescriptor;
     pub use super::{add_service, get_interface};
     pub use super::{
-        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode,
+        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, WpIBinder,
     };
 
     /// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 485bb42..17af099 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -102,6 +102,11 @@
             class.as_ref().map(|p| InterfaceClass::from_ptr(p))
         }
     }
+
+    /// Creates a new weak reference to this binder object.
+    pub fn downgrade(&mut self) -> WpIBinder {
+        WpIBinder::new(self)
+    }
 }
 
 /// An object that can be associate with an [`InterfaceClass`].
@@ -370,15 +375,25 @@
 
 /// A weak reference to a Binder remote object.
 ///
-/// This struct encapsulates the C++ `wp<IBinder>` class. However, this wrapper
-/// is untyped, so properly typed versions implementing a particular binder
-/// interface should be crated with [`declare_binder_interface!`].
+/// This struct encapsulates the generic C++ `wp<IBinder>` class. This wrapper
+/// is untyped; typed interface access is implemented by the AIDL compiler.
 pub struct WpIBinder(*mut sys::AIBinder_Weak);
 
+impl fmt::Debug for WpIBinder {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("WpIBinder")
+    }
+}
+
+/// # Safety
+///
+/// A `WpIBinder` is a handle to a C++ IBinder, which is thread-safe.
+unsafe impl Send for WpIBinder {}
+
 impl WpIBinder {
     /// Create a new weak reference from an object that can be converted into a
     /// raw `AIBinder` pointer.
-    pub fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
+    fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
         let ptr = unsafe {
             // Safety: `SpIBinder` guarantees that `binder` always contains a
             // valid pointer to an `AIBinder`.
@@ -401,6 +416,16 @@
     }
 }
 
+impl Drop for WpIBinder {
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
+            // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
+            sys::AIBinder_Weak_delete(self.0);
+        }
+    }
+}
+
 /// Rust wrapper around DeathRecipient objects.
 #[repr(C)]
 pub struct DeathRecipient {
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 497361a..bb8c492 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -482,4 +482,17 @@
         let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
             .expect("Could not re-interpret service as the ITestSameDescriptor interface");
     }
+
+    /// Test that we can round-trip a rust service through a generic IBinder
+    #[test]
+    fn reassociate_rust_binder() {
+        let service_name = "testing_service";
+        let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
+            .as_binder();
+
+        let service: Box<dyn ITest> = service_ibinder.into_interface()
+            .expect("Could not reassociate the generic ibinder");
+
+        assert_eq!(service.test().unwrap(), service_name);
+    }
 }
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index ad4729d..a5261e5 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
 #include <binder/IServiceManager.h>
 
 #include <private/binder/binder_module.h>
+#include <linux/sched.h>
 #include <sys/epoll.h>
 #include <sys/prctl.h>
 
@@ -53,6 +54,7 @@
 
 static constexpr int kSchedPolicy = SCHED_RR;
 static constexpr int kSchedPriority = 7;
+static constexpr int kSchedPriorityMore = 8;
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
 
@@ -402,6 +404,13 @@
     EXPECT_EQ(NO_ERROR, ret);
 }
 
+TEST_F(BinderLibTest, NopTransactionOneway) {
+    status_t ret;
+    Parcel data, reply;
+    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 TEST_F(BinderLibTest, NopTransactionClear) {
     status_t ret;
     Parcel data, reply;
@@ -1088,6 +1097,25 @@
     EXPECT_EQ(kSchedPriority, priority);
 }
 
+TEST_F(BinderLibTest, InheritRt) {
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+
+    const struct sched_param param {
+        .sched_priority = kSchedPriorityMore,
+    };
+    EXPECT_EQ(0, sched_setscheduler(getpid(), SCHED_RR, &param));
+
+    Parcel data, reply;
+    status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    int policy = reply.readInt32();
+    int priority = reply.readInt32();
+
+    EXPECT_EQ(kSchedPolicy, policy & (~SCHED_RESET_ON_FORK));
+    EXPECT_EQ(kSchedPriorityMore, priority);
+}
 
 TEST_F(BinderLibTest, VectorSent) {
     Parcel data, reply;
@@ -1161,9 +1189,6 @@
         virtual status_t onTransact(uint32_t code,
                                     const Parcel& data, Parcel* reply,
                                     uint32_t flags = 0) {
-            //printf("%s: code %d\n", __func__, code);
-            (void)flags;
-
             if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) {
                 return PERMISSION_DENIED;
             }
@@ -1237,8 +1262,12 @@
                 return NO_ERROR;
             case BINDER_LIB_TEST_NOP_TRANSACTION_WAIT:
                 usleep(5000);
-                return NO_ERROR;
+                [[fallthrough]];
             case BINDER_LIB_TEST_NOP_TRANSACTION:
+                // oneway error codes should be ignored
+                if (flags & TF_ONE_WAY) {
+                    return UNKNOWN_ERROR;
+                }
                 return NO_ERROR;
             case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
                 // Note: this transaction is only designed for use with a
@@ -1460,6 +1489,8 @@
 
         testService->setMinSchedulerPolicy(kSchedPolicy, kSchedPriority);
 
+        testService->setInheritRt(true);
+
         /*
          * Normally would also contain functionality as well, but we are only
          * testing the extension mechanism.
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 2f9d85e..ffb3ef2 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -36,12 +36,15 @@
 #include <optional>
 
 #include <sys/eventfd.h>
+#include <sys/prctl.h>
 
 using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
 
 namespace android {
 namespace tests {
 
+static const String16 kServiceName("SafeInterfaceTest");
+
 enum class TestEnum : uint32_t {
     INVALID = 0,
     INITIAL = 1,
@@ -601,40 +604,13 @@
     static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
 
     sp<ISafeInterfaceTest> getRemoteService() {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wexit-time-destructors"
-        static std::mutex sMutex;
-        static sp<ISafeInterfaceTest> sService;
-        static sp<IBinder> sDeathToken = new BBinder;
-#pragma clang diagnostic pop
+        sp<IBinder> binder = defaultServiceManager()->getService(kServiceName);
+        sp<ISafeInterfaceTest> iface = interface_cast<ISafeInterfaceTest>(binder);
+        EXPECT_TRUE(iface != nullptr);
 
-        std::unique_lock<decltype(sMutex)> lock;
-        if (sService == nullptr) {
-            ALOG(LOG_INFO, getLogTag(), "Forking remote process");
-            pid_t forkPid = fork();
-            EXPECT_NE(forkPid, -1);
+        iface->setDeathToken(new BBinder);
 
-            const String16 serviceName("SafeInterfaceTest");
-
-            if (forkPid == 0) {
-                ALOG(LOG_INFO, getLogTag(), "Remote process checking in");
-                sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
-                defaultServiceManager()->addService(serviceName,
-                                                    IInterface::asBinder(nativeService));
-                ProcessState::self()->startThreadPool();
-                IPCThreadState::self()->joinThreadPool();
-                // We shouldn't get to this point
-                [&]() { FAIL(); }();
-            }
-
-            sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
-            sService = interface_cast<ISafeInterfaceTest>(binder);
-            EXPECT_TRUE(sService != nullptr);
-
-            sService->setDeathToken(sDeathToken);
-        }
-
-        return sService;
+        return iface;
     }
 };
 
@@ -840,5 +816,23 @@
     ASSERT_EQ(b + 1, bPlusOne);
 }
 
+extern "C" int main(int argc, char **argv) {
+    testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        sp<BnSafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
+        status_t status = defaultServiceManager()->addService(kServiceName, nativeService);
+        if (status != OK) {
+            ALOG(LOG_INFO, "SafeInterfaceServer", "could not register");
+            return EXIT_FAILURE;
+        }
+        IPCThreadState::self()->joinThreadPool();
+        return EXIT_FAILURE;
+    }
+
+    return RUN_ALL_TESTS();
+}
+
 } // namespace tests
 } // namespace android
diff --git a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
index 9ac65bb..69f1b9d 100644
--- a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
+++ b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
@@ -37,8 +37,8 @@
                                   bbinder->isRequestingSid();
                               },
                               [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
-                                  bool request_sid = fdp->ConsumeBool();
-                                  bbinder->setRequestingSid(request_sid);
+                                  bool requestSid = fdp->ConsumeBool();
+                                  bbinder->setRequestingSid(requestSid);
                               },
                               [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
                                   bbinder->getExtension();
@@ -63,6 +63,13 @@
                               [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
                                   bbinder->getMinSchedulerPriority();
                               },
+                              [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
+                                  bool inheritRt = fdp->ConsumeBool();
+                                  bbinder->setInheritRt(inheritRt);
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->isInheritRt();
+                              },
                               [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
                                   bbinder->getDebugPid();
                               }};
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
index c685b41..6ca0e2f 100644
--- a/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
@@ -48,9 +48,7 @@
 static const std::vector<std::function<void(FuzzedDataProvider*, const sp<BpBinder>&,
                                             const sp<IBinder::DeathRecipient>&)>>
         gBPBinderOperations =
-                {[](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
-                    const sp<IBinder::DeathRecipient>&) -> void { bpbinder->handle(); },
-                 [](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
+                {[](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
                     const sp<IBinder::DeathRecipient>& s_recipient) -> void {
                      // Clean up possible leftover memory.
                      wp<IBinder::DeathRecipient> outRecipient(nullptr);
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
new file mode 100644
index 0000000..343246a
--- /dev/null
+++ b/libs/binderdebug/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libbinderdebug",
+    vendor_available: true,
+    shared_libs: [
+        "libbase",
+        "libbinder",
+    ],
+    srcs: [
+        "BinderDebug.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/binderdebug/BinderDebug.cpp b/libs/binderdebug/BinderDebug.cpp
new file mode 100644
index 0000000..b435dba
--- /dev/null
+++ b/libs/binderdebug/BinderDebug.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <binder/Binder.h>
+#include <sys/types.h>
+#include <fstream>
+#include <regex>
+
+#include <binderdebug/BinderDebug.h>
+
+namespace android {
+
+static std::string contextToString(BinderDebugContext context) {
+    switch (context) {
+        case BinderDebugContext::BINDER:
+            return "binder";
+        case BinderDebugContext::HWBINDER:
+            return "hwbinder";
+        case BinderDebugContext::VNDBINDER:
+            return "vndbinder";
+        default:
+            return std::string();
+    }
+}
+
+static status_t scanBinderContext(pid_t pid, const std::string& contextName,
+                                  std::function<void(const std::string&)> eachLine) {
+    std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
+    if (!ifs.is_open()) {
+        ifs.open("/d/binder/proc/" + std::to_string(pid));
+        if (!ifs.is_open()) {
+            return -errno;
+        }
+    }
+    static const std::regex kContextLine("^context (\\w+)$");
+
+    bool isDesiredContext = false;
+    std::string line;
+    std::smatch match;
+    while (getline(ifs, line)) {
+        if (std::regex_search(line, match, kContextLine)) {
+            isDesiredContext = match.str(1) == contextName;
+            continue;
+        }
+        if (!isDesiredContext) {
+            continue;
+        }
+        eachLine(line);
+    }
+    return OK;
+}
+
+status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
+    std::smatch match;
+    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
+    std::string contextStr = contextToString(context);
+    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
+        if (std::regex_search(line, match, kReferencePrefix)) {
+            const std::string& ptrString = "0x" + match.str(2); // use number after c
+            uint64_t ptr;
+            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+                // Should not reach here, but just be tolerant.
+                return;
+            }
+            const std::string proc = " proc ";
+            auto pos = line.rfind(proc);
+            if (pos != std::string::npos) {
+                for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
+                    int32_t pid;
+                    if (!::android::base::ParseInt(pidStr, &pid)) {
+                        return;
+                    }
+                    pidInfo->refPids[ptr].push_back(pid);
+                }
+            }
+
+            return;
+        }
+        if (std::regex_search(line, match, kThreadPrefix)) {
+            // "1" is waiting in binder driver
+            // "2" is poll. It's impossible to tell if these are in use.
+            //     and HIDL default code doesn't use it.
+            bool isInUse = match.str(1) != "1";
+            // "0" is a thread that has called into binder
+            // "1" is looper thread
+            // "2" is main looper thread
+            bool isBinderThread = match.str(2) != "0";
+            if (!isBinderThread) {
+                return;
+            }
+            if (isInUse) {
+                pidInfo->threadUsage++;
+            }
+
+            pidInfo->threadCount++;
+            return;
+        }
+        return;
+    });
+    return ret;
+}
+
+} // namespace  android
diff --git a/libs/binderdebug/TEST_MAPPING b/libs/binderdebug/TEST_MAPPING
new file mode 100644
index 0000000..2f3353e
--- /dev/null
+++ b/libs/binderdebug/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "libbinderdebug_test"
+    }
+  ]
+}
diff --git a/libs/binderdebug/include/binderdebug/BinderDebug.h b/libs/binderdebug/include/binderdebug/BinderDebug.h
new file mode 100644
index 0000000..14a0ef3
--- /dev/null
+++ b/libs/binderdebug/include/binderdebug/BinderDebug.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <map>
+#include <vector>
+
+namespace android {
+
+struct BinderPidInfo {
+    std::map<uint64_t, std::vector<pid_t>> refPids; // cookie -> processes which hold binder
+    uint32_t threadUsage;                           // number of threads in use
+    uint32_t threadCount;                           // number of threads total
+};
+
+enum class BinderDebugContext {
+    BINDER,
+    HWBINDER,
+    VNDBINDER,
+};
+
+status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
+
+} // namespace  android
diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp
new file mode 100644
index 0000000..4c06b1d
--- /dev/null
+++ b/libs/binderdebug/tests/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "libbinderdebug_test",
+    test_suites: ["general-tests"],
+    srcs: [
+        "binderdebug_test.cpp",
+        "android/binderdebug/test/IControl.aidl",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+    static_libs: ["libbinderdebug"],
+    cflags: ["-Wall", "-Werror"],
+    require_root: true,
+}
diff --git a/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl b/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
new file mode 100644
index 0000000..8efeb63
--- /dev/null
+++ b/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.binderdebug.test;
+
+interface IControl {
+    // Notifies the service to continue execution
+    void Continue();
+}
diff --git a/libs/binderdebug/tests/binderdebug_test.cpp b/libs/binderdebug/tests/binderdebug_test.cpp
new file mode 100644
index 0000000..ea799c0
--- /dev/null
+++ b/libs/binderdebug/tests/binderdebug_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/IPCThreadState.h>
+#include <binderdebug/BinderDebug.h>
+#include <gtest/gtest.h>
+#include <semaphore.h>
+#include <thread>
+
+#include <android/binderdebug/test/BnControl.h>
+#include <android/binderdebug/test/IControl.h>
+
+namespace android {
+namespace binderdebug {
+namespace test {
+
+class Control : public BnControl {
+public:
+    Control() {sem_init(&s, 1, 0);};
+    ::android::binder::Status Continue() override;
+    sem_t s;
+};
+
+::android::binder::Status Control::Continue() {
+    IPCThreadState::self()->flushCommands();
+    sem_post(&s);
+    return binder::Status::ok();
+}
+
+TEST(BinderDebugTests, BinderPid) {
+    BinderPidInfo pidInfo;
+    const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
+    ASSERT_EQ(status, OK);
+    // There should be one referenced PID for servicemanager
+    EXPECT_TRUE(!pidInfo.refPids.empty());
+}
+
+TEST(BinderDebugTests, BinderThreads) {
+    BinderPidInfo pidInfo;
+    const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
+    ASSERT_EQ(status, OK);
+    EXPECT_TRUE(pidInfo.threadUsage <= pidInfo.threadCount);
+    // The second looper thread can sometimes take longer to spawn.
+    EXPECT_GE(pidInfo.threadCount, 1);
+}
+
+extern "C" {
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Create a child/client process to call into the main process so we can ensure
+    // looper thread has been registered before attempting to get the BinderPidInfo
+    pid_t pid = fork();
+    if (pid == 0) {
+        sp<IBinder> binder = android::defaultServiceManager()->getService(String16("binderdebug"));
+        sp<IControl> service;
+        if (binder != nullptr) {
+            service = android::interface_cast<IControl>(binder);
+        }
+        service->Continue();
+        exit(0);
+    }
+    sp<Control> iface = new Control;
+    android::defaultServiceManager()->addService(String16("binderdebug"), iface);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
+    ProcessState::self()->startThreadPool();
+    sem_wait(&iface->s);
+
+    return RUN_ALL_TESTS();
+}
+} // extern "C"
+} // namespace  test
+} // namespace  binderdebug
+} // namespace  android
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index b1943a4..e3cd085 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -33,5 +33,6 @@
         "-Wall",
         "-Wextra",
     ],
+    require_root: true,
 }
 
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 6058430..4209dc5 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -59,6 +59,7 @@
 static unique_fd gTisMapFd;
 static unique_fd gConcurrentMapFd;
 static unique_fd gUidLastUpdateMapFd;
+static unique_fd gPidTisMapFd;
 
 static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
     std::string data;
@@ -139,6 +140,12 @@
             unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
     if (gUidLastUpdateMapFd < 0) return false;
 
+    gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_time_in_state_pid_time_in_state_map")};
+    if (gPidTisMapFd < 0) return false;
+
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    if (trackedPidMapFd < 0) return false;
+
     gInitialized = true;
     return true;
 }
@@ -222,7 +229,8 @@
     }
 
     gTracking = attachTracepointProgram("sched", "sched_switch") &&
-            attachTracepointProgram("power", "cpu_frequency");
+            attachTracepointProgram("power", "cpu_frequency") &&
+            attachTracepointProgram("sched", "sched_process_free");
     return gTracking;
 }
 
@@ -502,5 +510,106 @@
     return true;
 }
 
+bool startTrackingProcessCpuTimes(pid_t pid) {
+    if (!gInitialized && !initGlobals()) return false;
+
+    unique_fd trackedPidHashMapFd(
+            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_hash_map"));
+    if (trackedPidHashMapFd < 0) return false;
+
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    if (trackedPidMapFd < 0) return false;
+
+    for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
+        // Find first available [index, pid] entry in the pid_tracked_hash_map map
+        if (writeToMapEntry(trackedPidHashMapFd, &index, &pid, BPF_NOEXIST) != 0) {
+            if (errno != EEXIST) {
+                return false;
+            }
+            continue; // This index is already taken
+        }
+
+        tracked_pid_t tracked_pid = {.pid = pid, .state = TRACKED_PID_STATE_ACTIVE};
+        if (writeToMapEntry(trackedPidMapFd, &index, &tracked_pid, BPF_ANY) != 0) {
+            return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+// Marks the specified task identified by its PID (aka TID) for CPU time-in-state tracking
+// aggregated with other tasks sharing the same TGID and aggregation key.
+bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
+    if (!gInitialized && !initGlobals()) return false;
+
+    unique_fd taskAggregationMapFd(
+            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_task_aggregation_map"));
+    if (taskAggregationMapFd < 0) return false;
+
+    return writeToMapEntry(taskAggregationMapFd, &pid, &aggregationKey, BPF_ANY) == 0;
+}
+
+// Retrieves the times in ns that each thread spent running at each CPU freq, aggregated by
+// aggregation key.
+// Return contains no value on error, otherwise it contains a map from aggregation keys
+// to vectors of vectors using the format:
+// { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+//   aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+// where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest freq.
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys) {
+    if (!gInitialized && !initGlobals()) return {};
+
+    uint32_t maxFreqCount = 0;
+    std::vector<std::vector<uint64_t>> mapFormat;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+        mapFormat.emplace_back(freqList.size(), 0);
+    }
+
+    bool dataCollected = false;
+    std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
+    std::vector<tis_val_t> vals(gNCpus);
+    for (uint16_t aggregationKey : aggregationKeys) {
+        map.emplace(aggregationKey, mapFormat);
+
+        aggregated_task_tis_key_t key{.tgid = tgid, .aggregation_key = aggregationKey};
+        for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+            if (findMapEntry(gPidTisMapFd, &key, vals.data()) != 0) {
+                if (errno != ENOENT) {
+                    return {};
+                }
+                continue;
+            } else {
+                dataCollected = true;
+            }
+
+            // Combine data by aggregating time-in-state data grouped by CPU cluster aka policy.
+            uint32_t offset = key.bucket * FREQS_PER_ENTRY;
+            uint32_t nextOffset = offset + FREQS_PER_ENTRY;
+            for (uint32_t j = 0; j < gNPolicies; ++j) {
+                if (offset >= gPolicyFreqs[j].size()) continue;
+                auto begin = map[key.aggregation_key][j].begin() + offset;
+                auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY
+                                                               : map[key.aggregation_key][j].end();
+                for (const auto &cpu : gPolicyCpus[j]) {
+                    std::transform(begin, end, std::begin(vals[cpu].ar), begin,
+                                   std::plus<uint64_t>());
+                }
+            }
+        }
+    }
+
+    if (!dataCollected) {
+        // Check if eBPF is supported on this device. If it is, gTisMap should not be empty.
+        time_key_t key;
+        if (getFirstMapKey(gTisMapFd, &key) != 0) {
+            return {};
+        }
+    }
+    return map;
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index b7600f5..87a328a 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -41,5 +41,10 @@
     getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate);
 bool clearUidTimes(unsigned int uid);
 
+bool startTrackingProcessCpuTimes(pid_t pid);
+bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey);
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+getAggregatedTaskCpuFreqTimes(pid_t pid, const std::vector<uint16_t> &aggregationKeys);
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 0d5f412..519689b 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -19,6 +19,8 @@
 
 #include <sys/sysinfo.h>
 
+#include <pthread.h>
+#include <semaphore.h>
 #include <numeric>
 #include <unordered_map>
 #include <vector>
@@ -504,5 +506,85 @@
     for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
 }
 
+uint64_t timeNanos() {
+    struct timespec spec;
+    clock_gettime(CLOCK_MONOTONIC, &spec);
+    return spec.tv_sec * 1000000000 + spec.tv_nsec;
+}
+
+// Keeps CPU busy with some number crunching
+void useCpu() {
+    long sum = 0;
+    for (int i = 0; i < 100000; i++) {
+        sum *= i;
+    }
+}
+
+sem_t pingsem, pongsem;
+
+void *testThread(void *) {
+    for (int i = 0; i < 10; i++) {
+        sem_wait(&pingsem);
+        useCpu();
+        sem_post(&pongsem);
+    }
+    return nullptr;
+}
+
+TEST(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
+    uint64_t startTimeNs = timeNanos();
+
+    sem_init(&pingsem, 0, 1);
+    sem_init(&pongsem, 0, 0);
+
+    pthread_t thread;
+    ASSERT_EQ(pthread_create(&thread, NULL, &testThread, NULL), 0);
+
+    // This process may have been running for some time, so when we start tracking
+    // CPU time, the very first switch may include the accumulated time.
+    // Yield the remainder of this timeslice to the newly created thread.
+    sem_wait(&pongsem);
+    sem_post(&pingsem);
+
+    pid_t tgid = getpid();
+    startTrackingProcessCpuTimes(tgid);
+
+    pid_t tid = pthread_gettid_np(thread);
+    startAggregatingTaskCpuTimes(tid, 42);
+
+    // Play ping-pong with the other thread to ensure that both threads get
+    // some CPU time.
+    for (int i = 0; i < 9; i++) {
+        sem_wait(&pongsem);
+        useCpu();
+        sem_post(&pingsem);
+    }
+
+    pthread_join(thread, NULL);
+
+    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> optionalMap =
+            getAggregatedTaskCpuFreqTimes(tgid, {0, 42});
+    ASSERT_TRUE(optionalMap);
+
+    std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map = *optionalMap;
+    ASSERT_EQ(map.size(), 2u);
+
+    uint64_t testDurationNs = timeNanos() - startTimeNs;
+    for (auto pair : map) {
+        uint16_t aggregationKey = pair.first;
+        ASSERT_TRUE(aggregationKey == 0 || aggregationKey == 42);
+
+        std::vector<std::vector<uint64_t>> timesInState = pair.second;
+        uint64_t totalCpuTime = 0;
+        for (size_t i = 0; i < timesInState.size(); i++) {
+            for (size_t j = 0; j < timesInState[i].size(); j++) {
+                totalCpuTime += timesInState[i][j];
+            }
+        }
+        ASSERT_GT(totalCpuTime, 0ul);
+        ASSERT_LE(totalCpuTime, testDurationNs);
+    }
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
index 4a95778..93879d8 100644
--- a/libs/gralloc/OWNERS
+++ b/libs/gralloc/OWNERS
@@ -1,2 +1 @@
 chrisforbes@google.com
-vhau@google.com
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index 1a7c2c9..2f418ac 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -32,202 +32,6 @@
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
 
 namespace android {
-
-/**
- * Define equality operators for Stable AIDL types.
- */
-inline bool operator==(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
-                const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
-    return !std::strcmp(lhs.name.c_str(), rhs.name.c_str()) && lhs.value == rhs.value;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
-                const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
-    if (lhs.type.name != rhs.type.name) {
-        return false;
-    }
-    if (lhs.type.value != rhs.type.value) {
-        return false;
-    }
-    if (lhs.sizeInBits != rhs.sizeInBits) {
-        return false;
-    }
-    if (lhs.offsetInBits != rhs.offsetInBits) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Rect& lhs,
-                const aidl::android::hardware::graphics::common::Rect& rhs) {
-    if (lhs.left != rhs.left) {
-        return false;
-    }
-    if (lhs.top != rhs.top) {
-        return false;
-    }
-    if (lhs.right != rhs.right) {
-        return false;
-    }
-    if (lhs.bottom != rhs.bottom) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lhs,
-                const aidl::android::hardware::graphics::common::Rect& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
-    if (lhs.size() != rhs.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.size(); i++) {
-        if (lhs[i] != rhs[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
-    if (lhs.offsetInBytes != rhs.offsetInBytes) {
-        return false;
-    }
-    if (lhs.sampleIncrementInBits != rhs.sampleIncrementInBits) {
-        return false;
-    }
-    if (lhs.strideInBytes != rhs.strideInBytes) {
-        return false;
-    }
-    if (lhs.widthInSamples != rhs.widthInSamples) {
-        return false;
-    }
-    if (lhs.heightInSamples != rhs.heightInSamples) {
-        return false;
-    }
-    if (lhs.totalSizeInBytes != rhs.totalSizeInBytes) {
-        return false;
-    }
-    if (lhs.horizontalSubsampling != rhs.horizontalSubsampling) {
-        return false;
-    }
-    if (lhs.verticalSubsampling != rhs.verticalSubsampling) {
-        return false;
-    }
-    if (lhs.components.size() != rhs.components.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.components.size(); i++) {
-        if (lhs.components[i] != rhs.components[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
-    if (lhs.size() != rhs.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.size(); i++) {
-        if (lhs[i] != rhs[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::XyColor& lhs,
-                const aidl::android::hardware::graphics::common::XyColor& rhs) {
-    if (lhs.x != rhs.x) {
-        return false;
-    }
-    if (lhs.y != rhs.y) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::XyColor& lhs,
-                const aidl::android::hardware::graphics::common::XyColor& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
-                const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
-    if (lhs.primaryRed != rhs.primaryRed) {
-        return false;
-    }
-    if (lhs.primaryGreen != rhs.primaryGreen) {
-        return false;
-    }
-    if (lhs.primaryBlue != rhs.primaryBlue) {
-        return false;
-    }
-    if (lhs.whitePoint != rhs.whitePoint) {
-        return false;
-    }
-    if (lhs.maxLuminance != rhs.maxLuminance) {
-        return false;
-    }
-    if (lhs.minLuminance != rhs.minLuminance) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
-                const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
-                const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
-    if (lhs.maxContentLightLevel != rhs.maxContentLightLevel) {
-        return false;
-    }
-    if (lhs.maxFrameAverageLightLevel != rhs.maxFrameAverageLightLevel) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
-                const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
-    return !(lhs == rhs);
-}
-
 namespace gralloc4 {
 
 #define GRALLOC4_STANDARD_METADATA_TYPE "android.hardware.graphics.common.StandardMetadataType"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 4a4510e..18ade37 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -32,9 +32,10 @@
 
 cc_library_shared {
     name: "libgui",
-    vendor_available: false,
+    vendor_available: true,
     vndk: {
         enabled: true,
+        private: true,
     },
     double_loadable: true,
 
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index ecccf29..1667fb0 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -7,9 +7,7 @@
 lpy@google.com
 mathias@google.com
 racarr@google.com
-steventhomas@google.com
 stoza@google.com
-vhau@google.com
 vishnun@google.com
 
 per-file EndToEndNativeInputTest.cpp = svv@google.com
@@ -22,4 +20,4 @@
 per-file include/gui/BufferQueue* = set noparent
 per-file include/gui/BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com
 per-file include/gui/IGraphicBuffer* = set noparent
-per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
\ No newline at end of file
+per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 02021c9..56d470e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -409,6 +409,23 @@
     mImageManager = std::make_unique<ImageManager>(this);
     mImageManager->initThread();
     mDrawingBuffer = createFramebuffer();
+    sp<GraphicBuffer> buf =
+            new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, 1,
+                              GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "placeholder");
+
+    const status_t err = buf->initCheck();
+    if (err != OK) {
+        ALOGE("Error allocating placeholder buffer: %d", err);
+        return;
+    }
+    mPlaceholderBuffer = buf.get();
+    EGLint attributes[] = {
+            EGL_NONE,
+    };
+    mPlaceholderImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                          mPlaceholderBuffer, attributes);
+    ALOGE_IF(mPlaceholderImage == EGL_NO_IMAGE_KHR, "Failed to create placeholder image: %#x",
+             eglGetError());
 }
 
 GLESRenderEngine::~GLESRenderEngine() {
@@ -423,6 +440,7 @@
         eglDestroyImageKHR(mEGLDisplay, expired);
         DEBUG_EGL_IMAGE_TRACKER_DESTROY();
     }
+    eglDestroyImageKHR(mEGLDisplay, mPlaceholderImage);
     mImageCache.clear();
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(mEGLDisplay);
@@ -589,6 +607,9 @@
 }
 
 void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+    for (int i = 0; i < count; ++i) {
+        mTextureView.erase(names[i]);
+    }
     glDeleteTextures(count, names);
 }
 
@@ -646,6 +667,7 @@
         }
 
         bindExternalTextureImage(texName, *cachedImage->second);
+        mTextureView.insert_or_assign(texName, buffer->getId());
     }
 
     // Wait for the new buffer to be ready.
@@ -887,7 +909,7 @@
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
-bool GLESRenderEngine::cleanupPostRender() {
+bool GLESRenderEngine::cleanupPostRender(CleanupMode mode) {
     ATRACE_CALL();
 
     if (mPriorResourcesCleaned ||
@@ -896,6 +918,30 @@
         return false;
     }
 
+    // This is a bit of a band-aid fix for FrameCaptureProcessor, as we should
+    // not need to keep memory around if we don't need to do so.
+    if (mode == CleanupMode::CLEAN_ALL) {
+        // TODO: SurfaceFlinger memory utilization may benefit from resetting
+        // texture bindings as well. Assess if it does and there's no performance regression
+        // when rebinding the same image data to the same texture, and if so then its mode
+        // behavior can be tweaked.
+        if (mPlaceholderImage != EGL_NO_IMAGE_KHR) {
+            for (auto [textureName, bufferId] : mTextureView) {
+                if (bufferId && mPlaceholderImage != EGL_NO_IMAGE_KHR) {
+                    glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureName);
+                    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
+                                                 static_cast<GLeglImageOES>(mPlaceholderImage));
+                    mTextureView[textureName] = std::nullopt;
+                    checkErrors();
+                }
+            }
+        }
+        {
+            std::lock_guard<std::mutex> lock(mRenderingMutex);
+            mImageCache.clear();
+        }
+    }
+
     // Bind the texture to placeholder so that backing image data can be freed.
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing());
     glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer);
@@ -1622,6 +1668,16 @@
     return cachedImage != mImageCache.end();
 }
 
+bool GLESRenderEngine::isTextureNameKnownForTesting(uint32_t texName) {
+    const auto& entry = mTextureView.find(texName);
+    return entry != mTextureView.end();
+}
+
+std::optional<uint64_t> GLESRenderEngine::getBufferIdForTextureNameForTesting(uint32_t texName) {
+    const auto& entry = mTextureView.find(texName);
+    return entry != mTextureView.end() ? entry->second : std::nullopt;
+}
+
 bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) {
     std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
     return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(),
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 0e003a0..d554041 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -75,7 +75,7 @@
                         const std::vector<const LayerSettings*>& layers,
                         ANativeWindowBuffer* buffer, const bool useFramebufferCache,
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
-    bool cleanupPostRender() override;
+    bool cleanupPostRender(CleanupMode mode) override;
 
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     // Creates an output image for rendering to
@@ -86,6 +86,12 @@
     // Test-only methods
     // Returns true iff mImageCache contains an image keyed by bufferId
     bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex);
+    // Returns true iff texName was previously generated by RenderEngine and was
+    // not destroyed.
+    bool isTextureNameKnownForTesting(uint32_t texName);
+    // Returns the buffer ID of the content bound to texName, or nullopt if no
+    // such mapping exists.
+    std::optional<uint64_t> getBufferIdForTextureNameForTesting(uint32_t texName);
     // Returns true iff mFramebufferImageCache contains an image keyed by bufferId
     bool isFramebufferImageCachedForTesting(uint64_t bufferId)
             EXCLUDES(mFramebufferImageCacheMutex);
@@ -225,6 +231,8 @@
 
     // Cache of GL images that we'll store per GraphicBuffer ID
     std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache GUARDED_BY(mRenderingMutex);
+    std::unordered_map<uint32_t, std::optional<uint64_t>> mTextureView;
+
     // Mutex guarding rendering operations, so that:
     // 1. GL operations aren't interleaved, and
     // 2. Internal state related to rendering that is potentially modified by
@@ -238,6 +246,11 @@
     // ensure that we align on a word. Allocating 16 bytes will provide a
     // guarantee that we don't clobber memory.
     uint32_t mPlaceholderDrawBuffer[4];
+    // Placeholder buffer and image, similar to mPlaceholderDrawBuffer, but
+    // instead these are intended for cleaning up texture memory with the
+    // GL_TEXTURE_EXTERNAL_OES target.
+    ANativeWindowBuffer* mPlaceholderBuffer = nullptr;
+    EGLImage mPlaceholderImage = EGL_NO_IMAGE_KHR;
     sp<Fence> mLastDrawFence;
     // Store a separate boolean checking if prior resources were cleaned up, as
     // devices that don't support native sync fences can't rely on a last draw
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index dc8ce54..611755e 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -742,15 +742,6 @@
         if (needs.isOpaque()) {
             fs << "gl_FragColor.a = 1.0;";
         }
-        if (needs.hasAlpha()) {
-            // modulate the current alpha value with alpha set
-            if (needs.isPremultiplied()) {
-                // ... and the color too if we're premultiplied
-                fs << "gl_FragColor *= color.a;";
-            } else {
-                fs << "gl_FragColor.a *= color.a;";
-            }
-        }
     }
 
     if (needs.hasTransformMatrix() ||
@@ -770,6 +761,23 @@
         }
     }
 
+    /*
+     * Whether applying layer alpha before or after color transform doesn't matter,
+     * as long as we can undo premultiplication. But we cannot un-premultiply
+     * for color transform if the layer alpha = 0, e.g. 0 / (0 + 0.0019) = 0.
+     */
+    if (!needs.drawShadows()) {
+        if (needs.hasAlpha()) {
+            // modulate the current alpha value with alpha set
+            if (needs.isPremultiplied()) {
+                // ... and the color too if we're premultiplied
+                fs << "gl_FragColor *= color.a;";
+            } else {
+                fs << "gl_FragColor.a *= color.a;";
+            }
+        }
+    }
+
     if (needs.hasRoundedCorners()) {
         if (needs.isPremultiplied()) {
             fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));";
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e06e128..74bc44b 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -111,14 +111,25 @@
     // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
     virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
     virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
+
+    enum class CleanupMode {
+        CLEAN_OUTPUT_RESOURCES,
+        CLEAN_ALL,
+    };
     // Clean-up method that should be called on the main thread after the
     // drawFence returned by drawLayers fires. This method will free up
     // resources used by the most recently drawn frame. If the frame is still
     // being drawn, then this call is silently ignored.
     //
+    // If mode is CLEAN_OUTPUT_RESOURCES, then only resources related to the
+    // output framebuffer are cleaned up, including the sibling texture.
+    //
+    // If mode is CLEAN_ALL, then we also cleanup resources related to any input
+    // buffers.
+    //
     // Returns true if resources were cleaned up, and false if we didn't need to
     // do any work.
-    virtual bool cleanupPostRender() = 0;
+    virtual bool cleanupPostRender(CleanupMode mode = CleanupMode::CLEAN_OUTPUT_RESOURCES) = 0;
 
     // queries
     virtual size_t getMaxTextureSize() const = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index df0f17a..101cbb7 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -56,7 +56,7 @@
     MOCK_CONST_METHOD0(isProtected, bool());
     MOCK_CONST_METHOD0(supportsProtectedContent, bool());
     MOCK_METHOD1(useProtectedContext, bool(bool));
-    MOCK_METHOD0(cleanupPostRender, bool());
+    MOCK_METHOD1(cleanupPostRender, bool(CleanupMode mode));
     MOCK_METHOD6(drawLayers,
                  status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
                           ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index a720a27..1ec9412 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -86,6 +86,7 @@
         }
         for (uint32_t texName : mTexNames) {
             sRE->deleteTextures(1, &texName);
+            EXPECT_FALSE(sRE->isTextureNameKnownForTesting(texName));
         }
         for (uint32_t texName : mTexNamesCM) {
             sRECM->deleteTextures(1, &texName);
@@ -344,6 +345,12 @@
     void fillBufferColorTransformCM();
 
     template <typename SourceVariant>
+    void fillBufferWithColorTransformZeroLayerAlpha();
+
+    template <typename SourceVariant>
+    void fillBufferColorTransformZeroLayerAlpha();
+
+    template <typename SourceVariant>
     void fillRedBufferWithRoundedCorners();
 
     template <typename SourceVariant>
@@ -709,6 +716,39 @@
 }
 
 template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = Rect(1, 1);
+
+    std::vector<const renderengine::LayerSettings*> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+    SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+    layer.alpha = 0;
+
+    // construct a fake color matrix
+    // simple inverse color
+    settings.colorTransform = mat4(-1, 0, 0, 0,
+                                   0, -1, 0, 0,
+                                   0, 0, -1, 0,
+                                   1, 1, 1, 1);
+
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(&layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransformZeroLayerAlpha() {
+    fillBufferWithColorTransformZeroLayerAlpha<SourceVariant>();
+    expectBufferColor(fullscreenRect(), 0, 0, 0, 0);
+}
+
+template <typename SourceVariant>
 void RenderEngineTest::fillRedBufferWithRoundedCorners() {
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1115,6 +1155,10 @@
     fillBufferColorTransformCM<ColorSourceVariant>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
+    fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
     fillBufferWithRoundedCorners<ColorSourceVariant>();
 }
@@ -1175,6 +1219,10 @@
     fillBufferColorTransformCM<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
+    fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
     fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
@@ -1235,6 +1283,10 @@
     fillBufferColorTransformCM<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
+    fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
     fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
@@ -1472,10 +1524,44 @@
     if (fd >= 0) {
         sync_wait(fd, -1);
     }
-
     // Only cleanup the first time.
-    EXPECT_TRUE(sRE->cleanupPostRender());
-    EXPECT_FALSE(sRE->cleanupPostRender());
+    EXPECT_TRUE(sRE->cleanupPostRender(
+            renderengine::RenderEngine::CleanupMode::CLEAN_OUTPUT_RESOURCES));
+    EXPECT_FALSE(sRE->cleanupPostRender(
+            renderengine::RenderEngine::CleanupMode::CLEAN_OUTPUT_RESOURCES));
+}
+
+TEST_F(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<const renderengine::LayerSettings*> layers;
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0;
+    layers.push_back(&layer);
+
+    base::unique_fd fence;
+    sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, base::unique_fd(), &fence);
+
+    const int fd = fence.get();
+    if (fd >= 0) {
+        sync_wait(fd, -1);
+    }
+
+    uint64_t bufferId = layer.source.buffer.buffer->getId();
+    uint32_t texName = layer.source.buffer.textureName;
+    EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+    EXPECT_EQ(bufferId, sRE->getBufferIdForTextureNameForTesting(texName));
+
+    EXPECT_TRUE(sRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL));
+
+    // Now check that our view of memory is good.
+    EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+    EXPECT_EQ(std::nullopt, sRE->getBufferIdForTextureNameForTesting(bufferId));
+    EXPECT_TRUE(sRE->isTextureNameKnownForTesting(texName));
 }
 
 } // namespace android
diff --git a/libs/sensorprivacy/OWNERS b/libs/sensorprivacy/OWNERS
new file mode 100644
index 0000000..be955f5
--- /dev/null
+++ b/libs/sensorprivacy/OWNERS
@@ -0,0 +1,3 @@
+cbrubaker@google.com
+evanseverson@google.com
+mpgroover@google.com
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
new file mode 100644
index 0000000..0997e9f
--- /dev/null
+++ b/libs/vibrator/OWNERS
@@ -0,0 +1,2 @@
+lsandrade@google.com
+michaelwr@google.com
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 393ced7..48abdce 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,36 +52,17 @@
     license: "include/KHR/NOTICE",
 }
 
-llndk_library {
-    name: "libEGL.llndk",
-    symbol_file: "libs/libEGL.map.txt",
-    export_include_dirs: ["include"],
-}
-
-llndk_library {
-    name: "libGLESv1_CM.llndk",
-    symbol_file: "libs/libGLESv1_CM.map.txt",
-    export_include_dirs: ["include"],
-}
-
-llndk_library {
-    name: "libGLESv2.llndk",
-    symbol_file: "libs/libGLESv2.map.txt",
-    export_include_dirs: ["include"],
-}
-
-llndk_library {
-    name: "libGLESv3.llndk",
-    symbol_file: "libs/libGLESv3.map.txt",
-    export_include_dirs: ["include"],
-}
-
 cc_library_headers {
     name: "gl_headers",
     vendor_available: true,
     export_include_dirs: ["include"],
 }
 
+llndk_headers {
+    name: "gl_llndk_headers",
+    export_include_dirs: ["include"],
+}
+
 subdirs = [
     "*",
 ]
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index e7c2e94..ed2ed83 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -230,3 +230,27 @@
     srcs: ["GLES2/gl2.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv3\""],
 }
+
+llndk_library {
+    name: "libEGL.llndk",
+    symbol_file: "libEGL.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
+
+llndk_library {
+    name: "libGLESv1_CM.llndk",
+    symbol_file: "libGLESv1_CM.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
+
+llndk_library {
+    name: "libGLESv2.llndk",
+    symbol_file: "libGLESv2.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
+
+llndk_library {
+    name: "libGLESv3.llndk",
+    symbol_file: "libGLESv3.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index b4b5f98..3cccaf9 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <log/log.h>
 #include <sys/socket.h>
 #include <utils/threads.h>
 
@@ -28,6 +29,12 @@
 #define UNUSED(x) (void)(x)
 
 namespace android {
+namespace {
+
+// Used as the default value for the target SDK until it's obtained via getTargetSdkVersion.
+constexpr int kTargetSdkUnknown = 0;
+
+}  // namespace
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
@@ -35,9 +42,9 @@
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
       mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
-      mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false) {
+      mPackageName(packageName), mOpPackageName(opPackageName), mTargetSdk(kTargetSdkUnknown),
+      mDestroyed(false) {
     mChannel = new BitTube(mService->mSocketBufferSize);
-    mTargetSdk = SensorService::getTargetSdkVersion(opPackageName);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
     mTotalAcksNeeded = mTotalAcksReceived = 0;
@@ -47,20 +54,13 @@
 SensorService::SensorEventConnection::~SensorEventConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
     destroy();
-}
-
-void SensorService::SensorEventConnection::destroy() {
-    Mutex::Autolock _l(mDestroyLock);
-
-    // destroy once only
-    if (mDestroyed) {
-        return;
-    }
-
     mService->cleanupConnection(this);
     if (mEventCache != nullptr) {
         delete[] mEventCache;
     }
+}
+
+void SensorService::SensorEventConnection::destroy() {
     mDestroyed = true;
 }
 
@@ -445,6 +445,14 @@
     bool success = true;
     const auto iter = mHandleToAppOp.find(event.sensor);
     if (iter != mHandleToAppOp.end()) {
+        if (mTargetSdk == kTargetSdkUnknown) {
+            // getTargetSdkVersion returns -1 if it fails so this operation should only be run once
+            // per connection and then cached. Perform this here as opposed to in the constructor to
+            // avoid log spam for NDK/VNDK clients that don't use sensors guarded with permissions
+            // and pass in invalid op package names.
+            mTargetSdk = SensorService::getTargetSdkVersion(mOpPackageName);
+        }
+
         // Special handling for step count/detect backwards compatibility: if the app's target SDK
         // is pre-Q, still permit delivering events to the app even if permission isn't granted
         // (since this permission was only introduced in Q)
@@ -665,6 +673,11 @@
         int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
         int reservedFlags)
 {
+    if (mDestroyed) {
+        android_errorWriteLog(0x534e4554, "168211968");
+        return DEAD_OBJECT;
+    }
+
     status_t err;
     if (enabled) {
         err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
@@ -679,10 +692,19 @@
 status_t SensorService::SensorEventConnection::setEventRate(
         int handle, nsecs_t samplingPeriodNs)
 {
+    if (mDestroyed) {
+        android_errorWriteLog(0x534e4554, "168211968");
+        return DEAD_OBJECT;
+    }
+
     return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
 }
 
 status_t  SensorService::SensorEventConnection::flush() {
+    if (mDestroyed) {
+        return DEAD_OBJECT;
+    }
+
     return  mService->flushSensor(this, mOpPackageName);
 }
 
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 8f2d5db..9487a39 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SENSOR_EVENT_CONNECTION_H
 #define ANDROID_SENSOR_EVENT_CONNECTION_H
 
+#include <atomic>
 #include <stdint.h>
 #include <sys/types.h>
 #include <unordered_map>
@@ -182,8 +183,8 @@
     int mTotalAcksNeeded, mTotalAcksReceived;
 #endif
 
-    mutable Mutex mDestroyLock;
-    bool mDestroyed;
+    // Used to track if this object was inappropriately used after destroy().
+    std::atomic_bool mDestroyed;
 
     // Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
     // valid mapping for sensors that require a permission in order to reduce the lookup time.
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 60f9cd9..3ca34bb 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -79,6 +79,8 @@
 bool SensorService::sHmacGlobalKeyIsValid = false;
 std::map<String16, int> SensorService::sPackageTargetVersion;
 Mutex SensorService::sPackageTargetVersionLock;
+String16 SensorService::sSensorInterfaceDescriptorPrefix =
+        String16("android.frameworks.sensorservice@");
 AppOpsManager SensorService::sAppOpsManager;
 
 #define SENSOR_SERVICE_DIR "/data/system/sensor_service"
@@ -1847,6 +1849,13 @@
 }
 
 int SensorService::getTargetSdkVersion(const String16& opPackageName) {
+    // Don't query the SDK version for the ISensorManager descriptor as it doesn't have one. This
+    // descriptor tends to be used for VNDK clients, but can technically be set by anyone so don't
+    // give it elevated privileges.
+    if (opPackageName.startsWith(sSensorInterfaceDescriptorPrefix)) {
+        return -1;
+    }
+
     Mutex::Autolock packageLock(sPackageTargetVersionLock);
     int targetSdkVersion = -1;
     auto entry = sPackageTargetVersion.find(opPackageName);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 3bb8421..052cbfe 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -424,6 +424,7 @@
     static AppOpsManager sAppOpsManager;
     static std::map<String16, int> sPackageTargetVersion;
     static Mutex sPackageTargetVersionLock;
+    static String16 sSensorInterfaceDescriptorPrefix;
 };
 
 } // namespace android
diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp
index 80c3b65..ae0a984 100644
--- a/services/stats/StatsHal.cpp
+++ b/services/stats/StatsHal.cpp
@@ -58,7 +58,7 @@
     std::vector<int32_t> buckets = chargeCycles.cycleBucket;
     int initialSize = buckets.size();
     for (int i = 0; i < 10 - initialSize; i++) {
-        buckets.push_back(-1); // Push -1 for buckets that do not exist.
+        buckets.push_back(0); // Push 0 for buckets that do not exist.
     }
     android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1],
             buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8],
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 34dc536..d3247e1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -835,6 +835,8 @@
             needsProtected == renderEngine.isProtected()) {
             mRenderSurface->setProtected(needsProtected);
         }
+    } else if (!outputState.isSecure && renderEngine.isProtected()) {
+        renderEngine.useProtectedContext(false);
     }
 
     base::unique_fd fd;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 09f37fb..29fd4b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -159,6 +159,7 @@
         EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     }
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 7a06400..8f76afa 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -2871,6 +2871,7 @@
     mOutput.mState.usesClientComposition = false;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
 
@@ -2883,6 +2884,7 @@
     mOutput.mState.flipClientTarget = true;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2892,6 +2894,7 @@
 
 TEST_F(OutputComposeSurfacesTest, doesMinimalWorkIfDequeueBufferFailsForClientComposition) {
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
 
@@ -2904,6 +2907,7 @@
     mOutput.mState.flipClientTarget = true;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
 
@@ -2914,6 +2918,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2936,6 +2941,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2963,6 +2969,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2991,6 +2998,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3019,6 +3027,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3050,6 +3059,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
             .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
@@ -3072,6 +3082,7 @@
 struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
     OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
         EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
                 .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3219,6 +3230,8 @@
     mOutput.mState.isSecure = false;
     mLayer2.mLayerFEState.hasProtectedContent = true;
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+    EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
+    EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
 
     mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
 }
@@ -3311,6 +3324,7 @@
         EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
         EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
                 .WillRepeatedly(Return());
         EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index fba3261..c8cd442 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -73,6 +73,7 @@
         mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
         mProducerSlotSource(0),
         mProducerBuffers(),
+        mProducerSlotNeedReallocation(0),
         mQueueBufferOutput(),
         mSinkBufferWidth(0),
         mSinkBufferHeight(0),
@@ -335,10 +336,14 @@
             dbgSourceStr(source), *sslot, pslot, result);
     uint64_t sourceBit = static_cast<uint64_t>(source) << pslot;
 
+    // reset producer slot reallocation flag
+    mProducerSlotNeedReallocation &= ~(1ULL << pslot);
+
     if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) {
         // This slot was previously dequeued from the other source; must
         // re-request the buffer.
-        result |= BUFFER_NEEDS_REALLOCATION;
+        mProducerSlotNeedReallocation |= 1ULL << pslot;
+
         mProducerSlotSource &= ~(1ULL << pslot);
         mProducerSlotSource |= sourceBit;
     }
@@ -360,6 +365,9 @@
                 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
                 mProducerBuffers[pslot]->getPixelFormat(),
                 mProducerBuffers[pslot]->getUsage());
+
+        // propagate reallocation to VDS consumer
+        mProducerSlotNeedReallocation |= 1ULL << pslot;
     }
 
     return result;
@@ -434,6 +442,11 @@
     if (outBufferAge) {
         *outBufferAge = 0;
     }
+
+    if ((mProducerSlotNeedReallocation & (1ULL << *pslot)) != 0) {
+        result |= BUFFER_NEEDS_REALLOCATION;
+    }
+
     return result;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 3cbad8f..22b5528 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -180,6 +180,10 @@
     uint64_t mProducerSlotSource;
     sp<GraphicBuffer> mProducerBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
 
+    // Need to propagate reallocation to VDS consumer.
+    // Each bit corresponds to a producer slot.
+    uint64_t mProducerSlotNeedReallocation;
+
     // The QueueBufferOutput with the latest info from the sink, and with the
     // transform hint cleared. Since we defer queueBuffer from the GPU driver
     // to the sink, we have to return the previous version.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 03903f6..55af849 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -793,7 +793,9 @@
             // to be applied as per normal (no synchronization).
             mCurrentState.barrierLayer_legacy = nullptr;
         } else {
-            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy, this);
+            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy,
+                                                         this,
+                                                         barrierLayer);
             if (barrierLayer->addSyncPoint(syncPoint)) {
                 std::stringstream ss;
                 ss << "Adding sync point " << mCurrentState.frameNumber_legacy;
@@ -818,7 +820,7 @@
     ATRACE_CALL();
     *stateToCommit = mPendingStates[0];
 
-    mPendingStates.removeAt(0);
+    mPendingStates.pop_front();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
@@ -857,6 +859,7 @@
                 mRemoteSyncPoints.pop_front();
             } else {
                 ATRACE_NAME("!frameIsAvailable");
+                mRemoteSyncPoints.front()->checkTimeoutAndLog();
                 break;
             }
         } else {
@@ -1445,6 +1448,13 @@
 
 void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
     ATRACE_CALL();
+    if (mLayerDetached) {
+        // If the layer is detached, then we don't defer this transaction since we will not
+        // commit the pending state while the layer is detached. Adding sync points may cause
+        // the barrier layer to wait for the states to be committed before dequeuing a buffer.
+        return;
+    }
+
     mCurrentState.barrierLayer_legacy = barrierLayer;
     mCurrentState.frameNumber_legacy = frameNumber;
     // We don't set eTransactionNeeded, because just receiving a deferral
@@ -2403,7 +2413,15 @@
     xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
     ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
 
-    layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
+    // inset while protecting from overflow TODO(b/161235021): What is going wrong
+    // in the overflow scenario?
+    {
+    int32_t tmp;
+    if (!__builtin_add_overflow(layerBounds.left, xSurfaceInset, &tmp)) layerBounds.left = tmp;
+    if (!__builtin_sub_overflow(layerBounds.right, xSurfaceInset, &tmp)) layerBounds.right = tmp;
+    if (!__builtin_add_overflow(layerBounds.top, ySurfaceInset, &tmp)) layerBounds.top = tmp;
+    if (!__builtin_sub_overflow(layerBounds.bottom, ySurfaceInset, &tmp)) layerBounds.bottom = tmp;
+    }
 
     // Input coordinate should match the layer bounds.
     info.frameLeft = layerBounds.left;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2c90c92..d071710 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -35,6 +35,7 @@
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
+#include <chrono>
 #include <cstdint>
 #include <list>
 #include <optional>
@@ -881,12 +882,14 @@
 
     class SyncPoint {
     public:
-        explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer)
+        explicit SyncPoint(uint64_t frameNumber,
+                           wp<Layer> requestedSyncLayer,
+                           wp<Layer> barrierLayer_legacy)
               : mFrameNumber(frameNumber),
                 mFrameIsAvailable(false),
                 mTransactionIsApplied(false),
-                mRequestedSyncLayer(requestedSyncLayer) {}
-
+                mRequestedSyncLayer(requestedSyncLayer),
+                mBarrierLayer_legacy(barrierLayer_legacy) {}
         uint64_t getFrameNumber() const { return mFrameNumber; }
 
         bool frameIsAvailable() const { return mFrameIsAvailable; }
@@ -899,11 +902,41 @@
 
         sp<Layer> getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); }
 
+        sp<Layer> getBarrierLayer() const { return mBarrierLayer_legacy.promote(); }
+
+        bool isTimeout() const {
+            using namespace std::chrono_literals;
+            static constexpr std::chrono::nanoseconds TIMEOUT_THRESHOLD = 1s;
+
+            return std::chrono::steady_clock::now() - mCreateTimeStamp > TIMEOUT_THRESHOLD;
+        }
+
+        void checkTimeoutAndLog() {
+            using namespace std::chrono_literals;
+            static constexpr std::chrono::nanoseconds LOG_PERIOD = 1s;
+
+            if (!frameIsAvailable() && isTimeout()) {
+                const auto now = std::chrono::steady_clock::now();
+                if (now - mLastLogTime > LOG_PERIOD) {
+                    mLastLogTime = now;
+                    sp<Layer> requestedSyncLayer = getRequestedSyncLayer();
+                    sp<Layer> barrierLayer = getBarrierLayer();
+                    ALOGW("[%s] sync point %" PRIu64 " wait timeout %lld for %s",
+                          requestedSyncLayer ? requestedSyncLayer->getDebugName() : "Removed",
+                          mFrameNumber, (now - mCreateTimeStamp).count(),
+                          barrierLayer ? barrierLayer->getDebugName() : "Removed");
+                }
+            }
+        }
     private:
         const uint64_t mFrameNumber;
         std::atomic<bool> mFrameIsAvailable;
         std::atomic<bool> mTransactionIsApplied;
         wp<Layer> mRequestedSyncLayer;
+        wp<Layer> mBarrierLayer_legacy;
+        const std::chrono::time_point<std::chrono::steady_clock> mCreateTimeStamp =
+            std::chrono::steady_clock::now();
+        std::chrono::time_point<std::chrono::steady_clock> mLastLogTime;
     };
 
     // SyncPoints which will be signaled when the correct frame is at the head
@@ -984,12 +1017,12 @@
     State mDrawingState;
     // Store a copy of the pending state so that the drawing thread can access the
     // states without a lock.
-    Vector<State> mPendingStatesSnapshot;
+    std::deque<State> mPendingStatesSnapshot;
 
     // these are protected by an external lock (mStateLock)
     State mCurrentState;
     std::atomic<uint32_t> mTransactionFlags{0};
-    Vector<State> mPendingStates;
+    std::deque<State> mPendingStates;
 
     // Timestamp history for UIAutomation. Thread safe.
     FrameTracker mFrameTracker;
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index c5a4689..f273725 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -4,7 +4,5 @@
 chaviw@google.com
 lpy@google.com
 racarr@google.com
-steventhomas@google.com
 stoza@google.com
-vhau@google.com
 vishnun@google.com
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index ab5773d..61f3fbb 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -255,21 +255,9 @@
     }
 }
 
-bool VSyncPredictor::needsMoreSamples(nsecs_t now) const {
-    using namespace std::literals::chrono_literals;
+bool VSyncPredictor::needsMoreSamples() const {
     std::lock_guard<std::mutex> lk(mMutex);
-    bool needsMoreSamples = true;
-    if (mTimestamps.size() >= kMinimumSamplesForPrediction) {
-        nsecs_t constexpr aLongTime =
-                std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
-        if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) {
-            auto const lastTimestamp = mTimestamps[mLastTimestampIndex];
-            needsMoreSamples = !((lastTimestamp + aLongTime) > now);
-        }
-    }
-
-    ATRACE_INT("VSP-moreSamples", needsMoreSamples);
-    return needsMoreSamples;
+    return mTimestamps.size() < kMinimumSamplesForPrediction;
 }
 
 void VSyncPredictor::resetModel() {
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 3ca878d..5f3c418 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -52,11 +52,10 @@
      */
     void setPeriod(nsecs_t period) final;
 
-    /* Query if the model is in need of more samples to make a prediction at timePoint.
-     * \param [in] timePoint    The timePoint to inquire of.
+    /* Query if the model is in need of more samples to make a prediction.
      * \return  True, if model would benefit from more samples, False if not.
      */
-    bool needsMoreSamples(nsecs_t timePoint) const;
+    bool needsMoreSamples() const final;
 
     std::tuple<nsecs_t /* slope */, nsecs_t /* intercept */> getVSyncPredictionModel() const;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index c743de0..efa8bab 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -233,6 +233,7 @@
 }
 
 void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
+    ATRACE_CALL();
     mPeriodConfirmationInProgress = true;
     mPeriodTransitioningTo = newPeriod;
     mMoreSamplesNeeded = true;
@@ -240,8 +241,7 @@
 }
 
 void VSyncReactor::endPeriodTransition() {
-    setIgnorePresentFencesInternal(false);
-    mMoreSamplesNeeded = false;
+    ATRACE_CALL();
     mPeriodTransitioningTo.reset();
     mPeriodConfirmationInProgress = false;
     mLastHwVsync.reset();
@@ -254,6 +254,8 @@
 
     if (!mSupportKernelIdleTimer && period == getPeriod()) {
         endPeriodTransition();
+        setIgnorePresentFencesInternal(false);
+        mMoreSamplesNeeded = false;
     } else {
         startPeriodTransition(period);
     }
@@ -303,6 +305,7 @@
 
     std::lock_guard<std::mutex> lk(mMutex);
     if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
+        ATRACE_NAME("VSR: period confirmed");
         if (mPeriodTransitioningTo) {
             mTracker->setPeriod(*mPeriodTransitioningTo);
             for (auto& entry : mCallbacks) {
@@ -310,17 +313,29 @@
             }
             *periodFlushed = true;
         }
+
+        if (mLastHwVsync) {
+            mTracker->addVsyncTimestamp(*mLastHwVsync);
+        }
+        mTracker->addVsyncTimestamp(timestamp);
+
         endPeriodTransition();
+        mMoreSamplesNeeded = mTracker->needsMoreSamples();
     } else if (mPeriodConfirmationInProgress) {
+        ATRACE_NAME("VSR: still confirming period");
         mLastHwVsync = timestamp;
         mMoreSamplesNeeded = true;
         *periodFlushed = false;
     } else {
-        mMoreSamplesNeeded = false;
+        ATRACE_NAME("VSR: adding sample");
         *periodFlushed = false;
+        mTracker->addVsyncTimestamp(timestamp);
+        mMoreSamplesNeeded = mTracker->needsMoreSamples();
     }
 
-    mTracker->addVsyncTimestamp(timestamp);
+    if (!mMoreSamplesNeeded) {
+        setIgnorePresentFencesInternal(false);
+    }
     return mMoreSamplesNeeded;
 }
 
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 05a6fc3..107c540 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -66,6 +66,8 @@
     /* Inform the tracker that the samples it has are not accurate for prediction. */
     virtual void resetModel() = 0;
 
+    virtual bool needsMoreSamples() const = 0;
+
     virtual void dump(std::string& result) const = 0;
 
 protected:
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
index db82772..f42cd53 100644
--- a/services/surfaceflinger/StartPropertySetThread.cpp
+++ b/services/surfaceflinger/StartPropertySetThread.cpp
@@ -31,6 +31,7 @@
     property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
     // Clear BootAnimation exit flag
     property_set("service.bootanim.exit", "0");
+    property_set("service.bootanim.progress", "0");
     // Start BootAnimation if not started
     property_set("ctl.start", "bootanim");
     // Exit immediately
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f96814c..02b5324 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1567,7 +1567,7 @@
     mEventQueue->refresh();
 }
 
-nsecs_t SurfaceFlinger::getVsyncPeriod() const {
+nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
     const auto displayId = getInternalDisplayIdLocked();
     if (!displayId || !getHwComposer().isConnected(*displayId)) {
         return 0;
@@ -1774,7 +1774,7 @@
     setPowerModeInternal(display, currentDisplayPowerMode);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const nsecs_t vsyncPeriod = getVsyncPeriod();
+    const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
 
     // The present fences returned from vr_hwc are not an accurate
@@ -4193,8 +4193,7 @@
                         {});
 
     setPowerModeInternal(display, hal::PowerMode::ON);
-
-    const nsecs_t vsyncPeriod = getVsyncPeriod();
+    const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
 
     // Use phase of 0 since phase is not known.
@@ -4229,7 +4228,7 @@
     if (mInterceptor->isEnabled()) {
         mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
     }
-
+    const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
     if (currentMode == hal::PowerMode::OFF) {
         if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
             ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
@@ -4238,7 +4237,7 @@
         if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
             getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
             mScheduler->onScreenAcquired(mAppConnectionHandle);
-            mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+            mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
         }
 
         mVisibleRegionsDirty = true;
@@ -4265,7 +4264,7 @@
         getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->onScreenAcquired(mAppConnectionHandle);
-            mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+            mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
         }
     } else if (mode == hal::PowerMode::DOZE_SUSPEND) {
         // Leave display going to doze
@@ -4378,7 +4377,7 @@
 }
 
 void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
-    StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriod());
+    StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC());
 
     if (args.size() > 1) {
         const auto name = String8(args[1]);
@@ -4443,7 +4442,7 @@
     mPhaseConfiguration->dump(result);
     StringAppendF(&result,
                   "      present offset: %9" PRId64 " ns\t     VSYNC period: %9" PRId64 " ns\n\n",
-                  dispSyncPresentTimeOffset, getVsyncPeriod());
+                  dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
 
     scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
     StringAppendF(&result,
@@ -6226,6 +6225,11 @@
         Mutex::Autolock lock(mStateLock);
         if (authenticateSurfaceTextureLocked(surface)) {
             sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+            if (layer == nullptr) {
+                ALOGE("Attempt to set frame rate on a layer that no longer exists");
+                return BAD_VALUE;
+            }
+
             if (layer->setFrameRate(
                         Layer::FrameRate(frameRate,
                                          Layer::FrameRate::convertCompatibility(compatibility)))) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ccaeb2d..c727574 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -852,7 +852,7 @@
     /* ------------------------------------------------------------------------
      * VSync
      */
-    nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
+    nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index ce5f35c..06bdcdc 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -85,7 +85,7 @@
 using HotplugEvent = TestableSurfaceFlinger::HotplugEvent;
 using HWC2Display = TestableSurfaceFlinger::HWC2Display;
 
-constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667;
 constexpr int32_t DEFAULT_DPI = 320;
 constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
 
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index be49ef3..c2a7752 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -51,6 +51,7 @@
 
     void setPeriod(nsecs_t) final {}
     void resetModel() final {}
+    bool needsMoreSamples() const final { return false; }
     void dump(std::string&) const final {}
 
 private:
@@ -86,6 +87,7 @@
 
     void setPeriod(nsecs_t) final {}
     void resetModel() final {}
+    bool needsMoreSamples() const final { return false; }
     void dump(std::string&) const final {}
 
 private:
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index fa5cc32..f630e3b 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -47,6 +47,7 @@
     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(resetModel, void());
+    MOCK_CONST_METHOD0(needsMoreSamples, bool());
     MOCK_CONST_METHOD1(dump, void(std::string&));
 
     nsecs_t nextVSyncTime(nsecs_t timePoint) const {
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index fc39235..d4cd11d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -73,27 +73,27 @@
 
 TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
-        EXPECT_TRUE(tracker.needsMoreSamples(mNow += mPeriod));
-        tracker.addVsyncTimestamp(mNow);
+        EXPECT_TRUE(tracker.needsMoreSamples());
+        tracker.addVsyncTimestamp(mNow += mPeriod);
     }
-    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+    EXPECT_FALSE(tracker.needsMoreSamples());
 }
 
 TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
         tracker.addVsyncTimestamp(mNow += mPeriod);
     }
-    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+    EXPECT_FALSE(tracker.needsMoreSamples());
 
     auto const changedPeriod = mPeriod * 2;
     tracker.setPeriod(changedPeriod);
-    EXPECT_TRUE(tracker.needsMoreSamples(mNow));
+    EXPECT_TRUE(tracker.needsMoreSamples());
 
     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
-        EXPECT_TRUE(tracker.needsMoreSamples(mNow += changedPeriod));
-        tracker.addVsyncTimestamp(mNow);
+        EXPECT_TRUE(tracker.needsMoreSamples());
+        tracker.addVsyncTimestamp(mNow += changedPeriod);
     }
-    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+    EXPECT_FALSE(tracker.needsMoreSamples());
 }
 
 TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
@@ -320,20 +320,6 @@
     EXPECT_THAT(intercept, Eq(0));
 }
 
-TEST_F(VSyncPredictorTest, willBecomeInaccurateAfterA_longTimeWithNoSamples) {
-    auto const simulatedVsyncs = generateVsyncTimestamps(kMinimumSamplesForPrediction, mPeriod, 0);
-
-    for (auto const& timestamp : simulatedVsyncs) {
-        tracker.addVsyncTimestamp(timestamp);
-    }
-    auto const mNow = *simulatedVsyncs.rbegin();
-    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
-
-    // TODO: would be better to decay this as a result of the variance of the samples
-    static auto constexpr aLongTimeOut = 1000000000;
-    EXPECT_TRUE(tracker.needsMoreSamples(mNow + aLongTimeOut));
-}
-
 TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
     auto const simulatedVsyncs =
             generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
@@ -443,7 +429,7 @@
         // When VsyncPredictor returns the period it means that it doesn't know how to predict and
         // it needs to get more samples
         if (slope == mPeriod && intercept == 0) {
-            EXPECT_TRUE(tracker.needsMoreSamples(now));
+            EXPECT_TRUE(tracker.needsMoreSamples());
         }
     }
 }
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index a972562..6856612 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -41,6 +41,7 @@
     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(resetModel, void());
+    MOCK_CONST_METHOD0(needsMoreSamples, bool());
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
@@ -57,6 +58,7 @@
     nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
     void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
     void resetModel() final { mTracker->resetModel(); }
+    bool needsMoreSamples() const final { return mTracker->needsMoreSamples(); }
     void dump(std::string& result) const final { mTracker->dump(result); }
 
 private:
@@ -455,6 +457,83 @@
     EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
 }
 
+TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTracker) {
+    auto time = 0;
+    bool periodFlushed = false;
+    nsecs_t const newPeriod = 4000;
+    mReactor.setPeriod(newPeriod);
+
+    static auto constexpr numSamplesWithNewPeriod = 4;
+    Sequence seq;
+    EXPECT_CALL(*mMockTracker, needsMoreSamples())
+            .Times(numSamplesWithNewPeriod - 2)
+            .InSequence(seq)
+            .WillRepeatedly(Return(true));
+    EXPECT_CALL(*mMockTracker, needsMoreSamples())
+            .Times(1)
+            .InSequence(seq)
+            .WillRepeatedly(Return(false));
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(numSamplesWithNewPeriod);
+
+    EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+
+    EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+    // confirmed period, but predictor wants numRequest samples. This one and prior are valid.
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+}
+
+TEST_F(VSyncReactorTest, hwVsyncturnsOffOnConfirmationWhenTrackerDoesntRequest) {
+    auto time = 0;
+    bool periodFlushed = false;
+    nsecs_t const newPeriod = 4000;
+    mReactor.setPeriod(newPeriod);
+
+    Sequence seq;
+    EXPECT_CALL(*mMockTracker, needsMoreSamples())
+            .Times(1)
+            .InSequence(seq)
+            .WillRepeatedly(Return(false));
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
+
+    EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed));
+}
+
+TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) {
+    auto time = 0;
+    bool periodFlushed = false;
+    nsecs_t const newPeriod1 = 4000;
+    nsecs_t const newPeriod2 = 7000;
+
+    mReactor.setPeriod(newPeriod1);
+
+    Sequence seq;
+    EXPECT_CALL(*mMockTracker, needsMoreSamples())
+            .Times(4)
+            .InSequence(seq)
+            .WillRepeatedly(Return(true));
+    EXPECT_CALL(*mMockTracker, needsMoreSamples())
+            .Times(1)
+            .InSequence(seq)
+            .WillRepeatedly(Return(false));
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(7);
+
+    EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed));
+    // confirmed period, but predictor wants numRequest samples. This one and prior are valid.
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed));
+
+    mReactor.setPeriod(newPeriod2);
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
+}
+
 static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
     return period - phase;
 }
@@ -648,7 +727,7 @@
 
 TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) {
     bool periodFlushed = true;
-    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(3);
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
     mReactor.setIgnorePresentFences(true);
 
     nsecs_t const newPeriod = 5000;
@@ -672,7 +751,7 @@
                                     kPendingLimit, true /* supportKernelIdleTimer */);
 
     bool periodFlushed = true;
-    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(5);
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(4);
     idleReactor.setIgnorePresentFences(true);
 
     // First, set the same period, which should only be confirmed when we receive two
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 921b095..1d29bab 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -90,7 +90,6 @@
         "libhardware",
         "libsync",
         "libbase",
-        "libdl_android",
         "libhidlbase",
         "liblog",
         "libui",
@@ -101,6 +100,7 @@
         "libnativebridge_lazy",
         "libnativeloader_lazy",
         "libnativewindow",
+        "libvndksupport",
         "android.hardware.graphics.common@1.0",
         "libSurfaceFlingerProp",
     ],
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index c63fdf5..55d80fb 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,20 +28,17 @@
 #include <android/dlext.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
-#include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
 #include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
 #include <sys/prctl.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
+#include <vndksupport/linker.h>
 
 #include <algorithm>
 #include <array>
 #include <climits>
 #include <new>
-#include <string_view>
-#include <sstream>
 #include <vector>
 
 #include "stubhal.h"
@@ -151,19 +148,11 @@
 
 Hal Hal::hal_;
 
-void* LoadLibrary(const android_dlextinfo& dlextinfo,
-                  const std::string_view subname) {
-    ATRACE_CALL();
-
-    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 = {{
     "ro.hardware.vulkan",
     "ro.board.platform",
 }};
+constexpr int LIB_DL_FLAGS = RTLD_LOCAL | RTLD_NOW;
 
 // LoadDriver returns:
 // * 0 when succeed, or
@@ -174,20 +163,26 @@
                const hwvulkan_module_t** module) {
     ATRACE_CALL();
 
-    const android_dlextinfo dlextinfo = {
-        .flags = ANDROID_DLEXT_USE_NAMESPACE,
-        .library_namespace = library_namespace,
-    };
     void* so = nullptr;
-    char prop[PROPERTY_VALUE_MAX];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-        int prop_len = property_get(key, prop, nullptr);
-        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;
+        std::string lib_name = android::base::GetProperty(key, "");
+        if (lib_name.empty())
+            continue;
+
+        lib_name = "vulkan." + lib_name + ".so";
+        if (library_namespace) {
+            // load updated driver
+            const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = library_namespace,
+            };
+            so = android_dlopen_ext(lib_name.c_str(), LIB_DL_FLAGS, &dlextinfo);
+        } else {
+            // load built-in driver
+            so = android_load_sphal_library(lib_name.c_str(), LIB_DL_FLAGS);
         }
+        if (so)
+            break;
     }
     if (!so)
         return -ENOENT;
@@ -211,12 +206,9 @@
 int LoadBuiltinDriver(const hwvulkan_module_t** module) {
     ATRACE_CALL();
 
-    auto ns = android_get_exported_namespace("sphal");
-    if (!ns)
-        return -ENOENT;
     android::GraphicsEnv::getInstance().setDriverToLoad(
         android::GpuStatsInfo::Driver::VULKAN);
-    return LoadDriver(ns, module);
+    return LoadDriver(nullptr, module);
 }
 
 int LoadUpdatedDriver(const hwvulkan_module_t** module) {