Merge "IInterface: remove some C++ AIDL exceptions" into main
diff --git a/Android.bp b/Android.bp
index 119c7ea..ba55082 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,6 +42,7 @@
export_include_dirs: [
"include/",
],
+ product_available: true,
}
ndk_headers {
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index b8e5ce1..17ae0aa 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -67,6 +67,8 @@
MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
const sp<LocalRegistrationCallback>&));
MOCK_METHOD0(getServiceDebugInfo, std::vector<ServiceDebugInfo>());
+ MOCK_METHOD1(enableAddServiceCache, void(bool));
+
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
index b1c6940..50ea0c7 100644
--- a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
+++ b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
@@ -47,6 +47,8 @@
} // namespace android
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+ signal(SIGPIPE, SIG_IGN);
auto service = sp<InstalldNativeService>::make();
fuzzService(service, FuzzedDataProvider(data, size));
return 0;
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index fa7cb64..38a125b 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -396,7 +396,7 @@
SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
- *outBinder = tryGetBinder(name, true);
+ *outBinder = tryGetBinder(name, true).service;
// returns ok regardless of result for legacy reasons
return Status::ok();
}
@@ -430,13 +430,15 @@
return os::Service::make<os::Service::Tag::accessor>(nullptr);
}
return os::Service::make<os::Service::Tag::accessor>(
- tryGetBinder(*accessorName, startIfNotFound));
+ tryGetBinder(*accessorName, startIfNotFound).service);
} else {
- return os::Service::make<os::Service::Tag::binder>(tryGetBinder(name, startIfNotFound));
+ return os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ tryGetBinder(name, startIfNotFound));
}
}
-sp<IBinder> ServiceManager::tryGetBinder(const std::string& name, bool startIfNotFound) {
+os::ServiceWithMetadata 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())));
@@ -450,13 +452,13 @@
if (!service->allowIsolated && is_multiuser_uid_isolated(ctx.uid)) {
LOG(WARNING) << "Isolated app with UID " << ctx.uid << " requested '" << name
<< "', but the service is not allowed for isolated apps.";
- return nullptr;
+ return os::ServiceWithMetadata();
}
out = service->binder;
}
if (!mAccess->canFind(ctx, name)) {
- return nullptr;
+ return os::ServiceWithMetadata();
}
if (!out && startIfNotFound) {
@@ -473,8 +475,11 @@
CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false));
service->guaranteeClient = true;
}
-
- return out;
+ os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
+ serviceWithMetadata.service = out;
+ serviceWithMetadata.isLazyService =
+ service ? service->dumpPriority & FLAG_IS_LAZY_SERVICE : false;
+ return serviceWithMetadata;
}
bool isValidServiceName(const std::string& name) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c92141b..964abee 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -114,7 +114,7 @@
void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it);
os::Service tryGetService(const std::string& name, bool startIfNotFound);
- sp<IBinder> tryGetBinder(const std::string& name, bool startIfNotFound);
+ os::ServiceWithMetadata 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,
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 95f459f..e620770 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -92,6 +92,11 @@
auto sm = getPermissiveServiceManager();
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_TRUE(sm->addService("lazyfoo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT |
+ IServiceManager::FLAG_IS_LAZY_SERVICE)
+ .isOk());
}
TEST(AddService, EmptyNameDisallowed) {
@@ -156,7 +161,7 @@
Service outA;
EXPECT_TRUE(sm->getService2("foo", &outA).isOk());
- EXPECT_EQ(serviceA, outA.get<Service::Tag::binder>());
+ EXPECT_EQ(serviceA, outA.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinderA;
EXPECT_TRUE(sm->getService("foo", &outBinderA).isOk());
EXPECT_EQ(serviceA, outBinderA);
@@ -168,7 +173,7 @@
Service outB;
EXPECT_TRUE(sm->getService2("foo", &outB).isOk());
- EXPECT_EQ(serviceB, outB.get<Service::Tag::binder>());
+ EXPECT_EQ(serviceB, outB.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinderB;
EXPECT_TRUE(sm->getService("foo", &outBinderB).isOk());
EXPECT_EQ(serviceB, outBinderB);
@@ -195,7 +200,7 @@
Service out;
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(service, out.get<Service::Tag::binder>());
+ EXPECT_EQ(service, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(service, outBinder);
@@ -206,7 +211,7 @@
Service out;
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+ EXPECT_EQ(nullptr, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(nullptr, outBinder);
@@ -227,7 +232,7 @@
Service out;
// returns nullptr but has OK status for legacy compatibility
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+ EXPECT_EQ(nullptr, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(nullptr, outBinder);
@@ -257,7 +262,7 @@
Service out;
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(service, out.get<Service::Tag::binder>());
+ EXPECT_EQ(service, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(service, outBinder);
@@ -289,7 +294,7 @@
Service out;
// returns nullptr but has OK status for legacy compatibility
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+ EXPECT_EQ(nullptr, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(nullptr, outBinder);
diff --git a/data/etc/android.hardware.bluetooth_le.channel_sounding.xml b/data/etc/android.hardware.bluetooth_le.channel_sounding.xml
new file mode 100644
index 0000000..f0ee5d9
--- /dev/null
+++ b/data/etc/android.hardware.bluetooth_le.channel_sounding.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!-- Adds the feature indicating support for the BLE Channel sounding -->
+<permissions>
+ <feature name="android.hardware.bluetooth_le.channel_sounding" />
+</permissions>
diff --git a/include/android/OWNERS b/include/android/OWNERS
index 64d7e54..9dfa279 100644
--- a/include/android/OWNERS
+++ b/include/android/OWNERS
@@ -5,4 +5,9 @@
per-file input_transfer_token.h = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
# CoGS
-per-file *luts* = file:platform/frameworks/base:/graphics/java/android/graphics/OWNERS
\ No newline at end of file
+per-file *luts* = file:platform/frameworks/base:/graphics/java/android/graphics/OWNERS
+
+# ADPF
+per-file performance_hint.h = file:platform/frameworks/base:/ADPF_OWNERS
+per-file system_health.h = file:platform/frameworks/base:/ADPF_OWNERS
+per-file thermal.h = file:platform/frameworks/base:/ADPF_OWNERS
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index bec3283..2622a01 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -318,7 +318,7 @@
/**
* Gets the token used by the platform to identify the frame timeline at the given \c index.
- * q
+ *
* Available since API level 33.
*
* \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
diff --git a/include/android/looper.h b/include/android/looper.h
index d80a366..8cf1396 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -90,20 +90,23 @@
ALOOPER_POLL_WAKE = -1,
/**
- * Result from ALooper_pollOnce() and ALooper_pollAll():
- * One or more callbacks were executed.
+ * Result from ALooper_pollOnce():
+ * One or more callbacks were executed. The poll may also have been
+ * explicitly woken by ALooper_wake().
*/
ALOOPER_POLL_CALLBACK = -2,
/**
* Result from ALooper_pollOnce() and ALooper_pollAll():
- * The timeout expired.
+ * The timeout expired. The poll may also have been explicitly woken by
+ * ALooper_wake().
*/
ALOOPER_POLL_TIMEOUT = -3,
/**
* Result from ALooper_pollOnce() and ALooper_pollAll():
- * An error occurred.
+ * An error occurred. The poll may also have been explicitly woken by
+ * ALooper_wake(()).
*/
ALOOPER_POLL_ERROR = -4,
};
@@ -182,10 +185,13 @@
* If the timeout is zero, returns immediately without blocking.
* If the timeout is negative, waits indefinitely until an event appears.
*
+ * **All return values may also imply ALOOPER_POLL_WAKE.** If you call this in a
+ * loop, you must treat all return values as if they also indicated
+ * ALOOPER_POLL_WAKE.
+ *
* Returns ALOOPER_POLL_WAKE if the poll was awoken using ALooper_wake() before
* the timeout expired and no callbacks were invoked and no other file
- * descriptors were ready. **All return values may also imply
- * ALOOPER_POLL_WAKE.**
+ * descriptors were ready.
*
* Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. The poll
* may also have been explicitly woken by ALooper_wake.
@@ -214,9 +220,9 @@
* data has been consumed or a file descriptor is available with no callback.
* This function will never return ALOOPER_POLL_CALLBACK.
*
- * This API cannot be used safely, but a safe alternative exists (see below). As
- * such, new builds will not be able to call this API and must migrate to the
- * safe API. Binary compatibility is preserved to support already-compiled apps.
+ * This API will not reliably respond to ALooper_wake. As such, this API is
+ * hidden and callers should migrate to ALooper_pollOnce. Binary compatibility
+ * is preserved to support already-compiled apps.
*
* \bug ALooper_pollAll will not wake in response to ALooper_wake calls if it
* also handles another event at the same time.
@@ -235,6 +241,8 @@
*
* This method can be called on any thread.
* This method returns immediately.
+ *
+ * \bug ALooper_pollAll will not reliably wake in response to ALooper_wake.
*/
void ALooper_wake(ALooper* looper);
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 7f9d2ed..1d7ad12 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -254,7 +254,7 @@
* The headroom threshold is used to interpret the possible thermal throttling status based on
* the headroom prediction. For example, if the headroom threshold for
* {@link ATHERMAL_STATUS_LIGHT} is 0.7, and a headroom prediction in 10s returns 0.75
- * (or {@code AThermal_getThermalHeadroom(10)=0.75}), one can expect that in 10 seconds the system
+ * (or `AThermal_getThermalHeadroom(10)=0.75`), one can expect that in 10 seconds the system
* could be in lightly throttled state if the workload remains the same. The app can consider
* taking actions according to the nearest throttling status the difference between the headroom and
* the threshold.
@@ -262,10 +262,10 @@
* For new devices it's guaranteed to have a single sensor, but for older devices with multiple
* sensors reporting different threshold values, the minimum threshold is taken to be conservative
* on predictions. Thus, when reading real-time headroom, it's not guaranteed that a real-time value
- * of 0.75 (or {@code AThermal_getThermalHeadroom(0)}=0.75) exceeding the threshold of 0.7 above
+ * of 0.75 (or `AThermal_getThermalHeadroom(0)`=0.75) exceeding the threshold of 0.7 above
* will always come with lightly throttled state
- * (or {@code AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_LIGHT}) but it can be lower
- * (or {@code AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_NONE}).
+ * (or `AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_LIGHT`) but it can be lower
+ * (or `AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_NONE`).
* While it's always guaranteed that the device won't be throttled heavier than the unmet
* threshold's state, so a real-time headroom of 0.75 will never come with
* {@link #ATHERMAL_STATUS_MODERATE} but always lower, and 0.65 will never come with
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 6548810..b26a194 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -275,7 +275,7 @@
* Return DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveMessage(InputMessage* msg);
+ android::base::Result<InputMessage> receiveMessage();
/* Tells whether there is a message in the channel available to be received.
*
diff --git a/include/powermanager/OWNERS b/include/powermanager/OWNERS
new file mode 100644
index 0000000..9f40e27
--- /dev/null
+++ b/include/powermanager/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:/ADPF_OWNERS
\ No newline at end of file
diff --git a/include/private/OWNERS b/include/private/OWNERS
new file mode 100644
index 0000000..37da96d
--- /dev/null
+++ b/include/private/OWNERS
@@ -0,0 +1,3 @@
+# ADPF
+per-file thermal_private.h = file:platform/frameworks/base:/ADPF_OWNERS
+per-file performance_hint_private.h = file:platform/frameworks/base:/ADPF_OWNERS
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2ef642a..aac369d 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -456,6 +456,28 @@
}
soong_config_module_type {
+ name: "libbinder_remove_cache_static_list_config",
+ module_type: "cc_defaults",
+ config_namespace: "libbinder",
+ bool_variables: ["release_libbinder_remove_cache_static_list"],
+ properties: [
+ "cflags",
+ ],
+}
+
+libbinder_remove_cache_static_list_config {
+ name: "libbinder_remove_cache_static_list_flag",
+ soong_config_variables: {
+ release_libbinder_remove_cache_static_list: {
+ cflags: ["-DLIBBINDER_REMOVE_CACHE_STATIC_LIST"],
+ conditions_default: {
+ cflags: ["-DNO_LIBBINDER_REMOVE_CACHE_STATIC_LIST"],
+ },
+ },
+ },
+}
+
+soong_config_module_type {
name: "libbinder_client_cache_config",
module_type: "cc_defaults",
config_namespace: "libbinder",
@@ -477,9 +499,35 @@
},
}
+soong_config_module_type {
+ name: "libbinder_addservice_cache_config",
+ module_type: "cc_defaults",
+ config_namespace: "libbinder",
+ bool_variables: ["release_libbinder_addservice_cache"],
+ properties: [
+ "cflags",
+ ],
+}
+
+libbinder_addservice_cache_config {
+ name: "libbinder_addservice_cache_flag",
+ soong_config_variables: {
+ release_libbinder_addservice_cache: {
+ cflags: ["-DLIBBINDER_ADDSERVICE_CACHE"],
+ conditions_default: {
+ cflags: ["-DNO_LIBBINDER_ADDSERVICE_CACHE"],
+ },
+ },
+ },
+}
+
cc_defaults {
name: "libbinder_kernel_defaults",
- defaults: ["libbinder_client_cache_flag"],
+ defaults: [
+ "libbinder_client_cache_flag",
+ "libbinder_addservice_cache_flag",
+ "libbinder_remove_cache_static_list_flag",
+ ],
srcs: [
"BufferedTextOutput.cpp",
"BackendUnifiedServiceManager.cpp",
@@ -801,6 +849,7 @@
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
"aidl/android/os/Service.aidl",
+ "aidl/android/os/ServiceWithMetadata.aidl",
"aidl/android/os/ServiceDebugInfo.aidl",
],
path: "aidl",
@@ -829,6 +878,7 @@
backend: {
rust: {
apex_available: [
+ "//apex_available:platform",
"com.android.virt",
],
enabled: true,
@@ -881,7 +931,6 @@
":__subpackages__",
"//packages/modules/Virtualization:__subpackages__",
"//device/google/cuttlefish/shared/minidroid:__subpackages__",
- "//system/software_defined_vehicle:__subpackages__",
"//visibility:any_system_partition",
],
}
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index d32eecd..34d5a09 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -16,6 +16,7 @@
#include "BackendUnifiedServiceManager.h"
#include <android/os/IAccessor.h>
+#include <android/os/IServiceManager.h>
#include <binder/RpcSession.h>
#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
@@ -30,6 +31,18 @@
constexpr bool kUseCache = false;
#endif
+#ifdef LIBBINDER_ADDSERVICE_CACHE
+constexpr bool kUseCacheInAddService = true;
+#else
+constexpr bool kUseCacheInAddService = false;
+#endif
+
+#ifdef LIBBINDER_REMOVE_CACHE_STATIC_LIST
+constexpr bool kRemoveStaticList = true;
+#else
+constexpr bool kRemoveStaticList = false;
+#endif
+
using AidlServiceManager = android::os::IServiceManager;
using android::os::IAccessor;
using binder::Status;
@@ -104,6 +117,13 @@
// go/keep-sorted end
};
+os::ServiceWithMetadata createServiceWithMetadata(const sp<IBinder>& service, bool isLazyService) {
+ os::ServiceWithMetadata out = os::ServiceWithMetadata();
+ out.service = service;
+ out.isLazyService = isLazyService;
+ return out;
+}
+
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
sp<ProcessState> self = ProcessState::selfOrNull();
if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) {
@@ -112,6 +132,7 @@
serviceName.c_str());
return false;
}
+ if (kRemoveStaticList) return true;
for (const char* name : kStaticCachableList) {
if (name == serviceName) {
return true;
@@ -125,31 +146,44 @@
if (!kUseCache) {
return Status::ok();
}
+
+ if (service.getTag() == os::Service::Tag::serviceWithMetadata) {
+ auto serviceWithMetadata = service.get<os::Service::Tag::serviceWithMetadata>();
+ return updateCache(serviceName, serviceWithMetadata.service,
+ serviceWithMetadata.isLazyService);
+ }
+ return Status::ok();
+}
+
+Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
+ const sp<IBinder>& binder, bool isServiceLazy) {
std::string traceStr;
+ // Don't cache if service is lazy
+ if (kRemoveStaticList && isServiceLazy) {
+ return Status::ok();
+ }
if (atrace_is_tag_enabled(ATRACE_TAG_AIDL)) {
traceStr = "BinderCacheWithInvalidation::updateCache : " + serviceName;
}
binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, traceStr.c_str());
-
- if (service.getTag() == os::Service::Tag::binder) {
- sp<IBinder> binder = service.get<os::Service::Tag::binder>();
- if (!binder) {
- binder::ScopedTrace
- aidlTrace(ATRACE_TAG_AIDL,
- "BinderCacheWithInvalidation::updateCache failed: binder_null");
- } else if (!binder->isBinderAlive()) {
- binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
- "BinderCacheWithInvalidation::updateCache failed: "
- "isBinderAlive_false");
- } else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) {
- binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
- "BinderCacheWithInvalidation::updateCache successful");
- return mCacheForGetService->setItem(serviceName, binder);
- } else {
- binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
- "BinderCacheWithInvalidation::updateCache failed: "
- "caching_not_enabled");
- }
+ if (!binder) {
+ binder::ScopedTrace
+ aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache failed: binder_null");
+ } else if (!binder->isBinderAlive()) {
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache failed: "
+ "isBinderAlive_false");
+ }
+ // If we reach here with kRemoveStaticList=true then we know service isn't lazy
+ else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) {
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache successful");
+ return mCacheForGetService->setItem(serviceName, binder);
+ } else {
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache failed: "
+ "caching_not_enabled");
}
return Status::ok();
}
@@ -162,7 +196,7 @@
sp<IBinder> item = mCacheForGetService->getItem(serviceName);
// TODO(b/363177618): Enable caching for binders which are always null.
if (item != nullptr && item->isBinderAlive()) {
- *_out = os::Service::make<os::Service::Tag::binder>(item);
+ *_out = createServiceWithMetadata(item, false);
return true;
}
return false;
@@ -177,7 +211,7 @@
sp<IBinder>* _aidl_return) {
os::Service service;
Status status = getService2(name, &service);
- *_aidl_return = service.get<os::Service::Tag::binder>();
+ *_aidl_return = service.get<os::Service::Tag::serviceWithMetadata>().service;
return status;
}
@@ -216,14 +250,16 @@
Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
const os::Service& in, os::Service* _out) {
switch (in.getTag()) {
- case os::Service::Tag::binder: {
- if (in.get<os::Service::Tag::binder>() == nullptr) {
+ case os::Service::Tag::serviceWithMetadata: {
+ auto serviceWithMetadata = in.get<os::Service::Tag::serviceWithMetadata>();
+ if (serviceWithMetadata.service == nullptr) {
// failed to find a service. Check to see if we have any local
// injected Accessors for this service.
os::Service accessor;
Status status = getInjectedAccessor(name, &accessor);
if (!status.isOk()) {
- *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ createServiceWithMetadata(nullptr, false));
return status;
}
if (accessor.getTag() == os::Service::Tag::accessor &&
@@ -244,7 +280,8 @@
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);
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ createServiceWithMetadata(nullptr, false));
return Status::ok();
}
auto request = [=] {
@@ -265,7 +302,8 @@
return Status::fromStatusT(status);
}
session->setSessionSpecificRoot(accessorBinder);
- *_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ createServiceWithMetadata(session->getRootObject(), false));
return Status::ok();
}
default: {
@@ -277,7 +315,13 @@
Status BackendUnifiedServiceManager::addService(const ::std::string& name,
const sp<IBinder>& service, bool allowIsolated,
int32_t dumpPriority) {
- return mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority);
+ Status status = mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority);
+ // mEnableAddServiceCache is true by default.
+ if (kUseCacheInAddService && mEnableAddServiceCache && status.isOk()) {
+ return updateCache(name, service,
+ dumpPriority & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE);
+ }
+ return status;
}
Status BackendUnifiedServiceManager::listServices(int32_t dumpPriority,
::std::vector<::std::string>* _aidl_return) {
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index abc0eda..6a0d06a 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -105,8 +105,7 @@
binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
"BinderCacheWithInvalidation::setItem Successfully Cached");
std::lock_guard<std::mutex> lock(mCacheMutex);
- Entry entry = {.service = item, .deathRecipient = deathRecipient};
- mCache[key] = entry;
+ mCache[key] = {.service = item, .deathRecipient = deathRecipient};
return binder::Status::ok();
}
@@ -147,17 +146,21 @@
const sp<IBinder>& service) override;
binder::Status getServiceDebugInfo(::std::vector<os::ServiceDebugInfo>* _aidl_return) override;
+ void enableAddServiceCache(bool value) { mEnableAddServiceCache = value; }
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
return mTheRealServiceManager->getInterfaceDescriptor();
}
private:
+ bool mEnableAddServiceCache = true;
std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService;
sp<os::IServiceManager> mTheRealServiceManager;
binder::Status toBinderService(const ::std::string& name, const os::Service& in,
os::Service* _out);
binder::Status updateCache(const std::string& serviceName, const os::Service& service);
+ binder::Status updateCache(const std::string& serviceName, const sp<IBinder>& binder,
+ bool isLazyService);
bool returnIfCached(const std::string& serviceName, os::Service* _out);
};
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 39d8c24..53435c3 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -127,6 +127,8 @@
}
IBinder* onAsBinder() override { return IInterface::asBinder(mUnifiedServiceManager).get(); }
+ void enableAddServiceCache(bool value) { mUnifiedServiceManager->enableAddServiceCache(value); }
+
protected:
sp<BackendUnifiedServiceManager> mUnifiedServiceManager;
// AidlRegistrationCallback -> services that its been registered for
@@ -150,7 +152,8 @@
virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
Service service;
Status status = mUnifiedServiceManager->getService2(name, &service);
- *_aidl_return = service.get<Service::Tag::binder>();
+ auto serviceWithMetadata = service.get<Service::Tag::serviceWithMetadata>();
+ *_aidl_return = serviceWithMetadata.service;
return status;
}
};
@@ -605,7 +608,7 @@
if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
return nullptr;
}
- return ret.get<Service::Tag::binder>();
+ return ret.get<Service::Tag::serviceWithMetadata>().service;
}
status_t CppBackendShim::addService(const String16& name, const sp<IBinder>& service,
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index 0f0af0b..27cfe0c 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -19,7 +19,6 @@
#include <android/os/BnClientCallback.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/LazyServiceRegistrar.h>
namespace android {
@@ -134,6 +133,12 @@
std::string regStr = (reRegister) ? "Re-registering" : "Registering";
ALOGI("%s service %s", regStr.c_str(), name.c_str());
+ if (dumpFlags & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE) {
+ ALOGW("FLAG_IS_LAZY_SERVICE flag already set. This should only be set by "
+ "ClientCounterCallbackImpl in LazyServiceRegistrar");
+ }
+ dumpFlags |= android::os::IServiceManager::FLAG_IS_LAZY_SERVICE;
+
if (Status status = manager->addService(name.c_str(), service, allowIsolated, dumpFlags);
!status.isOk()) {
ALOGE("Failed to register service %s (%s)", name.c_str(), status.toString8().c_str());
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index ab44957..9e5e79f 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -67,15 +67,10 @@
"name": "fuzz_service_test"
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-filter": "android.os.cts.BinderTest"
- },
- {
- "include-filter": "android.os.cts.ParcelTest"
- }
- ]
+ "name": "CtsOsTestCases_ParcelAndBinderTests"
+ },
+ {
+ "name": "FrameworksCoreTests_all_binder"
},
{
"name": "libbinder_rs-internal_test"
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 1d1f84f..69edef8 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -49,6 +49,8 @@
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
| DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+ const int FLAG_IS_LAZY_SERVICE = 1 << 30;
+
/* Allows services to dump sections in protobuf format. */
const int DUMP_FLAG_PROTO = 1 << 4;
@@ -61,7 +63,8 @@
*
* Returns null if the service does not exist.
*
- * @deprecated TODO(b/355394904): Use getService2 instead.
+ * @deprecated TODO(b/355394904): Use getService2 instead. This does not return metadata
+ * that is included in ServiceWithMetadata
*/
@UnsupportedAppUsage
@nullable IBinder getService(@utf8InCpp String name);
diff --git a/libs/binder/aidl/android/os/Service.aidl b/libs/binder/aidl/android/os/Service.aidl
index 4c52109..3bc6588 100644
--- a/libs/binder/aidl/android/os/Service.aidl
+++ b/libs/binder/aidl/android/os/Service.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.os.ServiceWithMetadata;
+
/**
* Service is a union of different service types that can be returned
* by the internal {@link ServiceManager#getService(name)} API.
@@ -23,6 +25,6 @@
* @hide
*/
union Service {
- @nullable IBinder binder;
+ ServiceWithMetadata serviceWithMetadata;
@nullable IBinder accessor;
}
\ No newline at end of file
diff --git a/libs/binder/aidl/android/os/ServiceWithMetadata.aidl b/libs/binder/aidl/android/os/ServiceWithMetadata.aidl
new file mode 100644
index 0000000..96f76ff
--- /dev/null
+++ b/libs/binder/aidl/android/os/ServiceWithMetadata.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 binder with metadata.
+ * @hide
+ */
+parcelable ServiceWithMetadata {
+ /**
+ * IBinder to service
+ */
+ @nullable IBinder service;
+ /**
+ * boolean if the IBinder can be cached by client.
+ */
+ boolean isLazyService;
+}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 81f7cdb..7d79baa 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -150,6 +150,12 @@
int pid;
};
virtual std::vector<ServiceDebugInfo> getServiceDebugInfo() = 0;
+
+ /**
+ * Directly enable or disable caching binder during addService calls.
+ * Only used for testing. This is enabled by default.
+ */
+ virtual void enableAddServiceCache(bool value) = 0;
};
LIBBINDER_EXPORTED sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp
index 53ab68e..bb5989d 100644
--- a/libs/binder/ndk/binder_rpc.cpp
+++ b/libs/binder/ndk/binder_rpc.cpp
@@ -107,16 +107,20 @@
ABinderRpc_AccessorProvider_getAccessorCallback provider,
const char* const* const instances, size_t numInstances, void* data,
ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) {
- if (provider == nullptr) {
- ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider");
- return nullptr;
- }
if (data && onDelete == nullptr) {
ALOGE("If a non-null data ptr is passed to ABinderRpc_registerAccessorProvider, then a "
"ABinderRpc_AccessorProviderUserData_deleteCallback must also be passed to delete "
"the data object once the ABinderRpc_AccessorProvider is removed.");
return nullptr;
}
+ // call the onDelete when the last reference of this goes away (when the
+ // last reference to the generate std::function goes away).
+ std::shared_ptr<OnDeleteProviderHolder> onDeleteHolder =
+ std::make_shared<OnDeleteProviderHolder>(data, onDelete);
+ if (provider == nullptr) {
+ ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider");
+ return nullptr;
+ }
if (numInstances == 0 || instances == nullptr) {
ALOGE("No instances passed to ABinderRpc_registerAccessorProvider. numInstances: %zu",
numInstances);
@@ -126,10 +130,6 @@
for (size_t i = 0; i < numInstances; i++) {
instanceStrings.emplace(instances[i]);
}
- // call the onDelete when the last reference of this goes away (when the
- // last reference to the generate std::function goes away).
- std::shared_ptr<OnDeleteProviderHolder> onDeleteHolder =
- std::make_shared<OnDeleteProviderHolder>(data, onDelete);
android::RpcAccessorProvider generate = [provider,
onDeleteHolder](const String16& name) -> sp<IBinder> {
ABinderRpc_Accessor* accessor = provider(String8(name).c_str(), onDeleteHolder->mData);
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index cc4943b..f5df8d5 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -34,6 +34,7 @@
ADD_SERVICE_DUMP_FLAG_PRIORITY_HIGH = 1 << 2,
ADD_SERVICE_DUMP_FLAG_PRIORITY_NORMAL = 1 << 3,
ADD_SERVICE_DUMP_FLAG_PRIORITY_DEFAULT = 1 << 4,
+ // All other bits are reserved for internal usage
};
/**
diff --git a/libs/binder/ndk/include_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h
index 7d54e2d..1318889 100644
--- a/libs/binder/ndk/include_platform/android/binder_rpc.h
+++ b/libs/binder/ndk/include_platform/android/binder_rpc.h
@@ -139,6 +139,8 @@
* registered. In the error case of duplicate instances, if data was
* provided with a ABinderRpc_AccessorProviderUserData_deleteCallback,
* the callback will be called to delete the data.
+ * If nullptr is returned, ABinderRpc_AccessorProviderUserData_deleteCallback
+ * will be called on data immediately.
* Otherwise returns a pointer to the ABinderRpc_AccessorProvider that
* can be used to remove with ABinderRpc_unregisterAccessorProvider.
*/
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4d691f8..a637165 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -164,96 +164,53 @@
LIBBINDER_NDK35 { # introduced=VanillaIceCream
global:
APersistableBundle_readFromParcel;
- APersistableBundle_readFromParcel; # llndk=202404
APersistableBundle_writeToParcel;
- APersistableBundle_writeToParcel; # llndk=202404
APersistableBundle_new;
- APersistableBundle_new; # llndk=202404
APersistableBundle_dup;
- APersistableBundle_dup; # llndk=202404
APersistableBundle_delete;
- APersistableBundle_delete; # llndk=202404
APersistableBundle_isEqual;
- APersistableBundle_isEqual; # llndk=202404
APersistableBundle_size;
- APersistableBundle_size; # llndk=202404
APersistableBundle_erase;
- APersistableBundle_erase; # llndk=202404
APersistableBundle_putBoolean;
- APersistableBundle_putBoolean; # llndk=202404
APersistableBundle_putInt;
- APersistableBundle_putInt; # llndk=202404
APersistableBundle_putLong;
- APersistableBundle_putLong; # llndk=202404
APersistableBundle_putDouble;
- APersistableBundle_putDouble; # llndk=202404
APersistableBundle_putString;
- APersistableBundle_putString; # llndk=202404
APersistableBundle_putBooleanVector;
- APersistableBundle_putBooleanVector; # llndk=202404
APersistableBundle_putIntVector;
- APersistableBundle_putIntVector; # llndk=202404
APersistableBundle_putLongVector;
- APersistableBundle_putLongVector; # llndk=202404
APersistableBundle_putDoubleVector;
- APersistableBundle_putDoubleVector; # llndk=202404
APersistableBundle_putStringVector;
- APersistableBundle_putStringVector; # llndk=202404
APersistableBundle_putPersistableBundle;
- APersistableBundle_putPersistableBundle; # llndk=202404
APersistableBundle_getBoolean;
- APersistableBundle_getBoolean; # llndk=202404
APersistableBundle_getInt;
- APersistableBundle_getInt; # llndk=202404
APersistableBundle_getLong;
- APersistableBundle_getLong; # llndk=202404
APersistableBundle_getDouble;
- APersistableBundle_getDouble; # llndk=202404
APersistableBundle_getString;
- APersistableBundle_getString; # llndk=202404
APersistableBundle_getBooleanVector;
- APersistableBundle_getBooleanVector; # llndk=202404
APersistableBundle_getIntVector;
- APersistableBundle_getIntVector; # llndk=202404
APersistableBundle_getLongVector;
- APersistableBundle_getLongVector; # llndk=202404
APersistableBundle_getDoubleVector;
- APersistableBundle_getDoubleVector; # llndk=202404
APersistableBundle_getStringVector;
- APersistableBundle_getStringVector; # llndk=202404
APersistableBundle_getPersistableBundle;
- APersistableBundle_getPersistableBundle; # llndk=202404
APersistableBundle_getBooleanKeys;
- APersistableBundle_getBooleanKeys; # llndk=202404
APersistableBundle_getIntKeys;
- APersistableBundle_getIntKeys; # llndk=202404
APersistableBundle_getLongKeys;
- APersistableBundle_getLongKeys; # llndk=202404
APersistableBundle_getDoubleKeys;
- APersistableBundle_getDoubleKeys; # llndk=202404
APersistableBundle_getStringKeys;
- APersistableBundle_getStringKeys; # llndk=202404
APersistableBundle_getBooleanVectorKeys;
- APersistableBundle_getBooleanVectorKeys; # llndk=202404
APersistableBundle_getIntVectorKeys;
- APersistableBundle_getIntVectorKeys; # llndk=202404
APersistableBundle_getLongVectorKeys;
- APersistableBundle_getLongVectorKeys; # llndk=202404
APersistableBundle_getDoubleVectorKeys;
- APersistableBundle_getDoubleVectorKeys; # llndk=202404
APersistableBundle_getStringVectorKeys;
- APersistableBundle_getStringVectorKeys; # llndk=202404
APersistableBundle_getPersistableBundleKeys;
- APersistableBundle_getPersistableBundleKeys; # llndk=202404
- AServiceManager_openDeclaredPassthroughHal; # systemapi llndk=202404
+ AServiceManager_openDeclaredPassthroughHal; # systemapi llndk
};
LIBBINDER_NDK36 { # introduced=36
global:
AIBinder_Class_setTransactionCodeToFunctionNameMap;
- AIBinder_Class_setTransactionCodeToFunctionNameMap; # llndk=202504
AIBinder_Class_getFunctionName;
- AIBinder_Class_getFunctionName; # llndk=202504
ABinderRpc_registerAccessorProvider; # systemapi
ABinderRpc_unregisterAccessorProvider; # systemapi
ABinderRpc_Accessor_new; # systemapi
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 174fe8a..4036551 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -27,7 +27,6 @@
visibility: [
"//device/google/cuttlefish/shared/minidroid/sample",
"//packages/modules/Virtualization:__subpackages__",
- "//system/software_defined_vehicle:__subpackages__",
],
apex_available: [
"//apex_available:platform",
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 14493db..1b24b0a 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -126,7 +126,7 @@
#[cfg(not(any(trusty, android_ndk)))]
pub use state::{ProcessState, ThreadState};
#[cfg(not(any(android_vendor, android_vndk, android_ndk)))]
-pub use system_only::{delegate_accessor, Accessor, ConnectionInfo};
+pub use system_only::{delegate_accessor, Accessor, AccessorProvider, ConnectionInfo};
/// Binder result containing a [`Status`] on error.
pub type Result<T> = std::result::Result<T, Status>;
diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs
index 9833cbe..1a58d6b 100644
--- a/libs/binder/rust/src/system_only.rs
+++ b/libs/binder/rust/src/system_only.rs
@@ -91,6 +91,32 @@
Accessor { accessor }
}
+ /// Creates a new Accessor instance based on an existing Accessor's binder.
+ /// This is useful when the Accessor instance is hosted in another process
+ /// that has the permissions to create the socket connection FD.
+ ///
+ /// The `instance` argument must match the instance that the original Accessor
+ /// is responsible for.
+ /// `instance` must not contain null bytes and is used to create a CString to
+ /// pass through FFI.
+ /// The `binder` argument must be a valid binder from an Accessor
+ pub fn from_binder(instance: &str, binder: SpIBinder) -> Option<Accessor> {
+ let inst = CString::new(instance).unwrap();
+
+ // Safety: All `SpIBinder` objects (the `binder` argument) hold a valid pointer
+ // to an `AIBinder` that is guaranteed to remain valid for the lifetime of the
+ // SpIBinder. `ABinderRpc_Accessor_fromBinder` creates a new pointer to that binder
+ // that it is responsible for.
+ // The `inst` argument is a new CString that will copied by
+ // `ABinderRpc_Accessor_fromBinder` and not modified.
+ let accessor =
+ unsafe { sys::ABinderRpc_Accessor_fromBinder(inst.as_ptr(), binder.as_raw()) };
+ if accessor.is_null() {
+ return None;
+ }
+ Some(Accessor { accessor })
+ }
+
/// Get the underlying binder for this Accessor for when it needs to be either
/// registered with service manager or sent to another process.
pub fn as_binder(&self) -> Option<SpIBinder> {
@@ -100,17 +126,36 @@
unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) }
}
+ /// Release the underlying ABinderRpc_Accessor pointer for use with the ndk API
+ /// This gives up ownership of the ABinderRpc_Accessor and it is the responsibility of
+ /// the caller to delete it with ABinderRpc_Accessor_delete
+ ///
+ /// # Safety
+ ///
+ /// - The returned `ABinderRpc_Accessor` pointer is now owned by the caller, who must
+ /// call `ABinderRpc_Accessor_delete` to delete the object.
+ /// - This `Accessor` object is now useless after `release` so it can be dropped.
+ unsafe fn release(mut self) -> *mut sys::ABinderRpc_Accessor {
+ if self.accessor.is_null() {
+ log::error!("Attempting to release an Accessor that was already released");
+ return ptr::null_mut();
+ }
+ let ptr = self.accessor;
+ self.accessor = ptr::null_mut();
+ ptr
+ }
+
/// Callback invoked from C++ when the connection info is needed.
///
/// # Safety
///
- /// The `instance` parameter must be a non-null pointer to a valid C string for
- /// CStr::from_ptr. The memory must contain a valid null terminator at the end of
- /// the string within isize::MAX from the pointer. The memory must not be mutated for
- /// the duration of this function call and must be valid for reads from the pointer
- /// to the null terminator.
- /// The `cookie` parameter must be the cookie for an `Arc<F>` and
- /// the caller must hold a ref-count to it.
+ /// - The `instance` parameter must be a non-null pointer to a valid C string for
+ /// CStr::from_ptr. The memory must contain a valid null terminator at the end of
+ /// the string within isize::MAX from the pointer. The memory must not be mutated for
+ /// the duration of this function call and must be valid for reads from the pointer
+ /// to the null terminator.
+ /// - The `cookie` parameter must be the cookie for an `Arc<F>` and
+ /// the caller must hold a ref-count to it.
unsafe extern "C" fn connection_info<F>(
instance: *const c_char,
cookie: *mut c_void,
@@ -172,8 +217,8 @@
///
/// # Safety
///
- /// The `cookie` parameter must be the cookie for an `Arc<F>` and
- /// the owner must give up a ref-count to it.
+ /// - The `cookie` parameter must be the cookie for an `Arc<F>` and
+ /// the owner must give up a ref-count to it.
unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
where
F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
@@ -185,6 +230,10 @@
impl Drop for Accessor {
fn drop(&mut self) {
+ if self.accessor.is_null() {
+ // This Accessor was already released.
+ return;
+ }
// Safety: `self.accessor` is always a valid, owned
// `ABinderRpc_Accessor` pointer returned by
// `ABinderRpc_Accessor_new` when `self` was created. This delete
@@ -218,3 +267,140 @@
// point, so can be safely passed to `SpIBinder::from_raw`.
Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") })
}
+
+/// Rust wrapper around ABinderRpc_AccessorProvider objects for RPC binder service management.
+///
+/// Dropping the `AccessorProvider` will drop/unregister the underlying object.
+#[derive(Debug)]
+pub struct AccessorProvider {
+ accessor_provider: *mut sys::ABinderRpc_AccessorProvider,
+}
+
+/// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is
+/// `Sync` and `Send`. As
+/// `ABinderRpc_AccessorProvider` is threadsafe, this structure is too.
+/// The Fn owned the AccessorProvider has `Sync` and `Send` properties
+unsafe impl Send for AccessorProvider {}
+
+/// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is
+/// `Sync` and `Send`. As `ABinderRpc_AccessorProvider` is threadsafe, this structure is too.
+/// The Fn owned the AccessorProvider has `Sync` and `Send` properties
+unsafe impl Sync for AccessorProvider {}
+
+impl AccessorProvider {
+ /// Create a new `AccessorProvider` that will give libbinder `Accessors` in order to
+ /// connect to binder services over sockets.
+ ///
+ /// `instances` is a list of all instances that this `AccessorProvider` is responsible for.
+ /// It is declaring these instances as available to this process and will return
+ /// `Accessor` objects for them when libbinder calls the `provider` callback.
+ /// `provider` is the callback that libbinder will call when a service is being requested.
+ /// The callback takes a `&str` argument representing the service that is being requested.
+ /// See the `ABinderRpc_AccessorProvider_getAccessorCallback` for the C++ equivalent.
+ pub fn new<F>(instances: &[String], provider: F) -> Option<AccessorProvider>
+ where
+ F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
+ {
+ let callback: *mut c_void = Arc::into_raw(Arc::new(provider)) as *mut c_void;
+ let c_str_instances: Vec<CString> =
+ instances.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect();
+ let mut c_instances: Vec<*const c_char> =
+ c_str_instances.iter().map(|s| s.as_ptr()).collect();
+ let num_instances: usize = c_instances.len();
+ // Safety:
+ // - The function pointer for the first argument is a valid `get_accessor` callback.
+ // - This call returns an owned `ABinderRpc_AccessorProvider` pointer which
+ // must be destroyed via `ABinderRpc_unregisterAccessorProvider` when no longer
+ // needed.
+ // - When the underlying ABinderRpc_AccessorProvider is deleted, it will call
+ // the `cookie_decr_refcount` callback on the `callback` pointer to release its
+ // strong ref.
+ // - The `c_instances` vector is not modified by the function
+ let accessor_provider = unsafe {
+ sys::ABinderRpc_registerAccessorProvider(
+ Some(Self::get_accessor::<F>),
+ c_instances.as_mut_ptr(),
+ num_instances,
+ callback,
+ Some(Self::accessor_cookie_decr_refcount::<F>),
+ )
+ };
+
+ if accessor_provider.is_null() {
+ return None;
+ }
+ Some(AccessorProvider { accessor_provider })
+ }
+
+ /// Callback invoked from C++ when an Accessor is needed.
+ ///
+ /// # Safety
+ ///
+ /// - libbinder guarantees the `instance` argument is a valid C string if it's not null.
+ /// - The `cookie` pointer is same pointer that we pass to ABinderRpc_registerAccessorProvider
+ /// in AccessorProvider.new() which is the closure that we will delete with
+ /// self.accessor_cookie_decr_refcount when unregistering the AccessorProvider.
+ unsafe extern "C" fn get_accessor<F>(
+ instance: *const c_char,
+ cookie: *mut c_void,
+ ) -> *mut binder_ndk_sys::ABinderRpc_Accessor
+ where
+ F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
+ {
+ if cookie.is_null() || instance.is_null() {
+ log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!");
+ return ptr::null_mut();
+ }
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
+
+ let inst = {
+ // Safety: The caller in libbinder_ndk will have already verified this is a valid
+ // C string
+ match unsafe { CStr::from_ptr(instance) }.to_str() {
+ Ok(s) => s,
+ Err(err) => {
+ log::error!("Failed to get a valid C string! {err:?}");
+ return ptr::null_mut();
+ }
+ }
+ };
+
+ match callback(inst) {
+ Some(a) => {
+ // Safety: This is giving up ownership of this ABinderRpc_Accessor
+ // to the caller of this function (libbinder) and it is responsible
+ // for deleting it.
+ unsafe { a.release() }
+ }
+ None => ptr::null_mut(),
+ }
+ }
+
+ /// Callback that decrements the ref-count.
+ /// This is invoked from C++ when the provider is unregistered.
+ ///
+ /// # Safety
+ ///
+ /// - The `cookie` parameter must be the cookie for an `Arc<F>` and
+ /// the owner must give up a ref-count to it.
+ unsafe extern "C" fn accessor_cookie_decr_refcount<F>(cookie: *mut c_void)
+ where
+ F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
+ {
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ unsafe { Arc::decrement_strong_count(cookie as *const F) };
+ }
+}
+
+impl Drop for AccessorProvider {
+ fn drop(&mut self) {
+ // Safety: `self.accessor_provider` is always a valid, owned
+ // `ABinderRpc_AccessorProvider` pointer returned by
+ // `ABinderRpc_registerAccessorProvider` when `self` was created. This delete
+ // method can only be called once when `self` is dropped.
+ unsafe {
+ sys::ABinderRpc_unregisterAccessorProvider(self.accessor_provider);
+ }
+ }
+}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 489fa0a..da4f128 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -384,8 +384,8 @@
use std::time::Duration;
use binder::{
- Accessor, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder,
- StatusCode, Strong,
+ Accessor, AccessorProvider, BinderFeatures, DeathRecipient, FromIBinder, IBinder,
+ Interface, SpIBinder, StatusCode, Strong,
};
// Import from impl API for testing only, should not be necessary as long as
// you are using AIDL.
@@ -982,6 +982,90 @@
assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND));
}
+ #[test]
+ fn test_accessor_provider_simple() {
+ let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
+ let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
+ assert!(accessor.is_some());
+ }
+
+ #[test]
+ fn test_accessor_provider_no_instance() {
+ let instances: Vec<String> = vec![];
+ let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
+ assert!(accessor.is_none());
+ }
+
+ #[test]
+ fn test_accessor_provider_double_register() {
+ let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
+ let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
+ assert!(accessor.is_some());
+ let accessor2 = AccessorProvider::new(&instances, move |_inst: &str| None);
+ assert!(accessor2.is_none());
+ }
+
+ #[test]
+ fn test_accessor_provider_register_drop_register() {
+ let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
+ {
+ let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
+ assert!(accessor.is_some());
+ // accessor drops and unregisters the provider
+ }
+ {
+ let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
+ assert!(accessor.is_some());
+ }
+ }
+
+ #[test]
+ fn test_accessor_provider_callback_destruction() {
+ let deleted: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
+ let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
+ {
+ let accessor: Option<AccessorProvider>;
+ {
+ let helper = ToBeDeleted { deleted: deleted.clone() };
+ accessor = AccessorProvider::new(&instances, move |_inst: &str| {
+ let _ = &helper;
+ None
+ });
+ }
+ assert!(accessor.is_some());
+ assert!(!deleted.load(Ordering::Relaxed));
+ }
+ assert!(deleted.load(Ordering::Relaxed));
+ }
+
+ #[test]
+ fn test_accessor_from_accessor_binder() {
+ let get_connection_info = move |_instance: &str| None;
+ let accessor = Accessor::new("foo.service", get_connection_info);
+ let accessor2 =
+ Accessor::from_binder("foo.service", accessor.as_binder().unwrap()).unwrap();
+ assert_eq!(accessor.as_binder(), accessor2.as_binder());
+ }
+
+ #[test]
+ fn test_accessor_from_non_accessor_binder() {
+ let service_name = "rust_test_ibinder";
+ let _process = ScopedServiceProcess::new(service_name);
+ let binder = binder::get_service(service_name).unwrap();
+ assert!(binder.is_binder_alive());
+
+ let accessor = Accessor::from_binder("rust_test_ibinder", binder);
+ assert!(accessor.is_none());
+ }
+
+ #[test]
+ fn test_accessor_from_wrong_accessor_binder() {
+ let get_connection_info = move |_instance: &str| None;
+ let accessor = Accessor::new("foo.service", get_connection_info);
+ let accessor2 = Accessor::from_binder("NOT.foo.service", accessor.as_binder().unwrap());
+ assert!(accessor2.is_none());
+ }
+
#[tokio::test]
async fn reassociate_rust_binder_async() {
let service_name = "testing_service";
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 28a3f65..c21d7c6 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -70,7 +70,11 @@
static_libs: [
"libfakeservicemanager",
],
- defaults: ["libbinder_client_cache_flag"],
+ defaults: [
+ "libbinder_client_cache_flag",
+ "libbinder_addservice_cache_flag",
+ "libbinder_remove_cache_static_list_flag",
+ ],
test_suites: ["general-tests"],
require_root: true,
}
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
index c5ad793..19395c2 100644
--- a/libs/binder/tests/binderCacheUnitTest.cpp
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -34,6 +34,18 @@
constexpr bool kUseLibbinderCache = false;
#endif
+#ifdef LIBBINDER_ADDSERVICE_CACHE
+constexpr bool kUseCacheInAddService = true;
+#else
+constexpr bool kUseCacheInAddService = false;
+#endif
+
+#ifdef LIBBINDER_REMOVE_CACHE_STATIC_LIST
+constexpr bool kRemoveStaticList = true;
+#else
+constexpr bool kRemoveStaticList = false;
+#endif
+
// A service name which is in the static list of cachable services
const String16 kCachedServiceName = String16("isub");
@@ -63,8 +75,10 @@
MockAidlServiceManager() : innerSm() {}
binder::Status checkService(const ::std::string& name, os::Service* _out) override {
- sp<IBinder> binder = innerSm.getService(String16(name.c_str()));
- *_out = os::Service::make<os::Service::Tag::binder>(binder);
+ os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
+ serviceWithMetadata.service = innerSm.getService(String16(name.c_str()));
+ serviceWithMetadata.isLazyService = false;
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(serviceWithMetadata);
return binder::Status::ok();
}
@@ -74,14 +88,127 @@
innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority));
}
+ void clearServices() { innerSm.clear(); }
+
FakeServiceManager innerSm;
};
+// Returns services with isLazyService flag as true.
+class MockAidlServiceManager2 : public os::IServiceManagerDefault {
+public:
+ MockAidlServiceManager2() : innerSm() {}
+
+ binder::Status checkService(const ::std::string& name, os::Service* _out) override {
+ os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
+ serviceWithMetadata.service = innerSm.getService(String16(name.c_str()));
+ serviceWithMetadata.isLazyService = true;
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(serviceWithMetadata);
+ return binder::Status::ok();
+ }
+
+ binder::Status addService(const std::string& name, const sp<IBinder>& service,
+ bool allowIsolated, int32_t dumpPriority) override {
+ return binder::Status::fromStatusT(
+ innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority));
+ }
+
+ void clearServices() { innerSm.clear(); }
+
+ FakeServiceManager innerSm;
+};
+
+class LibbinderCacheRemoveStaticList : public ::testing::Test {
+protected:
+ void SetUp() override {
+ fakeServiceManager = sp<MockAidlServiceManager2>::make();
+ mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
+ mServiceManager->enableAddServiceCache(true);
+ }
+ void TearDown() override {}
+
+public:
+ void cacheAddServiceAndConfirmCacheMiss(const sp<IBinder>& binder1) {
+ // Add a service. This shouldn't cache it.
+ EXPECT_EQ(OK,
+ mServiceManager->addService(kCachedServiceName, binder1,
+ /*allowIsolated = */ false,
+ android::os::IServiceManager::FLAG_IS_LAZY_SERVICE));
+ // Try to populate cache. Cache shouldn't be updated.
+ EXPECT_EQ(binder1, mServiceManager->checkService(kCachedServiceName));
+ fakeServiceManager->clearServices();
+ EXPECT_EQ(nullptr, mServiceManager->checkService(kCachedServiceName));
+ }
+
+ sp<MockAidlServiceManager2> fakeServiceManager;
+ sp<android::IServiceManager> mServiceManager;
+};
+
+TEST_F(LibbinderCacheRemoveStaticList, AddLocalServiceAndConfirmCacheMiss) {
+ if (!kRemoveStaticList) {
+ GTEST_SKIP() << "Skipping as feature is not enabled";
+ return;
+ }
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ cacheAddServiceAndConfirmCacheMiss(binder1);
+}
+
+TEST_F(LibbinderCacheRemoveStaticList, AddRemoteServiceAndConfirmCacheMiss) {
+ if (!kRemoveStaticList) {
+ GTEST_SKIP() << "Skipping as feature is not enabled";
+ return;
+ }
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ ASSERT_NE(binder1, nullptr);
+ cacheAddServiceAndConfirmCacheMiss(binder1);
+}
+
+class LibbinderCacheAddServiceTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ fakeServiceManager = sp<MockAidlServiceManager>::make();
+ mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
+ mServiceManager->enableAddServiceCache(true);
+ }
+
+ void TearDown() override {}
+
+public:
+ void cacheAddServiceAndConfirmCacheHit(const sp<IBinder>& binder1) {
+ // Add a service. This also caches it.
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+ // remove services from fakeservicemanager
+ fakeServiceManager->clearServices();
+
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ if (kUseCacheInAddService && kUseLibbinderCache) {
+ // If cache is enabled, we should get the binder.
+ EXPECT_EQ(binder1, result);
+ } else {
+ // If cache is disabled, then we should get the null binder
+ EXPECT_EQ(nullptr, result);
+ }
+ }
+ sp<MockAidlServiceManager> fakeServiceManager;
+ sp<android::IServiceManager> mServiceManager;
+};
+
+TEST_F(LibbinderCacheAddServiceTest, AddLocalServiceAndConfirmCacheHit) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ cacheAddServiceAndConfirmCacheHit(binder1);
+}
+
+TEST_F(LibbinderCacheAddServiceTest, AddRemoteServiceAndConfirmCacheHit) {
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ ASSERT_NE(binder1, nullptr);
+ cacheAddServiceAndConfirmCacheHit(binder1);
+}
+
class LibbinderCacheTest : public ::testing::Test {
protected:
void SetUp() override {
- sp<MockAidlServiceManager> sm = sp<MockAidlServiceManager>::make();
- mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(sm);
+ fakeServiceManager = sp<MockAidlServiceManager>::make();
+ mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
+ mServiceManager->enableAddServiceCache(false);
}
void TearDown() override {}
@@ -108,6 +235,7 @@
}
}
+ sp<MockAidlServiceManager> fakeServiceManager;
sp<android::IServiceManager> mServiceManager;
};
@@ -180,7 +308,13 @@
EXPECT_EQ(binder2, result);
}
+// TODO(b/333854840): Remove this test removing the static list
TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) {
+ if (kRemoveStaticList) {
+ GTEST_SKIP() << "Skipping test as static list is disabled";
+ return;
+ }
+
sp<IBinder> binder1 = sp<BBinder>::make();
sp<IBinder> binder2 = sp<BBinder>::make();
String16 serviceName = String16("NewLibbinderCacheTest");
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index ec2f50c..e56b7cf 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -220,6 +220,8 @@
ASSERT_GT(m_serverpid, 0);
sp<IServiceManager> sm = defaultServiceManager();
+ // disable caching during addService.
+ sm->enableAddServiceCache(false);
//printf("%s: pid %d, get service\n", __func__, m_pid);
LIBBINDER_IGNORE("-Wdeprecated-declarations")
m_server = sm->getService(binderLibTestServiceName);
@@ -295,6 +297,9 @@
virtual void SetUp() {
m_server = static_cast<BinderLibTestEnv *>(binder_env)->getServer();
IPCThreadState::self()->restoreCallingWorkSource(0);
+ sp<IServiceManager> sm = defaultServiceManager();
+ // disable caching during addService.
+ sm->enableAddServiceCache(false);
}
virtual void TearDown() {
}
@@ -1644,6 +1649,7 @@
TEST(ServiceNotifications, Unregister) {
auto sm = defaultServiceManager();
+ sm->enableAddServiceCache(false);
using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback {
void onServiceRegistration(const String16 &, const sp<IBinder> &) override {}
@@ -2374,6 +2380,8 @@
status_t ret;
sp<IServiceManager> sm = defaultServiceManager();
+ sm->enableAddServiceCache(false);
+
BinderLibTestService* testServicePtr;
{
sp<BinderLibTestService> testService = new BinderLibTestService(index);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 506fc71..da5a8e3 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1400,6 +1400,26 @@
EXPECT_TRUE(isDeleted);
}
+TEST_F(BinderARpcNdk, ARpcProviderDeleteOnError) {
+ bool isDeleted = false;
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, 0, data,
+ accessorProviderDataOnDelete);
+
+ ASSERT_EQ(provider, nullptr);
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcProvideOnErrorNoDeleteCbNoCrash) {
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, 0, nullptr,
+ nullptr);
+
+ ASSERT_EQ(provider, nullptr);
+}
+
TEST_F(BinderARpcNdk, ARpcProviderDuplicateInstance) {
const char* instance = "some.instance.name.IFoo/default";
const uint32_t numInstances = 2;
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
index 690c39a..4008c56 100644
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
@@ -59,6 +59,11 @@
darwin: {
enabled: false,
},
+ host: {
+ data_libs: [
+ "libc++",
+ ],
+ },
},
test_suites: ["general-tests"],
}
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
index 5d68fe1..b623c5f 100755
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
@@ -39,6 +39,7 @@
else
echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash"
echo "${color_reset}"
+ cat "$FUZZER_OUT"
exit 1
fi
done
diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp
index 17919c2..0580046 100644
--- a/libs/binder/trusty/RpcServerTrusty.cpp
+++ b/libs/binder/trusty/RpcServerTrusty.cpp
@@ -151,8 +151,10 @@
int RpcServerTrusty::handleMessageInternal(void* ctx) {
auto* channelContext = reinterpret_cast<ChannelContext*>(ctx);
- LOG_ALWAYS_FATAL_IF(channelContext == nullptr,
- "bad state: message received on uninitialized channel");
+ if (channelContext == nullptr) {
+ LOG_RPC_DETAIL("bad state: message received on uninitialized channel");
+ return ERR_BAD_STATE;
+ }
auto& session = channelContext->session;
auto& connection = channelContext->connection;
diff --git a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
index f62241d..f2b2aa7 100644
--- a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
+++ b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
@@ -65,6 +65,7 @@
std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
+ void enableAddServiceCache(bool /*value*/) override {}
// Clear all of the registered services
void clear();
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 8dabc2c..f9f304a 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -56,7 +56,7 @@
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-V5-ndk",
+ "android.hardware.graphics.common-V6-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 4c3f4a6..cd083fe 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -92,7 +92,7 @@
"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-V6-ndk.so:"
"android.hardware.graphics.common@1.0.so:"
"android.hardware.graphics.common@1.1.so:"
"android.hardware.graphics.common@1.2.so:"
diff --git a/libs/input/InputConsumer.cpp b/libs/input/InputConsumer.cpp
index fcf490d..dce528f 100644
--- a/libs/input/InputConsumer.cpp
+++ b/libs/input/InputConsumer.cpp
@@ -235,8 +235,9 @@
mMsgDeferred = false;
} else {
// Receive a fresh message.
- status_t result = mChannel->receiveMessage(&mMsg);
- if (result == OK) {
+ android::base::Result<InputMessage> result = mChannel->receiveMessage();
+ if (result.ok()) {
+ mMsg = std::move(result.value());
const auto [_, inserted] =
mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
@@ -244,11 +245,11 @@
// Trace the event processing timeline - event was just read from the socket
ATRACE_ASYNC_BEGIN(mProcessingTraceTag.c_str(), /*cookie=*/mMsg.header.seq);
- }
- if (result) {
+ } else {
// Consume the next batched event unless batches are being held for later.
- if (consumeBatches || result != WOULD_BLOCK) {
- result = consumeBatch(factory, frameTime, outSeq, outEvent);
+ if (consumeBatches || result.error().code() != WOULD_BLOCK) {
+ result = android::base::Error(
+ consumeBatch(factory, frameTime, outSeq, outEvent));
if (*outEvent) {
ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
"channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -256,7 +257,7 @@
break;
}
}
- return result;
+ return result.error().code();
}
}
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 15d992f..e193983 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -362,36 +362,36 @@
std::vector<InputMessage> InputConsumerNoResampling::readAllMessages() {
std::vector<InputMessage> messages;
while (true) {
- InputMessage msg;
- status_t result = mChannel->receiveMessage(&msg);
- switch (result) {
- case OK: {
- const auto [_, inserted] =
- mConsumeTimes.emplace(msg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
- LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
- msg.header.seq);
+ android::base::Result<InputMessage> result = mChannel->receiveMessage();
+ if (result.ok()) {
+ const InputMessage& msg = *result;
+ const auto [_, inserted] =
+ mConsumeTimes.emplace(msg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
+ LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
+ msg.header.seq);
- // Trace the event processing timeline - event was just read from the socket
- // TODO(b/329777420): distinguish between multiple instances of InputConsumer
- // in the same process.
- ATRACE_ASYNC_BEGIN("InputConsumer processing", /*cookie=*/msg.header.seq);
- messages.push_back(msg);
- break;
- }
- case WOULD_BLOCK: {
- return messages;
- }
- case DEAD_OBJECT: {
- LOG(FATAL) << "Got a dead object for " << mChannel->getName();
- break;
- }
- case BAD_VALUE: {
- LOG(FATAL) << "Got a bad value for " << mChannel->getName();
- break;
- }
- default: {
- LOG(FATAL) << "Unexpected error: " << result;
- break;
+ // Trace the event processing timeline - event was just read from the socket
+ // TODO(b/329777420): distinguish between multiple instances of InputConsumer
+ // in the same process.
+ ATRACE_ASYNC_BEGIN("InputConsumer processing", /*cookie=*/msg.header.seq);
+ messages.push_back(msg);
+ } else { // !result.ok()
+ switch (result.error().code()) {
+ case WOULD_BLOCK: {
+ return messages;
+ }
+ case DEAD_OBJECT: {
+ LOG(FATAL) << "Got a dead object for " << mChannel->getName();
+ break;
+ }
+ case BAD_VALUE: {
+ LOG(FATAL) << "Got a bad value for " << mChannel->getName();
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unexpected error: " << result.error().message();
+ break;
+ }
}
}
}
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 47b4228..bac681d 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -424,10 +424,11 @@
return OK;
}
-status_t InputChannel::receiveMessage(InputMessage* msg) {
+android::base::Result<InputMessage> InputChannel::receiveMessage() {
ssize_t nRead;
+ InputMessage msg;
do {
- nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT);
+ nRead = ::recv(getFd(), &msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
@@ -435,36 +436,36 @@
ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ receive message failed, errno=%d",
name.c_str(), errno);
if (error == EAGAIN || error == EWOULDBLOCK) {
- return WOULD_BLOCK;
+ return android::base::Error(WOULD_BLOCK);
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
- return DEAD_OBJECT;
+ return android::base::Error(DEAD_OBJECT);
}
- return -error;
+ return android::base::Error(-error);
}
if (nRead == 0) { // check for EOF
ALOGD_IF(DEBUG_CHANNEL_MESSAGES,
"channel '%s' ~ receive message failed because peer was closed", name.c_str());
- return DEAD_OBJECT;
+ return android::base::Error(DEAD_OBJECT);
}
- if (!msg->isValid(nRead)) {
+ if (!msg.isValid(nRead)) {
ALOGE("channel '%s' ~ received invalid message of size %zd", name.c_str(), nRead);
- return BAD_VALUE;
+ return android::base::Error(BAD_VALUE);
}
ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ received message of type %s", name.c_str(),
- ftl::enum_string(msg->header.type).c_str());
+ ftl::enum_string(msg.header.type).c_str());
if (ATRACE_ENABLED()) {
// Add an additional trace point to include data about the received message.
std::string message =
StringPrintf("receiveMessage(inputChannel=%s, seq=0x%" PRIx32 ", type=%s)",
- name.c_str(), msg->header.seq,
- ftl::enum_string(msg->header.type).c_str());
+ name.c_str(), msg.header.seq,
+ ftl::enum_string(msg.header.type).c_str());
ATRACE_NAME(message.c_str());
}
- return OK;
+ return msg;
}
bool InputChannel::probablyHasInput() const {
@@ -729,15 +730,16 @@
}
android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveConsumerResponse() {
- InputMessage msg;
- status_t result = mChannel->receiveMessage(&msg);
- if (result) {
- if (debugTransportPublisher() && result != WOULD_BLOCK) {
+ android::base::Result<InputMessage> result = mChannel->receiveMessage();
+ if (!result.ok()) {
+ if (debugTransportPublisher() && result.error().code() != WOULD_BLOCK) {
LOG(INFO) << "channel '" << mChannel->getName() << "' publisher ~ " << __func__ << ": "
- << strerror(result);
+ << result.error().message();
}
- return android::base::Error(result);
+ return result.error();
}
+
+ const InputMessage& msg = *result;
if (msg.header.type == InputMessage::Type::FINISHED) {
ALOGD_IF(debugTransportPublisher(),
"channel '%s' publisher ~ %s: finished: seq=%u, handled=%s",
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 02d4c07..435bdcd 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -78,9 +78,10 @@
EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
<< "server channel should be able to send message to client channel";
- InputMessage clientMsg;
- EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+ android::base::Result<InputMessage> clientMsgResult = clientChannel->receiveMessage();
+ ASSERT_TRUE(clientMsgResult.ok())
<< "client channel should be able to receive message from server channel";
+ const InputMessage& clientMsg = *clientMsgResult;
EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
<< "client channel should receive the correct message from server channel";
EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
@@ -94,9 +95,10 @@
EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
<< "client channel should be able to send message to server channel";
- InputMessage serverReply;
- EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply))
+ android::base::Result<InputMessage> serverReplyResult = serverChannel->receiveMessage();
+ ASSERT_TRUE(serverReplyResult.ok())
<< "server channel should be able to receive message from client channel";
+ const InputMessage& serverReply = *serverReplyResult;
EXPECT_EQ(clientReply.header.type, serverReply.header.type)
<< "server channel should receive the correct message from client channel";
EXPECT_EQ(clientReply.header.seq, serverReply.header.seq)
@@ -134,9 +136,10 @@
<< "client channel should observe that message is available before receiving it";
// Receive (consume) the message.
- InputMessage clientMsg;
- EXPECT_EQ(OK, receiverChannel->receiveMessage(&clientMsg))
+ android::base::Result<InputMessage> clientMsgResult = receiverChannel->receiveMessage();
+ ASSERT_TRUE(clientMsgResult.ok())
<< "client channel should be able to receive message from server channel";
+ const InputMessage& clientMsg = *clientMsgResult;
EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
<< "client channel should receive the correct message from server channel";
EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
@@ -156,8 +159,8 @@
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
- InputMessage msg;
- EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
+ android::base::Result<InputMessage> msgResult = clientChannel->receiveMessage();
+ EXPECT_EQ(WOULD_BLOCK, msgResult.error().code())
<< "receiveMessage should have returned WOULD_BLOCK";
}
@@ -172,8 +175,8 @@
serverChannel.reset(); // close server channel
- InputMessage msg;
- EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
+ android::base::Result<InputMessage> msgResult = clientChannel->receiveMessage();
+ EXPECT_EQ(DEAD_OBJECT, msgResult.error().code())
<< "receiveMessage should have returned DEAD_OBJECT";
}
@@ -207,7 +210,7 @@
MotionClassification::DEEP_PRESS,
};
- InputMessage serverMsg = {}, clientMsg;
+ InputMessage serverMsg = {};
serverMsg.header.type = InputMessage::Type::MOTION;
serverMsg.header.seq = 1;
serverMsg.body.motion.pointerCount = 1;
@@ -218,11 +221,13 @@
EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
<< "server channel should be able to send message to client channel";
- EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+ android::base::Result<InputMessage> clientMsgResult = clientChannel->receiveMessage();
+ ASSERT_TRUE(clientMsgResult.ok())
<< "client channel should be able to receive message from server channel";
+ const InputMessage& clientMsg = *clientMsgResult;
EXPECT_EQ(serverMsg.header.type, clientMsg.header.type);
- EXPECT_EQ(classification, clientMsg.body.motion.classification) <<
- "Expected to receive " << motionClassificationToString(classification);
+ EXPECT_EQ(classification, clientMsg.body.motion.classification)
+ << "Expected to receive " << motionClassificationToString(classification);
}
}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index 014c912..d760285 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -30,12 +30,14 @@
StatusCode,
};
use ffi::{
- AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
- AHardwareBuffer_writeToParcel,
+ AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_Plane, AHardwareBuffer_Planes,
+ AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel, ARect,
};
+use std::ffi::c_void;
use std::fmt::{self, Debug, Formatter};
-use std::mem::ManuallyDrop;
-use std::ptr::{self, null_mut, NonNull};
+use std::mem::{forget, ManuallyDrop};
+use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
+use std::ptr::{self, null, null_mut, NonNull};
/// Wrapper around a C `AHardwareBuffer_Desc`.
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -267,10 +269,192 @@
rfu0: 0,
rfu1: 0,
};
- // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the
+ // AHardwareBuffer_Desc pointer is valid because it comes from a reference.
unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
HardwareBufferDescription(buffer_desc)
}
+
+ /// Locks the hardware buffer for direct CPU access.
+ ///
+ /// # Safety
+ ///
+ /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
+ /// before calling this function.
+ /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
+ /// buffer simultaneously, but the caller must ensure that they don't access it simultaneously
+ /// and break Rust's aliasing rules, like any other shared memory.
+ /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
+ /// `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
+ /// processes lock the buffer simultaneously for any usage.
+ /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
+ /// simultaneously.
+ /// - If `rect` is not `None`, the caller must not modify the buffer outside of that rectangle.
+ pub unsafe fn lock<'a>(
+ &'a self,
+ usage: AHardwareBuffer_UsageFlags,
+ fence: Option<BorrowedFd>,
+ rect: Option<&ARect>,
+ ) -> Result<HardwareBufferGuard<'a>, StatusCode> {
+ let fence = if let Some(fence) = fence { fence.as_raw_fd() } else { -1 };
+ let rect = rect.map(ptr::from_ref).unwrap_or(null());
+ let mut address = null_mut();
+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the buffer address out
+ // pointer is valid because it comes from a reference. Our caller promises that writes have
+ // completed and there will be no simultaneous read/write locks.
+ let status = unsafe {
+ ffi::AHardwareBuffer_lock(self.0.as_ptr(), usage.0, fence, rect, &mut address)
+ };
+ status_result(status)?;
+ Ok(HardwareBufferGuard {
+ buffer: self,
+ address: NonNull::new(address)
+ .expect("AHardwareBuffer_lock set a null outVirtualAddress"),
+ })
+ }
+
+ /// Lock a potentially multi-planar hardware buffer for direct CPU access.
+ ///
+ /// # Safety
+ ///
+ /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
+ /// before calling this function.
+ /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
+ /// buffer simultaneously, but the caller must ensure that they don't access it simultaneously
+ /// and break Rust's aliasing rules, like any other shared memory.
+ /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
+ /// `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
+ /// processes lock the buffer simultaneously for any usage.
+ /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
+ /// simultaneously.
+ /// - If `rect` is not `None`, the caller must not modify the buffer outside of that rectangle.
+ pub unsafe fn lock_planes<'a>(
+ &'a self,
+ usage: AHardwareBuffer_UsageFlags,
+ fence: Option<BorrowedFd>,
+ rect: Option<&ARect>,
+ ) -> Result<Vec<PlaneGuard<'a>>, StatusCode> {
+ let fence = if let Some(fence) = fence { fence.as_raw_fd() } else { -1 };
+ let rect = rect.map(ptr::from_ref).unwrap_or(null());
+ let mut planes = AHardwareBuffer_Planes {
+ planeCount: 0,
+ planes: [const { AHardwareBuffer_Plane { data: null_mut(), pixelStride: 0, rowStride: 0 } };
+ 4],
+ };
+
+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the various out
+ // pointers are valid because they come from references. Our caller promises that writes have
+ // completed and there will be no simultaneous read/write locks.
+ let status = unsafe {
+ ffi::AHardwareBuffer_lockPlanes(self.0.as_ptr(), usage.0, fence, rect, &mut planes)
+ };
+ status_result(status)?;
+ let plane_count = planes.planeCount.try_into().unwrap();
+ Ok(planes.planes[..plane_count]
+ .iter()
+ .map(|plane| PlaneGuard {
+ guard: HardwareBufferGuard {
+ buffer: self,
+ address: NonNull::new(plane.data)
+ .expect("AHardwareBuffer_lockAndGetInfo set a null outVirtualAddress"),
+ },
+ pixel_stride: plane.pixelStride,
+ row_stride: plane.rowStride,
+ })
+ .collect())
+ }
+
+ /// Locks the hardware buffer for direct CPU access, returning information about the bytes per
+ /// pixel and stride as well.
+ ///
+ /// # Safety
+ ///
+ /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
+ /// before calling this function.
+ /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
+ /// buffer simultaneously, but the caller must ensure that they don't access it simultaneously
+ /// and break Rust's aliasing rules, like any other shared memory.
+ /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
+ /// `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
+ /// processes lock the buffer simultaneously for any usage.
+ /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
+ /// simultaneously.
+ pub unsafe fn lock_and_get_info<'a>(
+ &'a self,
+ usage: AHardwareBuffer_UsageFlags,
+ fence: Option<BorrowedFd>,
+ rect: Option<&ARect>,
+ ) -> Result<LockedBufferInfo<'a>, StatusCode> {
+ let fence = if let Some(fence) = fence { fence.as_raw_fd() } else { -1 };
+ let rect = rect.map(ptr::from_ref).unwrap_or(null());
+ let mut address = null_mut();
+ let mut bytes_per_pixel = 0;
+ let mut stride = 0;
+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the various out
+ // pointers are valid because they come from references. Our caller promises that writes have
+ // completed and there will be no simultaneous read/write locks.
+ let status = unsafe {
+ ffi::AHardwareBuffer_lockAndGetInfo(
+ self.0.as_ptr(),
+ usage.0,
+ fence,
+ rect,
+ &mut address,
+ &mut bytes_per_pixel,
+ &mut stride,
+ )
+ };
+ status_result(status)?;
+ Ok(LockedBufferInfo {
+ guard: HardwareBufferGuard {
+ buffer: self,
+ address: NonNull::new(address)
+ .expect("AHardwareBuffer_lockAndGetInfo set a null outVirtualAddress"),
+ },
+ bytes_per_pixel: bytes_per_pixel as u32,
+ stride: stride as u32,
+ })
+ }
+
+ /// Unlocks the hardware buffer from direct CPU access.
+ ///
+ /// Must be called after all changes to the buffer are completed by the caller. This will block
+ /// until the unlocking is complete and the buffer contents are updated.
+ fn unlock(&self) -> Result<(), StatusCode> {
+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid.
+ let status = unsafe { ffi::AHardwareBuffer_unlock(self.0.as_ptr(), null_mut()) };
+ status_result(status)?;
+ Ok(())
+ }
+
+ /// Unlocks the hardware buffer from direct CPU access.
+ ///
+ /// Must be called after all changes to the buffer are completed by the caller.
+ ///
+ /// This may not block until all work is completed, but rather will return a file descriptor
+ /// which will be signalled once the unlocking is complete and the buffer contents is updated.
+ /// If `Ok(None)` is returned then unlocking has already completed and no further waiting is
+ /// necessary. The file descriptor may be passed to a subsequent call to [`Self::lock`].
+ pub fn unlock_with_fence(
+ &self,
+ guard: HardwareBufferGuard,
+ ) -> Result<Option<OwnedFd>, StatusCode> {
+ // Forget the guard so that its `Drop` implementation doesn't try to unlock the
+ // HardwareBuffer again.
+ forget(guard);
+
+ let mut fence = -2;
+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid.
+ let status = unsafe { ffi::AHardwareBuffer_unlock(self.0.as_ptr(), &mut fence) };
+ let fence = if fence < 0 {
+ None
+ } else {
+ // SAFETY: `AHardwareBuffer_unlock` gives us ownership of the fence file descriptor.
+ Some(unsafe { OwnedFd::from_raw_fd(fence) })
+ };
+ status_result(status)?;
+ Ok(fence)
+ }
}
impl Drop for HardwareBuffer {
@@ -346,6 +530,49 @@
// according to the docs on the underlying gralloc calls)
unsafe impl Sync for HardwareBuffer {}
+/// A guard for when a `HardwareBuffer` is locked.
+///
+/// The `HardwareBuffer` will be unlocked when this is dropped, or may be unlocked via
+/// [`HardwareBuffer::unlock_with_fence`].
+#[derive(Debug)]
+pub struct HardwareBufferGuard<'a> {
+ buffer: &'a HardwareBuffer,
+ /// The address of the buffer in memory.
+ pub address: NonNull<c_void>,
+}
+
+impl<'a> Drop for HardwareBufferGuard<'a> {
+ fn drop(&mut self) {
+ self.buffer
+ .unlock()
+ .expect("Failed to unlock HardwareBuffer when dropping HardwareBufferGuard");
+ }
+}
+
+/// A guard for when a `HardwareBuffer` is locked, with additional information about the number of
+/// bytes per pixel and stride.
+#[derive(Debug)]
+pub struct LockedBufferInfo<'a> {
+ /// The locked buffer guard.
+ pub guard: HardwareBufferGuard<'a>,
+ /// The number of bytes used for each pixel in the buffer.
+ pub bytes_per_pixel: u32,
+ /// The stride in bytes between rows in the buffer.
+ pub stride: u32,
+}
+
+/// A guard for a single plane of a locked `HardwareBuffer`, with additional information about the
+/// stride.
+#[derive(Debug)]
+pub struct PlaneGuard<'a> {
+ /// The locked buffer guard.
+ pub guard: HardwareBufferGuard<'a>,
+ /// The stride in bytes between the color channel for one pixel to the next pixel.
+ pub pixel_stride: u32,
+ /// The stride in bytes between rows in the buffer.
+ pub row_stride: u32,
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -499,4 +726,108 @@
assert_eq!(buffer.description(), buffer_description);
assert_eq!(buffer2.description(), buffer_description);
}
+
+ #[test]
+ fn lock() {
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ 0,
+ ))
+ .expect("Failed to create buffer");
+
+ // SAFETY: No other threads or processes have access to the buffer.
+ let guard = unsafe {
+ buffer.lock(
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ None,
+ None,
+ )
+ }
+ .unwrap();
+
+ drop(guard);
+ }
+
+ #[test]
+ fn lock_with_rect() {
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ 0,
+ ))
+ .expect("Failed to create buffer");
+ let rect = ARect { left: 10, right: 20, top: 35, bottom: 45 };
+
+ // SAFETY: No other threads or processes have access to the buffer.
+ let guard = unsafe {
+ buffer.lock(
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ None,
+ Some(&rect),
+ )
+ }
+ .unwrap();
+
+ drop(guard);
+ }
+
+ #[test]
+ fn unlock_with_fence() {
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ 0,
+ ))
+ .expect("Failed to create buffer");
+
+ // SAFETY: No other threads or processes have access to the buffer.
+ let guard = unsafe {
+ buffer.lock(
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ None,
+ None,
+ )
+ }
+ .unwrap();
+
+ buffer.unlock_with_fence(guard).unwrap();
+ }
+
+ #[test]
+ fn lock_with_info() {
+ const WIDTH: u32 = 1024;
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+ WIDTH,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ 0,
+ ))
+ .expect("Failed to create buffer");
+
+ // SAFETY: No other threads or processes have access to the buffer.
+ let info = unsafe {
+ buffer.lock_and_get_info(
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ None,
+ None,
+ )
+ }
+ .unwrap();
+
+ assert_eq!(info.bytes_per_pixel, 4);
+ assert_eq!(info.stride, WIDTH * 4);
+ drop(info);
+ }
}
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index e62640e..cf995bf 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -970,7 +970,7 @@
const auto& item = layer.source.buffer;
auto imageTextureRef = getOrCreateBackendTexture(item.buffer->getBuffer(), false);
- // if the layer's buffer has a fence, then we must must respect the fence prior to using
+ // if the layer's buffer has a fence, then we must respect the fence prior to using
// the buffer.
if (layer.source.buffer.fence != nullptr) {
waitFence(context, layer.source.buffer.fence->get());
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index 72bd292..b63e919 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -23,6 +23,11 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+vintf_fragment {
+ name: "manifest_android.frameworks.automotive.display@1.0.xml",
+ src: "manifest_android.frameworks.automotive.display@1.0.xml",
+}
+
cc_binary {
name: "android.frameworks.automotive.display@1.0-service",
defaults: ["hidl_defaults"],
@@ -50,7 +55,7 @@
"-DLOG_TAG=\"AutomotiveDisplayService\""
],
- vintf_fragments: [
+ vintf_fragment_modules: [
"manifest_android.frameworks.automotive.display@1.0.xml",
],
}
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpuWork.c b/services/gpuservice/gpuwork/bpfprogs/gpuWork.c
index f470189..94abc69 100644
--- a/services/gpuservice/gpuwork/bpfprogs/gpuWork.c
+++ b/services/gpuservice/gpuwork/bpfprogs/gpuWork.c
@@ -20,11 +20,7 @@
#include <stddef.h>
#include <stdint.h>
-#ifdef MOCK_BPF
-#include <test/mock_bpf_helpers.h>
-#else
#include <bpf_helpers.h>
-#endif
#define S_IN_NS (1000000000)
#define SMALL_TIME_GAP_LIMIT_NS (S_IN_NS)
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index a4dd909..2ebe708 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -35,109 +35,34 @@
]
},
{
- "name": "CtsHardwareTestCases",
- "options": [
- {
- "include-filter": "android.hardware.input.cts.tests"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsHardwareTestCases_cts_tests"
},
{
"name": "CtsInputTestCases"
},
{
- "name": "CtsViewTestCases",
- "options": [
- {
- "include-filter": "android.view.cts.input"
- }
- ]
+ "name": "CtsViewTestCases_cts_input"
},
{
- "name": "CtsViewTestCases",
- "options": [
- {
- "include-filter": "android.view.cts.HoverTest"
- },
- {
- "include-filter": "android.view.cts.MotionEventTest"
- },
- {
- "include-filter": "android.view.cts.PointerCaptureTest"
- },
- {
- "include-filter": "android.view.cts.TooltipTest"
- },
- {
- "include-filter": "android.view.cts.TouchDelegateTest"
- },
- {
- "include-filter": "android.view.cts.VerifyInputEventTest"
- },
- {
- "include-filter": "android.view.cts.ViewTest"
- },
- {
- "include-filter": "android.view.cts.ViewUnbufferedTest"
- }
- ]
+ "name": "CtsViewTestCases_input_related"
},
{
- "name": "CtsWidgetTestCases",
- "options": [
- {
- "include-filter": "android.widget.cts.NumberPickerTest"
- },
- {
- "include-filter": "android.widget.cts.SeekBarTest"
- }
- ]
+ "name": "CtsWidgetTestCases_seekbar_and_numberpicker"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.hardware.input"
- }
- ]
+ "name": "FrameworksCoreTests_hardware_input"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.view.VerifiedKeyEventTest"
- },
- {
- "include-filter": "android.view.VerifiedMotionEventTest"
- }
- ]
+ "name": "FrameworksCoreTests_view_verified"
},
{
- "name": "CtsAppTestCases",
- "options": [
- {
- "include-filter": "android.app.cts.ToolbarActionBarTest"
- }
- ]
+ "name": "CtsAppTestCases_cts_toolbaractionbartest"
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.input"
- }
- ]
+ "name": "FrameworksServicesTests_android_server_input"
},
{
- "name": "CtsSecurityTestCases",
- "options": [
- {
- "include-filter": "android.security.cts.MotionEventTest"
- }
- ]
+ "name": "CtsSecurityTestCases_cts_motioneventtest"
},
{
"name": "CtsSecurityBulletinHostTestCases",
@@ -153,12 +78,7 @@
],
"postsubmit": [
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.WindowInputTests"
- }
- ]
+ "name": "CtsWindowManagerDeviceWindow_window_windowinputtests"
},
{
"name": "libinput_tests"
@@ -184,98 +104,31 @@
]
},
{
- "name": "CtsHardwareTestCases",
- "options": [
- {
- "include-filter": "android.hardware.input.cts.tests"
- }
- ]
+ "name": "CtsHardwareTestCases_cts_tests"
},
{
"name": "CtsInputTestCases"
},
{
- "name": "CtsViewTestCases",
- "options": [
- {
- "include-filter": "android.view.cts.input"
- }
- ]
+ "name": "CtsViewTestCases_cts_input"
},
{
- "name": "CtsViewTestCases",
- "options": [
- {
- "include-filter": "android.view.cts.HoverTest"
- },
- {
- "include-filter": "android.view.cts.MotionEventTest"
- },
- {
- "include-filter": "android.view.cts.PointerCaptureTest"
- },
- {
- "include-filter": "android.view.cts.TooltipTest"
- },
- {
- "include-filter": "android.view.cts.TouchDelegateTest"
- },
- {
- "include-filter": "android.view.cts.VerifyInputEventTest"
- },
- {
- "include-filter": "android.view.cts.ViewTest"
- },
- {
- "include-filter": "android.view.cts.ViewUnbufferedTest"
- }
- ]
+ "name": "CtsViewTestCases_input_related"
},
{
- "name": "CtsWidgetTestCases",
- "options": [
- {
- "include-filter": "android.widget.cts.NumberPickerTest"
- },
- {
- "include-filter": "android.widget.cts.SeekBarTest"
- }
- ]
+ "name": "CtsWidgetTestCases_seekbar_and_numberpicker"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.view.VerifiedKeyEventTest"
- },
- {
- "include-filter": "android.view.VerifiedMotionEventTest"
- }
- ]
+ "name": "FrameworksCoreTests_view_verified"
},
{
- "name": "CtsAppTestCases",
- "options": [
- {
- "include-filter": "android.app.cts.ToolbarActionBarTest"
- }
- ]
+ "name": "CtsAppTestCases_cts_toolbaractionbartest"
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.input"
- }
- ]
+ "name": "FrameworksServicesTests_server_input"
},
{
- "name": "CtsSecurityTestCases",
- "options": [
- {
- "include-filter": "android.security.cts.MotionEventTest"
- }
- ]
+ "name": "CtsSecurityTestCases_cts_motioneventtest"
},
{
"name": "CtsSecurityBulletinHostTestCases",
diff --git a/services/inputflinger/dispatcher/EventLogTags.logtags b/services/inputflinger/dispatcher/EventLogTags.logtags
index 2c5fe21..4dd6073 100644
--- a/services/inputflinger/dispatcher/EventLogTags.logtags
+++ b/services/inputflinger/dispatcher/EventLogTags.logtags
@@ -31,7 +31,7 @@
# 6: Percent
# Default value for data of type int/long is 2 (bytes).
#
-# See system/core/logcat/event.logtags for the master copy of the tags.
+# See system/logging/logcat/event.logtags for the master copy of the tags.
# 62000 - 62199 reserved for inputflinger
diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags
index 6c851dd..76154cb 100644
--- a/services/surfaceflinger/EventLog/EventLogTags.logtags
+++ b/services/surfaceflinger/EventLog/EventLogTags.logtags
@@ -31,7 +31,7 @@
# 6: Percent
# Default value for data of type int/long is 2 (bytes).
#
-# See system/core/logcat/event.logtags for the master copy of the tags.
+# See system/logging/logcat/event.logtags for the master copy of the tags.
# 60100 - 60199 reserved for surfaceflinger
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index f430526..eae8d6d 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -32,7 +32,7 @@
virtual void onChoreographerAttached() = 0;
virtual void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>,
Fps renderRate) = 0;
- virtual void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) = 0;
+ virtual void onCommitNotComposited() = 0;
virtual void vrrDisplayIdle(bool idle) = 0;
protected:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5ec7e48..60f11b8 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -234,7 +234,7 @@
if (FlagManager::getInstance().vrr_config()) {
compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
}
- mSchedulerCallback.onCommitNotComposited(pacesetterPtr->displayId);
+ mSchedulerCallback.onCommitNotComposited();
return;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d4d32aa..8fa7e3a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2580,7 +2580,7 @@
}
{
- ATRACE_NAME("LLM:commitChanges");
+ ATRACE_NAME("LayerLifecycleManager:commitChanges");
mLayerLifecycleManager.commitChanges();
}
@@ -4472,7 +4472,7 @@
scheduleNotifyExpectedPresentHint(displayId);
}
-void SurfaceFlinger::onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) {
+void SurfaceFlinger::onCommitNotComposited() {
if (FlagManager::getInstance().commit_not_composited()) {
mFrameTimeline->onCommitNotComposited();
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2369043..da797f8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -701,7 +701,7 @@
void onChoreographerAttached() override;
void onExpectedPresentTimePosted(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
Fps renderRate) override;
- void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) override
+ void onCommitNotComposited() override
REQUIRES(kMainThreadContext);
void vrrDisplayIdle(bool idle) override;
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index dac9265..fae236d 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -158,6 +158,7 @@
a.presentTime == b.presentTime;
}
+ NO_THREAD_SAFETY_ANALYSIS
const std::map<int64_t, TimelineItem>& getPredictions() const {
return mTokenManager->mPredictions;
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 8f21cdb..0ac4b68 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -30,7 +30,7 @@
MOCK_METHOD(void, onChoreographerAttached, (), (override));
MOCK_METHOD(void, onExpectedPresentTimePosted, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps),
(override));
- MOCK_METHOD(void, onCommitNotComposited, (PhysicalDisplayId), (override));
+ MOCK_METHOD(void, onCommitNotComposited, (), (override));
MOCK_METHOD(void, vrrDisplayIdle, (bool), (override));
};
@@ -41,7 +41,7 @@
void triggerOnFrameRateOverridesChanged() override {}
void onChoreographerAttached() override {}
void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
- void onCommitNotComposited(PhysicalDisplayId) override {}
+ void onCommitNotComposited() override {}
void vrrDisplayIdle(bool) override {}
};