Merge "libbinder: don't hold global locks for callbacks.." 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 1333599..fa7cb64 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;
@@ -249,9 +258,28 @@
return names;
}
+static std::optional<std::string> getVintfAccessorName(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname, false)) return std::nullopt;
+
+ std::optional<std::string> accessor;
+ forEachManifest([&](const ManifestWithDescription& mwd) {
+ mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+ if (manifestInstance.format() != vintf::HalFormat::AIDL) return true;
+ if (manifestInstance.package() != aname.package) return true;
+ if (manifestInstance.interface() != aname.iface) return true;
+ if (manifestInstance.instance() != aname.instance) return true;
+ accessor = manifestInstance.accessor();
+ return false; // break (libvintf uses opposite convention)
+ });
+ return false; // continue
+ });
+ return accessor;
+}
+
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;
@@ -365,23 +393,52 @@
}
Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
- 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())));
- *outBinder = tryGetService(name, true);
+ *outBinder = tryGetBinder(name, true);
// returns ok regardless of result for legacy reasons
return Status::ok();
}
-Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
- SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+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())));
- *outBinder = tryGetService(name, false);
+ *outService = tryGetService(name, true);
// returns ok regardless of result for legacy reasons
return Status::ok();
}
-sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
- SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_ARG_STRING("name", name.c_str()));
+Status ServiceManager::checkService(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, false);
+ // returns ok regardless of result for legacy reasons
+ return Status::ok();
+}
+
+os::Service ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
+ std::optional<std::string> accessorName;
+#ifndef VENDORSERVICEMANAGER
+ accessorName = getVintfAccessorName(name);
+#endif
+ if (accessorName.has_value()) {
+ auto ctx = mAccess->getCallingContext();
+ if (!mAccess->canFind(ctx, name)) {
+ return os::Service::make<os::Service::Tag::accessor>(nullptr);
+ }
+ return os::Service::make<os::Service::Tag::accessor>(
+ tryGetBinder(*accessorName, startIfNotFound));
+ } else {
+ return os::Service::make<os::Service::Tag::binder>(tryGetBinder(name, startIfNotFound));
+ }
+}
+
+sp<IBinder> ServiceManager::tryGetBinder(const std::string& name, bool startIfNotFound) {
+ SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
+ PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
auto ctx = mAccess->getCallingContext();
@@ -421,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;
@@ -438,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();
@@ -446,8 +505,9 @@
return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services.");
}
- if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
if (binder == nullptr) {
@@ -561,12 +621,16 @@
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();
- if (!mAccess->canFind(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux");
+ // TODO(b/338541373): Implement the notification mechanism for services accessed via
+ // IAccessor.
+ std::optional<std::string> accessorName;
+ if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
// note - we could allow isolated apps to get notifications if we
@@ -609,12 +673,14 @@
}
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();
- if (!mAccess->canFind(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
bool found = false;
@@ -634,12 +700,14 @@
}
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();
- if (!mAccess->canFind(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
*outReturn = false;
@@ -651,7 +719,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();
@@ -662,8 +731,10 @@
outReturn->clear();
+ std::optional<std::string> _accessorName;
for (const std::string& instance : allInstances) {
- if (mAccess->canFind(ctx, interface + "/" + instance)) {
+ if (auto status = canFindService(ctx, interface + "/" + instance, &_accessorName);
+ status.isOk()) {
outReturn->push_back(instance);
}
}
@@ -677,12 +748,14 @@
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();
- if (!mAccess->canFind(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> _accessorName;
+ if (auto status = canFindService(ctx, name, &_accessorName); !status.isOk()) {
+ return status;
}
*outReturn = std::nullopt;
@@ -695,7 +768,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();
@@ -706,8 +780,9 @@
outReturn->clear();
+ std::optional<std::string> _accessorName;
for (const std::string& name : apexUpdatableNames) {
- if (mAccess->canFind(ctx, name)) {
+ if (auto status = canFindService(ctx, name, &_accessorName); status.isOk()) {
outReturn->push_back(name);
}
}
@@ -720,12 +795,14 @@
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();
- if (!mAccess->canFind(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> _accessorName;
+ if (auto status = canFindService(ctx, name, &_accessorName); !status.isOk()) {
+ return status;
}
*outReturn = std::nullopt;
@@ -804,15 +881,17 @@
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.");
}
auto ctx = mAccess->getCallingContext();
- if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
auto serviceIt = mNameToService.find(name);
@@ -966,15 +1045,17 @@
}
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.");
}
auto ctx = mAccess->getCallingContext();
- if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
auto serviceIt = mNameToService.find(name);
@@ -1032,6 +1113,40 @@
return Status::ok();
}
+Status ServiceManager::canAddService(const Access::CallingContext& ctx, const std::string& name,
+ std::optional<std::string>* accessor) {
+ if (!mAccess->canAdd(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied for service.");
+ }
+#ifndef VENDORSERVICEMANAGER
+ *accessor = getVintfAccessorName(name);
+#endif
+ if (accessor->has_value()) {
+ if (!mAccess->canAdd(ctx, accessor->value())) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "SELinux denied for the accessor of the service.");
+ }
+ }
+ return Status::ok();
+}
+
+Status ServiceManager::canFindService(const Access::CallingContext& ctx, const std::string& name,
+ std::optional<std::string>* accessor) {
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied for service.");
+ }
+#ifndef VENDORSERVICEMANAGER
+ *accessor = getVintfAccessorName(name);
+#endif
+ if (accessor->has_value()) {
+ if (!mAccess->canFind(ctx, accessor->value())) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "SELinux denied for the accessor of the service.");
+ }
+ }
+ return Status::ok();
+}
+
Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outReturn) {
SM_PERFETTO_TRACE_FUNC();
if (!mAccess->canList(mAccess->getCallingContext())) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 1536014..c92141b 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -45,7 +45,8 @@
// getService will try to start any services it cannot find
binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override;
- binder::Status checkService(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;
binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override;
@@ -112,7 +113,12 @@
// this updates the iterator to the next location
void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it);
- sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound);
+ os::Service tryGetService(const std::string& name, bool startIfNotFound);
+ sp<IBinder> tryGetBinder(const std::string& name, bool startIfNotFound);
+ binder::Status canAddService(const Access::CallingContext& ctx, const std::string& name,
+ std::optional<std::string>* accessor);
+ binder::Status canFindService(const Access::CallingContext& ctx, const std::string& name,
+ std::optional<std::string>* accessor);
ServiceMap mNameToService;
ServiceCallbackMap mNameToRegistrationCallback;
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index b575053..95f459f 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -38,6 +38,7 @@
using android::binder::Status;
using android::os::BnServiceCallback;
using android::os::IServiceManager;
+using android::os::Service;
using testing::_;
using testing::ElementsAre;
using testing::NiceMock;
@@ -153,18 +154,24 @@
EXPECT_TRUE(sm->addService("foo", serviceA, false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
- sp<IBinder> outA;
- EXPECT_TRUE(sm->getService("foo", &outA).isOk());
- EXPECT_EQ(serviceA, outA);
+ Service outA;
+ 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();
EXPECT_TRUE(sm->addService("foo", serviceB, false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
- sp<IBinder> outB;
- EXPECT_TRUE(sm->getService("foo", &outB).isOk());
- EXPECT_EQ(serviceB, outB);
+ Service outB;
+ 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) {
@@ -186,17 +193,23 @@
EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
- sp<IBinder> out;
- EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(service, out);
+ Service out;
+ 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();
- sp<IBinder> out;
- EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get());
+ Service out;
+ 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) {
@@ -204,31 +217,37 @@
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));
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
- sp<IBinder> out;
+ Service out;
// returns nullptr but has OK status for legacy compatibility
- EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get());
+ 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));
@@ -236,21 +255,27 @@
EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
- sp<IBinder> out;
- EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(service, out.get());
+ Service out;
+ 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
@@ -261,10 +286,13 @@
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
- sp<IBinder> out;
+ Service out;
// returns nullptr but has OK status for legacy compatibility
- EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get());
+ 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/Android.bp b/libs/binder/Android.bp
index cdc7166..de331b7 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -450,8 +450,31 @@
],
}
+soong_config_module_type {
+ name: "libbinder_client_cache_config",
+ module_type: "cc_defaults",
+ config_namespace: "libbinder",
+ bool_variables: ["release_libbinder_client_cache"],
+ properties: [
+ "cflags",
+ ],
+}
+
+libbinder_client_cache_config {
+ name: "libbinder_client_cache_flag",
+ soong_config_variables: {
+ release_libbinder_client_cache: {
+ cflags: ["-DLIBBINDER_CLIENT_CACHE"],
+ conditions_default: {
+ cflags: ["-DNO_LIBBINDER_CLIENT_CACHE"],
+ },
+ },
+ },
+}
+
cc_defaults {
name: "libbinder_kernel_defaults",
+ defaults: ["libbinder_client_cache_flag"],
srcs: [
"BufferedTextOutput.cpp",
"BackendUnifiedServiceManager.cpp",
@@ -771,11 +794,41 @@
"aidl/android/os/IClientCallback.aidl",
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
+ "aidl/android/os/Service.aidl",
"aidl/android/os/ServiceDebugInfo.aidl",
+ ":libbinder_accessor_aidl",
],
path: "aidl",
}
+filegroup {
+ name: "libbinder_accessor_aidl",
+ srcs: [
+ "aidl/android/os/IAccessor.aidl",
+ ],
+ path: "aidl",
+}
+
+// TODO(b/353492849): Make this interface private to libbinder.
+aidl_interface {
+ name: "android.os.accessor",
+ srcs: [":libbinder_accessor_aidl"],
+ unstable: true,
+ backend: {
+ rust: {
+ enabled: true,
+ apex_available: [
+ "com.android.virt",
+ ],
+ },
+ },
+ visibility: [
+ ":__subpackages__",
+ "//system/tools/aidl:__subpackages__",
+ "//packages/modules/Virtualization:__subpackages__",
+ ],
+}
+
aidl_interface {
name: "packagemanager_aidl",
unstable: true,
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index b0d3048..54f687b 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -15,6 +15,9 @@
*/
#include "BackendUnifiedServiceManager.h"
+#include <android/os/IAccessor.h>
+#include <binder/RpcSession.h>
+
#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
#include <android-base/properties.h>
#endif
@@ -22,6 +25,7 @@
namespace android {
using AidlServiceManager = android::os::IServiceManager;
+using IAccessor = android::os::IAccessor;
BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl)
: mTheRealServiceManager(impl) {}
@@ -29,14 +33,67 @@
sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
return mTheRealServiceManager;
}
+
binder::Status BackendUnifiedServiceManager::getService(const ::std::string& name,
sp<IBinder>* _aidl_return) {
- return mTheRealServiceManager->getService(name, _aidl_return);
+ os::Service 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;
+}
+
binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name,
- sp<IBinder>* _aidl_return) {
- return mTheRealServiceManager->checkService(name, _aidl_return);
+ os::Service* _out) {
+ os::Service service;
+ binder::Status status = mTheRealServiceManager->checkService(name, &service);
+ toBinderService(service, _out);
+ return status;
}
+
+void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Service* _out) {
+ switch (in.getTag()) {
+ case os::Service::Tag::binder: {
+ *_out = in;
+ break;
+ }
+ case os::Service::Tag::accessor: {
+ sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>();
+ sp<IAccessor> accessor = interface_cast<IAccessor>(accessorBinder);
+ if (accessor == nullptr) {
+ ALOGE("Service#accessor doesn't have accessor. VM is maybe starting...");
+ *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+ break;
+ }
+ auto request = [=] {
+ os::ParcelFileDescriptor fd;
+ binder::Status ret = accessor->addConnection(&fd);
+ if (ret.isOk()) {
+ return base::unique_fd(fd.release());
+ } else {
+ ALOGE("Failed to connect to RpcSession: %s", ret.toString8().c_str());
+ return base::unique_fd(-1);
+ }
+ };
+ auto session = RpcSession::make();
+ session->setupPreconnectedClient(base::unique_fd{}, request);
+ session->setSessionSpecificRoot(accessorBinder);
+ *_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
+ break;
+ }
+ default: {
+ LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag());
+ }
+ }
+}
+
binder::Status BackendUnifiedServiceManager::addService(const ::std::string& name,
const sp<IBinder>& service,
bool allowIsolated, int32_t dumpPriority) {
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index d72b5bb..f5d7e66 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -27,7 +27,8 @@
sp<os::IServiceManager> getImpl();
binder::Status getService(const ::std::string& name, sp<IBinder>* _aidl_return) override;
- binder::Status checkService(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;
binder::Status listServices(int32_t dumpPriority,
@@ -60,6 +61,7 @@
private:
sp<os::IServiceManager> mTheRealServiceManager;
+ void toBinderService(const os::Service& in, os::Service* _out);
};
sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager();
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 17e522d..8b80aed 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -26,6 +26,7 @@
#include <android-base/properties.h>
#include <android/os/BnServiceCallback.h>
+#include <android/os/IAccessor.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
@@ -57,6 +58,8 @@
using AidlServiceManager = android::os::IServiceManager;
using android::binder::Status;
+using android::os::IAccessor;
+using android::os::Service;
// libbinder's IServiceManager.h can't rely on the values generated by AIDL
// because many places use its headers via include_dirs (meaning, without
@@ -139,7 +142,10 @@
// When implementing ServiceManagerShim, use realGetService instead of
// mUnifiedServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
- return mUnifiedServiceManager->getService(name, _aidl_return);
+ Service service;
+ Status status = mUnifiedServiceManager->getService2(name, &service);
+ *_aidl_return = service.get<Service::Tag::binder>();
+ return status;
}
};
@@ -327,11 +333,11 @@
sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
{
- sp<IBinder> ret;
+ Service ret;
if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
return nullptr;
}
- return ret;
+ return ret.get<Service::Tag::binder>();
}
status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 29ad8ef..d278534 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -24,7 +24,6 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Stability.h>
-#include <cutils/atomic.h>
#include <utils/AndroidThreads.h>
#include <utils/String8.h>
#include <utils/Thread.h>
@@ -392,7 +391,7 @@
}
String8 ProcessState::makeBinderThreadName() {
- int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+ int32_t s = mThreadPoolSeq.fetch_add(1, std::memory_order_release);
pid_t pid = getpid();
std::string_view driverName = mDriverName.c_str();
@@ -434,8 +433,17 @@
}
size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
+ // Need to read `mKernelStartedThreads` before `mThreadPoolStarted` (with
+ // non-relaxed memory ordering) to avoid a race like the following:
+ //
+ // thread A: if (mThreadPoolStarted) { // evaluates false
+ // thread B: mThreadPoolStarted = true;
+ // thread B: mKernelStartedThreads++;
+ // thread A: size_t kernelStarted = mKernelStartedThreads;
+ // thread A: LOG_ALWAYS_FATAL_IF(kernelStarted != 0, ...);
+ size_t kernelStarted = mKernelStartedThreads;
+
if (mThreadPoolStarted) {
- size_t kernelStarted = mKernelStartedThreads;
size_t max = mMaxThreads;
size_t current = mCurrentThreads;
@@ -465,7 +473,6 @@
// must not be initialized or maybe has poll thread setup, we
// currently don't track this in libbinder
- size_t kernelStarted = mKernelStartedThreads;
LOG_ALWAYS_FATAL_IF(kernelStarted != 0, "Expecting 0 kernel started threads but have %zu",
kernelStarted);
return mCurrentThreads;
@@ -582,7 +589,7 @@
#ifdef __ANDROID__
LOG_ALWAYS_FATAL_IF(!opened.ok(),
"Binder driver '%s' could not be opened. Error: %s. Terminating.",
- error.c_str(), driver);
+ driver, error.c_str());
#endif
if (opened.ok()) {
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 16a7f9f..49def82 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -801,6 +801,14 @@
return true;
}
+void RpcSession::setSessionSpecificRoot(const sp<IBinder>& sessionSpecificRoot) {
+ LOG_ALWAYS_FATAL_IF(mSessionSpecificRootObject != nullptr,
+ "Session specific root object already set");
+ LOG_ALWAYS_FATAL_IF(mForServer != nullptr,
+ "Session specific root object cannot be set for a server");
+ mSessionSpecificRootObject = sessionSpecificRoot;
+}
+
sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
std::unique_ptr<RpcTransport> rpcTransport) {
RpcMutexLockGuard _l(mMutex);
diff --git a/libs/binder/aidl/android/os/IAccessor.aidl b/libs/binder/aidl/android/os/IAccessor.aidl
new file mode 100644
index 0000000..a3134a3
--- /dev/null
+++ b/libs/binder/aidl/android/os/IAccessor.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Interface for accessing the RPC server of a service.
+ *
+ * @hide
+ */
+interface IAccessor {
+ /**
+ * Adds a connection to the RPC server of the service managed by the IAccessor.
+ *
+ * This method can be called multiple times to establish multiple distinct
+ * connections to the same RPC server.
+ *
+ * @return A file descriptor connected to the RPC session of the service managed
+ * by IAccessor.
+ */
+ ParcelFileDescriptor addConnection();
+
+ // TODO(b/350941051): Add API for debugging.
+}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 0fb1615..1d1f84f 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -18,6 +18,7 @@
import android.os.IClientCallback;
import android.os.IServiceCallback;
+import android.os.Service;
import android.os.ServiceDebugInfo;
import android.os.ConnectionInfo;
@@ -59,17 +60,31 @@
* exists for legacy purposes.
*
* Returns null if the service does not exist.
+ *
+ * @deprecated TODO(b/355394904): Use getService2 instead.
*/
@UnsupportedAppUsage
@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
* manager. Non-blocking. Returns null if the service does not
* exist.
*/
@UnsupportedAppUsage
- @nullable IBinder checkService(@utf8InCpp String name);
+ Service checkService(@utf8InCpp String name);
/**
* Place a new @a service called @a name into the service
diff --git a/libs/binder/aidl/android/os/Service.aidl b/libs/binder/aidl/android/os/Service.aidl
new file mode 100644
index 0000000..4c52109
--- /dev/null
+++ b/libs/binder/aidl/android/os/Service.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Service is a union of different service types that can be returned
+ * by the internal {@link ServiceManager#getService(name)} API.
+ *
+ * @hide
+ */
+union Service {
+ @nullable IBinder binder;
+ @nullable IBinder accessor;
+}
\ No newline at end of file
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 021bd58..ccc2d2e 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -188,8 +188,8 @@
Vector<handle_entry> mHandleToObject;
bool mForked;
- bool mThreadPoolStarted;
- volatile int32_t mThreadPoolSeq;
+ std::atomic_bool mThreadPoolStarted;
+ std::atomic_int32_t mThreadPoolSeq;
CallRestriction mCallRestriction;
};
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 40102bb..af37bf2 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -220,6 +220,12 @@
// internal only
LIBBINDER_EXPORTED const std::unique_ptr<RpcState>& state() { return mRpcBinderState; }
+ /**
+ * Sets the session-specific root object. This is the object that will be used to attach
+ * the IAccessor binder to the RpcSession when a binder is set up via accessor.
+ */
+ LIBBINDER_EXPORTED void setSessionSpecificRoot(const sp<IBinder>& sessionSpecificRoot);
+
private:
friend sp<RpcSession>;
friend RpcServer;
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 33dfe19..7f70396 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -1333,7 +1333,7 @@
let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
- let u16s = [u16::max_value(), 12_345, 42, 117];
+ let u16s = [u16::MAX, 12_345, 42, 117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1348,7 +1348,7 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::MAX
assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
@@ -1361,9 +1361,9 @@
let vec = Vec::<u16>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+ assert_eq!(vec, [u16::MAX, 12_345, 42, 117]);
- let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+ let i16s = [i16::MAX, i16::MIN, 42, -117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1378,8 +1378,8 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::MAX
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::MIN
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
@@ -1391,9 +1391,9 @@
let vec = Vec::<i16>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+ assert_eq!(vec, [i16::MAX, i16::MIN, 42, -117]);
- let u32s = [u32::max_value(), 12_345, 42, 117];
+ let u32s = [u32::MAX, 12_345, 42, 117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1408,7 +1408,7 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::MAX
assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
@@ -1421,9 +1421,9 @@
let vec = Vec::<u32>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+ assert_eq!(vec, [u32::MAX, 12_345, 42, 117]);
- let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+ let i32s = [i32::MAX, i32::MIN, 42, -117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1438,8 +1438,8 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::MAX
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::MIN
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
@@ -1451,9 +1451,9 @@
let vec = Vec::<i32>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+ assert_eq!(vec, [i32::MAX, i32::MIN, 42, -117]);
- let u64s = [u64::max_value(), 12_345, 42, 117];
+ let u64s = [u64::MAX, 12_345, 42, 117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1469,9 +1469,9 @@
let vec = Vec::<u64>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+ assert_eq!(vec, [u64::MAX, 12_345, 42, 117]);
- let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+ let i64s = [i64::MAX, i64::MIN, 42, -117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1487,9 +1487,9 @@
let vec = Vec::<i64>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+ assert_eq!(vec, [i64::MAX, i64::MIN, 42, -117]);
- let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
+ let f32s = [f32::NAN, f32::INFINITY, 1.23456789, f32::EPSILON];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1509,7 +1509,7 @@
assert!(vec[0].is_nan());
assert_eq!(vec[1..], f32s[1..]);
- let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
+ let f64s = [f64::NAN, f64::INFINITY, 1.234567890123456789, f64::EPSILON];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 2b6c282..a902e96 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -124,7 +124,7 @@
bindings::Transaction_TEST_BYTE => {
assert_eq!(parcel.read::<i8>()?, 0);
assert_eq!(parcel.read::<i8>()?, 1);
- assert_eq!(parcel.read::<i8>()?, i8::max_value());
+ assert_eq!(parcel.read::<i8>()?, i8::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 });
// SAFETY: Just reading an extern constant.
@@ -133,7 +133,7 @@
reply.write(&0i8)?;
reply.write(&1i8)?;
- reply.write(&i8::max_value())?;
+ reply.write(&i8::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?;
// SAFETY: Just reading an extern constant.
@@ -143,14 +143,14 @@
bindings::Transaction_TEST_U16 => {
assert_eq!(parcel.read::<u16>()?, 0);
assert_eq!(parcel.read::<u16>()?, 1);
- assert_eq!(parcel.read::<u16>()?, u16::max_value());
+ assert_eq!(parcel.read::<u16>()?, u16::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
reply.write(&0u16)?;
reply.write(&1u16)?;
- reply.write(&u16::max_value())?;
+ reply.write(&u16::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?;
reply.write(&(None as Option<Vec<u16>>))?;
@@ -158,14 +158,14 @@
bindings::Transaction_TEST_I32 => {
assert_eq!(parcel.read::<i32>()?, 0);
assert_eq!(parcel.read::<i32>()?, 1);
- assert_eq!(parcel.read::<i32>()?, i32::max_value());
+ assert_eq!(parcel.read::<i32>()?, i32::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
reply.write(&0i32)?;
reply.write(&1i32)?;
- reply.write(&i32::max_value())?;
+ reply.write(&i32::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?;
reply.write(&(None as Option<Vec<i32>>))?;
@@ -173,14 +173,14 @@
bindings::Transaction_TEST_I64 => {
assert_eq!(parcel.read::<i64>()?, 0);
assert_eq!(parcel.read::<i64>()?, 1);
- assert_eq!(parcel.read::<i64>()?, i64::max_value());
+ assert_eq!(parcel.read::<i64>()?, i64::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
reply.write(&0i64)?;
reply.write(&1i64)?;
- reply.write(&i64::max_value())?;
+ reply.write(&i64::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?;
reply.write(&(None as Option<Vec<i64>>))?;
@@ -188,14 +188,14 @@
bindings::Transaction_TEST_U64 => {
assert_eq!(parcel.read::<u64>()?, 0);
assert_eq!(parcel.read::<u64>()?, 1);
- assert_eq!(parcel.read::<u64>()?, u64::max_value());
+ assert_eq!(parcel.read::<u64>()?, u64::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
reply.write(&0u64)?;
reply.write(&1u64)?;
- reply.write(&u64::max_value())?;
+ reply.write(&u64::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?;
reply.write(&(None as Option<Vec<u64>>))?;
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 18b178b..be99065 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -123,8 +123,11 @@
// We can't send BpBinder for regular binder over RPC.
return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
}
- android::binder::Status checkService(const std::string&,
- android::sp<android::IBinder>*) override {
+ 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);
+ }
+ android::binder::Status checkService(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/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 62b8433..7c19614 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -111,7 +111,9 @@
} else {
binder = getRandomBinder(&provider);
}
- CHECK(OK == p->writeStrongBinder(binder));
+
+ // may fail if mixing kernel binder and RPC binder
+ (void) p->writeStrongBinder(binder);
},
});
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/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index f4cf11e..a9bd11e 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <set>
+#include <utility>
#include <android-base/file.h>
#include <android-base/parseint.h>
@@ -115,7 +116,7 @@
/* list of extra hal interfaces to dump containing process during native dumps */
// This is filled when dumpstate is called.
-static std::set<const std::string> extra_hal_interfaces_to_dump;
+static std::set<std::string> extra_hal_interfaces_to_dump;
static void read_extra_hals_to_dump_from_property() {
// extra hals to dump are already filled
@@ -129,7 +130,7 @@
if (trimmed_token.length() == 0) {
continue;
}
- extra_hal_interfaces_to_dump.insert(trimmed_token);
+ extra_hal_interfaces_to_dump.insert(std::move(trimmed_token));
}
}
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/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 6fcb3a4..d05ff34 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -326,7 +326,7 @@
* COMPOSER_OVERLAY, the system will try to prioritize the buffer receiving
* an overlay plane & avoid caching it in intermediate composition buffers.
*/
- AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1UL << 32,
+ AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1ULL << 32,
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index abe0d9b..7b3b176 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -718,8 +718,7 @@
const auto externalTexture =
std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
impl::ExternalTexture::Usage::READABLE);
- std::vector<const std::shared_ptr<ExternalTexture>> textures =
- {srcTexture, externalTexture};
+ std::vector<std::shared_ptr<ExternalTexture>> textures = {srcTexture, externalTexture};
// Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
// It doesn't have to be f16, but it can't be the usual 8888.
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index af0bcff..3297fe0 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -262,7 +262,7 @@
hnd = attempt_to_load_updated_driver(cnx);
// If updated driver apk is set but fail to load, abort here.
- LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(),
+ LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace() && !hnd,
"couldn't find an OpenGL ES implementation from %s",
android::GraphicsEnv::getInstance().getDriverPath().c_str());
}
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/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c91ba38..2fd1763 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2624,6 +2624,9 @@
if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
continue;
}
+ if (!touchedWindow.hasTouchingPointers(entry.deviceId)) {
+ continue;
+ }
touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers);
}
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 168e74c..dc13fed 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1340,6 +1340,13 @@
WithFlags(expectedFlags)));
}
+ inline void consumeMotionPointerDown(int32_t pointerIdx,
+ const ::testing::Matcher<MotionEvent>& matcher) {
+ const int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
+ }
+
void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
int32_t expectedFlags = 0) {
const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
@@ -1348,6 +1355,13 @@
WithFlags(expectedFlags)));
}
+ inline void consumeMotionPointerUp(int32_t pointerIdx,
+ const ::testing::Matcher<MotionEvent>& matcher) {
+ const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
+ }
+
void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
int32_t expectedFlags = 0) {
consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDisplayId(expectedDisplayId),
@@ -4771,6 +4785,72 @@
rightWindow->assertNoEvents();
}
+/**
+ * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
+ * down event to the right window. Device B sends a down event to the left window, and then a
+ * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
+ * POINTER_DOWN event should only go to the left window, and not to the right window.
+ * This test attempts to reproduce a crash.
+ */
+TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> leftWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
+ ADISPLAY_ID_DEFAULT);
+ leftWindow->setFrame(Rect(0, 0, 100, 100));
+ leftWindow->setPreventSplitting(true);
+
+ sp<FakeWindowHandle> rightWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
+ ADISPLAY_ID_DEFAULT);
+ rightWindow->setFrame(Rect(100, 0, 200, 100));
+
+ mDispatcher->onWindowInfosChanged(
+ {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
+
+ const DeviceId deviceA = 9;
+ const DeviceId deviceB = 3;
+ // Touch the right window with device A
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
+ .deviceId(deviceA)
+ .build());
+ rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
+ // Touch the left window with device B
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .deviceId(deviceB)
+ .build());
+ leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
+ // Send a second pointer from device B to the right window. It shouldn't go to the right window
+ // because the left window prevents splitting.
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceB)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
+ .build());
+ leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
+
+ // Finish the gesture for both devices
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceB)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
+ .build());
+ leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .deviceId(deviceB)
+ .build());
+ leftWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), WithPointerId(0, 0)));
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
+ .deviceId(deviceA)
+ .build());
+ rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA)));
+}
+
TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index a3e8eaf..76170eb 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -609,10 +609,33 @@
return arg.getRepeatCount() == repeatCount;
}
-MATCHER_P2(WithPointerId, index, id, "MotionEvent with specified pointer ID for pointer index") {
- const auto argPointerId = arg.pointerProperties[index].id;
- *result_listener << "expected pointer with index " << index << " to have ID " << argPointerId;
- return argPointerId == id;
+class WithPointerIdMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithPointerIdMatcher(size_t index, int32_t pointerId)
+ : mIndex(index), mPointerId(pointerId) {}
+
+ bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const {
+ return args.pointerProperties[mIndex].id == mPointerId;
+ }
+
+ bool MatchAndExplain(const MotionEvent& event, std::ostream*) const {
+ return event.getPointerId(mIndex) == mPointerId;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "with pointer[" << mIndex << "] id = " << mPointerId;
+ }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "wrong pointerId"; }
+
+private:
+ const size_t mIndex;
+ const int32_t mPointerId;
+};
+
+inline WithPointerIdMatcher WithPointerId(size_t index, int32_t pointerId) {
+ return WithPointerIdMatcher(index, pointerId);
}
MATCHER_P2(WithCursorPosition, x, y, "InputEvent with specified cursor position") {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
index 6be6735..9c0e072 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
@@ -92,15 +92,15 @@
}
private:
- std::vector<const LayerState> copyLayers(const std::vector<const LayerState*>& layers) {
- std::vector<const LayerState> copiedLayers;
+ std::vector<LayerState> copyLayers(const std::vector<const LayerState*>& layers) {
+ std::vector<LayerState> copiedLayers;
copiedLayers.reserve(layers.size());
std::transform(layers.cbegin(), layers.cend(), std::back_inserter(copiedLayers),
[](const LayerState* layerState) { return *layerState; });
return copiedLayers;
}
- std::vector<const LayerState> mLayers;
+ std::vector<LayerState> mLayers;
// TODO(b/180976743): Tune kMaxDifferingFields
constexpr static int kMaxDifferingFields = 6;
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
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 81fd118..e9204ab 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -339,10 +339,13 @@
ALOGD("Unload builtin Vulkan driver.");
- // Close the opened device
- int err = hal_.dev_->common.close(
- const_cast<struct hw_device_t*>(&hal_.dev_->common));
- ALOG_ASSERT(!err, "hw_device_t::close() failed.");
+ if (hal_.dev_->common.close != nullptr)
+ {
+ // Close the opened device
+ int err = hal_.dev_->common.close(
+ const_cast<struct hw_device_t*>(&hal_.dev_->common));
+ ALOG_ASSERT(!err, "hw_device_t::close() failed.");
+ }
// Close the opened shared library in the hw_module_t
android_unload_sphal_library(hal_.dev_->common.module->dso);