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