Merge "fix race in ProcessState::getThreadPoolMaxTotalThreadCount" into main
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index 9384926..28bd793 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -50,37 +50,6 @@
   exit 1
 fi
 
-# A source that infinitely emits arbitrary lines.
-# When connected to STDIN of another process, this source keeps STDIN open until
-# the consumer process closes STDIN or this script dies.
-function infinite_source {
-  while echo .; do
-    sleep 1
-  done
-}
-
-PR_DEXOPT_JOB_VERSION="$(pm art pr-dexopt-job --version)"
-if (( $? == 0 )) && (( $PR_DEXOPT_JOB_VERSION >= 2 )); then
-  # Delegate to Pre-reboot Dexopt, a feature of ART Service.
-  # ART Service decides what to do with this request:
-  # - If Pre-reboot Dexopt is disabled or unsupported, the command returns
-  #   non-zero. This is always the case if the current system is Android 14 or
-  #   earlier.
-  # - If Pre-reboot Dexopt is enabled in synchronous mode, the command blocks
-  #   until Pre-reboot Dexopt finishes, and returns zero no matter it succeeds or
-  #   not. This is the default behavior if the current system is Android 15.
-  # - If Pre-reboot Dexopt is enabled in asynchronous mode, the command schedules
-  #   an asynchronous job and returns 0 immediately. The job will then run by the
-  #   job scheduler when the device is idle and charging.
-  if infinite_source | pm art on-ota-staged --slot "$TARGET_SLOT_SUFFIX"; then
-    # Handled by Pre-reboot Dexopt.
-    exit 0
-  fi
-  echo "Pre-reboot Dexopt not enabled. Fall back to otapreopt."
-else
-  echo "Pre-reboot Dexopt is too old. Fall back to otapreopt."
-fi
-
 if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then
   # We require an updated chroot wrapper that reads dexopt commands from stdin.
   # Even if we kept compat with the old binary, the OTA preopt wouldn't work due
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 0f251d2..ef2fa4d 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -29,6 +29,7 @@
 #include <thread>
 
 #if !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__)
+#include "perfetto/public/protos/trace/android/android_track_event.pzc.h"
 #include "perfetto/public/te_category_macros.h"
 #include "perfetto/public/te_macros.h"
 #endif // !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__)
@@ -57,6 +58,12 @@
 #define SM_PERFETTO_TRACE_FUNC(...) \
     PERFETTO_TE_SCOPED(servicemanager, PERFETTO_TE_SLICE_BEGIN(__func__) __VA_OPT__(, ) __VA_ARGS__)
 
+constexpr uint32_t kProtoServiceName =
+        perfetto_protos_AndroidTrackEvent_binder_service_name_field_number;
+constexpr uint32_t kProtoInterfaceName =
+        perfetto_protos_AndroidTrackEvent_binder_interface_name_field_number;
+constexpr uint32_t kProtoApexName = perfetto_protos_AndroidTrackEvent_apex_name_field_number;
+
 #endif // !(defined(VENDORSERVICEMANAGER) || defined(__ANDROID_RECOVERY__))
 
 bool is_multiuser_uid_isolated(uid_t uid) {
@@ -112,13 +119,15 @@
     std::string iface;
     std::string instance;
 
-    static bool fill(const std::string& name, AidlName* aname) {
+    static bool fill(const std::string& name, AidlName* aname, bool logError) {
         size_t firstSlash = name.find('/');
         size_t lastDot = name.rfind('.', firstSlash);
         if (firstSlash == std::string::npos || lastDot == std::string::npos) {
-            ALOGE("VINTF HALs require names in the format type/instance (e.g. "
-                  "some.package.foo.IFoo/default) but got: %s",
-                  name.c_str());
+            if (logError) {
+                ALOGE("VINTF HALs require names in the format type/instance (e.g. "
+                      "some.package.foo.IFoo/default) but got: %s",
+                      name.c_str());
+            }
             return false;
         }
         aname->package = name.substr(0, lastDot);
@@ -151,7 +160,7 @@
     }
 
     AidlName aname;
-    if (!AidlName::fill(name, &aname)) return false;
+    if (!AidlName::fill(name, &aname, true)) return false;
 
     bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
         if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
@@ -209,7 +218,7 @@
     }
 
     AidlName aname;
-    if (!AidlName::fill(name, &aname)) return std::nullopt;
+    if (!AidlName::fill(name, &aname, true)) return std::nullopt;
 
     std::optional<std::string> updatableViaApex;
 
@@ -251,7 +260,7 @@
 
 static std::optional<std::string> getVintfAccessorName(const std::string& name) {
     AidlName aname;
-    if (!AidlName::fill(name, &aname)) return std::nullopt;
+    if (!AidlName::fill(name, &aname, false)) return std::nullopt;
 
     std::optional<std::string> accessor;
     forEachManifest([&](const ManifestWithDescription& mwd) {
@@ -270,7 +279,7 @@
 
 static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) {
     AidlName aname;
-    if (!AidlName::fill(name, &aname)) return std::nullopt;
+    if (!AidlName::fill(name, &aname, true)) return std::nullopt;
 
     std::optional<std::string> ip;
     std::optional<uint64_t> port;
@@ -383,8 +392,18 @@
     }
 }
 
-Status ServiceManager::getService(const std::string& name, os::Service* outService) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
+
+    *outBinder = tryGetBinder(name, true);
+    // returns ok regardless of result for legacy reasons
+    return Status::ok();
+}
+
+Status ServiceManager::getService2(const std::string& name, os::Service* outService) {
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     *outService = tryGetService(name, true);
     // returns ok regardless of result for legacy reasons
@@ -392,7 +411,8 @@
 }
 
 Status ServiceManager::checkService(const std::string& name, os::Service* outService) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     *outService = tryGetService(name, false);
     // returns ok regardless of result for legacy reasons
@@ -417,7 +437,8 @@
 }
 
 sp<IBinder> ServiceManager::tryGetBinder(const std::string& name, bool startIfNotFound) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -457,7 +478,8 @@
 }
 
 bool isValidServiceName(const std::string& name) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     if (name.size() == 0) return false;
     if (name.size() > 127) return false;
@@ -474,7 +496,8 @@
 }
 
 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -597,7 +620,8 @@
 
 Status ServiceManager::registerForNotifications(
         const std::string& name, const sp<IServiceCallback>& callback) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -648,7 +672,8 @@
 }
 Status ServiceManager::unregisterForNotifications(
         const std::string& name, const sp<IServiceCallback>& callback) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -674,7 +699,8 @@
 }
 
 Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -692,7 +718,8 @@
 }
 
 binder::Status ServiceManager::getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("interface", interface.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoInterfaceName, interface.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -720,7 +747,8 @@
 
 Status ServiceManager::updatableViaApex(const std::string& name,
                                         std::optional<std::string>* outReturn) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -739,7 +767,8 @@
 
 Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& apexName,
                                          std::vector<std::string>* outReturn) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("apexName", apexName.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoApexName, apexName.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -765,7 +794,8 @@
 
 Status ServiceManager::getConnectionInfo(const std::string& name,
                                          std::optional<ConnectionInfo>* outReturn) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     auto ctx = mAccess->getCallingContext();
 
@@ -850,7 +880,8 @@
 
 Status ServiceManager::registerClientCallback(const std::string& name, const sp<IBinder>& service,
                                               const sp<IClientCallback>& cb) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     if (cb == nullptr) {
         return Status::fromExceptionCode(Status::EX_NULL_POINTER, "Callback null.");
@@ -1012,7 +1043,8 @@
 }
 
 Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IBinder>& binder) {
-    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
 
     if (binder == nullptr) {
         return Status::fromExceptionCode(Status::EX_NULL_POINTER, "Null service.");
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 18bae68..0d666c6 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -44,7 +44,8 @@
     ~ServiceManager();
 
     // getService will try to start any services it cannot find
-    binder::Status getService(const std::string& name, os::Service* outService) override;
+    binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override;
+    binder::Status getService2(const std::string& name, os::Service* outService) override;
     binder::Status checkService(const std::string& name, os::Service* outService) override;
     binder::Status addService(const std::string& name, const sp<IBinder>& binder,
                               bool allowIsolated, int32_t dumpPriority) override;
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 9d22641..95f459f 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -155,8 +155,11 @@
         IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
 
     Service outA;
-    EXPECT_TRUE(sm->getService("foo", &outA).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &outA).isOk());
     EXPECT_EQ(serviceA, outA.get<Service::Tag::binder>());
+    sp<IBinder> outBinderA;
+    EXPECT_TRUE(sm->getService("foo", &outBinderA).isOk());
+    EXPECT_EQ(serviceA, outBinderA);
 
     // serviceA should be overwritten by serviceB
     sp<IBinder> serviceB = getBinder();
@@ -164,8 +167,11 @@
         IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
 
     Service outB;
-    EXPECT_TRUE(sm->getService("foo", &outB).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &outB).isOk());
     EXPECT_EQ(serviceB, outB.get<Service::Tag::binder>());
+    sp<IBinder> outBinderB;
+    EXPECT_TRUE(sm->getService("foo", &outBinderB).isOk());
+    EXPECT_EQ(serviceB, outBinderB);
 }
 
 TEST(AddService, NoPermissions) {
@@ -188,16 +194,22 @@
         IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
 
     Service out;
-    EXPECT_TRUE(sm->getService("foo", &out).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &out).isOk());
     EXPECT_EQ(service, out.get<Service::Tag::binder>());
+    sp<IBinder> outBinder;
+    EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
+    EXPECT_EQ(service, outBinder);
 }
 
 TEST(GetService, NonExistant) {
     auto sm = getPermissiveServiceManager();
 
     Service out;
-    EXPECT_TRUE(sm->getService("foo", &out).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &out).isOk());
     EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+    sp<IBinder> outBinder;
+    EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
+    EXPECT_EQ(nullptr, outBinder);
 }
 
 TEST(GetService, NoPermissionsForGettingService) {
@@ -205,7 +217,7 @@
 
     EXPECT_CALL(*access, getCallingContext()).WillRepeatedly(Return(Access::CallingContext{}));
     EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true));
-    EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(false));
+    EXPECT_CALL(*access, canFind(_, _)).WillRepeatedly(Return(false));
 
     sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
 
@@ -214,22 +226,28 @@
 
     Service out;
     // returns nullptr but has OK status for legacy compatibility
-    EXPECT_TRUE(sm->getService("foo", &out).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &out).isOk());
     EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+    sp<IBinder> outBinder;
+    EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
+    EXPECT_EQ(nullptr, outBinder);
 }
 
 TEST(GetService, AllowedFromIsolated) {
     std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
 
     EXPECT_CALL(*access, getCallingContext())
-        // something adds it
-        .WillOnce(Return(Access::CallingContext{}))
-        // next call is from isolated app
-        .WillOnce(Return(Access::CallingContext{
-            .uid = AID_ISOLATED_START,
-        }));
+            // something adds it
+            .WillOnce(Return(Access::CallingContext{}))
+            // next calls is from isolated app
+            .WillOnce(Return(Access::CallingContext{
+                    .uid = AID_ISOLATED_START,
+            }))
+            .WillOnce(Return(Access::CallingContext{
+                    .uid = AID_ISOLATED_START,
+            }));
     EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true));
-    EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true));
+    EXPECT_CALL(*access, canFind(_, _)).WillRepeatedly(Return(true));
 
     sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
 
@@ -238,20 +256,26 @@
         IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
 
     Service out;
-    EXPECT_TRUE(sm->getService("foo", &out).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &out).isOk());
     EXPECT_EQ(service, out.get<Service::Tag::binder>());
+    sp<IBinder> outBinder;
+    EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
+    EXPECT_EQ(service, outBinder);
 }
 
 TEST(GetService, NotAllowedFromIsolated) {
     std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
 
     EXPECT_CALL(*access, getCallingContext())
-        // something adds it
-        .WillOnce(Return(Access::CallingContext{}))
-        // next call is from isolated app
-        .WillOnce(Return(Access::CallingContext{
-            .uid = AID_ISOLATED_START,
-        }));
+            // something adds it
+            .WillOnce(Return(Access::CallingContext{}))
+            // next calls is from isolated app
+            .WillOnce(Return(Access::CallingContext{
+                    .uid = AID_ISOLATED_START,
+            }))
+            .WillOnce(Return(Access::CallingContext{
+                    .uid = AID_ISOLATED_START,
+            }));
     EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true));
 
     // TODO(b/136023468): when security check is first, this should be called first
@@ -264,8 +288,11 @@
 
     Service out;
     // returns nullptr but has OK status for legacy compatibility
-    EXPECT_TRUE(sm->getService("foo", &out).isOk());
+    EXPECT_TRUE(sm->getService2("foo", &out).isOk());
     EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+    sp<IBinder> outBinder;
+    EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
+    EXPECT_EQ(nullptr, outBinder);
 }
 
 TEST(ListServices, NoPermissions) {
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 3c82d88..62d0423 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -53,6 +53,7 @@
  */
 
 #include <android/api-level.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <unistd.h>
 
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 0765e01..665d9c6 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -369,6 +369,28 @@
                                   float b, float alpha, enum ADataSpace dataspace)
         __INTRODUCED_IN(29);
 
+// These APIs (setGeometry and setCrop) were originally written in a
+// C-incompatible form using references instead of pointers, and the OS shipped
+// that version for years before it was noticed. Fortunately the compiled code
+// for callers is the same regardless of whether it's a pointer or a reference,
+// so we can declare this as a nonnull pointer for C and keep the existing C++
+// decl and definition.
+//
+// We could alternatively change the decl and the definition to both be a
+// pointer (with an inline definition using references to preserve source compat
+// for existing C++ callers), but that requires changing the definition of an
+// API that has been in the OS for years. It's theoretically a safe change, but
+// without being able to prove it that's a very big risk to take. By keeping the
+// C-compatibility hack in the header, we can be sure that we haven't changed
+// anything for existing callers. By definition there were no C users of the
+// reference-based decl; if there were any C callers of the API at all, they were
+// using the same workaround that is now used below.
+//
+// Even if this workaround turns out to not work for C, there's no permanent
+// damage done to the platform (unlike if we were to change the definition). At
+// worst it continues to work for C++ (since the preprocessed header as seen by
+// C++ hasn't changed, nor has the definition) and continues to not work for C.
+
 /**
  * \param source The sub-rect within the buffer's content to be rendered inside the surface's area
  * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
@@ -379,7 +401,7 @@
  * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
  *
  * \param transform The transform applied after the source rect is applied to the buffer. This
- * parameter should be set to 0 for no transform. To specify a transfrom use the
+ * parameter should be set to 0 for no transform. To specify a transform use the
  * NATIVE_WINDOW_TRANSFORM_* enum.
  *
  * Available since API level 29.
@@ -390,9 +412,14 @@
  * properties at once.
  */
 void ASurfaceTransaction_setGeometry(ASurfaceTransaction* _Nonnull transaction,
-                                     ASurfaceControl* _Nonnull surface_control, const ARect& source,
-                                     const ARect& destination, int32_t transform)
-        __INTRODUCED_IN(29);
+                                     ASurfaceControl* _Nonnull surface_control,
+#if defined(__cplusplus)
+                                     const ARect& source, const ARect& destination,
+#else
+                                     const ARect* _Nonnull source,
+                                     const ARect* _Nonnull destination,
+#endif
+                                     int32_t transform) __INTRODUCED_IN(29);
 
 /**
  * Bounds the surface and its children to the bounds specified. The crop and buffer size will be
@@ -404,7 +431,12 @@
  * Available since API level 31.
  */
 void ASurfaceTransaction_setCrop(ASurfaceTransaction* _Nonnull transaction,
-                                 ASurfaceControl* _Nonnull surface_control, const ARect& crop)
+                                 ASurfaceControl* _Nonnull surface_control,
+#if defined(__cplusplus)
+                                 const ARect& crop)
+#else
+                                 const ARect* _Nonnull crop)
+#endif
         __INTRODUCED_IN(31);
 
 /**
diff --git a/include/android/thermal.h b/include/android/thermal.h
index fa168cd..7f9d2ed 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -85,6 +85,7 @@
     /** Need shutdown immediately. */
     ATHERMAL_STATUS_SHUTDOWN = 6,
 };
+typedef enum AThermalStatus AThermalStatus;
 
 /**
  * An opaque type representing a handle to a thermal manager.
@@ -240,6 +241,7 @@
     float headroom;
     AThermalStatus thermalStatus;
 };
+typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold;
 
 /**
  * Gets the thermal headroom thresholds for all available thermal status.
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 0bf3cad..54f687b 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -33,10 +33,19 @@
 sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
     return mTheRealServiceManager;
 }
+
 binder::Status BackendUnifiedServiceManager::getService(const ::std::string& name,
-                                                        os::Service* _out) {
+                                                        sp<IBinder>* _aidl_return) {
     os::Service service;
-    binder::Status status = mTheRealServiceManager->getService(name, &service);
+    binder::Status status = getService2(name, &service);
+    *_aidl_return = service.get<os::Service::Tag::binder>();
+    return status;
+}
+
+binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name,
+                                                         os::Service* _out) {
+    os::Service service;
+    binder::Status status = mTheRealServiceManager->getService2(name, &service);
     toBinderService(service, _out);
     return status;
 }
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index 4715be4..f5d7e66 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -26,7 +26,8 @@
     explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl);
 
     sp<os::IServiceManager> getImpl();
-    binder::Status getService(const ::std::string& name, os::Service* out) override;
+    binder::Status getService(const ::std::string& name, sp<IBinder>* _aidl_return) override;
+    binder::Status getService2(const ::std::string& name, os::Service* out) override;
     binder::Status checkService(const ::std::string& name, os::Service* out) override;
     binder::Status addService(const ::std::string& name, const sp<IBinder>& service,
                               bool allowIsolated, int32_t dumpPriority) override;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 12a18f2..8b80aed 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -143,7 +143,7 @@
     // mUnifiedServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
     virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
         Service service;
-        Status status = mUnifiedServiceManager->getService(name, &service);
+        Status status = mUnifiedServiceManager->getService2(name, &service);
         *_aidl_return = service.get<Service::Tag::binder>();
         return status;
     }
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index ac95188..1d1f84f 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -60,9 +60,23 @@
      * exists for legacy purposes.
      *
      * Returns null if the service does not exist.
+     *
+     * @deprecated TODO(b/355394904): Use getService2 instead.
      */
     @UnsupportedAppUsage
-    Service getService(@utf8InCpp String name);
+    @nullable IBinder getService(@utf8InCpp String name);
+
+    /**
+     * Retrieve an existing service called @a name from the
+     * service manager.
+     *
+     * This is the same as checkService (returns immediately) but
+     * exists for legacy purposes.
+     *
+     * Returns an enum Service that can be of different types. The
+     * enum value is null if the service does not exist.
+     */
+    Service getService2(@utf8InCpp String name);
 
     /**
      * Retrieve an existing service called @a name from the service
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 201dfbc..be99065 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -118,7 +118,12 @@
 class ServiceManagerProxyToNative : public android::os::BnServiceManager {
 public:
     ServiceManagerProxyToNative(const sp<android::os::IServiceManager>& impl) : mImpl(impl) {}
-    android::binder::Status getService(const std::string&, android::os::Service*) override {
+    android::binder::Status getService(const std::string&,
+                                       android::sp<android::IBinder>*) override {
+        // We can't send BpBinder for regular binder over RPC.
+        return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+    }
+    android::binder::Status getService2(const std::string&, android::os::Service*) override {
         // We can't send BpBinder for regular binder over RPC.
         return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
     }
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 4c7684c..dd50fbd 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -235,6 +235,16 @@
         "binder_test_defaults",
     ],
 
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+
     static_libs: [
         "libbinder_test_utils",
         "libbinder_tls_static",
@@ -267,7 +277,6 @@
     defaults: [
         "binderRpcTest_common_defaults",
     ],
-    compile_multilib: "first",
 
     srcs: [
         "binderRpcTest.cpp",
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3efd84f..cd78e82 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -19,6 +19,12 @@
 #include <aidl/IBinderRpcTest.h>
 #endif
 
+#if defined(__LP64__)
+#define TEST_FILE_SUFFIX "64"
+#else
+#define TEST_FILE_SUFFIX "32"
+#endif
+
 #include <chrono>
 #include <cstdlib>
 #include <iostream>
@@ -259,7 +265,8 @@
 
     std::string path = GetExecutableDirectory();
     auto servicePath = path + "/binder_rpc_test_service" +
-            (singleThreaded ? "_single_threaded" : "") + (noKernel ? "_no_kernel" : "");
+            (singleThreaded ? "_single_threaded" : "") + (noKernel ? "_no_kernel" : "") +
+            TEST_FILE_SUFFIX;
 
     unique_fd bootstrapClientFd, socketFd;
 
diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt
index ff3ae5a..4f293b9 100644
--- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt
+++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt
@@ -1,7 +1,5 @@
 package com.android.graphics.bufferstreamsdemoapp
 
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
@@ -29,10 +27,11 @@
             navigationIcon = {
                 if (canNavigateBack) {
                     IconButton(onClick = navigateUp) {
-                        Icon(
-                                imageVector = Icons.AutoMirrored.Filled.ArrowBack,
-                                contentDescription = stringResource(R.string.back_button)
-                        )
+                        // b/355293776
+                        // Icon(
+                        //     imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+                        //     contentDescription = stringResource(R.string.back_button)
+                        // )
                     }
                 }
             }
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 81f6a58..44cdc02 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -41,7 +41,7 @@
 static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
 
 // Declare busy loop variable globally to prevent removal during optimization
-static long sum __attribute__((used)) = 0;
+static volatile long sum __attribute__((used)) = 1;
 
 using std::vector;
 
@@ -579,8 +579,8 @@
 
 // Keeps CPU busy with some number crunching
 void useCpu() {
-    sum = 0;
-    for (int i = 0; i < 100000; i++) {
+    sum = 1;
+    for (int i = 1; i < 100000; i++) {
         sum *= i;
     }
 }
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 11f5174..69d25be 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -42,6 +42,8 @@
 
 #include <system/window.h>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
 
 // Macros for include BufferQueueCore information in log messages
@@ -370,79 +372,94 @@
         return BAD_VALUE;
     }
 
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    sp<IProducerListener> listener;
+    {
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
 
-    if (mCore->mSharedBufferMode) {
-        BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
-        return BAD_VALUE;
-    }
-
-    // Make sure we don't have too many acquired buffers
-    int numAcquiredBuffers = 0;
-    for (int s : mCore->mActiveBuffers) {
-        if (mSlots[s].mBufferState.isAcquired()) {
-            ++numAcquiredBuffers;
+        if (mCore->mSharedBufferMode) {
+            BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
+            return BAD_VALUE;
         }
+
+        // Make sure we don't have too many acquired buffers
+        int numAcquiredBuffers = 0;
+        for (int s : mCore->mActiveBuffers) {
+            if (mSlots[s].mBufferState.isAcquired()) {
+                ++numAcquiredBuffers;
+            }
+        }
+
+        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+            BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
+                    "(max %d)", numAcquiredBuffers,
+                    mCore->mMaxAcquiredBufferCount);
+            return INVALID_OPERATION;
+        }
+
+        if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+            BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
+                    "[queue %u]", buffer->getGenerationNumber(),
+                    mCore->mGenerationNumber);
+            return BAD_VALUE;
+        }
+
+        // Find a free slot to put the buffer into
+        int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+        if (!mCore->mFreeSlots.empty()) {
+            auto slot = mCore->mFreeSlots.begin();
+            found = *slot;
+            mCore->mFreeSlots.erase(slot);
+        } else if (!mCore->mFreeBuffers.empty()) {
+            found = mCore->mFreeBuffers.front();
+            mCore->mFreeBuffers.remove(found);
+        }
+        if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+            BQ_LOGE("attachBuffer: could not find free buffer slot");
+            return NO_MEMORY;
+        }
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+        if (mCore->mBufferAttachedCbEnabled) {
+            listener = mCore->mConnectedProducerListener;
+        }
+#endif
+
+        mCore->mActiveBuffers.insert(found);
+        *outSlot = found;
+        ATRACE_BUFFER_INDEX(*outSlot);
+        BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
+
+        mSlots[*outSlot].mGraphicBuffer = buffer;
+        mSlots[*outSlot].mBufferState.attachConsumer();
+        mSlots[*outSlot].mNeedsReallocation = true;
+        mSlots[*outSlot].mFence = Fence::NO_FENCE;
+        mSlots[*outSlot].mFrameNumber = 0;
+
+        // mAcquireCalled tells BufferQueue that it doesn't need to send a valid
+        // GraphicBuffer pointer on the next acquireBuffer call, which decreases
+        // Binder traffic by not un/flattening the GraphicBuffer. However, it
+        // requires that the consumer maintain a cached copy of the slot <--> buffer
+        // mappings, which is why the consumer doesn't need the valid pointer on
+        // acquire.
+        //
+        // The StreamSplitter is one of the primary users of the attach/detach
+        // logic, and while it is running, all buffers it acquires are immediately
+        // detached, and all buffers it eventually releases are ones that were
+        // attached (as opposed to having been obtained from acquireBuffer), so it
+        // doesn't make sense to maintain the slot/buffer mappings, which would
+        // become invalid for every buffer during detach/attach. By setting this to
+        // false, the valid GraphicBuffer pointer will always be sent with acquire
+        // for attached buffers.
+        mSlots[*outSlot].mAcquireCalled = false;
+
+        VALIDATE_CONSISTENCY();
     }
 
-    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
-        BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
-                "(max %d)", numAcquiredBuffers,
-                mCore->mMaxAcquiredBufferCount);
-        return INVALID_OPERATION;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+    if (listener != nullptr) {
+        listener->onBufferAttached();
     }
-
-    if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
-        BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
-                "[queue %u]", buffer->getGenerationNumber(),
-                mCore->mGenerationNumber);
-        return BAD_VALUE;
-    }
-
-    // Find a free slot to put the buffer into
-    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
-    if (!mCore->mFreeSlots.empty()) {
-        auto slot = mCore->mFreeSlots.begin();
-        found = *slot;
-        mCore->mFreeSlots.erase(slot);
-    } else if (!mCore->mFreeBuffers.empty()) {
-        found = mCore->mFreeBuffers.front();
-        mCore->mFreeBuffers.remove(found);
-    }
-    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
-        BQ_LOGE("attachBuffer: could not find free buffer slot");
-        return NO_MEMORY;
-    }
-
-    mCore->mActiveBuffers.insert(found);
-    *outSlot = found;
-    ATRACE_BUFFER_INDEX(*outSlot);
-    BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
-
-    mSlots[*outSlot].mGraphicBuffer = buffer;
-    mSlots[*outSlot].mBufferState.attachConsumer();
-    mSlots[*outSlot].mNeedsReallocation = true;
-    mSlots[*outSlot].mFence = Fence::NO_FENCE;
-    mSlots[*outSlot].mFrameNumber = 0;
-
-    // mAcquireCalled tells BufferQueue that it doesn't need to send a valid
-    // GraphicBuffer pointer on the next acquireBuffer call, which decreases
-    // Binder traffic by not un/flattening the GraphicBuffer. However, it
-    // requires that the consumer maintain a cached copy of the slot <--> buffer
-    // mappings, which is why the consumer doesn't need the valid pointer on
-    // acquire.
-    //
-    // The StreamSplitter is one of the primary users of the attach/detach
-    // logic, and while it is running, all buffers it acquires are immediately
-    // detached, and all buffers it eventually releases are ones that were
-    // attached (as opposed to having been obtained from acquireBuffer), so it
-    // doesn't make sense to maintain the slot/buffer mappings, which would
-    // become invalid for every buffer during detach/attach. By setting this to
-    // false, the valid GraphicBuffer pointer will always be sent with acquire
-    // for attached buffers.
-    mSlots[*outSlot].mAcquireCalled = false;
-
-    VALIDATE_CONSISTENCY();
+#endif
 
     return NO_ERROR;
 }
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 648db67..e0c5b1f 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -96,6 +96,7 @@
         mLinkedToDeath(),
         mConnectedProducerListener(),
         mBufferReleasedCbEnabled(false),
+        mBufferAttachedCbEnabled(false),
         mSlots(),
         mQueue(),
         mFreeSlots(),
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index fb69fda..88d456b 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1324,6 +1324,9 @@
 #endif
                 mCore->mConnectedProducerListener = listener;
                 mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+                mCore->mBufferAttachedCbEnabled = listener->needsAttachNotify();
+#endif
             }
             break;
         default:
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 0683087..7700795 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -25,6 +25,9 @@
     ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
     NEEDS_RELEASE_NOTIFY,
     ON_BUFFERS_DISCARDED,
+    ON_BUFFER_DETACHED,
+    ON_BUFFER_ATTACHED,
+    NEEDS_ATTACH_NOTIFY,
 };
 
 class BpProducerListener : public BpInterface<IProducerListener>
@@ -64,6 +67,38 @@
         data.writeInt32Vector(discardedSlots);
         remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+    virtual void onBufferDetached(int slot) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        data.writeInt32(slot);
+        remote()->transact(ON_BUFFER_DETACHED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onBufferAttached() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        remote()->transact(ON_BUFFER_ATTACHED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual bool needsAttachNotify() {
+        bool result;
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        status_t err = remote()->transact(NEEDS_ATTACH_NOTIFY, data, &reply);
+        if (err != NO_ERROR) {
+            ALOGE("IProducerListener: binder call \'needsAttachNotify\' failed");
+            return true;
+        }
+        err = reply.readBool(&result);
+        if (err != NO_ERROR) {
+            ALOGE("IProducerListener: malformed binder reply");
+            return true;
+        }
+        return result;
+    }
+#endif
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -115,6 +150,27 @@
             onBuffersDiscarded(discardedSlots);
             return NO_ERROR;
         }
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+        case ON_BUFFER_DETACHED: {
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            int slot;
+            status_t result = data.readInt32(&slot);
+            if (result != NO_ERROR) {
+                ALOGE("ON_BUFFER_DETACHED failed to read slot: %d", result);
+                return result;
+            }
+            onBufferDetached(slot);
+            return NO_ERROR;
+        }
+        case ON_BUFFER_ATTACHED:
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            onBufferAttached();
+            return NO_ERROR;
+        case NEEDS_ATTACH_NOTIFY:
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            reply->writeBool(needsAttachNotify());
+            return NO_ERROR;
+#endif
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 070f6bf..b97cee3 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,6 +1,8 @@
 # Bug component: 1075131
 
+carlosmr@google.com
 chrisforbes@google.com
+jshargo@google.com
 jreck@google.com
 
 file:/services/surfaceflinger/OWNERS
@@ -9,10 +11,10 @@
 
 # BufferQueue is feature-frozen
 per-file BufferQueue* = set noparent
-per-file BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com
 per-file IGraphicBuffer* = set noparent
-per-file IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com
 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/BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com
 per-file include/gui/IGraphicBuffer* = set noparent
-per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 22c2be7..c16e370 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -189,6 +189,10 @@
     // callback is registered by the listener. When set to false,
     // mConnectedProducerListener will not trigger onBufferReleased() callback.
     bool mBufferReleasedCbEnabled;
+    // mBufferAttachedCbEnabled is used to indicate whether onBufferAttached()
+    // callback is registered by the listener. When set to false,
+    // mConnectedProducerListener will not trigger onBufferAttached() callback.
+    bool mBufferAttachedCbEnabled;
 
     // mSlots is an array of buffer slots that must be mirrored on the producer
     // side. This allows buffer ownership to be transferred between the producer
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index b15f501..3dcc6b6 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -25,6 +25,8 @@
 #include <hidl/HybridInterface.h>
 #include <utils/RefBase.h>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
 
 // ProducerListener is the interface through which the BufferQueue notifies the
@@ -55,6 +57,16 @@
     // This is called without any lock held and can be called concurrently by
     // multiple threads.
     virtual void onBufferDetached(int /*slot*/) {} // Asynchronous
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+    // onBufferAttached is called from IGraphicBufferConsumer::attachBuffer to
+    // notify the producer that a buffer is attached.
+    //
+    // This is called without any lock held and can be called concurrently by
+    // multiple threads. This callback is enabled only when needsAttachNotify()
+    // returns {@code true}.
+    virtual void onBufferAttached() {} // Asynchronous
+    virtual bool needsAttachNotify() { return false; }
+#endif
 };
 
 #ifndef NO_BINDER
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 3864699..78fc590 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -10,6 +10,14 @@
 }
 
 flag {
+  name: "bq_consumer_attach_callback"
+  namespace: "core_graphics"
+  description: "Controls IProducerListener to have consumer side attach callback"
+  bug: "353202582"
+  is_fixed_read_only: true
+} # bq_consumer_attach_callback
+
+flag {
   name: "frametimestamps_previousrelease"
   namespace: "core_graphics"
   description: "Controls a fence fixup for timestamp apis"
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index df7739c..be6c7d6 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1257,6 +1257,91 @@
     ASSERT_TRUE(result == WOULD_BLOCK || result == TIMED_OUT || result == INVALID_OPERATION);
 }
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+struct BufferAttachedListener : public BnProducerListener {
+public:
+    BufferAttachedListener(bool enable) : mEnabled(enable), mAttached(0) {}
+    virtual ~BufferAttachedListener() = default;
+
+    virtual void onBufferReleased() {}
+    virtual bool needsReleaseNotify() { return true; }
+    virtual void onBufferAttached() {
+        ++mAttached;
+    }
+    virtual bool needsAttachNotify() { return mEnabled; }
+
+    int getNumAttached() const { return mAttached; }
+private:
+    const bool mEnabled;
+    int mAttached;
+};
+
+TEST_F(BufferQueueTest, TestConsumerAttachProducerListener) {
+    createBufferQueue();
+    sp<MockConsumer> mc1(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc1, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    // Do not enable attach callback.
+    sp<BufferAttachedListener> pl1(new BufferAttachedListener(false));
+    ASSERT_EQ(OK, mProducer->connect(pl1, NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK, mProducer->setDequeueTimeout(0));
+    ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+
+    sp<Fence> fence = Fence::NO_FENCE;
+    sp<GraphicBuffer> buffer = nullptr;
+
+    int slot;
+    status_t result = OK;
+
+    ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1));
+
+    result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
+                                      GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr);
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+
+    // Check # of attach is zero.
+    ASSERT_EQ(0, pl1->getNumAttached());
+
+    // Attach a buffer and check the callback was not called.
+    ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer));
+    ASSERT_EQ(0, pl1->getNumAttached());
+
+    mProducer = nullptr;
+    mConsumer = nullptr;
+    createBufferQueue();
+
+    sp<MockConsumer> mc2(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc2, true));
+    // Enable attach callback.
+    sp<BufferAttachedListener> pl2(new BufferAttachedListener(true));
+    ASSERT_EQ(OK, mProducer->connect(pl2, NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK, mProducer->setDequeueTimeout(0));
+    ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+
+    fence = Fence::NO_FENCE;
+    buffer = nullptr;
+
+    result = OK;
+
+    ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1));
+
+    result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
+                                      GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr);
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+
+    // Check # of attach is zero.
+    ASSERT_EQ(0, pl2->getNumAttached());
+
+    // Attach a buffer and check the callback was called.
+    ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer));
+    ASSERT_EQ(1, pl2->getNumAttached());
+}
+#endif
+
 TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
     createBufferQueue();
     sp<MockConsumer> mc(new MockConsumer);
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index 680b291..a391c81 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -24,9 +24,4 @@
 bpf {
     name: "gpuMem.o",
     srcs: ["gpuMem.c"],
-    btf: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
 }
diff --git a/services/gpuservice/gpuwork/bpfprogs/Android.bp b/services/gpuservice/gpuwork/bpfprogs/Android.bp
index fe45c98..2e444fe 100644
--- a/services/gpuservice/gpuwork/bpfprogs/Android.bp
+++ b/services/gpuservice/gpuwork/bpfprogs/Android.bp
@@ -20,11 +20,7 @@
     name: "gpuWork.o",
     srcs: ["gpuWork.c"],
     cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wformat",
         "-Wthread-safety",
-        "-Wunused",
         "-Wunreachable-code",
     ],
 }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 6051e89..e8153f5 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -304,7 +304,10 @@
     RefreshRateSelector(const RefreshRateSelector&) = delete;
     RefreshRateSelector& operator=(const RefreshRateSelector&) = delete;
 
-    const DisplayModes& displayModes() const { return mDisplayModes; }
+    DisplayModes displayModes() const {
+        std::lock_guard lock(mLock);
+        return mDisplayModes;
+    }
 
     // Returns whether switching modes (refresh rate or resolution) is possible.
     // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only