[automerger skipped] Enable single hop screenshots for only threaded re am: 7e84455e4c -s ours
am skip reason: Merged-In Ibf038ad6db3e87c84508d3e101ca1eb144836d7c with SHA-1 454f7f2768 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/28875899
Change-Id: Id5131105bb15b031ccae885eaba4a9dc1f325d3f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
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 97e4dc0..8736695 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 099a2bc..82cacca 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -373,6 +373,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
@@ -383,7 +405,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.
@@ -394,9 +416,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
@@ -408,7 +435,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/surface_control_input_receiver.h b/include/android/surface_control_input_receiver.h
index bdc5249..f0503f6 100644
--- a/include/android/surface_control_input_receiver.h
+++ b/include/android/surface_control_input_receiver.h
@@ -59,17 +59,13 @@
AInputEvent *_Nonnull keyEvent)
__INTRODUCED_IN(__ANDROID_API_V__);
-struct AInputReceiverCallbacks;
-
-struct AInputReceiver;
+typedef struct AInputReceiverCallbacks AInputReceiverCallbacks;
/**
* The InputReceiver that holds the reference to the registered input channel. This must be released
* using AInputReceiver_release
- *
- * Available since API level 35.
*/
-typedef struct AInputReceiver AInputReceiver __INTRODUCED_IN(__ANDROID_API_V__);
+typedef struct AInputReceiver AInputReceiver;
/**
* Registers an input receiver for an ASurfaceControl that will receive batched input event. For
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/include/input/OWNERS b/include/input/OWNERS
index c88bfe9..21d208f 100644
--- a/include/input/OWNERS
+++ b/include/input/OWNERS
@@ -1 +1,2 @@
+# Bug component: 136048
include platform/frameworks/base:/INPUT_OWNERS
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..8f3839f 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,
@@ -56,10 +57,9 @@
return mTheRealServiceManager->getInterfaceDescriptor();
}
- IBinder* onAsBinder() override { return IInterface::asBinder(mTheRealServiceManager).get(); }
-
private:
sp<os::IServiceManager> mTheRealServiceManager;
+ void toBinderService(const os::Service& in, os::Service* _out);
};
sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager();
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index c57c9cd..53bd08d 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -143,6 +143,22 @@
return reply.readNullableStrongBinder(out);
}
+status_t IBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ BpBinder* proxy = this->remoteBinder();
+ if (proxy != nullptr) {
+ return proxy->addFrozenStateChangeCallback(callback);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t IBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ BpBinder* proxy = this->remoteBinder();
+ if (proxy != nullptr) {
+ return proxy->removeFrozenStateChangeCallback(callback);
+ }
+ return INVALID_OPERATION;
+}
+
status_t IBinder::getDebugPid(pid_t* out) {
BBinder* local = this->localBinder();
if (local != nullptr) {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 6594aa6..eae844c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -160,11 +160,12 @@
// ---------------------------------------------------------------------------
-sp<BpBinder> BpBinder::create(int32_t handle) {
+sp<BpBinder> BpBinder::create(int32_t handle, std::function<void()>* postTask) {
if constexpr (!kEnableKernelIpc) {
LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
return nullptr;
}
+ LOG_ALWAYS_FATAL_IF(postTask == nullptr, "BAD STATE");
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
@@ -183,7 +184,11 @@
ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies "
"held)",
getuid(), trackedUid, trackedValue);
- if (sLimitCallback) sLimitCallback(trackedUid);
+
+ if (sLimitCallback) {
+ *postTask = [=]() { sLimitCallback(trackedUid); };
+ }
+
sLastLimitCallbackMap[trackedUid] = trackedValue;
}
} else {
@@ -197,7 +202,11 @@
ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
getuid(), trackedUid, trackedValue);
sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
- if (sLimitCallback) sLimitCallback(trackedUid);
+
+ if (sLimitCallback) {
+ *postTask = [=]() { sLimitCallback(trackedUid); };
+ }
+
sLastLimitCallbackMap[trackedUid] = trackedValue & COUNTING_VALUE_MASK;
if (sBinderProxyThrottleCreate) {
ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
@@ -557,6 +566,123 @@
}
}
+status_t BpBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(),
+ "addFrozenStateChangeCallback() is not supported for RPC Binder.");
+ LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
+ LOG_ALWAYS_FATAL_IF(ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0,
+ "addFrozenStateChangeCallback on %s but there are no threads "
+ "(yet?) listening to incoming transactions. See "
+ "ProcessState::startThreadPool "
+ "and ProcessState::setThreadPoolMaxThreadCount. Generally you should "
+ "setup the binder threadpool before other initialization steps.",
+ String8(getInterfaceDescriptor()).c_str());
+ LOG_ALWAYS_FATAL_IF(callback == nullptr,
+ "addFrozenStateChangeCallback(): callback must be non-NULL");
+
+ const sp<FrozenStateChangeCallback> strongCallback = callback.promote();
+ if (strongCallback == nullptr) {
+ return BAD_VALUE;
+ }
+
+ {
+ RpcMutexUniqueLock _l(mLock);
+ if (!mFrozen) {
+ ALOGV("Requesting freeze notification: %p handle %d\n", this, binderHandle());
+ IPCThreadState* self = IPCThreadState::self();
+ status_t status = self->addFrozenStateChangeCallback(binderHandle(), this);
+ if (status != NO_ERROR) {
+ // Avoids logspam if kernel does not support freeze
+ // notification.
+ if (status != INVALID_OPERATION) {
+ ALOGE("IPCThreadState.addFrozenStateChangeCallback "
+ "failed with %s. %p handle %d\n",
+ statusToString(status).c_str(), this, binderHandle());
+ }
+ return status;
+ }
+ mFrozen = std::make_unique<FrozenStateChange>();
+ if (!mFrozen) {
+ std::ignore =
+ IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
+ this);
+ return NO_MEMORY;
+ }
+ }
+ if (mFrozen->initialStateReceived) {
+ strongCallback->onStateChanged(wp<BpBinder>::fromExisting(this),
+ mFrozen->isFrozen
+ ? FrozenStateChangeCallback::State::FROZEN
+ : FrozenStateChangeCallback::State::UNFROZEN);
+ }
+ ssize_t res = mFrozen->callbacks.add(callback);
+ if (res < 0) {
+ return res;
+ }
+ return NO_ERROR;
+ }
+}
+
+status_t BpBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(),
+ "removeFrozenStateChangeCallback() is not supported for RPC Binder.");
+ LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
+
+ RpcMutexUniqueLock _l(mLock);
+
+ const size_t N = mFrozen ? mFrozen->callbacks.size() : 0;
+ for (size_t i = 0; i < N; i++) {
+ if (mFrozen->callbacks.itemAt(i) == callback) {
+ mFrozen->callbacks.removeAt(i);
+ if (mFrozen->callbacks.size() == 0) {
+ ALOGV("Clearing freeze notification: %p handle %d\n", this, binderHandle());
+ status_t status =
+ IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
+ this);
+ if (status != NO_ERROR) {
+ ALOGE("Unexpected error from "
+ "IPCThreadState.removeFrozenStateChangeCallback: %s. "
+ "%p handle %d\n",
+ statusToString(status).c_str(), this, binderHandle());
+ }
+ mFrozen.reset();
+ }
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+void BpBinder::onFrozenStateChanged(bool isFrozen) {
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(), "onFrozenStateChanged is not supported for RPC Binder.");
+ LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
+
+ ALOGV("Sending frozen state change notification for proxy %p handle %d, isFrozen=%s\n", this,
+ binderHandle(), isFrozen ? "true" : "false");
+
+ RpcMutexUniqueLock _l(mLock);
+ if (!mFrozen) {
+ return;
+ }
+ bool stateChanged = !mFrozen->initialStateReceived || mFrozen->isFrozen != isFrozen;
+ if (stateChanged) {
+ mFrozen->isFrozen = isFrozen;
+ mFrozen->initialStateReceived = true;
+ for (size_t i = 0; i < mFrozen->callbacks.size();) {
+ sp<FrozenStateChangeCallback> callback = mFrozen->callbacks.itemAt(i).promote();
+ if (callback != nullptr) {
+ callback->onStateChanged(wp<BpBinder>::fromExisting(this),
+ isFrozen ? FrozenStateChangeCallback::State::FROZEN
+ : FrozenStateChangeCallback::State::UNFROZEN);
+ i++;
+ } else {
+ mFrozen->callbacks.removeItemsAt(i);
+ }
+ }
+ }
+}
+
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
@@ -686,6 +812,10 @@
if (ipc) ipc->clearDeathNotification(binderHandle(), this);
mObituaries = nullptr;
}
+ if (mFrozen != nullptr) {
+ std::ignore = IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), this);
+ mFrozen.reset();
+ }
mLock.unlock();
if (obits != nullptr) {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 984c93d..1d26d85 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -89,26 +89,33 @@
"BR_FROZEN_REPLY",
"BR_ONEWAY_SPAM_SUSPECT",
"BR_TRANSACTION_PENDING_FROZEN",
+ "BR_FROZEN_BINDER",
+ "BR_CLEAR_FREEZE_NOTIFICATION_DONE",
};
-static const char *kCommandStrings[] = {
- "BC_TRANSACTION",
- "BC_REPLY",
- "BC_ACQUIRE_RESULT",
- "BC_FREE_BUFFER",
- "BC_INCREFS",
- "BC_ACQUIRE",
- "BC_RELEASE",
- "BC_DECREFS",
- "BC_INCREFS_DONE",
- "BC_ACQUIRE_DONE",
- "BC_ATTEMPT_ACQUIRE",
- "BC_REGISTER_LOOPER",
- "BC_ENTER_LOOPER",
- "BC_EXIT_LOOPER",
- "BC_REQUEST_DEATH_NOTIFICATION",
- "BC_CLEAR_DEATH_NOTIFICATION",
- "BC_DEAD_BINDER_DONE"
+static const char* kCommandStrings[] = {
+ "BC_TRANSACTION",
+ "BC_REPLY",
+ "BC_ACQUIRE_RESULT",
+ "BC_FREE_BUFFER",
+ "BC_INCREFS",
+ "BC_ACQUIRE",
+ "BC_RELEASE",
+ "BC_DECREFS",
+ "BC_INCREFS_DONE",
+ "BC_ACQUIRE_DONE",
+ "BC_ATTEMPT_ACQUIRE",
+ "BC_REGISTER_LOOPER",
+ "BC_ENTER_LOOPER",
+ "BC_EXIT_LOOPER",
+ "BC_REQUEST_DEATH_NOTIFICATION",
+ "BC_CLEAR_DEATH_NOTIFICATION",
+ "BC_DEAD_BINDER_DONE",
+ "BC_TRANSACTION_SG",
+ "BC_REPLY_SG",
+ "BC_REQUEST_FREEZE_NOTIFICATION",
+ "BC_CLEAR_FREEZE_NOTIFICATION",
+ "BC_FREEZE_NOTIFICATION_DONE",
};
static const int64_t kWorkSourcePropagatedBitIndex = 32;
@@ -203,6 +210,18 @@
out << ": death cookie " << (void*)(uint64_t)c;
} break;
+ case BR_FROZEN_BINDER: {
+ const int32_t c = *cmd++;
+ const int32_t h = *cmd++;
+ const int32_t isFrozen = *cmd++;
+ out << ": freeze cookie " << (void*)(uint64_t)c << " isFrozen: " << isFrozen;
+ } break;
+
+ case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": freeze cookie " << (void*)(uint64_t)c;
+ } break;
+
default:
// no details to show for: BR_OK, BR_DEAD_REPLY,
// BR_TRANSACTION_COMPLETE, BR_FINISHED
@@ -270,11 +289,23 @@
out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")";
} break;
+ case BC_REQUEST_FREEZE_NOTIFICATION:
+ case BC_CLEAR_FREEZE_NOTIFICATION: {
+ const int32_t h = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": handle=" << h << " (freeze cookie " << (void*)(uint64_t)c << ")";
+ } break;
+
case BC_DEAD_BINDER_DONE: {
const int32_t c = *cmd++;
out << ": death cookie " << (void*)(uint64_t)c;
} break;
+ case BC_FREEZE_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": freeze cookie " << (void*)(uint64_t)c;
+ } break;
+
default:
// no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
// BC_EXIT_LOOPER
@@ -953,6 +984,33 @@
return NO_ERROR;
}
+status_t IPCThreadState::addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
+ static bool isSupported =
+ ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
+ if (!isSupported) {
+ return INVALID_OPERATION;
+ }
+ proxy->getWeakRefs()->incWeak(proxy);
+ mOut.writeInt32(BC_REQUEST_FREEZE_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writePointer((uintptr_t)proxy);
+ flushCommands();
+ return NO_ERROR;
+}
+
+status_t IPCThreadState::removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
+ static bool isSupported =
+ ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
+ if (!isSupported) {
+ return INVALID_OPERATION;
+ }
+ mOut.writeInt32(BC_CLEAR_FREEZE_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writePointer((uintptr_t)proxy);
+ flushCommands();
+ return NO_ERROR;
+}
+
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mServingStackPointer(nullptr),
@@ -1487,6 +1545,26 @@
proxy->getWeakRefs()->decWeak(proxy);
} break;
+ case BR_FROZEN_BINDER: {
+ const struct binder_frozen_state_info* data =
+ reinterpret_cast<const struct binder_frozen_state_info*>(
+ mIn.readInplace(sizeof(struct binder_frozen_state_info)));
+ if (data == nullptr) {
+ result = UNKNOWN_ERROR;
+ break;
+ }
+ BpBinder* proxy = (BpBinder*)data->cookie;
+ bool isFrozen = mIn.readInt32() > 0;
+ proxy->getPrivateAccessor().onFrozenStateChanged(data->is_frozen);
+ mOut.writeInt32(BC_FREEZE_NOTIFICATION_DONE);
+ mOut.writePointer(data->cookie);
+ } break;
+
+ case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
+ BpBinder* proxy = (BpBinder*)mIn.readPointer();
+ proxy->getWeakRefs()->decWeak(proxy);
+ } break;
+
case BR_FINISHED:
result = TIMED_OUT;
break;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 17e522d..c55dd9d 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
@@ -76,10 +79,9 @@
IServiceManager::~IServiceManager() {}
// From the old libbinder IServiceManager interface to IServiceManager.
-class ServiceManagerShim : public IServiceManager
-{
+class CppBackendShim : public IServiceManager {
public:
- explicit ServiceManagerShim (const sp<AidlServiceManager>& impl);
+ explicit CppBackendShim(const sp<BackendUnifiedServiceManager>& impl);
sp<IBinder> getService(const String16& name) const override;
sp<IBinder> checkService(const String16& name) const override;
@@ -133,13 +135,16 @@
sp<RegistrationWaiter>* waiter);
// Directly get the service in a way that, for lazy services, requests the service to be started
- // if it is not currently started. This way, calls directly to ServiceManagerShim::getService
+ // if it is not currently started. This way, calls directly to CppBackendShim::getService
// will still have the 5s delay that is expected by a large amount of Android code.
//
- // When implementing ServiceManagerShim, use realGetService instead of
- // mUnifiedServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
+ // When implementing CppBackendShim, use realGetService instead of
+ // mUnifiedServiceManager->getService so that it can be overridden in CppServiceManagerHostShim.
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;
}
};
@@ -149,7 +154,7 @@
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
- gDefaultServiceManager = sp<ServiceManagerShim>::make(getBackendUnifiedServiceManager());
+ gDefaultServiceManager = sp<CppBackendShim>::make(getBackendUnifiedServiceManager());
});
return gDefaultServiceManager;
@@ -247,8 +252,11 @@
}
}
+#endif //__ANDROID_VNDK__
+
void* openDeclaredPassthroughHal(const String16& interface, const String16& instance, int flag) {
-#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) && !defined(__ANDROID_NATIVE_BRIDGE__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VENDOR__) && !defined(__ANDROID_RECOVERY__) && \
+ !defined(__ANDROID_NATIVE_BRIDGE__)
sp<IServiceManager> sm = defaultServiceManager();
String16 name = interface + String16("/") + instance;
if (!sm->isDeclared(name)) {
@@ -268,20 +276,16 @@
#endif
}
-#endif //__ANDROID_VNDK__
-
// ----------------------------------------------------------------------
-ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl) {
- mUnifiedServiceManager = sp<BackendUnifiedServiceManager>::make(impl);
-}
+CppBackendShim::CppBackendShim(const sp<BackendUnifiedServiceManager>& impl)
+ : mUnifiedServiceManager(impl) {}
// This implementation could be simplified and made more efficient by delegating
// to waitForService. However, this changes the threading structure in some
// cases and could potentially break prebuilts. Once we have higher logistical
// complexity, this could be attempted.
-sp<IBinder> ServiceManagerShim::getService(const String16& name) const
-{
+sp<IBinder> CppBackendShim::getService(const String16& name) const {
static bool gSystemBootCompleted = false;
sp<IBinder> svc = checkService(name);
@@ -325,25 +329,22 @@
return nullptr;
}
-sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
-{
- sp<IBinder> ret;
+sp<IBinder> CppBackendShim::checkService(const String16& name) const {
+ 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,
- bool allowIsolated, int dumpsysPriority)
-{
+status_t CppBackendShim::addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated, int dumpsysPriority) {
Status status = mUnifiedServiceManager->addService(String8(name).c_str(), service,
allowIsolated, dumpsysPriority);
return status.exceptionCode();
}
-Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
-{
+Vector<String16> CppBackendShim::listServices(int dumpsysPriority) {
std::vector<std::string> ret;
if (!mUnifiedServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
return {};
@@ -357,8 +358,7 @@
return res;
}
-sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
-{
+sp<IBinder> CppBackendShim::waitForService(const String16& name16) {
class Waiter : public android::os::BnServiceCallback {
Status onRegistration(const std::string& /*name*/,
const sp<IBinder>& binder) override {
@@ -447,7 +447,7 @@
}
}
-bool ServiceManagerShim::isDeclared(const String16& name) {
+bool CppBackendShim::isDeclared(const String16& name) {
bool declared;
if (Status status = mUnifiedServiceManager->isDeclared(String8(name).c_str(), &declared);
!status.isOk()) {
@@ -458,7 +458,7 @@
return declared;
}
-Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) {
+Vector<String16> CppBackendShim::getDeclaredInstances(const String16& interface) {
std::vector<std::string> out;
if (Status status =
mUnifiedServiceManager->getDeclaredInstances(String8(interface).c_str(), &out);
@@ -476,7 +476,7 @@
return res;
}
-std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
+std::optional<String16> CppBackendShim::updatableViaApex(const String16& name) {
std::optional<std::string> declared;
if (Status status = mUnifiedServiceManager->updatableViaApex(String8(name).c_str(), &declared);
!status.isOk()) {
@@ -487,7 +487,7 @@
return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
}
-Vector<String16> ServiceManagerShim::getUpdatableNames(const String16& apexName) {
+Vector<String16> CppBackendShim::getUpdatableNames(const String16& apexName) {
std::vector<std::string> out;
if (Status status = mUnifiedServiceManager->getUpdatableNames(String8(apexName).c_str(), &out);
!status.isOk()) {
@@ -504,7 +504,7 @@
return res;
}
-std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo(
+std::optional<IServiceManager::ConnectionInfo> CppBackendShim::getConnectionInfo(
const String16& name) {
std::optional<os::ConnectionInfo> connectionInfo;
if (Status status =
@@ -519,8 +519,8 @@
: std::nullopt;
}
-status_t ServiceManagerShim::registerForNotifications(const String16& name,
- const sp<AidlRegistrationCallback>& cb) {
+status_t CppBackendShim::registerForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
if (cb == nullptr) {
ALOGE("%s: null cb passed", __FUNCTION__);
return BAD_VALUE;
@@ -539,9 +539,9 @@
return OK;
}
-void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
- ServiceCallbackMap::iterator* it,
- sp<RegistrationWaiter>* waiter) {
+void CppBackendShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter) {
std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second;
for (auto lit = localRegistrationAndWaiters.begin();
lit != localRegistrationAndWaiters.end();) {
@@ -560,8 +560,8 @@
}
}
-status_t ServiceManagerShim::unregisterForNotifications(const String16& name,
- const sp<AidlRegistrationCallback>& cb) {
+status_t CppBackendShim::unregisterForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
if (cb == nullptr) {
ALOGE("%s: null cb passed", __FUNCTION__);
return BAD_VALUE;
@@ -590,7 +590,7 @@
return OK;
}
-std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() {
+std::vector<IServiceManager::ServiceDebugInfo> CppBackendShim::getServiceDebugInfo() {
std::vector<os::ServiceDebugInfo> serviceDebugInfos;
std::vector<IServiceManager::ServiceDebugInfo> ret;
if (Status status = mUnifiedServiceManager->getServiceDebugInfo(&serviceDebugInfos);
@@ -608,21 +608,21 @@
}
#ifndef __ANDROID__
-// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
+// CppBackendShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
// on-device service manager.
-class ServiceManagerHostShim : public ServiceManagerShim {
+class CppServiceManagerHostShim : public CppBackendShim {
public:
- ServiceManagerHostShim(const sp<AidlServiceManager>& impl,
- const RpcDelegateServiceManagerOptions& options)
- : ServiceManagerShim(impl), mOptions(options) {}
- // ServiceManagerShim::getService is based on checkService, so no need to override it.
+ CppServiceManagerHostShim(const sp<AidlServiceManager>& impl,
+ const RpcDelegateServiceManagerOptions& options)
+ : CppBackendShim(sp<BackendUnifiedServiceManager>::make(impl)), mOptions(options) {}
+ // CppBackendShim::getService is based on checkService, so no need to override it.
sp<IBinder> checkService(const String16& name) const override {
return getDeviceService({String8(name).c_str()}, mOptions);
}
protected:
- // Override realGetService for ServiceManagerShim::waitForService.
+ // Override realGetService for CppBackendShim::waitForService.
Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) override {
*_aidl_return = getDeviceService({"-g", name}, mOptions);
return Status::ok();
@@ -643,7 +643,7 @@
ALOGE("getDeviceService(\"manager\") returns non service manager");
return nullptr;
}
- return sp<ServiceManagerHostShim>::make(interface, options);
+ return sp<CppServiceManagerHostShim>::make(interface, options);
}
#endif
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index a42ede2..5e7f151 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>
@@ -57,6 +56,25 @@
// -------------------------------------------------------------------------
+namespace {
+bool readDriverFeatureFile(const char* filename) {
+ int fd = open(filename, O_RDONLY | O_CLOEXEC);
+ char on;
+ if (fd == -1) {
+ ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__, filename, strerror(errno));
+ return false;
+ }
+ if (read(fd, &on, sizeof(on)) == -1) {
+ ALOGE("%s: error reading to %s: %s", __func__, filename, strerror(errno));
+ close(fd);
+ return false;
+ }
+ close(fd);
+ return on == '1';
+}
+
+} // namespace
+
namespace android {
using namespace android::binder::impl;
@@ -311,6 +329,7 @@
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
+ std::function<void()> postTask;
std::unique_lock<std::mutex> _l(mLock);
@@ -358,7 +377,7 @@
return nullptr;
}
- sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
+ sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle, &postTask);
e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
@@ -371,6 +390,10 @@
}
}
+ _l.unlock();
+
+ if (postTask) postTask();
+
return result;
}
@@ -387,7 +410,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();
@@ -429,8 +452,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;
@@ -460,7 +492,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;
@@ -472,27 +503,20 @@
#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
- static const char* const names[] = {
- [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
- DRIVER_FEATURES_PATH "oneway_spam_detection",
- [static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
- DRIVER_FEATURES_PATH "extended_error",
- };
- int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
- char on;
- if (fd == -1) {
- ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
- names[static_cast<int>(feature)], strerror(errno));
- return false;
+ // Use static variable to cache the results.
+ if (feature == DriverFeature::ONEWAY_SPAM_DETECTION) {
+ static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "oneway_spam_detection");
+ return enabled;
}
- if (read(fd, &on, sizeof(on)) == -1) {
- ALOGE("%s: error reading to %s: %s", __func__,
- names[static_cast<int>(feature)], strerror(errno));
- close(fd);
- return false;
+ if (feature == DriverFeature::EXTENDED_ERROR) {
+ static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "extended_error");
+ return enabled;
}
- close(fd);
- return on == '1';
+ if (feature == DriverFeature::FREEZE_NOTIFICATION) {
+ static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "freeze_notification");
+ return enabled;
+ }
+ return false;
}
status_t ProcessState::enableOnewaySpamDetection(bool enable) {
@@ -577,7 +601,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/binder_module.h b/libs/binder/binder_module.h
index b3a2d9e..65cdcd7 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -32,4 +32,34 @@
#include <linux/android/binder.h>
#include <sys/ioctl.h>
+struct binder_frozen_state_info {
+ binder_uintptr_t cookie;
+ __u32 is_frozen;
+};
+
+#ifndef BR_FROZEN_BINDER
+// Temporary definition of BR_FROZEN_BINDER until UAPI binder.h includes it.
+#define BR_FROZEN_BINDER _IOR('r', 21, struct binder_frozen_state_info)
+#endif // BR_FROZEN_BINDER
+
+#ifndef BR_CLEAR_FREEZE_NOTIFICATION_DONE
+// Temporary definition of BR_CLEAR_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it.
+#define BR_CLEAR_FREEZE_NOTIFICATION_DONE _IOR('r', 22, binder_uintptr_t)
+#endif // BR_CLEAR_FREEZE_NOTIFICATION_DONE
+
+#ifndef BC_REQUEST_FREEZE_NOTIFICATION
+// Temporary definition of BC_REQUEST_FREEZE_NOTIFICATION until UAPI binder.h includes it.
+#define BC_REQUEST_FREEZE_NOTIFICATION _IOW('c', 19, struct binder_handle_cookie)
+#endif // BC_REQUEST_FREEZE_NOTIFICATION
+
+#ifndef BC_CLEAR_FREEZE_NOTIFICATION
+// Temporary definition of BC_CLEAR_FREEZE_NOTIFICATION until UAPI binder.h includes it.
+#define BC_CLEAR_FREEZE_NOTIFICATION _IOW('c', 20, struct binder_handle_cookie)
+#endif // BC_CLEAR_FREEZE_NOTIFICATION
+
+#ifndef BC_FREEZE_NOTIFICATION_DONE
+// Temporary definition of BC_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it.
+#define BC_FREEZE_NOTIFICATION_DONE _IOW('c', 21, binder_uintptr_t)
+#endif // BC_FREEZE_NOTIFICATION_DONE
+
#endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index d7f74c4..7518044 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -29,6 +29,7 @@
// ---------------------------------------------------------------------------
namespace android {
+class IPCThreadState;
class RpcSession;
class RpcState;
namespace internal {
@@ -66,6 +67,12 @@
void* cookie = nullptr, uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
+ [[nodiscard]] status_t addFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& recipient);
+
+ [[nodiscard]] status_t removeFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& recipient);
+
LIBBINDER_EXPORTED virtual void* attachObject(const void* objectID, void* object,
void* cleanupCookie,
object_cleanup_func func) final;
@@ -75,7 +82,6 @@
LIBBINDER_EXPORTED sp<IBinder> lookupOrCreateWeak(const void* objectID,
IBinder::object_make_func make,
const void* makeArgs);
-
LIBBINDER_EXPORTED virtual BpBinder* remoteBinder();
LIBBINDER_EXPORTED void sendObituary();
@@ -132,9 +138,14 @@
friend class ::android::ProcessState;
friend class ::android::RpcSession;
friend class ::android::RpcState;
- explicit PrivateAccessor(const BpBinder* binder) : mBinder(binder) {}
+ friend class ::android::IPCThreadState;
+ explicit PrivateAccessor(const BpBinder* binder)
+ : mBinder(binder), mMutableBinder(nullptr) {}
+ explicit PrivateAccessor(BpBinder* binder) : mBinder(binder), mMutableBinder(binder) {}
- static sp<BpBinder> create(int32_t handle) { return BpBinder::create(handle); }
+ static sp<BpBinder> create(int32_t handle, std::function<void()>* postTask) {
+ return BpBinder::create(handle, postTask);
+ }
static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address) {
return BpBinder::create(session, address);
}
@@ -146,17 +157,22 @@
uint64_t rpcAddress() const { return mBinder->rpcAddress(); }
const sp<RpcSession>& rpcSession() const { return mBinder->rpcSession(); }
+ void onFrozenStateChanged(bool isFrozen) { mMutableBinder->onFrozenStateChanged(isFrozen); }
const BpBinder* mBinder;
+ BpBinder* mMutableBinder;
};
+
LIBBINDER_EXPORTED const PrivateAccessor getPrivateAccessor() const {
return PrivateAccessor(this);
}
+ PrivateAccessor getPrivateAccessor() { return PrivateAccessor(this); }
+
private:
friend PrivateAccessor;
friend class sp<BpBinder>;
- static sp<BpBinder> create(int32_t handle);
+ static sp<BpBinder> create(int32_t handle, std::function<void()>* postTask);
static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address);
struct BinderHandle {
@@ -192,6 +208,14 @@
uint32_t flags;
};
+ void onFrozenStateChanged(bool isFrozen);
+
+ struct FrozenStateChange {
+ bool isFrozen = false;
+ Vector<wp<FrozenStateChangeCallback>> callbacks;
+ bool initialStateReceived = false;
+ };
+
void reportOneDeath(const Obituary& obit);
bool isDescriptorCached() const;
@@ -199,6 +223,7 @@
volatile int32_t mAlive;
volatile int32_t mObitsSent;
Vector<Obituary>* mObituaries;
+ std::unique_ptr<FrozenStateChange> mFrozen;
ObjectManager mObjects;
mutable String16 mDescriptorCache;
int32_t mTrackedUid;
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 4eb1c08..1ed7c91 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -202,9 +202,18 @@
virtual void binderDied(const wp<IBinder>& who) = 0;
};
- #if defined(__clang__)
- #pragma clang diagnostic pop
- #endif
+ class FrozenStateChangeCallback : public virtual RefBase {
+ public:
+ enum class State {
+ FROZEN,
+ UNFROZEN,
+ };
+ virtual void onStateChanged(const wp<IBinder>& who, State state) = 0;
+ };
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
/**
* Register the @a recipient for a notification if this binder
@@ -253,6 +262,48 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr) = 0;
+ /**
+ * addFrozenStateChangeCallback provides a callback mechanism to notify
+ * about process frozen/unfrozen events. Upon registration and any
+ * subsequent state changes, the callback is invoked with the latest process
+ * frozen state.
+ *
+ * If the listener process (the one using this API) is itself frozen, state
+ * change events might be combined into a single one with the latest state.
+ * (meaning 'frozen, unfrozen' might just be 'unfrozen'). This single event
+ * would then be delivered when the listener process becomes unfrozen.
+ * Similarly, if an event happens before the previous event is consumed,
+ * they might be combined. This means the callback might not be called for
+ * every single state change, so don't rely on this API to count how many
+ * times the state has changed.
+ *
+ * @note When all references to the binder are dropped, the callback is
+ * automatically removed. So, you must hold onto a binder in order to
+ * receive notifications about it.
+ *
+ * @note You will only receive freeze notifications for remote binders, as
+ * local binders by definition can't be frozen without you being frozen as
+ * well. Trying to use this function on a local binder will result in an
+ * INVALID_OPERATION code being returned and nothing happening.
+ *
+ * @note This binder always holds a weak reference to the callback.
+ *
+ * @note You will only receive a weak reference to the binder object. You
+ * should not try to promote this to a strong reference. (Nor should you
+ * need to, as there is nothing useful you can directly do with it now that
+ * it has passed on.)
+ */
+ [[nodiscard]] status_t addFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& callback);
+
+ /**
+ * Remove a previously registered freeze callback.
+ * The @a callback will no longer be called if this object
+ * changes its frozen state.
+ */
+ [[nodiscard]] status_t removeFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& callback);
+
virtual bool checkSubclass(const void* subclassID) const;
typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 09ab442..9ef4e69 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -174,6 +174,8 @@
LIBBINDER_EXPORTED static void expungeHandle(int32_t handle, IBinder* binder);
LIBBINDER_EXPORTED status_t requestDeathNotification(int32_t handle, BpBinder* proxy);
LIBBINDER_EXPORTED status_t clearDeathNotification(int32_t handle, BpBinder* proxy);
+ [[nodiscard]] status_t addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy);
+ [[nodiscard]] status_t removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy);
LIBBINDER_EXPORTED static void shutdown();
@@ -210,13 +212,14 @@
IPCThreadState();
~IPCThreadState();
- status_t sendReply(const Parcel& reply, uint32_t flags);
- status_t waitForResponse(Parcel* reply, status_t* acquireResult = nullptr);
- status_t talkWithDriver(bool doReceive = true);
- status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code,
- const Parcel& data, status_t* statusBuffer);
- status_t getAndExecuteCommand();
- status_t executeCommand(int32_t command);
+ [[nodiscard]] status_t sendReply(const Parcel& reply, uint32_t flags);
+ [[nodiscard]] status_t waitForResponse(Parcel* reply, status_t* acquireResult = nullptr);
+ [[nodiscard]] status_t talkWithDriver(bool doReceive = true);
+ [[nodiscard]] status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle,
+ uint32_t code, const Parcel& data,
+ status_t* statusBuffer);
+ [[nodiscard]] status_t getAndExecuteCommand();
+ [[nodiscard]] status_t executeCommand(int32_t command);
void processPendingDerefs();
void processPostWriteDerefs();
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 021bd58..21bfd42 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -133,6 +133,7 @@
enum class DriverFeature {
ONEWAY_SPAM_DETECTION,
EXTENDED_ERROR,
+ FREEZE_NOTIFICATION,
};
// Determine whether a feature is supported by the binder driver.
LIBBINDER_EXPORTED static bool isDriverFeatureEnabled(const DriverFeature feature);
@@ -188,8 +189,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/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 26c228d..4e02ace 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -255,6 +255,9 @@
"include_cpp/android/*.h",
],
license: "NOTICE",
+ // These are intentionally not C. It's a mistake that they're in the NDK.
+ // See the bug above.
+ skip_verification: true,
}
ndk_library {
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index 68528e1..6aff994 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -47,8 +47,11 @@
* be called once before startThreadPool. The number of threads can never decrease.
*
* This count refers to the number of threads that will be created lazily by the kernel, in
- * addition to the threads created by ABinderProcess_startThreadPool or
- * ABinderProcess_joinThreadPool.
+ * addition to the single threads created by ABinderProcess_startThreadPool (+1) or
+ * ABinderProcess_joinThreadPool (+1). Note: ABinderProcess_startThreadPool starts a thread
+ * itself, but it also enables up to the number of threads passed to this function to start.
+ * This function does not start any threads itself; it only configures
+ * ABinderProcess_startThreadPool.
*
* Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
* function should be responsible for configuring the threadpool for the entire application.
@@ -63,8 +66,8 @@
bool ABinderProcess_isThreadPoolStarted(void);
/**
* This adds the current thread to the threadpool. This thread will be in addition to the thread
- * started by ABinderProcess_startThreadPool and the lazy kernel-started threads specified by
- * ABinderProcess_setThreadPoolMaxThreadCount.
+ * configured with ABinderProcess_setThreadPoolMaxThreadCount and started with
+ * ABinderProcess_startThreadPool.
*
* Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
* function should be responsible for configuring the threadpool for the entire application.
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..21c32ac 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -42,6 +42,9 @@
defaults: ["binder_test_defaults"],
header_libs: ["libbinder_headers"],
srcs: ["binderDriverInterfaceTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ ],
test_suites: [
"device-tests",
"vts",
@@ -127,6 +130,7 @@
"libbase",
"libbinder",
"liblog",
+ "libprocessgroup",
"libutils",
],
static_libs: [
@@ -235,6 +239,16 @@
"binder_test_defaults",
],
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
static_libs: [
"libbinder_test_utils",
"libbinder_tls_static",
@@ -267,7 +281,6 @@
defaults: [
"binderRpcTest_common_defaults",
],
- compile_multilib: "first",
srcs: [
"binderRpcTest.cpp",
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 7be4f21..af82860 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -20,12 +20,15 @@
#include <stdlib.h>
#include <binder/IBinder.h>
+#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <linux/android/binder.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include "../binder_module.h"
+
#define BINDER_DEV_NAME "/dev/binder"
testing::Environment* binder_env;
@@ -365,6 +368,251 @@
binderTestReadEmpty();
}
+TEST_F(BinderDriverInterfaceTest, RequestFrozenNotification) {
+ if (!android::ProcessState::isDriverFeatureEnabled(
+ android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
+ return;
+ }
+ binder_uintptr_t cookie = 1234;
+ struct {
+ uint32_t cmd0;
+ uint32_t arg0;
+ uint32_t cmd1;
+ struct binder_handle_cookie arg1;
+ } __attribute__((packed)) bc1 = {
+ .cmd0 = BC_INCREFS,
+ .arg0 = 0,
+ .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
+ .arg1 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ };
+ struct {
+ uint32_t cmd0;
+ // Expecting a BR_FROZEN_BINDER since BC_REQUEST_FREEZE_NOTIFICATION
+ // above should lead to an immediate notification of the current state.
+ uint32_t cmd1;
+ struct binder_frozen_state_info arg1;
+ uint32_t pad[16];
+ } __attribute__((packed)) br1;
+ struct {
+ uint32_t cmd2;
+ binder_uintptr_t arg2;
+ uint32_t cmd3;
+ struct binder_handle_cookie arg3;
+ uint32_t cmd4;
+ uint32_t arg4;
+ } __attribute__((packed)) bc2 = {
+ // Tell kernel that userspace has done handling BR_FROZEN_BINDER.
+ .cmd2 = BC_FREEZE_NOTIFICATION_DONE,
+ .arg2 = cookie,
+ .cmd3 = BC_CLEAR_FREEZE_NOTIFICATION,
+ .arg3 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ .cmd4 = BC_DECREFS,
+ .arg4 = 0,
+ };
+ struct {
+ uint32_t cmd2;
+ uint32_t cmd3;
+ binder_uintptr_t arg3;
+ uint32_t pad[16];
+ } __attribute__((packed)) br2;
+
+ struct binder_write_read bwr1 = binder_write_read();
+ bwr1.write_buffer = (uintptr_t)&bc1;
+ bwr1.write_size = sizeof(bc1);
+ bwr1.read_buffer = (uintptr_t)&br1;
+ bwr1.read_size = sizeof(br1);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr1);
+ EXPECT_EQ(sizeof(bc1), bwr1.write_consumed);
+ EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed);
+ EXPECT_EQ(BR_NOOP, br1.cmd0);
+ ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1);
+ EXPECT_FALSE(br1.arg1.is_frozen);
+
+ struct binder_write_read bwr2 = binder_write_read();
+ bwr2.write_buffer = (uintptr_t)&bc2;
+ bwr2.write_size = sizeof(bc2);
+ bwr2.read_buffer = (uintptr_t)&br2;
+ bwr2.read_size = sizeof(br2);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr2);
+ EXPECT_EQ(sizeof(bc2), bwr2.write_consumed);
+ EXPECT_EQ(sizeof(br2) - sizeof(br2.pad), bwr2.read_consumed);
+ EXPECT_EQ(BR_NOOP, br2.cmd2);
+ EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br2.cmd3);
+ EXPECT_EQ(cookie, br2.arg3);
+
+ binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, OverwritePendingFrozenNotification) {
+ if (!android::ProcessState::isDriverFeatureEnabled(
+ android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
+ return;
+ }
+ binder_uintptr_t cookie = 1234;
+ struct {
+ uint32_t cmd0;
+ uint32_t arg0;
+ uint32_t cmd1;
+ struct binder_handle_cookie arg1;
+ uint32_t cmd2;
+ struct binder_handle_cookie arg2;
+ uint32_t cmd3;
+ uint32_t arg3;
+ } __attribute__((packed)) bc = {
+ .cmd0 = BC_INCREFS,
+ .arg0 = 0,
+ .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
+ // This BC_REQUEST_FREEZE_NOTIFICATION should lead to a pending
+ // frozen notification inserted into the queue.
+ .arg1 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ // Send BC_CLEAR_FREEZE_NOTIFICATION before the above frozen
+ // notification has a chance of being sent. The notification should
+ // be overwritten. Userspace is expected to only receive
+ // BR_CLEAR_FREEZE_NOTIFICATION_DONE.
+ .cmd2 = BC_CLEAR_FREEZE_NOTIFICATION,
+ .arg2 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ .cmd3 = BC_DECREFS,
+ .arg3 = 0,
+ };
+ struct {
+ uint32_t cmd0;
+ uint32_t cmd1;
+ binder_uintptr_t arg1;
+ uint32_t pad[16];
+ } __attribute__((packed)) br;
+ struct binder_write_read bwr = binder_write_read();
+
+ bwr.write_buffer = (uintptr_t)&bc;
+ bwr.write_size = sizeof(bc);
+ bwr.read_buffer = (uintptr_t)&br;
+ bwr.read_size = sizeof(br);
+
+ binderTestIoctl(BINDER_WRITE_READ, &bwr);
+ EXPECT_EQ(sizeof(bc), bwr.write_consumed);
+ EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed);
+ EXPECT_EQ(BR_NOOP, br.cmd0);
+ EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br.cmd1);
+ EXPECT_EQ(cookie, br.arg1);
+ binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, ResendFrozenNotification) {
+ if (!android::ProcessState::isDriverFeatureEnabled(
+ android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
+ return;
+ }
+ binder_uintptr_t cookie = 1234;
+ struct {
+ uint32_t cmd0;
+ uint32_t arg0;
+ uint32_t cmd1;
+ struct binder_handle_cookie arg1;
+ } __attribute__((packed)) bc1 = {
+ .cmd0 = BC_INCREFS,
+ .arg0 = 0,
+ .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
+ .arg1 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ };
+ struct {
+ uint32_t cmd0;
+ uint32_t cmd1;
+ struct binder_frozen_state_info arg1;
+ uint32_t pad[16];
+ } __attribute__((packed)) br1;
+ struct {
+ uint32_t cmd2;
+ struct binder_handle_cookie arg2;
+ } __attribute__((packed)) bc2 = {
+ // Clear the notification before acknowledging the in-flight
+ // BR_FROZEN_BINDER. Kernel should hold off sending
+ // BR_CLEAR_FREEZE_NOTIFICATION_DONE until the acknowledgement
+ // reaches kernel.
+ .cmd2 = BC_CLEAR_FREEZE_NOTIFICATION,
+ .arg2 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ };
+ struct {
+ uint32_t pad[16];
+ } __attribute__((packed)) br2;
+ struct {
+ uint32_t cmd3;
+ binder_uintptr_t arg3;
+ uint32_t cmd4;
+ uint32_t arg4;
+ } __attribute__((packed)) bc3 = {
+ // Send the acknowledgement. Now the kernel should send out
+ // BR_CLEAR_FREEZE_NOTIFICATION_DONE.
+ .cmd3 = BC_FREEZE_NOTIFICATION_DONE,
+ .arg3 = cookie,
+ .cmd4 = BC_DECREFS,
+ .arg4 = 0,
+ };
+ struct {
+ uint32_t cmd2;
+ uint32_t cmd3;
+ binder_uintptr_t arg3;
+ uint32_t pad[16];
+ } __attribute__((packed)) br3;
+
+ struct binder_write_read bwr1 = binder_write_read();
+ bwr1.write_buffer = (uintptr_t)&bc1;
+ bwr1.write_size = sizeof(bc1);
+ bwr1.read_buffer = (uintptr_t)&br1;
+ bwr1.read_size = sizeof(br1);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr1);
+ EXPECT_EQ(sizeof(bc1), bwr1.write_consumed);
+ EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed);
+ EXPECT_EQ(BR_NOOP, br1.cmd0);
+ ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1);
+ EXPECT_FALSE(br1.arg1.is_frozen);
+
+ struct binder_write_read bwr2 = binder_write_read();
+ bwr2.write_buffer = (uintptr_t)&bc2;
+ bwr2.write_size = sizeof(bc2);
+ bwr2.read_buffer = (uintptr_t)&br2;
+ bwr2.read_size = sizeof(br2);
+ binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr2, EAGAIN);
+ binderTestReadEmpty();
+
+ struct binder_write_read bwr3 = binder_write_read();
+ bwr3.write_buffer = (uintptr_t)&bc3;
+ bwr3.write_size = sizeof(bc3);
+ bwr3.read_buffer = (uintptr_t)&br3;
+ bwr3.read_size = sizeof(br3);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr3);
+ EXPECT_EQ(sizeof(bc3), bwr3.write_consumed);
+ EXPECT_EQ(sizeof(br3) - sizeof(br3.pad), bwr3.read_consumed);
+ EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br3.cmd3);
+ EXPECT_EQ(cookie, br3.arg3);
+ binderTestReadEmpty();
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 9b1ba01..bcab6de 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -27,6 +27,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/result-gmock.h>
#include <binder/Binder.h>
@@ -39,6 +40,8 @@
#include <binder/RpcSession.h>
#include <binder/Status.h>
#include <binder/unique_fd.h>
+#include <input/BlockingQueue.h>
+#include <processgroup/processgroup.h>
#include <utils/Flattenable.h>
#include <linux/sched.h>
@@ -57,6 +60,7 @@
using android::base::testing::HasValue;
using android::binder::Status;
using android::binder::unique_fd;
+using std::chrono_literals::operator""ms;
using testing::ExplainMatchResult;
using testing::Matcher;
using testing::Not;
@@ -115,6 +119,8 @@
BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_GETUID,
+ BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE,
+ BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS,
BINDER_LIB_TEST_ECHO_VECTOR,
BINDER_LIB_TEST_GET_NON_BLOCKING_FD,
BINDER_LIB_TEST_REJECT_OBJECTS,
@@ -247,6 +253,43 @@
sp<IBinder> m_server;
};
+class TestFrozenStateChangeCallback : public IBinder::FrozenStateChangeCallback {
+public:
+ BlockingQueue<std::pair<const wp<IBinder>, State>> events;
+
+ virtual void onStateChanged(const wp<IBinder>& who, State state) {
+ events.push(std::make_pair(who, state));
+ }
+
+ void ensureFrozenEventReceived() {
+ auto event = events.popWithTimeout(500ms);
+ ASSERT_TRUE(event.has_value());
+ EXPECT_EQ(State::FROZEN, event->second); // isFrozen should be true
+ EXPECT_EQ(0u, events.size());
+ }
+
+ void ensureUnfrozenEventReceived() {
+ auto event = events.popWithTimeout(500ms);
+ ASSERT_TRUE(event.has_value());
+ EXPECT_EQ(State::UNFROZEN, event->second); // isFrozen should be false
+ EXPECT_EQ(0u, events.size());
+ }
+
+ std::vector<bool> getAllAndClear() {
+ std::vector<bool> results;
+ while (true) {
+ auto event = events.popWithTimeout(0ms);
+ if (!event.has_value()) {
+ break;
+ }
+ results.push_back(event->second == State::FROZEN);
+ }
+ return results;
+ }
+
+ sp<IBinder> binder;
+};
+
class BinderLibTest : public ::testing::Test {
public:
virtual void SetUp() {
@@ -291,6 +334,51 @@
EXPECT_EQ(1, ret);
}
+ bool checkFreezeSupport() {
+ std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
+ // Pass test on devices where the cgroup v2 freezer is not supported
+ if (freezer_file.fail()) {
+ return false;
+ }
+ return IPCThreadState::self()->freeze(getpid(), false, 0) == NO_ERROR;
+ }
+
+ bool checkFreezeAndNotificationSupport() {
+ if (!checkFreezeSupport()) {
+ return false;
+ }
+ return ProcessState::isDriverFeatureEnabled(
+ ProcessState::DriverFeature::FREEZE_NOTIFICATION);
+ }
+
+ bool getBinderPid(int32_t* pid, sp<IBinder> server) {
+ Parcel data, replypid;
+ if (server->transact(BINDER_LIB_TEST_GETPID, data, &replypid) != NO_ERROR) {
+ ALOGE("BINDER_LIB_TEST_GETPID failed");
+ return false;
+ }
+ *pid = replypid.readInt32();
+ if (*pid <= 0) {
+ ALOGE("pid should be greater than zero");
+ return false;
+ }
+ return true;
+ }
+
+ void freezeProcess(int32_t pid) {
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, true, 1000));
+ }
+
+ void unfreezeProcess(int32_t pid) {
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0));
+ }
+
+ void removeCallbackAndValidateNoEvent(sp<IBinder> binder,
+ sp<TestFrozenStateChangeCallback> callback) {
+ EXPECT_THAT(binder->removeFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ EXPECT_EQ(0u, callback->events.size());
+ }
+
sp<IBinder> m_server;
};
@@ -516,29 +604,18 @@
}
TEST_F(BinderLibTest, Freeze) {
- Parcel data, reply, replypid;
- std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
-
- // Pass test on devices where the cgroup v2 freezer is not supported
- if (freezer_file.fail()) {
- GTEST_SKIP();
+ if (!checkFreezeSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support proceess freezing";
return;
}
-
+ Parcel data, reply, replypid;
EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR));
int32_t pid = replypid.readInt32();
for (int i = 0; i < 10; i++) {
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
}
- // Pass test on devices where BINDER_FREEZE ioctl is not supported
- int ret = IPCThreadState::self()->freeze(pid, false, 0);
- if (ret == -EINVAL) {
- GTEST_SKIP();
- return;
- }
- EXPECT_EQ(NO_ERROR, ret);
-
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0));
EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
// b/268232063 - succeeds ~0.08% of the time
@@ -835,6 +912,199 @@
EXPECT_THAT(callback->getResult(), StatusEq(NO_ERROR));
}
+TEST_F(BinderLibTest, ReturnErrorIfKernelDoesNotSupportFreezeNotification) {
+ if (ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ ASSERT_EQ(nullptr, binder->localBinder());
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(INVALID_OPERATION));
+}
+
+TEST_F(BinderLibTest, FrozenStateChangeNotificatiion) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback->ensureUnfrozenEventReceived();
+ // Check that the process hasn't died otherwise there's a risk of freezing
+ // the wrong process.
+ EXPECT_EQ(OK, binder->pingBinder());
+ freezeProcess(pid);
+ callback->ensureFrozenEventReceived();
+ unfreezeProcess(pid);
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+}
+
+TEST_F(BinderLibTest, AddFrozenCallbackWhenFrozen) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ // Check that the process hasn't died otherwise there's a risk of freezing
+ // the wrong process.
+ EXPECT_EQ(OK, binder->pingBinder());
+ freezeProcess(pid);
+ // Add the callback while the target process is frozen.
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ callback->ensureFrozenEventReceived();
+ unfreezeProcess(pid);
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+
+ // Check that the process hasn't died otherwise there's a risk of freezing
+ // the wrong process.
+ EXPECT_EQ(OK, binder->pingBinder());
+ freezeProcess(pid);
+ unfreezeProcess(pid);
+ // Make sure no callback happens since the listener has been removed.
+ EXPECT_EQ(0u, callback->events.size());
+}
+
+TEST_F(BinderLibTest, NoFrozenNotificationAfterCallbackRemoval) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+
+ // Make sure no callback happens after the listener is removed.
+ freezeProcess(pid);
+ unfreezeProcess(pid);
+ EXPECT_EQ(0u, callback->events.size());
+}
+
+TEST_F(BinderLibTest, MultipleFrozenStateChangeCallbacks) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback1 = sp<TestFrozenStateChangeCallback>::make();
+ sp<TestFrozenStateChangeCallback> callback2 = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback1), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback1->ensureUnfrozenEventReceived();
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback2), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback2->ensureUnfrozenEventReceived();
+
+ freezeProcess(pid);
+ callback1->ensureFrozenEventReceived();
+ callback2->ensureFrozenEventReceived();
+
+ removeCallbackAndValidateNoEvent(binder, callback1);
+ unfreezeProcess(pid);
+ EXPECT_EQ(0u, callback1->events.size());
+ callback2->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback2);
+
+ freezeProcess(pid);
+ EXPECT_EQ(0u, callback2->events.size());
+}
+
+TEST_F(BinderLibTest, RemoveThenAddFrozenStateChangeCallbacks) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ callback->ensureUnfrozenEventReceived();
+}
+
+TEST_F(BinderLibTest, CoalesceFreezeCallbacksWhenListenerIsFrozen) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<IBinder> binder = addServer();
+ sp<IBinder> listener = addServer();
+ ASSERT_NE(nullptr, binder);
+ ASSERT_NE(nullptr, listener);
+ int32_t pid, listenerPid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+ ASSERT_TRUE(getBinderPid(&listenerPid, listener));
+
+ // Ask the listener process to register for state change callbacks.
+ {
+ Parcel data, reply;
+ data.writeStrongBinder(binder);
+ ASSERT_THAT(listener->transact(BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE, data,
+ &reply),
+ StatusEq(NO_ERROR));
+ }
+ // Freeze the listener process.
+ freezeProcess(listenerPid);
+ createProcessGroup(getuid(), listenerPid);
+ ASSERT_TRUE(SetProcessProfiles(getuid(), listenerPid, {"Frozen"}));
+ // Repeatedly flip the target process between frozen and unfrozen states.
+ for (int i = 0; i < 1000; i++) {
+ usleep(50);
+ unfreezeProcess(pid);
+ usleep(50);
+ freezeProcess(pid);
+ }
+ // Unfreeze the listener process. Now it should receive the frozen state
+ // change notifications.
+ ASSERT_TRUE(SetProcessProfiles(getuid(), listenerPid, {"Unfrozen"}));
+ unfreezeProcess(listenerPid);
+ // Wait for 500ms to give the process enough time to wake up and handle
+ // notifications.
+ usleep(500 * 1000);
+ {
+ std::vector<bool> events;
+ Parcel data, reply;
+ ASSERT_THAT(listener->transact(BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS, data, &reply),
+ StatusEq(NO_ERROR));
+ reply.readBoolVector(&events);
+ // There should only be one single state change notifications delievered.
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(events[0]);
+ }
+}
+
TEST_F(BinderLibTest, PassFile) {
int ret;
int pipefd[2];
@@ -1981,6 +2251,26 @@
reply->writeInt32(param.sched_priority);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE: {
+ sp<IBinder> binder = data.readStrongBinder();
+ frozenStateChangeCallback = sp<TestFrozenStateChangeCallback>::make();
+ // Hold an strong pointer to the binder object so it doesn't go
+ // away.
+ frozenStateChangeCallback->binder = binder;
+ int ret = binder->addFrozenStateChangeCallback(frozenStateChangeCallback);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ auto event = frozenStateChangeCallback->events.popWithTimeout(10ms);
+ if (!event.has_value()) {
+ return NOT_ENOUGH_DATA;
+ }
+ return NO_ERROR;
+ }
+ case BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS: {
+ reply->writeBoolVector(frozenStateChangeCallback->getAllAndClear());
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_ECHO_VECTOR: {
std::vector<uint64_t> vector;
auto err = data.readUint64Vector(&vector);
@@ -2067,6 +2357,7 @@
sp<IBinder> m_callback;
bool m_exitOnDestroy;
std::mutex m_blockMutex;
+ sp<TestFrozenStateChangeCallback> frozenStateChangeCallback;
};
int run_server(int index, int readypipefd, bool usePoll)
diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp
index b975fad..f867b42 100644
--- a/libs/binder/tests/binderRecordReplayTest.cpp
+++ b/libs/binder/tests/binderRecordReplayTest.cpp
@@ -99,12 +99,12 @@
GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>);
Status setFileDescriptor(unique_fd input) {
- mFd = std::move(unique_fd(dup(input)));
+ mFd = unique_fd(dup(input));
return Status::ok();
}
Status getFileDescriptor(unique_fd* output) {
- *output = std::move(unique_fd(dup(mFd)));
+ *output = unique_fd(dup(mFd));
return Status::ok();
}
unique_fd mFd;
@@ -117,7 +117,7 @@
std::vector<uint8_t> buffer(fdStat.st_size);
auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size);
EXPECT_TRUE(readResult != 0);
- return std::move(buffer);
+ return buffer;
}
void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
@@ -387,8 +387,8 @@
// When fds are replayed, it will be replaced by /dev/null..reading from it should yield
// null data
- recordReplay(&IBinderRecordReplayTest::setFileDescriptor, std::move(unique_fd(dup(saved))),
- &IBinderRecordReplayTest::getFileDescriptor, std::move(unique_fd(dup(changed))));
+ recordReplay(&IBinderRecordReplayTest::setFileDescriptor, unique_fd(dup(saved)),
+ &IBinderRecordReplayTest::getFileDescriptor, unique_fd(dup(changed)));
}
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3efd84f..3038de9 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;
@@ -1377,8 +1384,8 @@
sp<IServiceManager> sm = defaultServiceManager();
ASSERT_NE(nullptr, sm);
// Any Java service with non-empty getInterfaceDescriptor() would do.
- // Let's pick batteryproperties.
- auto binder = sm->checkService(String16("batteryproperties"));
+ // Let's pick activity.
+ auto binder = sm->checkService(String16("activity"));
ASSERT_NE(nullptr, binder);
auto descriptor = binder->getInterfaceDescriptor();
ASSERT_GE(descriptor.size(), 0u);
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index f480780..c6fd487 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -301,7 +301,8 @@
auto proc = createRpcTestSocketServerProcess({});
- sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+ sp<IBinder> someRealBinder = defaultServiceManager()->getService(String16("activity"));
+ ASSERT_NE(someRealBinder, nullptr);
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
@@ -323,6 +324,22 @@
// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+class TestFrozenStateChangeCallback : public IBinder::FrozenStateChangeCallback {
+public:
+ virtual void onStateChanged(const wp<IBinder>&, State) {}
+};
+
+TEST_P(BinderRpc, RpcBinderShouldFailOnFrozenStateCallbacks) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> a;
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+ EXPECT_DEATH_IF_SUPPORTED(
+ { std::ignore = a->addFrozenStateChangeCallback(callback); },
+ "addFrozenStateChangeCallback\\(\\) is not supported for RPC Binder.");
+}
+
TEST_P(BinderRpc, RepeatRootObject) {
auto proc = createRpcTestSocketServerProcess({});
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
index fd9777a..0ed8a55 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -55,7 +55,7 @@
offset += CHAR_BIT;
}
- return std::move(reverseData);
+ return reverseData;
}
template <typename T>
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/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 52383ac..4c3f4a6 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -83,6 +83,55 @@
static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt";
+// List of libraries that were previously available via VNDK-SP,
+// and are now available via SPHAL.
+// On modern devices that lack the VNDK APEX, the device no longer
+// contains a helpful list of these libraries on the filesystem as above.
+// See system/sepolicy/vendor/file_contexts
+static const char* kFormerlyVndkspLibrariesList =
+ "android.hardware.common-V2-ndk.so:"
+ "android.hardware.common.fmq-V1-ndk.so:"
+ "android.hardware.graphics.allocator-V2-ndk.so:"
+ "android.hardware.graphics.common-V5-ndk.so:"
+ "android.hardware.graphics.common@1.0.so:"
+ "android.hardware.graphics.common@1.1.so:"
+ "android.hardware.graphics.common@1.2.so:"
+ "android.hardware.graphics.composer3-V1-ndk.so:"
+ "android.hardware.graphics.mapper@2.0.so:"
+ "android.hardware.graphics.mapper@2.1.so:"
+ "android.hardware.graphics.mapper@3.0.so:"
+ "android.hardware.graphics.mapper@4.0.so:"
+ "android.hardware.renderscript@1.0.so:"
+ "android.hidl.memory.token@1.0.so:"
+ "android.hidl.memory@1.0-impl.so:"
+ "android.hidl.memory@1.0.so:"
+ "android.hidl.safe_union@1.0.so:"
+ "libRSCpuRef.so:"
+ "libRSDriver.so:"
+ "libRS_internal.so:"
+ "libbacktrace.so:"
+ "libbase.so:"
+ "libbcinfo.so:"
+ "libblas.so:"
+ "libc++.so:"
+ "libcompiler_rt.so:"
+ "libcutils.so:"
+ "libdmabufheap.so:"
+ "libft2.so:"
+ "libgralloctypes.so:"
+ "libhardware.so:"
+ "libhidlbase.so:"
+ "libhidlmemory.so:"
+ "libion.so:"
+ "libjsoncpp.so:"
+ "liblzma.so:"
+ "libpng.so:"
+ "libprocessgroup.so:"
+ "libunwindstack.so:"
+ "libutils.so:"
+ "libutilscallstack.so:"
+ "libz.so";
+
static std::string vndkVersionStr() {
#ifdef __BIONIC__
return base::GetProperty("ro.vndk.version", "");
@@ -122,8 +171,12 @@
static const std::string getSystemNativeLibraries(NativeLibrary type) {
std::string nativeLibrariesSystemConfig = "";
- if (!isVndkEnabled() && type == NativeLibrary::LLNDK) {
- nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath;
+ if (!isVndkEnabled()) {
+ if (type == NativeLibrary::VNDKSP) {
+ return kFormerlyVndkspLibrariesList;
+ } else {
+ nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath;
+ }
} else {
nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
insertVndkVersionStr(&nativeLibrariesSystemConfig);
@@ -263,7 +316,7 @@
ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
}
- auto vndkNamespace = android_get_exported_namespace("vndk");
+ auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal");
if (!vndkNamespace) {
mDriverNamespace = nullptr;
return mDriverNamespace;
@@ -631,7 +684,7 @@
return mAngleNamespace;
}
- auto vndkNamespace = android_get_exported_namespace("vndk");
+ auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal");
if (!vndkNamespace) {
mAngleNamespace = nullptr;
return mAngleNamespace;
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/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index b18b544..223e4b6 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -239,8 +239,9 @@
float const luma_green = 0.7152;
uint32_t const rgba_blue = 0xFFFF0000;
float const luma_blue = 0.0722;
- float const error_margin = 0.01;
+ float const error_margin = 0.1;
float const luma_gray = 0.50;
+ static constexpr std::chrono::milliseconds EVENT_WAIT_TIME_MS = 5000ms;
};
TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
@@ -261,7 +262,7 @@
composer->removeRegionSamplingListener(listener);
}
-TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
+TEST_F(RegionSamplingTest, CollectsLuma) {
fill_render(rgba_green);
sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
@@ -273,7 +274,30 @@
sampleArea.bottom = 200;
composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+ composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsLumaForSecureLayer) {
+ fill_render(rgba_green);
+ SurfaceComposerClient::Transaction()
+ .setFlags(mContentLayer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+ .apply(/*synchronous=*/true);
+
+ sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
+ sp<Listener> listener = new Listener();
+ gui::ARect sampleArea;
+ sampleArea.left = 100;
+ sampleArea.top = 100;
+ sampleArea.right = 200;
+ sampleArea.bottom = 200;
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_green, error_margin);
composer->removeRegionSamplingListener(listener);
@@ -291,13 +315,14 @@
sampleArea.bottom = 200;
composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_green, error_margin);
listener->reset();
fill_render(rgba_blue);
- EXPECT_TRUE(listener->wait_event(300ms))
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
<< "timed out waiting for 2nd luma event to be received";
EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
@@ -323,10 +348,10 @@
graySampleArea.bottom = 200;
composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
- EXPECT_TRUE(grayListener->wait_event(300ms))
+ EXPECT_TRUE(grayListener->wait_event(EVENT_WAIT_TIME_MS))
<< "timed out waiting for luma event to be received";
EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
- EXPECT_TRUE(greenListener->wait_event(300ms))
+ EXPECT_TRUE(greenListener->wait_event(EVENT_WAIT_TIME_MS))
<< "timed out waiting for luma event to be received";
EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
@@ -334,7 +359,7 @@
composer->removeRegionSamplingListener(grayListener);
}
-TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) {
+TEST_F(RegionSamplingTest, TestIfInvalidInputParameters) {
sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
sp<Listener> listener = new Listener();
@@ -369,7 +394,7 @@
composer->removeRegionSamplingListener(listener);
}
-TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) {
+TEST_F(RegionSamplingTest, TestCallbackAfterRemoveListener) {
fill_render(rgba_green);
sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
sp<Listener> listener = new Listener();
@@ -381,7 +406,8 @@
composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
fill_render(rgba_green);
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_green, error_margin);
listener->reset();
@@ -404,11 +430,13 @@
// Test: listener in (100, 100). See layer before move, no layer after move.
fill_render(rgba_blue);
composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
listener->reset();
SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply();
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
composer->removeRegionSamplingListener(listener);
@@ -420,11 +448,13 @@
sampleAreaA.right = sampleArea.right;
sampleAreaA.bottom = sampleArea.bottom;
composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
listener->reset();
SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply();
- EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_TRUE(listener->wait_event(EVENT_WAIT_TIME_MS))
+ << "timed out waiting for luma event to be received";
EXPECT_NEAR(listener->luma(), luma_green, error_margin);
composer->removeRegionSamplingListener(listener);
}
diff --git a/libs/math/include/math/TVecHelpers.h b/libs/math/include/math/TVecHelpers.h
index 0dac662..7278d2d 100644
--- a/libs/math/include/math/TVecHelpers.h
+++ b/libs/math/include/math/TVecHelpers.h
@@ -620,15 +620,10 @@
} // namespace details
} // namespace android
-namespace std {
- template<template<typename T> class VECTOR, typename T>
- struct hash<VECTOR<T>> {
- static constexpr bool IS_VECTOR =
- std::is_base_of<android::details::TVecUnaryOperators<VECTOR, T>, VECTOR<T>>::value;
-
- typename std::enable_if<IS_VECTOR, size_t>::type
- operator()(const VECTOR<T>& v) const {
- return v.hash();
- }
- };
-}
+#define TVECHELPERS_STD_HASH(VECTOR) \
+ template <typename T> \
+ struct std::hash<VECTOR<T>> { \
+ size_t operator()(const VECTOR<T>& v) const { \
+ return v.hash(); \
+ } \
+ }
diff --git a/libs/math/include/math/mat2.h b/libs/math/include/math/mat2.h
index 3e6cd4c..24c2bad 100644
--- a/libs/math/include/math/mat2.h
+++ b/libs/math/include/math/mat2.h
@@ -373,5 +373,7 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TMat22);
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/mat3.h b/libs/math/include/math/mat3.h
index 5c8a9b2..4647a60 100644
--- a/libs/math/include/math/mat3.h
+++ b/libs/math/include/math/mat3.h
@@ -436,5 +436,7 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TMat33);
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/mat4.h b/libs/math/include/math/mat4.h
index c630d97..c9e118a 100644
--- a/libs/math/include/math/mat4.h
+++ b/libs/math/include/math/mat4.h
@@ -590,5 +590,7 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TMat44);
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h
index 07573c5..43c8038 100644
--- a/libs/math/include/math/quat.h
+++ b/libs/math/include/math/quat.h
@@ -187,6 +187,8 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TQuaternion);
+
#pragma clang diagnostic pop
#undef PURE
diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h
index e0adb7f..909c77e 100644
--- a/libs/math/include/math/vec2.h
+++ b/libs/math/include/math/vec2.h
@@ -122,4 +122,6 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TVec2);
+
#pragma clang diagnostic pop
diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h
index 21fb684..ff2b3e4 100644
--- a/libs/math/include/math/vec3.h
+++ b/libs/math/include/math/vec3.h
@@ -128,4 +128,6 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TVec3);
+
#pragma clang diagnostic pop
diff --git a/libs/math/include/math/vec4.h b/libs/math/include/math/vec4.h
index 1e279fe..16509c9 100644
--- a/libs/math/include/math/vec4.h
+++ b/libs/math/include/math/vec4.h
@@ -125,4 +125,6 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TVec4);
+
#pragma clang diagnostic pop
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 5261287..dd78049 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -300,7 +300,9 @@
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+ // P010 is word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved plane
+ if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010 ||
+ format == AHARDWAREBUFFER_FORMAT_YCbCr_422_I) {
outPlanes->planes[0].pixelStride = 2;
} else {
outPlanes->planes[0].pixelStride = 1;
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 4454f36..37dc931 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -30,6 +30,10 @@
to: "",
srcs: ["include/EGL/**/*.h"],
license: "include/EGL/NOTICE",
+ // eglext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
@@ -38,6 +42,10 @@
to: "",
srcs: ["include/GLES/**/*.h"],
license: "include/GLES/NOTICE",
+ // glext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
@@ -46,6 +54,10 @@
to: "",
srcs: ["include/GLES2/**/*.h"],
license: "include/GLES2/NOTICE",
+ // gl2ext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index ec7b190..bf0e38e 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -270,7 +270,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/trace/InputTracer.h b/services/inputflinger/dispatcher/trace/InputTracer.h
index cb525a4..96e619c 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.h
+++ b/services/inputflinger/dispatcher/trace/InputTracer.h
@@ -65,10 +65,10 @@
void onEventProcessingComplete(nsecs_t processingTimestamp);
InputTracer& tracer;
- std::vector<const TracedEvent> events;
+ std::vector<TracedEvent> events;
bool isEventProcessingComplete{false};
// A queue to hold dispatch args from being traced until event processing is complete.
- std::vector<const WindowDispatchArgs> pendingDispatchArgs;
+ std::vector<WindowDispatchArgs> pendingDispatchArgs;
// The metadata should not be modified after event processing is complete.
TracedEventMetadata metadata{};
};
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 7fa58df..ad5a760 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -48,6 +48,7 @@
"libtonemap",
"libaidlcommonsupport",
"libprocessgroup",
+ "libprocessgroup_util",
"libcgrouprc",
"libjsoncpp",
"libcgrouprc_format",
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 5b9a102..b40aea4 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1102,7 +1102,7 @@
}
ftl::Future<std::monostate> Output::presentFrameAndReleaseLayersAsync(bool flushEvenWhenDisabled) {
- return ftl::Future<bool>(std::move(mHwComposerAsyncWorker->send([&]() {
+ return ftl::Future<bool>(std::move(mHwComposerAsyncWorker->send([this, flushEvenWhenDisabled]() {
presentFrameAndReleaseLayers(flushEvenWhenDisabled);
return true;
})))
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 27ea4a9..05f4da2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -467,6 +467,12 @@
return false;
}
+void DisplayDevice::onVrrIdle(bool idle) {
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->onVrrIdle(idle);
+ }
+}
+
void DisplayDevice::animateOverlay() {
if (mRefreshRateOverlay) {
mRefreshRateOverlay->animate();
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 3cc8cf5..1b8a3a8 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -196,6 +196,7 @@
bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
void animateOverlay();
bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
+ void onVrrIdle(bool idle);
// Enables an overlay to be display with the hdr/sdr ratio
void enableHdrSdrRatioOverlay(bool enable) REQUIRES(kMainThreadContext);
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 12ab2c2..be95913 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -209,7 +209,7 @@
if (!buffer || buffer->initCheck() != ::android::OK) {
return nullptr;
}
- return std::move(buffer);
+ return buffer;
}
} // anonymous namespace
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index 55b395b..c63c738 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -22,22 +22,20 @@
std::unique_ptr<RenderArea> DisplayRenderArea::create(wp<const DisplayDevice> displayWeak,
const Rect& sourceCrop, ui::Size reqSize,
ui::Dataspace reqDataSpace,
- bool hintForSeamlessTransition,
- bool allowSecureLayers) {
+ ftl::Flags<Options> options) {
if (auto display = displayWeak.promote()) {
// Using new to access a private constructor.
- return std::unique_ptr<DisplayRenderArea>(
- new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
- hintForSeamlessTransition, allowSecureLayers));
+ return std::unique_ptr<DisplayRenderArea>(new DisplayRenderArea(std::move(display),
+ sourceCrop, reqSize,
+ reqDataSpace, options));
}
return nullptr;
}
DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool hintForSeamlessTransition, bool allowSecureLayers)
- : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, hintForSeamlessTransition,
- allowSecureLayers),
+ ftl::Flags<Options> options)
+ : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, options),
mDisplay(std::move(display)),
mSourceCrop(sourceCrop) {}
@@ -46,7 +44,7 @@
}
bool DisplayRenderArea::isSecure() const {
- return mAllowSecureLayers && mDisplay->isSecure();
+ return mOptions.test(Options::CAPTURE_SECURE_LAYERS) && mDisplay->isSecure();
}
sp<const DisplayDevice> DisplayRenderArea::getDisplayDevice() const {
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
index 4555a9e..677d019 100644
--- a/services/surfaceflinger/DisplayRenderArea.h
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -29,8 +29,7 @@
public:
static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace,
- bool hintForSeamlessTransition,
- bool allowSecureLayers = true);
+ ftl::Flags<Options> options);
const ui::Transform& getTransform() const override;
bool isSecure() const override;
@@ -39,7 +38,7 @@
private:
DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
- ui::Dataspace, bool hintForSeamlessTransition, bool allowSecureLayers = true);
+ ui::Dataspace, ftl::Flags<Options> options);
const sp<const DisplayDevice> mDisplay;
const Rect mSourceCrop;
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index f323ce7..bfe6d2a 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -27,10 +27,9 @@
LayerRenderArea::LayerRenderArea(sp<Layer> layer, frontend::LayerSnapshot layerSnapshot,
const Rect& crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool allowSecureLayers, const ui::Transform& layerTransform,
- const Rect& layerBufferSize, bool hintForSeamlessTransition)
- : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, hintForSeamlessTransition,
- allowSecureLayers),
+ const ui::Transform& layerTransform, const Rect& layerBufferSize,
+ ftl::Flags<RenderArea::Options> options)
+ : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, options),
mLayer(std::move(layer)),
mLayerSnapshot(std::move(layerSnapshot)),
mLayerBufferSize(layerBufferSize),
@@ -42,7 +41,7 @@
}
bool LayerRenderArea::isSecure() const {
- return mAllowSecureLayers;
+ return mOptions.test(Options::CAPTURE_SECURE_LAYERS);
}
sp<const DisplayDevice> LayerRenderArea::getDisplayDevice() const {
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index a12bfca..f72c7c7 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -33,9 +33,9 @@
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(sp<Layer> layer, frontend::LayerSnapshot layerSnapshot, const Rect& crop,
- ui::Size reqSize, ui::Dataspace reqDataSpace, bool allowSecureLayers,
+ ui::Size reqSize, ui::Dataspace reqDataSpace,
const ui::Transform& layerTransform, const Rect& layerBufferSize,
- bool hintForSeamlessTransition);
+ ftl::Flags<RenderArea::Options> options);
const ui::Transform& getTransform() const override;
bool isSecure() const override;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 9527a99..35f12a0 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -28,10 +28,11 @@
namespace android {
-auto RefreshRateOverlay::draw(int refreshRate, int renderFps, SkColor color,
+auto RefreshRateOverlay::draw(int refreshRate, int renderFps, bool idle, SkColor color,
ui::Transform::RotationFlags rotation, ftl::Flags<Features> features)
-> Buffers {
const size_t loopCount = features.test(Features::Spinner) ? 6 : 1;
+ const bool isSetByHwc = features.test(Features::SetByHwc);
Buffers buffers;
buffers.reserve(loopCount);
@@ -71,7 +72,11 @@
canvas->setMatrix(canvasTransform);
int left = 0;
- drawNumber(refreshRate, left, color, *canvas);
+ if (idle && !isSetByHwc) {
+ drawDash(left, *canvas);
+ } else {
+ drawNumber(refreshRate, left, color, *canvas);
+ }
left += 3 * (kDigitWidth + kDigitSpace);
if (features.test(Features::Spinner)) {
switch (i) {
@@ -104,7 +109,11 @@
left += kDigitWidth + kDigitSpace;
if (features.test(Features::RenderRate)) {
- drawNumber(renderFps, left, color, *canvas);
+ if (idle) {
+ drawDash(left, *canvas);
+ } else {
+ drawNumber(renderFps, left, color, *canvas);
+ }
}
left += 3 * (kDigitWidth + kDigitSpace);
@@ -138,6 +147,14 @@
SegmentDrawer::drawDigit(number % 10, left, color, canvas);
}
+void RefreshRateOverlay::drawDash(int left, SkCanvas& canvas) {
+ left += kDigitWidth + kDigitSpace;
+ SegmentDrawer::drawSegment(SegmentDrawer::Segment::Middle, left, SK_ColorRED, canvas);
+
+ left += kDigitWidth + kDigitSpace;
+ SegmentDrawer::drawSegment(SegmentDrawer::Segment::Middle, left, SK_ColorRED, canvas);
+}
+
std::unique_ptr<RefreshRateOverlay> RefreshRateOverlay::create(FpsRange range,
ftl::Flags<Features> features) {
std::unique_ptr<RefreshRateOverlay> overlay =
@@ -171,7 +188,8 @@
return mSurfaceControl != nullptr;
}
-auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps) -> const Buffers& {
+auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps, bool idle)
+ -> const Buffers& {
static const Buffers kNoBuffers;
if (!mSurfaceControl) return kNoBuffers;
@@ -197,8 +215,8 @@
createTransaction().setTransform(mSurfaceControl->get(), transform).apply();
- BufferCache::const_iterator it =
- mBufferCache.find({refreshRate.getIntValue(), renderFps.getIntValue(), transformHint});
+ BufferCache::const_iterator it = mBufferCache.find(
+ {refreshRate.getIntValue(), renderFps.getIntValue(), transformHint, idle});
if (it == mBufferCache.end()) {
const int maxFps = mFpsRange.max.getIntValue();
@@ -222,10 +240,10 @@
const SkColor color = colorBase.toSkColor();
- auto buffers = draw(refreshIntFps, renderIntFps, color, transformHint, mFeatures);
+ auto buffers = draw(refreshIntFps, renderIntFps, idle, color, transformHint, mFeatures);
it = mBufferCache
- .try_emplace({refreshIntFps, renderIntFps, transformHint}, std::move(buffers))
- .first;
+ .try_emplace({refreshIntFps, renderIntFps, transformHint, idle},
+ std::move(buffers)).first;
}
return it->second;
@@ -257,7 +275,15 @@
void RefreshRateOverlay::changeRefreshRate(Fps refreshRate, Fps renderFps) {
mRefreshRate = refreshRate;
mRenderFps = renderFps;
- const auto buffer = getOrCreateBuffers(refreshRate, renderFps)[mFrame];
+ const auto buffer = getOrCreateBuffers(refreshRate, renderFps, mIsVrrIdle)[mFrame];
+ createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
+}
+
+void RefreshRateOverlay::onVrrIdle(bool idle) {
+ mIsVrrIdle = idle;
+ if (!mRefreshRate || !mRenderFps) return;
+
+ const auto buffer = getOrCreateBuffers(*mRefreshRate, *mRenderFps, mIsVrrIdle)[mFrame];
createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
}
@@ -265,7 +291,7 @@
if (mFeatures.test(Features::RenderRate) && mRefreshRate &&
FlagManager::getInstance().misc1()) {
mRenderFps = renderFps;
- const auto buffer = getOrCreateBuffers(*mRefreshRate, renderFps)[mFrame];
+ const auto buffer = getOrCreateBuffers(*mRefreshRate, renderFps, mIsVrrIdle)[mFrame];
createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
}
}
@@ -273,7 +299,7 @@
void RefreshRateOverlay::animate() {
if (!mFeatures.test(Features::Spinner) || !mRefreshRate) return;
- const auto& buffers = getOrCreateBuffers(*mRefreshRate, *mRenderFps);
+ const auto& buffers = getOrCreateBuffers(*mRefreshRate, *mRenderFps, mIsVrrIdle);
mFrame = (mFrame + 1) % buffers.size();
const auto buffer = buffers[mFrame];
createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index b2896f0..d8aa048 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -57,6 +57,7 @@
void changeRenderRate(Fps);
void animate();
bool isSetByHwc() const { return mFeatures.test(RefreshRateOverlay::Features::SetByHwc); }
+ void onVrrIdle(bool idle);
RefreshRateOverlay(ConstructorTag, FpsRange, ftl::Flags<Features>);
@@ -65,11 +66,12 @@
using Buffers = std::vector<sp<GraphicBuffer>>;
- static Buffers draw(int refreshRate, int renderFps, SkColor, ui::Transform::RotationFlags,
- ftl::Flags<Features>);
+ static Buffers draw(int refreshRate, int renderFps, bool idle, SkColor,
+ ui::Transform::RotationFlags, ftl::Flags<Features>);
static void drawNumber(int number, int left, SkColor, SkCanvas&);
+ static void drawDash(int left, SkCanvas&);
- const Buffers& getOrCreateBuffers(Fps, Fps);
+ const Buffers& getOrCreateBuffers(Fps, Fps, bool);
SurfaceComposerClient::Transaction createTransaction() const;
@@ -77,10 +79,11 @@
int refreshRate;
int renderFps;
ui::Transform::RotationFlags flags;
+ bool idle;
bool operator==(Key other) const {
return refreshRate == other.refreshRate && renderFps == other.renderFps &&
- flags == other.flags;
+ flags == other.flags && idle == other.idle;
}
};
@@ -89,6 +92,7 @@
std::optional<Fps> mRefreshRate;
std::optional<Fps> mRenderFps;
+ bool mIsVrrIdle = false;
size_t mFrame = 0;
const FpsRange mFpsRange; // For color interpolation.
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 2ad70bb..c77bcfa 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -277,7 +277,6 @@
}
const Rect sampledBounds = sampleRegion.bounds();
- constexpr bool kHintForSeamlessTransition = false;
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
@@ -350,9 +349,8 @@
SurfaceFlinger::RenderAreaBuilderVariant
renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds,
- sampledBounds.getSize(), ui::Dataspace::V0_SRGB,
- kHintForSeamlessTransition, true /* captureSecureLayers */,
- displayWeak);
+ sampledBounds.getSize(), ui::Dataspace::V0_SRGB, displayWeak,
+ RenderArea::Options::CAPTURE_SECURE_LAYERS);
FenceResult fenceResult;
if (FlagManager::getInstance().single_hop_screenshot() &&
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index e8d20af..034e467 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -21,16 +21,23 @@
class RenderArea {
public:
enum class CaptureFill {CLEAR, OPAQUE};
+ enum class Options {
+ // If not set, the secure layer would be blacked out or skipped
+ // when rendered to an insecure render area
+ CAPTURE_SECURE_LAYERS = 1 << 0,
+ // If set, the render result may be used for system animations
+ // that must preserve the exact colors of the display
+ HINT_FOR_SEAMLESS_TRANSITION = 1 << 1,
+ };
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
- bool hintForSeamlessTransition, bool allowSecureLayers = false)
- : mAllowSecureLayers(allowSecureLayers),
+ ftl::Flags<Options> options)
+ : mOptions(options),
mReqSize(reqSize),
mReqDataSpace(reqDataSpace),
- mCaptureFill(captureFill),
- mHintForSeamlessTransition(hintForSeamlessTransition) {}
+ mCaptureFill(captureFill) {}
static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
std::function<void(const LayerVector::Visitor&)> traverseLayers) {
@@ -90,16 +97,17 @@
// Returns whether the render result may be used for system animations that
// must preserve the exact colors of the display.
- bool getHintForSeamlessTransition() const { return mHintForSeamlessTransition; }
+ bool getHintForSeamlessTransition() const {
+ return mOptions.test(Options::HINT_FOR_SEAMLESS_TRANSITION);
+ }
protected:
- const bool mAllowSecureLayers;
+ ftl::Flags<Options> mOptions;
private:
const ui::Size mReqSize;
const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
- const bool mHintForSeamlessTransition;
};
} // namespace android
diff --git a/services/surfaceflinger/RenderAreaBuilder.h b/services/surfaceflinger/RenderAreaBuilder.h
index a25c6e0..599fa7e 100644
--- a/services/surfaceflinger/RenderAreaBuilder.h
+++ b/services/surfaceflinger/RenderAreaBuilder.h
@@ -36,50 +36,34 @@
// Composition data space of the render area
ui::Dataspace reqDataSpace;
- // If true, the secure layer would be blacked out or skipped
- // when rendered to an insecure render area
- bool allowSecureLayers;
-
- // If true, the render result may be used for system animations
- // that must preserve the exact colors of the display
- bool hintForSeamlessTransition;
-
+ ftl::Flags<RenderArea::Options> options;
virtual std::unique_ptr<RenderArea> build() const = 0;
RenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool allowSecureLayers, bool hintForSeamlessTransition)
- : crop(crop),
- reqSize(reqSize),
- reqDataSpace(reqDataSpace),
- allowSecureLayers(allowSecureLayers),
- hintForSeamlessTransition(hintForSeamlessTransition) {}
+ ftl::Flags<RenderArea::Options> options)
+ : crop(crop), reqSize(reqSize), reqDataSpace(reqDataSpace), options(options) {}
virtual ~RenderAreaBuilder() = default;
};
struct DisplayRenderAreaBuilder : RenderAreaBuilder {
DisplayRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool allowSecureLayers, bool hintForSeamlessTransition,
- wp<const DisplayDevice> displayWeak)
- : RenderAreaBuilder(crop, reqSize, reqDataSpace, allowSecureLayers,
- hintForSeamlessTransition),
- displayWeak(displayWeak) {}
+ wp<const DisplayDevice> displayWeak,
+ ftl::Flags<RenderArea::Options> options)
+ : RenderAreaBuilder(crop, reqSize, reqDataSpace, options), displayWeak(displayWeak) {}
// Display that render area will be on
wp<const DisplayDevice> displayWeak;
std::unique_ptr<RenderArea> build() const override {
- return DisplayRenderArea::create(displayWeak, crop, reqSize, reqDataSpace,
- hintForSeamlessTransition, allowSecureLayers);
+ return DisplayRenderArea::create(displayWeak, crop, reqSize, reqDataSpace, options);
}
};
struct LayerRenderAreaBuilder : RenderAreaBuilder {
- LayerRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool allowSecureLayers, bool hintForSeamlessTransition, sp<Layer> layer,
- bool childrenOnly)
- : RenderAreaBuilder(crop, reqSize, reqDataSpace, allowSecureLayers,
- hintForSeamlessTransition),
+ LayerRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace, sp<Layer> layer,
+ bool childrenOnly, ftl::Flags<RenderArea::Options> options)
+ : RenderAreaBuilder(crop, reqSize, reqDataSpace, options),
layer(layer),
childrenOnly(childrenOnly) {}
@@ -110,8 +94,8 @@
std::unique_ptr<RenderArea> build() const override {
return std::make_unique<LayerRenderArea>(layer, std::move(layerSnapshot), crop, reqSize,
- reqDataSpace, allowSecureLayers, layerTransform,
- layerBufferSize, hintForSeamlessTransition);
+ reqDataSpace, layerTransform, layerBufferSize,
+ options);
}
};
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index 43cdb5e..f430526 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -33,6 +33,7 @@
virtual void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>,
Fps renderRate) = 0;
virtual void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) = 0;
+ virtual void vrrDisplayIdle(bool idle) = 0;
protected:
~ISchedulerCallback() = default;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 846727b..dd86e4f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1501,7 +1501,7 @@
return str;
};
ALOGV("%s render rates: %s, isVrrDevice? %d", rangeName, stringifyModes().c_str(),
- mIsVrrDevice);
+ mIsVrrDevice.load());
return frameRateModes;
};
@@ -1511,7 +1511,6 @@
}
bool RefreshRateSelector::isVrrDevice() const {
- std::lock_guard lock(mLock);
return mIsVrrDevice;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 4f491d9..998b1b8 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -321,7 +321,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
@@ -383,6 +386,7 @@
Callbacks platform;
Callbacks kernel;
+ Callbacks vrr;
};
void setIdleTimerCallbacks(IdleTimerCallbacks callbacks) EXCLUDES(mIdleTimerCallbacksMutex) {
@@ -501,6 +505,9 @@
std::optional<IdleTimerCallbacks::Callbacks> getIdleTimerCallbacks() const
REQUIRES(mIdleTimerCallbacksMutex) {
if (!mIdleTimerCallbacks) return {};
+
+ if (mIsVrrDevice) return mIdleTimerCallbacks->vrr;
+
return mConfig.kernelIdleTimerController.has_value() ? mIdleTimerCallbacks->kernel
: mIdleTimerCallbacks->platform;
}
@@ -536,7 +543,7 @@
std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock);
// Caches whether the device is VRR-compatible based on the active display mode.
- bool mIsVrrDevice GUARDED_BY(mLock) = false;
+ std::atomic_bool mIsVrrDevice = false;
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 60681a2..5ec7e48 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -82,7 +82,7 @@
mTouchTimer.reset();
// Stop idle timer and clear callbacks, as the RefreshRateSelector may outlive the Scheduler.
- demotePacesetterDisplay();
+ demotePacesetterDisplay({.toggleIdleTimer = true});
}
void Scheduler::initVsync(frametimeline::TokenManager& tokenManager,
@@ -117,35 +117,45 @@
}
}
-void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) {
- demotePacesetterDisplay();
+void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) {
+ constexpr PromotionParams kPromotionParams = {.toggleIdleTimer = true};
- promotePacesetterDisplay(pacesetterIdOpt);
+ demotePacesetterDisplay(kPromotionParams);
+ promotePacesetterDisplay(pacesetterId, kPromotionParams);
}
-void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
+void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ PhysicalDisplayId activeDisplayId) {
auto schedulePtr =
std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
[this](PhysicalDisplayId id, bool enable) {
onHardwareVsyncRequest(id, enable);
});
- registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr));
+ registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr),
+ activeDisplayId);
}
void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
RefreshRateSelectorPtr selectorPtr,
- VsyncSchedulePtr schedulePtr) {
- demotePacesetterDisplay();
+ VsyncSchedulePtr schedulePtr,
+ PhysicalDisplayId activeDisplayId) {
+ const bool isPrimary = (ftl::FakeGuard(mDisplayLock), !mPacesetterDisplayId);
- auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
+ // Start the idle timer for the first registered (i.e. primary) display.
+ const PromotionParams promotionParams = {.toggleIdleTimer = isPrimary};
+
+ demotePacesetterDisplay(promotionParams);
+
+ auto [pacesetterVsyncSchedule, isNew] = [&]() REQUIRES(kMainThreadContext) {
std::scoped_lock lock(mDisplayLock);
const bool isNew = mDisplays
.emplace_or_replace(displayId, displayId, std::move(selectorPtr),
std::move(schedulePtr), mFeatures)
.second;
- return std::make_pair(promotePacesetterDisplayLocked(), isNew);
+ return std::make_pair(promotePacesetterDisplayLocked(activeDisplayId, promotionParams),
+ isNew);
}();
applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
@@ -158,10 +168,13 @@
dispatchHotplug(displayId, Hotplug::Connected);
}
-void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
+void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, PhysicalDisplayId activeDisplayId) {
+ LOG_ALWAYS_FATAL_IF(displayId == activeDisplayId, "Cannot unregister the active display!");
+
dispatchHotplug(displayId, Hotplug::Disconnected);
- demotePacesetterDisplay();
+ constexpr PromotionParams kPromotionParams = {.toggleIdleTimer = false};
+ demotePacesetterDisplay(kPromotionParams);
std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
{
@@ -173,7 +186,7 @@
// headless virtual display.)
LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");
- pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
+ pacesetterVsyncSchedule = promotePacesetterDisplayLocked(activeDisplayId, kPromotionParams);
}
applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}
@@ -912,35 +925,38 @@
return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides);
}
-void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) {
+void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams params) {
std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
-
{
std::scoped_lock lock(mDisplayLock);
- pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterIdOpt);
+ pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterId, params);
}
applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}
std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
- std::optional<PhysicalDisplayId> pacesetterIdOpt) {
- // TODO(b/241286431): Choose the pacesetter display.
- mPacesetterDisplayId = pacesetterIdOpt.value_or(mDisplays.begin()->first);
- ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str());
+ PhysicalDisplayId pacesetterId, PromotionParams params) {
+ // TODO: b/241286431 - Choose the pacesetter among mDisplays.
+ mPacesetterDisplayId = pacesetterId;
+ ALOGI("Display %s is the pacesetter", to_string(pacesetterId).c_str());
std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr;
if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
const Display& pacesetter = *pacesetterOpt;
- pacesetter.selectorPtr->setIdleTimerCallbacks(
- {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
- .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
- .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
- .onExpired =
- [this] { kernelIdleTimerCallback(TimerState::Expired); }}});
+ if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
+ pacesetter.selectorPtr->setIdleTimerCallbacks(
+ {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
+ .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
+ .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
+ .onExpired =
+ [this] { kernelIdleTimerCallback(TimerState::Expired); }},
+ .vrr = {.onReset = [this] { mSchedulerCallback.vrrDisplayIdle(false); },
+ .onExpired = [this] { mSchedulerCallback.vrrDisplayIdle(true); }}});
- pacesetter.selectorPtr->startIdleTimer();
+ pacesetter.selectorPtr->startIdleTimer();
+ }
newVsyncSchedulePtr = pacesetter.schedulePtr;
@@ -960,11 +976,14 @@
}
}
-void Scheduler::demotePacesetterDisplay() {
- // No need to lock for reads on kMainThreadContext.
- if (const auto pacesetterPtr = FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
- pacesetterPtr->stopIdleTimer();
- pacesetterPtr->clearIdleTimerCallbacks();
+void Scheduler::demotePacesetterDisplay(PromotionParams params) {
+ if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
+ // No need to lock for reads on kMainThreadContext.
+ if (const auto pacesetterPtr =
+ FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
+ pacesetterPtr->stopIdleTimer();
+ pacesetterPtr->clearIdleTimerCallbacks();
+ }
}
// Clear state that depends on the pacesetter's RefreshRateSelector.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ccaa05f..94583db 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -92,8 +92,8 @@
void startTimers();
- // TODO(b/241285191): Remove this API by promoting pacesetter in onScreen{Acquired,Released}.
- void setPacesetterDisplay(std::optional<PhysicalDisplayId>) REQUIRES(kMainThreadContext)
+ // TODO: b/241285191 - Remove this API by promoting pacesetter in onScreen{Acquired,Released}.
+ void setPacesetterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext)
EXCLUDES(mDisplayLock);
using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;
@@ -101,9 +101,16 @@
using ConstVsyncSchedulePtr = std::shared_ptr<const VsyncSchedule>;
using VsyncSchedulePtr = std::shared_ptr<VsyncSchedule>;
- void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
+ // After registration/unregistration, `activeDisplayId` is promoted to pacesetter. Note that the
+ // active display is never unregistered, since hotplug disconnect never happens for activatable
+ // displays, i.e. a foldable's internal displays or otherwise the (internal or external) primary
+ // display.
+ // TODO: b/255635821 - Remove active display parameters.
+ void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr,
+ PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)
EXCLUDES(mDisplayLock);
- void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
+ void unregisterDisplay(PhysicalDisplayId, PhysicalDisplayId activeDisplayId)
+ REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
void run();
@@ -370,9 +377,16 @@
void resyncAllToHardwareVsync(bool allowToEnable) EXCLUDES(mDisplayLock);
void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod);
- // Chooses a pacesetter among the registered displays, unless `pacesetterIdOpt` is specified.
- // The new `mPacesetterDisplayId` is never `std::nullopt`.
- void promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt)
+ // TODO: b/241286431 - Remove this option, which assumes that the pacesetter does not change
+ // when a (secondary) display is registered or unregistered. In the short term, this avoids
+ // a deadlock where the main thread joins with the timer thread as the timer thread waits to
+ // lock a mutex held by the main thread.
+ struct PromotionParams {
+ // Whether to stop and start the idle timer. Ignored unless connected_display flag is set.
+ bool toggleIdleTimer;
+ };
+
+ void promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams)
REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
// Changes to the displays (e.g. registering and unregistering) must be made
@@ -381,17 +395,20 @@
// MessageQueue and EventThread need to use the new pacesetter's
// VsyncSchedule, and this must happen while mDisplayLock is *not* locked,
// or else we may deadlock with EventThread.
- std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(
- std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt)
+ std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(PhysicalDisplayId pacesetterId,
+ PromotionParams)
REQUIRES(kMainThreadContext, mDisplayLock);
void applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule>) EXCLUDES(mDisplayLock);
- // Blocks until the pacesetter's idle timer thread exits. `mDisplayLock` must not be locked by
- // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
- void demotePacesetterDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);
+ // If toggleIdleTimer is true, the calling thread blocks until the pacesetter's idle timer
+ // thread exits, in which case mDisplayLock must not be locked by the caller to avoid deadlock,
+ // since the timer thread locks it before exit.
+ void demotePacesetterDisplay(PromotionParams) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock, mPolicyLock);
- void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr)
- REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
+ void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr,
+ PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
struct Policy;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index dd3c4b0..1422cfa 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -737,9 +737,7 @@
return ticks<std::milli, float>(TimePoint::fromNs(timePoint) - now);
};
- Fps displayFps = !FlagManager::getInstance().vrr_bugfix_24q4() && mRenderRateOpt
- ? *mRenderRateOpt
- : Fps::fromPeriodNsecs(mIdealPeriod.ns());
+ Fps displayFps = Fps::fromPeriodNsecs(mIdealPeriod.ns());
const auto divisor = RefreshRateSelector::getFrameRateDivisor(displayFps, frameRate);
const auto now = TimePoint::now();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index abab49d..fcead9f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1414,6 +1414,8 @@
return future.get();
}
+// TODO: b/241285876 - Restore thread safety analysis once mStateLock below is unconditional.
+[[clang::no_thread_safety_analysis]]
void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) {
ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
@@ -1429,7 +1431,7 @@
if (const auto oldResolution =
mDisplayModeController.getActiveMode(displayId).modePtr->getResolution();
oldResolution != activeMode.modePtr->getResolution()) {
- Mutex::Autolock lock(mStateLock);
+ ConditionalLock lock(mStateLock, !FlagManager::getInstance().connected_display());
auto& state = mCurrentState.displays.editValueFor(getPhysicalDisplayTokenLocked(displayId));
// We need to generate new sequenceId in order to recreate the display (and this
@@ -1483,7 +1485,7 @@
std::optional<PhysicalDisplayId> displayToUpdateImmediately;
- for (const auto& [displayId, physical] : FTL_FAKE_GUARD(mStateLock, mPhysicalDisplays)) {
+ for (const auto& [displayId, physical] : mPhysicalDisplays) {
auto desiredModeOpt = mDisplayModeController.getDesiredMode(displayId);
if (!desiredModeOpt) {
continue;
@@ -2618,9 +2620,13 @@
return false;
}
- for (const auto [displayId, _] : frameTargets) {
- if (mDisplayModeController.isModeSetPending(displayId)) {
- finalizeDisplayModeChange(displayId);
+ {
+ ConditionalLock lock(mStateLock, FlagManager::getInstance().connected_display());
+
+ for (const auto [displayId, _] : frameTargets) {
+ if (mDisplayModeController.isModeSetPending(displayId)) {
+ finalizeDisplayModeChange(displayId);
+ }
}
}
@@ -2719,9 +2725,16 @@
? &mLayerHierarchyBuilder.getHierarchy()
: nullptr,
updateAttachedChoreographer);
+
+ if (FlagManager::getInstance().connected_display()) {
+ initiateDisplayModeChanges();
+ }
}
- initiateDisplayModeChanges();
+ if (!FlagManager::getInstance().connected_display()) {
+ ftl::FakeGuard guard(mStateLock);
+ initiateDisplayModeChanges();
+ }
updateCursorAsync();
if (!mustComposite) {
@@ -3855,7 +3868,8 @@
ftl::FakeGuard guard(kMainThreadContext);
// For hotplug reconnect, renew the registration since display modes have been reloaded.
- mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
+ mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector(),
+ mActiveDisplayId);
}
if (display->isVirtual()) {
@@ -3894,7 +3908,7 @@
if (display->isVirtual()) {
releaseVirtualDisplay(display->getVirtualId());
} else {
- mScheduler->unregisterDisplay(display->getPhysicalId());
+ mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId);
}
}
@@ -4506,7 +4520,8 @@
getFactory(), activeRefreshRate, *mTimeStats);
// The pacesetter must be registered before EventThread creation below.
- mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
+ mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector(),
+ mActiveDisplayId);
if (FlagManager::getInstance().vrr_config()) {
mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps,
/*applyImmediately*/ true);
@@ -7701,6 +7716,22 @@
}));
}
+void SurfaceFlinger::vrrDisplayIdle(bool idle) {
+ // Update the overlay on the main thread to avoid race conditions with
+ // RefreshRateSelector::getActiveMode
+ static_cast<void>(mScheduler->schedule([=, this] {
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
+ if (!display) {
+ ALOGW("%s: default display is null", __func__);
+ return;
+ }
+ if (!display->isRefreshRateOverlayEnabled()) return;
+
+ display->onVrrIdle(idle);
+ mScheduler->scheduleFrame();
+ }));
+}
+
std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) {
const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported(
@@ -7957,10 +7988,13 @@
GetLayerSnapshotsFunction getLayerSnapshotsFn =
getLayerSnapshotsForScreenshots(layerStack, args.uid, std::move(excludeLayerIds));
+ ftl::Flags<RenderArea::Options> options;
+ if (args.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS;
+ if (args.hintForSeamlessTransition)
+ options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION;
captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>,
args.sourceCrop, reqSize, args.dataspace,
- args.hintForSeamlessTransition,
- args.captureSecureLayers, displayWeak),
+ displayWeak, options),
getLayerSnapshotsFn, reqSize, args.pixelFormat, args.allowProtected,
args.grayscale, captureListener);
}
@@ -8011,10 +8045,12 @@
constexpr bool kAllowProtected = false;
constexpr bool kGrayscale = false;
+ ftl::Flags<RenderArea::Options> options;
+ if (args.hintForSeamlessTransition)
+ options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION;
captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>,
- Rect(), size, args.dataspace,
- args.hintForSeamlessTransition,
- false /* captureSecureLayers */, displayWeak),
+ Rect(), size, args.dataspace, displayWeak,
+ options),
getLayerSnapshotsFn, size, args.pixelFormat, kAllowProtected, kGrayscale,
captureListener);
}
@@ -8113,10 +8149,13 @@
return;
}
+ ftl::Flags<RenderArea::Options> options;
+ if (args.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS;
+ if (args.hintForSeamlessTransition)
+ options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION;
captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<LayerRenderAreaBuilder>, crop,
- reqSize, dataspace, args.captureSecureLayers,
- args.hintForSeamlessTransition, parent,
- args.childrenOnly),
+ reqSize, dataspace, parent, args.childrenOnly,
+ options),
getLayerSnapshotsFn, reqSize, args.pixelFormat, args.allowProtected,
args.grayscale, captureListener);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ee541c4..a3534b5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -703,6 +703,7 @@
Fps renderRate) override;
void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) override
REQUIRES(kMainThreadContext);
+ void vrrDisplayIdle(bool idle) override;
// ICEPowerCallback overrides:
void notifyCpuLoadUp() override;
@@ -737,9 +738,9 @@
status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps,
Fps maxFps);
- void initiateDisplayModeChanges() REQUIRES(kMainThreadContext) EXCLUDES(mStateLock);
+ void initiateDisplayModeChanges() REQUIRES(kMainThreadContext) REQUIRES(mStateLock);
void finalizeDisplayModeChange(PhysicalDisplayId) REQUIRES(kMainThreadContext)
- EXCLUDES(mStateLock);
+ REQUIRES(mStateLock);
void dropModeRequest(PhysicalDisplayId) REQUIRES(kMainThreadContext);
void applyActiveMode(PhysicalDisplayId) REQUIRES(kMainThreadContext);
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 0bafb71..b189598 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -62,12 +62,12 @@
proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size()));
for (auto& layerState : t.states) {
- proto.mutable_layer_changes()->Add(std::move(toProto(layerState)));
+ proto.mutable_layer_changes()->Add(toProto(layerState));
}
proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size()));
for (auto& displayState : t.displays) {
- proto.mutable_display_changes()->Add(std::move(toProto(displayState)));
+ proto.mutable_display_changes()->Add(toProto(displayState));
}
proto.mutable_merged_transaction_ids()->Reserve(
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index 696f348..bc9f809 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -244,7 +244,7 @@
static_cast<int32_t>(update.createdLayers.size()));
for (const auto& args : update.createdLayers) {
- entryProto.mutable_added_layers()->Add(std::move(mProtoParser.toProto(args)));
+ entryProto.mutable_added_layers()->Add(mProtoParser.toProto(args));
}
entryProto.mutable_destroyed_layers()->Reserve(
@@ -276,7 +276,7 @@
static_cast<int32_t>(update.displayInfos.size()));
for (auto& [layerStack, displayInfo] : update.displayInfos) {
entryProto.mutable_displays()->Add(
- std::move(mProtoParser.toProto(displayInfo, layerStack.id)));
+ mProtoParser.toProto(displayInfo, layerStack.id));
}
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 08973de..cdd77fe 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -70,6 +70,7 @@
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+using namespace ftl::flag_operators;
constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
constexpr hal::HWLayerId HWC_LAYER = 5000;
@@ -197,8 +198,11 @@
const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
constexpr bool regionSampling = false;
- auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
- ui::Dataspace::V0_SRGB, true, true);
+ auto renderArea =
+ DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
+ ui::Dataspace::V0_SRGB,
+ RenderArea::Options::CAPTURE_SECURE_LAYERS |
+ RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(),
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4fb0690..fc54a8b 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -343,12 +343,15 @@
}
TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
+ constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1;
mScheduler->registerDisplay(kDisplayId1,
std::make_shared<RefreshRateSelector>(kDisplay1Modes,
- kDisplay1Mode60->getId()));
+ kDisplay1Mode60->getId()),
+ kActiveDisplayId);
mScheduler->registerDisplay(kDisplayId2,
std::make_shared<RefreshRateSelector>(kDisplay2Modes,
- kDisplay2Mode60->getId()));
+ kDisplay2Mode60->getId()),
+ kActiveDisplayId);
mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
mScheduler->setDisplayPowerMode(kDisplayId2, hal::PowerMode::ON);
@@ -411,10 +414,10 @@
{
// The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
// Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
- mScheduler
- ->registerDisplay(kDisplayId3,
- std::make_shared<RefreshRateSelector>(kDisplay3Modes,
- kDisplay3Mode60->getId()));
+ mScheduler->registerDisplay(kDisplayId3,
+ std::make_shared<RefreshRateSelector>(kDisplay3Modes,
+ kDisplay3Mode60->getId()),
+ kActiveDisplayId);
mScheduler->setDisplayPowerMode(kDisplayId3, hal::PowerMode::ON);
const GlobalSignals globalSignals = {.touch = true};
@@ -457,12 +460,15 @@
}
TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) {
+ constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1;
mScheduler->registerDisplay(kDisplayId1,
std::make_shared<RefreshRateSelector>(kDisplay1Modes,
- kDisplay1Mode60->getId()));
+ kDisplay1Mode60->getId()),
+ kActiveDisplayId);
mScheduler->registerDisplay(kDisplayId2,
std::make_shared<RefreshRateSelector>(kDisplay2Modes,
- kDisplay2Mode60->getId()));
+ kDisplay2Mode60->getId()),
+ kActiveDisplayId);
using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
@@ -585,7 +591,8 @@
mFlinger.getTimeStats(),
mSchedulerCallback};
- scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker);
+ scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, std::nullopt,
+ vrrTracker);
vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate, /*applyImmediately*/ false);
vrrTracker->addVsyncTimestamp(0);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 198a5de..f063809 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -53,7 +53,7 @@
factory, selectorPtr->getActiveMode().fps, timeStats) {
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr), std::move(controller),
- std::move(tracker));
+ std::move(tracker), displayId);
ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
// Execute task to prevent broken promise exception on destruction.
@@ -85,14 +85,16 @@
void registerDisplay(
PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ std::optional<PhysicalDisplayId> activeDisplayIdOpt = {},
std::shared_ptr<VSyncTracker> vsyncTracker = std::make_shared<mock::VSyncTracker>()) {
registerDisplay(displayId, std::move(selectorPtr),
- std::make_unique<mock::VsyncController>(), vsyncTracker);
+ std::make_unique<mock::VsyncController>(), vsyncTracker,
+ activeDisplayIdOpt.value_or(displayId));
}
void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
std::unique_ptr<VsyncController> controller,
- std::shared_ptr<VSyncTracker> tracker) {
+ std::shared_ptr<VSyncTracker> tracker, PhysicalDisplayId activeDisplayId) {
ftl::FakeGuard guard(kMainThreadContext);
Scheduler::registerDisplayInternal(displayId, std::move(selectorPtr),
std::shared_ptr<VsyncSchedule>(
@@ -101,16 +103,12 @@
mock::VSyncDispatch>(),
std::move(controller),
mockRequestHardwareVsync
- .AsStdFunction())));
+ .AsStdFunction())),
+ activeDisplayId);
}
testing::MockFunction<void(PhysicalDisplayId, bool)> mockRequestHardwareVsync;
- void unregisterDisplay(PhysicalDisplayId displayId) {
- ftl::FakeGuard guard(kMainThreadContext);
- Scheduler::unregisterDisplay(displayId);
- }
-
void setDisplayPowerMode(PhysicalDisplayId displayId, hal::PowerMode powerMode) {
ftl::FakeGuard guard(kMainThreadContext);
Scheduler::setDisplayPowerMode(displayId, powerMode);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 007383b..4197cbd 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -1118,8 +1118,8 @@
if (mFlinger.scheduler() && mSchedulerRegistration) {
mFlinger.scheduler()->registerDisplay(*physicalId,
mCreationArgs.refreshRateSelector,
- std::move(controller),
- std::move(tracker));
+ std::move(controller), std::move(tracker),
+ mFlinger.mutableActiveDisplayId());
}
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index fb4ef70..7bf1674 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -131,14 +131,14 @@
// add layers and add some layer transaction
{
frontend::Update update;
- update.layerCreationArgs.emplace_back(std::move(
+ update.layerCreationArgs.emplace_back(
getLayerCreationArgs(mParentLayerId, /*parentId=*/UNASSIGNED_LAYER_ID,
/*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/123,
- /*addToRoot=*/true)));
- update.layerCreationArgs.emplace_back(std::move(
+ /*addToRoot=*/true));
+ update.layerCreationArgs.emplace_back(
getLayerCreationArgs(mChildLayerId, mParentLayerId,
/*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/456,
- /*addToRoot=*/true)));
+ /*addToRoot=*/true));
TransactionState transaction;
transaction.id = 50;
ResolvedComposerState layerState;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index dec5fa5..8f21cdb 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -31,6 +31,7 @@
MOCK_METHOD(void, onExpectedPresentTimePosted, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps),
(override));
MOCK_METHOD(void, onCommitNotComposited, (PhysicalDisplayId), (override));
+ MOCK_METHOD(void, vrrDisplayIdle, (bool), (override));
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
@@ -41,6 +42,7 @@
void onChoreographerAttached() override {}
void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
void onCommitNotComposited(PhysicalDisplayId) override {}
+ void vrrDisplayIdle(bool) override {}
};
} // namespace android::scheduler::mock
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 3f89960..ef213f0 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);