Merge "SF: HWComposer::isConnected can be called before a display is connected" into sc-dev
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 5c2211f..a546236 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -189,8 +189,8 @@
         "liblog",
         "libutils",
     ],
-    static_libs: [
-        "libapexd",
+    required: [
+      "apexd"
     ],
 }
 
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 379cf92..c04b558 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 
+#include <array>
 #include <fstream>
 #include <sstream>
 
@@ -31,10 +32,6 @@
 #include <libdm/dm.h>
 #include <selinux/android.h>
 
-#include <apex_file_repository.h>
-#include <apex_constants.h>
-#include <apexd.h>
-
 #include "installd_constants.h"
 #include "otapreopt_utils.h"
 
@@ -64,47 +61,14 @@
     }
 }
 
-static std::vector<apex::ApexFile> ActivateApexPackages() {
-    // The logic here is (partially) copied and adapted from
-    // system/apex/apexd/apexd.cpp.
-    //
-    // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
-    std::vector<std::string> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
-                                       apex::kApexPackageVendorDir};
-    // Initialize ApexFileRepository used internally in ScanPackagesDirAndActivate.
-    // This is a quick fix to fix apex activation in otapreopt_chroot.
-    apex::ApexFileRepository::GetInstance().AddPreInstalledApex(apex_dirs);
-    for (const auto& dir : apex_dirs) {
-        // Cast call to void to suppress warn_unused_result.
-        static_cast<void>(apex::ScanPackagesDirAndActivate(dir.c_str()));
-    }
-    return apex::GetActivePackages();
-}
+static void ActivateApexPackages() {
+    std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"};
+    std::string apexd_error_msg;
 
-static void CreateApexInfoList(const std::vector<apex::ApexFile>& apex_files) {
-    // Setup the apex-info-list.xml file
-    const std::string apex_info_file = std::string(apex::kApexRoot) + "/" + apex::kApexInfoList;
-    std::fstream xml(apex_info_file.c_str(), std::ios::out | std::ios::trunc);
-    if (!xml.is_open()) {
-        PLOG(ERROR) << "Failed to open " << apex_info_file;
-        exit(216);
-    }
-
-    // we do not care about inactive apexs
-    std::vector<apex::ApexFile> inactive;
-    apex::CollectApexInfoList(xml, apex_files, inactive);
-    xml.flush();
-    xml.close();
-}
-
-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);
-        if (!status.ok()) {
-            LOG(ERROR) << "Failed to deactivate " << package_path << ": "
-                       << status.error();
-        }
+    bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+    if (!exec_result) {
+        PLOG(ERROR) << "Running otapreopt failed: " << apexd_error_msg;
+        exit(220);
     }
 }
 
@@ -269,8 +233,7 @@
 
     // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
     // the ART APEX, as it is required by otapreopt to run dex2oat.
-    std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
-    CreateApexInfoList(active_packages);
+    ActivateApexPackages();
 
     // Check that an ART APEX has been activated; clean up and exit
     // early otherwise.
@@ -278,16 +241,27 @@
       "com.android.art",
       "com.android.runtime",
     };
-    for (std::string_view apex : kRequiredApexs) {
-        if (std::none_of(active_packages.begin(), active_packages.end(),
-                         [&](const apex::ApexFile& package) {
-                             return package.GetManifest().name() == apex;
-                         })) {
-            LOG(FATAL_WITHOUT_ABORT) << "No activated " << apex << " APEX package.";
-            DeactivateApexPackages(active_packages);
-            exit(217);
+    std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
+    DIR* apex_dir = opendir("/apex");
+    if (apex_dir == nullptr) {
+        PLOG(ERROR) << "unable to open /apex";
+        exit(220);
+    }
+    for (dirent* entry = readdir(apex_dir); entry != nullptr; entry = readdir(apex_dir)) {
+        for (int i = 0; i < found_apexs.size(); i++) {
+            if (kRequiredApexs[i] == std::string_view(entry->d_name)) {
+                found_apexs[i] = true;
+                break;
+            }
         }
     }
+    closedir(apex_dir);
+    auto it = std::find(found_apexs.cbegin(), found_apexs.cend(), false);
+    if (it != found_apexs.cend()) {
+        LOG(ERROR) << "No activated " << kRequiredApexs[std::distance(found_apexs.cbegin(), it)]
+                   << " package!";
+        exit(221);
+    }
 
     // Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category
     if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
@@ -323,9 +297,6 @@
         LOG(ERROR) << "Running otapreopt failed: " << error_msg;
     }
 
-    // Tear down the work down by the apexd logic. (i.e. deactivate packages).
-    DeactivateApexPackages(active_packages);
-
     if (!exec_result) {
         exit(213);
     }
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index fbf1e0c..e272025 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -351,7 +351,7 @@
             uid = kTestAppUid;
         }
         if (class_loader_context == nullptr) {
-            class_loader_context = "&";
+            class_loader_context = "PCL[]";
         }
         int32_t dexopt_needed = 0;  // does not matter;
         std::optional<std::string> out_path; // does not matter
@@ -478,7 +478,7 @@
                            bool should_binder_call_succeed,
                            /*out */ binder::Status* binder_result) {
         std::optional<std::string> out_path = oat_dir ? std::make_optional<std::string>(oat_dir) : std::nullopt;
-        std::string class_loader_context = "&";
+        std::string class_loader_context = "PCL[]";
         int32_t target_sdk_version = 0;  // default
         std::string profile_name = "primary.prof";
         std::optional<std::string> dm_path_opt = dm_path ? std::make_optional<std::string>(dm_path) : std::nullopt;
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index eb9c528..91726cd 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -286,6 +286,9 @@
  * The frameworks takes ownership of the \a acquire_fence_fd passed and is responsible
  * for closing it.
  *
+ * Note that the buffer must be allocated with AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE
+ * as the surface control might be composited using the GPU.
+ *
  * Available since API level 29.
  */
 void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 8854ba2..144dbd3 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -73,6 +73,7 @@
     "PermissionController.cpp",
     "ProcessInfoService.cpp",
     "IpPrefix.cpp",
+    ":activity_manager_procstate_aidl",
 ]
 
 cc_library {
@@ -130,8 +131,8 @@
         "Status.cpp",
         "TextOutput.cpp",
         "Utils.cpp",
+        ":packagemanager_aidl",
         ":libbinder_aidl",
-        ":activity_manager_procstate_aidl",
     ],
 
     target: {
@@ -232,9 +233,6 @@
 filegroup {
     name: "libbinder_aidl",
     srcs: [
-        "aidl/android/content/pm/IPackageChangeObserver.aidl",
-        "aidl/android/content/pm/IPackageManagerNative.aidl",
-        "aidl/android/content/pm/PackageChangeEvent.aidl",
         "aidl/android/os/IClientCallback.aidl",
         "aidl/android/os/IServiceCallback.aidl",
         "aidl/android/os/IServiceManager.aidl",
@@ -243,6 +241,16 @@
     path: "aidl",
 }
 
+filegroup {
+    name: "packagemanager_aidl",
+    srcs: [
+        "aidl/android/content/pm/IPackageChangeObserver.aidl",
+        "aidl/android/content/pm/IPackageManagerNative.aidl",
+        "aidl/android/content/pm/PackageChangeEvent.aidl",
+    ],
+    path: "aidl",
+}
+
 aidl_interface {
     name: "libbinder_aidl_test_stub",
     unstable: true,
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6f34159..7fedba2 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -41,11 +41,12 @@
 #include <binder/TextOutput.h>
 
 #include <cutils/ashmem.h>
+#include <cutils/compiler.h>
 #include <utils/Flattenable.h>
 #include <utils/Log.h>
-#include <utils/misc.h>
-#include <utils/String8.h>
 #include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/misc.h>
 
 #include <private/binder/binder_module.h>
 #include "RpcState.h"
@@ -590,12 +591,14 @@
 }
 
 status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
-    const IPCThreadState* threadState = IPCThreadState::self();
-    writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
-    updateWorkSourceRequestHeaderPosition();
-    writeInt32(threadState->shouldPropagateWorkSource() ?
-            threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
-    writeInt32(kHeader);
+    if (CC_LIKELY(!isForRpc())) {
+        const IPCThreadState* threadState = IPCThreadState::self();
+        writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+        updateWorkSourceRequestHeaderPosition();
+        writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid()
+                                                            : IPCThreadState::kUnsetWorkSource);
+        writeInt32(kHeader);
+    }
 
     // currently the interface identification token is just its name as a string
     return writeString16(str, len);
@@ -642,31 +645,34 @@
                               size_t len,
                               IPCThreadState* threadState) const
 {
-    // StrictModePolicy.
-    int32_t strictPolicy = readInt32();
-    if (threadState == nullptr) {
-        threadState = IPCThreadState::self();
+    if (CC_LIKELY(!isForRpc())) {
+        // StrictModePolicy.
+        int32_t strictPolicy = readInt32();
+        if (threadState == nullptr) {
+            threadState = IPCThreadState::self();
+        }
+        if ((threadState->getLastTransactionBinderFlags() & IBinder::FLAG_ONEWAY) != 0) {
+            // For one-way calls, the callee is running entirely
+            // disconnected from the caller, so disable StrictMode entirely.
+            // Not only does disk/network usage not impact the caller, but
+            // there's no way to communicate back violations anyway.
+            threadState->setStrictModePolicy(0);
+        } else {
+            threadState->setStrictModePolicy(strictPolicy);
+        }
+        // WorkSource.
+        updateWorkSourceRequestHeaderPosition();
+        int32_t workSource = readInt32();
+        threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
+        // vendor header
+        int32_t header = readInt32();
+        if (header != kHeader) {
+            ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader,
+                  header);
+            return false;
+        }
     }
-    if ((threadState->getLastTransactionBinderFlags() &
-         IBinder::FLAG_ONEWAY) != 0) {
-      // For one-way calls, the callee is running entirely
-      // disconnected from the caller, so disable StrictMode entirely.
-      // Not only does disk/network usage not impact the caller, but
-      // there's no way to commuicate back any violations anyway.
-      threadState->setStrictModePolicy(0);
-    } else {
-      threadState->setStrictModePolicy(strictPolicy);
-    }
-    // WorkSource.
-    updateWorkSourceRequestHeaderPosition();
-    int32_t workSource = readInt32();
-    threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
-    // vendor header
-    int32_t header = readInt32();
-    if (header != kHeader) {
-        ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header);
-        return false;
-    }
+
     // Interface descriptor.
     size_t parcel_interface_len;
     const char16_t* parcel_interface = readString16Inplace(&parcel_interface_len);
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 5df0012..5516914 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -26,6 +26,9 @@
  * This registers the service with the default service manager under this instance name. This does
  * not take ownership of binder.
  *
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
  * \param binder object to register globally with the service manager.
  * \param instance identifier of the service. This will be used to lookup the service.
  *
@@ -39,6 +42,9 @@
  * service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
  * function is responsible for calling AIBinder_decStrong).
  *
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
  * \param instance identifier of the service used to lookup the service.
  */
 __attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
@@ -48,6 +54,9 @@
  * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
  * for calling AIBinder_decStrong).
  *
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
  * \param instance identifier of the service used to lookup the service.
  */
 __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
@@ -78,6 +87,9 @@
  * This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
  * for calling AIBinder_decStrong).
  *
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
  * \param instance identifier of the service used to lookup the service.
  *
  * \return service if registered, null if not.
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 44ed48f..ce7255e 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,9 +30,7 @@
     FLAG_PRIVATE_VENDOR = 0x10000000,
 };
 
-// TODO(b/180646847): __ANDROID_APEX__ here is what allows product partition to
-// talk to system.
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_VENDOR__)
 
 enum {
     FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
@@ -47,7 +45,7 @@
     AIBinder_markVendorStability(binder);
 }
 
-#else  // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#else  // defined(__ANDROID_VENDOR__)
 
 enum {
     FLAG_PRIVATE_LOCAL = 0,
@@ -64,7 +62,7 @@
     AIBinder_markSystemStability(binder);
 }
 
-#endif  // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif  // defined(__ANDROID_VENDOR__)
 
 /**
  * This interface has system<->vendor stability
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 3899d47..321b422 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -56,6 +56,26 @@
     }
 }
 
+/// Interface stability promise
+///
+/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
+/// makes no stability guarantees ([`Local`]). [`Local`] is
+/// currently the default stability.
+pub enum Stability {
+    /// Default stability, visible to other modules in the same compilation
+    /// context (e.g. modules on system.img)
+    Local,
+
+    /// A Vendor Interface Object, which promises to be stable
+    Vintf,
+}
+
+impl Default for Stability {
+    fn default() -> Self {
+        Stability::Local
+    }
+}
+
 /// A local service that can be remotable via Binder.
 ///
 /// An object that implement this interface made be made into a Binder service
@@ -94,6 +114,8 @@
 pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
 /// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
 pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
+/// Set to the vendor flag if we are building for the VNDK, 0 otherwise
+pub const FLAG_PRIVATE_LOCAL: TransactionFlags = sys::FLAG_PRIVATE_LOCAL;
 
 /// Internal interface of binder local or remote objects for making
 /// transactions.
@@ -602,6 +624,23 @@
             $interface[$descriptor] {
                 native: $native($on_transact),
                 proxy: $proxy {},
+                stability: $crate::Stability::default(),
+            }
+        }
+    };
+
+    {
+        $interface:path[$descriptor:expr] {
+            native: $native:ident($on_transact:path),
+            proxy: $proxy:ident,
+            stability: $stability:expr,
+        }
+    } => {
+        $crate::declare_binder_interface! {
+            $interface[$descriptor] {
+                native: $native($on_transact),
+                proxy: $proxy {},
+                stability: $stability,
             }
         }
     };
@@ -616,12 +655,33 @@
     } => {
         $crate::declare_binder_interface! {
             $interface[$descriptor] {
+                native: $native($on_transact),
+                proxy: $proxy {
+                    $($fname: $fty = $finit),*
+                },
+                stability: $crate::Stability::default(),
+            }
+        }
+    };
+
+    {
+        $interface:path[$descriptor:expr] {
+            native: $native:ident($on_transact:path),
+            proxy: $proxy:ident {
+                $($fname:ident: $fty:ty = $finit:expr),*
+            },
+            stability: $stability:expr,
+        }
+    } => {
+        $crate::declare_binder_interface! {
+            $interface[$descriptor] {
                 @doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")]
                 native: $native($on_transact),
                 @doc[concat!("A binder [`Proxy`]($crate::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
                 proxy: $proxy {
                     $($fname: $fty = $finit),*
                 },
+                stability: $stability,
             }
         }
     };
@@ -635,6 +695,8 @@
             proxy: $proxy:ident {
                 $($fname:ident: $fty:ty = $finit:expr),*
             },
+
+            stability: $stability:expr,
         }
     } => {
         #[doc = $proxy_doc]
@@ -669,7 +731,7 @@
         impl $native {
             /// Create a new binder service.
             pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
-                let binder = $crate::Binder::new($native(Box::new(inner)));
+                let binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
                 $crate::Strong::new(Box::new(binder))
             }
         }
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 5bbd2a3..30928a5 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,8 +107,9 @@
 pub mod parcel;
 
 pub use crate::binder::{
-    FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable, Strong,
-    TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
+    FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
+    Stability, Strong, TransactionCode, TransactionFlags, Weak,
+    FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
     LAST_CALL_TRANSACTION,
 };
 pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 185645e..3b3fd08 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode};
+use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode};
 use crate::error::{status_result, status_t, Result, StatusCode};
 use crate::parcel::{Parcel, Serialize};
 use crate::proxy::SpIBinder;
@@ -49,11 +49,19 @@
 unsafe impl<T: Remotable> Send for Binder<T> {}
 
 impl<T: Remotable> Binder<T> {
-    /// Create a new Binder remotable object.
+    /// Create a new Binder remotable object with default stability
     ///
     /// This moves the `rust_object` into an owned [`Box`] and Binder will
     /// manage its lifetime.
     pub fn new(rust_object: T) -> Binder<T> {
+        Self::new_with_stability(rust_object, Stability::default())
+    }
+
+    /// Create a new Binder remotable object with the given stability
+    ///
+    /// This moves the `rust_object` into an owned [`Box`] and Binder will
+    /// manage its lifetime.
+    pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
         let class = T::get_class();
         let rust_object = Box::into_raw(Box::new(rust_object));
         let ibinder = unsafe {
@@ -65,10 +73,12 @@
             // ends.
             sys::AIBinder_new(class.into(), rust_object as *mut c_void)
         };
-        Binder {
+        let mut binder = Binder {
             ibinder,
             rust_object,
-        }
+        };
+        binder.mark_stability(stability);
+        binder
     }
 
     /// Set the extension of a binder interface. This allows a downstream
@@ -161,6 +171,42 @@
     pub fn get_descriptor() -> &'static str {
         T::get_descriptor()
     }
+
+    /// Mark this binder object with the given stability guarantee
+    fn mark_stability(&mut self, stability: Stability) {
+        match stability {
+            Stability::Local => self.mark_local_stability(),
+            Stability::Vintf => {
+                unsafe {
+                    // Safety: Self always contains a valid `AIBinder` pointer, so
+                    // we can always call this C API safely.
+                    sys::AIBinder_markVintfStability(self.as_native_mut());
+                }
+            }
+        }
+    }
+
+    /// Mark this binder object with local stability, which is vendor if we are
+    /// building for the VNDK and system otherwise.
+    #[cfg(vendor_ndk)]
+    fn mark_local_stability(&mut self) {
+        unsafe {
+            // Safety: Self always contains a valid `AIBinder` pointer, so
+            // we can always call this C API safely.
+            sys::AIBinder_markVendorStability(self.as_native_mut());
+        }
+    }
+
+    /// Mark this binder object with local stability, which is vendor if we are
+    /// building for the VNDK and system otherwise.
+    #[cfg(not(vendor_ndk))]
+    fn mark_local_stability(&mut self) {
+        unsafe {
+            // Safety: Self always contains a valid `AIBinder` pointer, so
+            // we can always call this C API safely.
+            sys::AIBinder_markSystemStability(self.as_native_mut());
+        }
+    }
 }
 
 impl<T: Remotable> Interface for Binder<T> {
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index ef142b5..65fa2ca 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -21,6 +21,7 @@
 #include <android/binder_parcel_platform.h>
 #include <android/binder_process.h>
 #include <android/binder_shell.h>
+#include <android/binder_stability.h>
 #include <android/binder_status.h>
 
 namespace android {
@@ -80,6 +81,7 @@
 enum {
     FLAG_ONEWAY = FLAG_ONEWAY,
     FLAG_CLEAR_BUF = FLAG_CLEAR_BUF,
+    FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_LOCAL,
 };
 
 } // namespace consts
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index c535597..ae3d88a 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -28,19 +28,19 @@
 namespace renderengine {
 namespace skia {
 
-AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
-                                       bool isRender) {
+AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer) {
     ATRACE_CALL();
     AHardwareBuffer_Desc desc;
     AHardwareBuffer_describe(buffer, &desc);
-    bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+    const bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+    const bool isRenderable = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER);
     GrBackendFormat backendFormat =
             GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
     mBackendTexture =
             GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height,
                                                        &mDeleteProc, &mUpdateProc, &mImageCtx,
                                                        createProtectedImage, backendFormat,
-                                                       isRender);
+                                                       isRenderable);
     mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
 }
 
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index bb75878..a6f73db 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -69,7 +69,7 @@
     };
 
     // Creates a GrBackendTexture whose contents come from the provided buffer.
-    AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender);
+    AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer);
 
     void ref() { mUsageCount++; }
 
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c5ee15d..c7001b9 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -499,7 +499,7 @@
         std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
                 std::make_shared<AutoBackendTexture::LocalRef>();
         imageTextureRef->setTexture(
-                new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false));
+                new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer()));
         cache.insert({buffer->getId(), imageTextureRef});
     }
     // restore the original state of the protected context if necessary
@@ -653,7 +653,7 @@
         ATRACE_NAME("Cache miss");
         surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
         surfaceTextureRef->setTexture(
-                new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true));
+                new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer()));
         if (useFramebufferCache) {
             ALOGD("Adding to cache");
             cache.insert({buffer->getId(), surfaceTextureRef});
@@ -860,9 +860,8 @@
                 imageTextureRef = iter->second;
             } else {
                 imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
-                imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(),
-                                                                   item.buffer->toAHardwareBuffer(),
-                                                                   false));
+                imageTextureRef->setTexture(
+                        new AutoBackendTexture(grContext.get(), item.buffer->toAHardwareBuffer()));
                 cache.insert({item.buffer->getId(), imageTextureRef});
             }
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 485fc99..76f6e74 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -386,7 +386,9 @@
 
     void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
 
-    bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
+    bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
+        return pid == INJECTOR_PID && uid == INJECTOR_UID;
+    }
 
     void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
         std::scoped_lock lock(mLock);
@@ -1090,7 +1092,8 @@
         const sp<InputDispatcher>& dispatcher, int32_t action, int32_t repeatCount,
         int32_t displayId = ADISPLAY_ID_NONE,
         InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
-        std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT) {
+        std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
+        bool allowKeyRepeat = true) {
     KeyEvent event;
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
@@ -1099,10 +1102,13 @@
                      INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
                      repeatCount, currentTime, currentTime);
 
+    int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+    if (!allowKeyRepeat) {
+        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
+    }
     // Inject event until dispatch out.
     return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
-                                        injectionTimeout,
-                                        POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+                                        injectionTimeout, policyFlags);
 }
 
 static InputEventInjectionResult injectKeyDown(const sp<InputDispatcher>& dispatcher,
@@ -1110,6 +1116,16 @@
     return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /* repeatCount */ 0, displayId);
 }
 
+// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
+// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
+// has to be woken up to process the repeating key.
+static InputEventInjectionResult injectKeyDownNoRepeat(const sp<InputDispatcher>& dispatcher,
+                                                       int32_t displayId = ADISPLAY_ID_NONE) {
+    return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /* repeatCount */ 0, displayId,
+                     InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
+                     /* allowKeyRepeat */ false);
+}
+
 static InputEventInjectionResult injectKeyUp(const sp<InputDispatcher>& dispatcher,
                                              int32_t displayId = ADISPLAY_ID_NONE) {
     return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /* repeatCount */ 0, displayId);
@@ -1254,7 +1270,7 @@
                                 .build();
 
     // Inject event until dispatch out.
-    return injectMotionEvent(dispatcher, event);
+    return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
 }
 
 static InputEventInjectionResult injectMotionDown(const sp<InputDispatcher>& dispatcher,
@@ -2749,13 +2765,14 @@
 
 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
     // Test inject a key down with display id specified.
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT))
             << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
     windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
     windowInSecondary->assertNoEvents();
 
     // Test inject a key down without display id specified.
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher))
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher))
             << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
     windowInPrimary->assertNoEvents();
     windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
@@ -2768,7 +2785,7 @@
                                     AKEY_EVENT_FLAG_CANCELED);
 
     // Test inject a key down, should timeout because of no target window.
-    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher))
+    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDownNoRepeat(mDispatcher))
             << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
     windowInPrimary->assertNoEvents();
     windowInSecondary->consumeFocusEvent(false);
@@ -2990,7 +3007,8 @@
 // Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
 // have focus. Ensure no window received the onPointerDownOutsideFocus callback.
 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT))
             << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
     mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
 
@@ -3271,7 +3289,7 @@
 
 // Send a regular key and respond, which should not cause an ANR.
 TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher));
     mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
     ASSERT_TRUE(mDispatcher->waitForIdle());
     mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -3284,7 +3302,8 @@
 
     InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/);
+                      InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/,
+                      false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
     // Key will not go to window because we have no focused window.
     // The 'no focused window' ANR timer should start instead.
@@ -3320,7 +3339,7 @@
 // Send a key to the app and have the app not respond right away.
 TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
     // Inject a key, and don't respond - expect that ANR is called.
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher));
     std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -3347,7 +3366,7 @@
     // injection times out (instead of failing).
     const InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
     mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
@@ -3366,7 +3385,7 @@
     // injection times out (instead of failing).
     const InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     const std::chrono::duration appTimeout =
             mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -3955,7 +3974,8 @@
     // Key will not be sent anywhere because we have no focused window. It will remain pending.
     InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/);
+                      InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/,
+                      false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
 
     // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4ace4c2..8f1aef0 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -185,10 +185,14 @@
             return std::nullopt;
         }
     }
-    bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
+    const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
             (isSecure() && !targetSettings.isSecure);
+    const bool bufferCanBeUsedAsHwTexture =
+            mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
     compositionengine::LayerFE::LayerSettings& layer = *result;
-    if (blackOutLayer) {
+    if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
+        ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
+                 mName.c_str());
         prepareClearClientComposition(layer, true /* blackout */);
         return layer;
     }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index b0e42b7..a56f28a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -70,7 +70,7 @@
     size_t getCreationCost() const;
     size_t getDisplayCost() const;
 
-    bool hasBufferUpdate(std::vector<const LayerState*>::const_iterator layers) const;
+    bool hasBufferUpdate() const;
     bool hasReadyBuffer() const;
 
     // Decomposes this CachedSet into a vector of its layers as individual CachedSets
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 5b9a9f0..2bd3249 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -45,8 +45,6 @@
     // Renders the newest cached sets with the supplied output dataspace
     void renderCachedSets(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
 
-    void reset();
-
     void dump(std::string& result) const;
 
 private:
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 137697b..4d3036a 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -116,12 +116,11 @@
     return static_cast<size_t>(mBounds.width() * mBounds.height());
 }
 
-bool CachedSet::hasBufferUpdate(std::vector<const LayerState*>::const_iterator layers) const {
+bool CachedSet::hasBufferUpdate() const {
     for (const Layer& layer : mLayers) {
         if (layer.getFramesSinceBufferUpdate() == 0) {
             return true;
         }
-        ++layers;
     }
     return false;
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 30b5761..60ebbb2 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -60,18 +60,6 @@
     mNewCachedSet->render(renderEngine, outputDataspace);
 }
 
-void Flattener::reset() {
-    resetActivities(0, std::chrono::steady_clock::now());
-
-    mUnflattenedDisplayCost = 0;
-    mFlattenedDisplayCost = 0;
-    mInitialLayerCounts.clear();
-    mFinalLayerCounts.clear();
-    mCachedSetCreationCount = 0;
-    mCachedSetCreationCost = 0;
-    mInvalidatedCachedSetAges.clear();
-}
-
 void Flattener::dump(std::string& result) const {
     const auto now = std::chrono::steady_clock::now();
 
@@ -208,7 +196,7 @@
         if (mNewCachedSet &&
             mNewCachedSet->getFingerprint() ==
                     (*incomingLayerIter)->getHash(LayerStateField::Buffer)) {
-            if (mNewCachedSet->hasBufferUpdate(incomingLayerIter)) {
+            if (mNewCachedSet->hasBufferUpdate()) {
                 ALOGV("[%s] Dropping new cached set", __func__);
                 ++mInvalidatedCachedSetAges[0];
                 mNewCachedSet = std::nullopt;
@@ -242,7 +230,7 @@
             }
         }
 
-        if (!currentLayerIter->hasBufferUpdate(incomingLayerIter)) {
+        if (!currentLayerIter->hasBufferUpdate()) {
             currentLayerIter->incrementAge();
             merged.emplace_back(*currentLayerIter);
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 377f817..7842efb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -201,13 +201,7 @@
     cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
     cachedSet.addLayer(layer3.getState(), kStartTime + 20ms);
 
-    std::vector<const LayerState*> incomingLayers = {
-            layer1.getState(),
-            layer2.getState(),
-            layer3.getState(),
-    };
-
-    EXPECT_FALSE(cachedSet.hasBufferUpdate(incomingLayers.begin()));
+    EXPECT_FALSE(cachedSet.hasBufferUpdate());
 }
 
 TEST_F(CachedSetTest, hasBufferUpdate_BufferUpdate) {
@@ -221,13 +215,7 @@
 
     mTestLayers[1]->layerState->resetFramesSinceBufferUpdate();
 
-    std::vector<const LayerState*> incomingLayers = {
-            layer1.getState(),
-            layer2.getState(),
-            layer3.getState(),
-    };
-
-    EXPECT_TRUE(cachedSet.hasBufferUpdate(incomingLayers.begin()));
+    EXPECT_TRUE(cachedSet.hasBufferUpdate());
 }
 
 TEST_F(CachedSetTest, append) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f9a7ee7..b73d032 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -967,8 +967,10 @@
     std::vector<Hwc2::IComposerClient::LayerGenericMetadataKey> supportedMetadataKeyInfo;
     const auto error = mComposer->getLayerGenericMetadataKeys(&supportedMetadataKeyInfo);
     if (error != hardware::graphics::composer::V2_4::Error::NONE) {
-        ALOGE("%s: %s failed: %s (%d)", __FUNCTION__, "getLayerGenericMetadataKeys",
-              toString(error).c_str(), static_cast<int32_t>(error));
+        if (error != hardware::graphics::composer::V2_4::Error::UNSUPPORTED) {
+            ALOGE("%s: %s failed: %s (%d)", __FUNCTION__, "getLayerGenericMetadataKeys",
+                  toString(error).c_str(), static_cast<int32_t>(error));
+        }
         return;
     }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 91e8043..a5cf797 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -499,11 +499,7 @@
         // Now that we scored all the refresh rates we need to pick the one that got the highest
         // score.
         const RefreshRate* bestRefreshRate = getBestRefreshRate(scores.begin(), scores.end());
-
-        // If the nest refresh rate is the current one, we don't have an override
-        if (!bestRefreshRate->getFps().equalsWithMargin(displayFrameRate)) {
-            frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
-        }
+        frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
     }
 
     return frameRateOverrides;
@@ -839,11 +835,6 @@
     return static_cast<int>(numPeriodsRounded);
 }
 
-int RefreshRateConfigs::getRefreshRateDivider(Fps frameRate) const {
-    std::lock_guard lock(mLock);
-    return getFrameRateDivider(mCurrentRefreshRate->getFps(), frameRate);
-}
-
 void RefreshRateConfigs::dump(std::string& result) const {
     std::lock_guard lock(mLock);
     base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 2bc22b4..ee89149 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -324,8 +324,10 @@
 
     bool supportsFrameRateOverride() const { return mSupportsFrameRateOverride; }
 
-    // Returns a divider for the current refresh rate
-    int getRefreshRateDivider(Fps frameRate) const EXCLUDES(mLock);
+    // Return the display refresh rate divider to match the layer
+    // frame rate, or 0 if the display refresh rate is not a multiple of the
+    // layer refresh rate.
+    static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
 
     using UidToFrameRateOverride = std::map<uid_t, Fps>;
     // Returns the frame rate override for each uid.
@@ -373,11 +375,6 @@
     const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
     bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
 
-    // Return the display refresh rate divider to match the layer
-    // frame rate, or 0 if the display refresh rate is not a multiple of the
-    // layer refresh rate.
-    static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
-
     // calculates a score for a layer. Used to determine the display refresh rate
     // and the frame rate override for certains applications.
     float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 9813270..4edbdd2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -235,12 +235,7 @@
         return true;
     }
 
-    const auto divider = mRefreshRateConfigs.getRefreshRateDivider(*frameRate);
-    if (divider <= 1) {
-        return true;
-    }
-
-    return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, divider);
+    return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, *frameRate);
 }
 
 impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
@@ -354,6 +349,10 @@
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
         // Cache the last reported modes for primary display.
         mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod};
+
+        // Invalidate content based refresh rate selection so it could be calculated
+        // again for the new refresh rate.
+        mFeatures.contentRequirements.clear();
     }
     onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
 }
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 7cca206..028f7a6 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -30,6 +30,7 @@
 #include <algorithm>
 #include <chrono>
 #include <sstream>
+#include "RefreshRateConfigs.h"
 
 #undef LOG_TAG
 #define LOG_TAG "VSyncPredictor"
@@ -225,13 +226,14 @@
 }
 
 /*
- * Returns whether a given vsync timestamp is in phase with a vsync divider.
- * For example, if the vsync timestamps are (16,32,48,64):
- * isVSyncInPhase(16, 2) = true
- * isVSyncInPhase(32, 2) = false
- * isVSyncInPhase(48, 2) = true
+ * Returns whether a given vsync timestamp is in phase with a frame rate.
+ * If the frame rate is not a divider of the refresh rate, it is always considered in phase.
+ * For example, if the vsync timestamps are (16.6,33.3,50.0,66.6):
+ * isVSyncInPhase(16.6, 30) = true
+ * isVSyncInPhase(33.3, 30) = false
+ * isVSyncInPhase(50.0, 30) = true
  */
-bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, int divider) const {
+bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const {
     struct VsyncError {
         nsecs_t vsyncTimestamp;
         float error;
@@ -239,11 +241,13 @@
         bool operator<(const VsyncError& other) const { return error < other.error; }
     };
 
+    std::lock_guard lock(mMutex);
+    const auto divider =
+            RefreshRateConfigs::getFrameRateDivider(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
     if (divider <= 1 || timePoint == 0) {
         return true;
     }
 
-    std::lock_guard lock(mMutex);
     const nsecs_t period = mRateMap[mIdealPeriod].slope;
     const nsecs_t justBeforeTimePoint = timePoint - period / 2;
     const nsecs_t dividedPeriod = mIdealPeriod / divider;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 381cf81..40e6944 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -64,7 +64,7 @@
 
     VSyncPredictor::Model getVSyncPredictionModel() const EXCLUDES(mMutex);
 
-    bool isVSyncInPhase(nsecs_t timePoint, int divider) const final EXCLUDES(mMutex);
+    bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex);
 
     void dump(std::string& result) const final EXCLUDES(mMutex);
 
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 2cd9b3d..95750ad 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <utils/Timers.h>
+#include "Fps.h"
 #include "VSyncDispatch.h"
 
 namespace android::scheduler {
@@ -69,12 +70,12 @@
     virtual bool needsMoreSamples() const = 0;
 
     /*
-     * Checks if a vsync timestamp is in phase for a given divider.
+     * Checks if a vsync timestamp is in phase for a frame rate
      *
      * \param [in] timePoint  A vsync timestamp
-     * \param [in] divider  The divider to check for
+     * \param [in] frameRate  The frame rate to check for
      */
-    virtual bool isVSyncInPhase(nsecs_t timePoint, int divider) const = 0;
+    virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0;
 
     virtual void dump(std::string& result) const = 0;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 525b043..a387587 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3450,6 +3450,7 @@
         const bool acquireFenceChanged = (s.what & layer_state_t::eAcquireFenceChanged);
         if (acquireFenceChanged && s.acquireFence &&
             s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+            ATRACE_NAME("fence unsignaled");
             ready = false;
         }
 
@@ -5926,8 +5927,11 @@
     const status_t bufferStatus = buffer->initCheck();
     LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
                         bufferStatus);
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
-                               false /* regionSampling */, grayscale, captureListener);
+    getRenderEngine().cacheExternalTextureBuffer(buffer);
+    status_t result = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+                                          false /* regionSampling */, grayscale, captureListener);
+    getRenderEngine().unbindExternalTextureBuffer(buffer->getId());
+    return result;
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
@@ -5967,15 +5971,6 @@
                                             regionSampling, grayscale, captureResults);
         });
 
-        // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine
-        // Only do this when we're not doing region sampling, to allow the region sampling thread to
-        // manage buffer lifecycle itself.
-        if (!regionSampling &&
-            getRenderEngine().getRenderEngineType() ==
-                    renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) {
-            getRenderEngine().unbindExternalTextureBuffer(buffer->getId());
-        }
-
         captureResults.result = result;
         captureListener->onScreenCaptureCompleted(captureResults);
     }));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 06f2036..15bd0e1 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1621,29 +1621,35 @@
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateDivider) {
+TEST_F(RefreshRateConfigsTest, getFrameRateDivider) {
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_30);
 
     const auto frameRate = Fps(30.f);
-    EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDivider(frameRate));
+    Fps displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
+    EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_60);
-    EXPECT_EQ(2, refreshRateConfigs->getRefreshRateDivider(frameRate));
+    displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
+    EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_72);
-    EXPECT_EQ(0, refreshRateConfigs->getRefreshRateDivider(frameRate));
+    displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
-    EXPECT_EQ(3, refreshRateConfigs->getRefreshRateDivider(frameRate));
+    displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
+    EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_120);
-    EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(frameRate));
+    displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
-    EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.5f)));
-    EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.6f)));
+    displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.5f)));
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.6f)));
 }
 
 TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 0af5f30..42b1993 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -52,7 +52,7 @@
     void setPeriod(nsecs_t) final {}
     void resetModel() final {}
     bool needsMoreSamples() const final { return false; }
-    bool isVSyncInPhase(nsecs_t, int) const final { return false; }
+    bool isVSyncInPhase(nsecs_t, Fps) const final { return false; }
     void dump(std::string&) const final {}
 
 private:
@@ -89,7 +89,7 @@
     void setPeriod(nsecs_t) final {}
     void resetModel() final {}
     bool needsMoreSamples() const final { return false; }
-    bool isVSyncInPhase(nsecs_t, int) const final { return false; }
+    bool isVSyncInPhase(nsecs_t, Fps) 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 00cf574..b64cce9 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -49,7 +49,7 @@
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(resetModel, void());
     MOCK_CONST_METHOD0(needsMoreSamples, bool());
-    MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, int));
+    MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
     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 a4ddbf4..2a658dd 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -469,7 +469,9 @@
     for (int divider = 1; divider < maxDivider; divider++) {
         for (int i = 0; i < maxPeriods; i++) {
             const bool expectedInPhase = (i % divider) == 0;
-            EXPECT_THAT(expectedInPhase, tracker.isVSyncInPhase(mNow + i * mPeriod - bias, divider))
+            EXPECT_THAT(expectedInPhase,
+                        tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
+                                               Fps::fromPeriodNsecs(divider * mPeriod)))
                     << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
                     << (expectedInPhase ? "not " : "") << "in phase for divider " << divider;
         }
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index b9651ea..5826a9b 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -46,7 +46,7 @@
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(resetModel, void());
     MOCK_CONST_METHOD0(needsMoreSamples, bool());
-    MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, int));
+    MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
index de98025..5b0c1f3 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
@@ -33,7 +33,7 @@
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(resetModel, void());
     MOCK_CONST_METHOD0(needsMoreSamples, bool());
-    MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, int));
+    MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };