Merge "Add a method for libbinder to wrap an accessor in a delegator" into main am: 9fe5f80e57 am: 936e404dde

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/3250211

Change-Id: Iabc24e650bacc45e63ba78b384da7c9cba4102cd
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 379b609..6903cb5 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -489,6 +489,7 @@
         "ProcessState.cpp",
         "Static.cpp",
         ":libbinder_aidl",
+        ":libbinder_accessor_aidl",
         ":libbinder_device_interface_sources",
     ],
     target: {
@@ -801,7 +802,6 @@
         "aidl/android/os/IServiceManager.aidl",
         "aidl/android/os/Service.aidl",
         "aidl/android/os/ServiceDebugInfo.aidl",
-        ":libbinder_accessor_aidl",
     ],
     path: "aidl",
 }
@@ -812,26 +812,7 @@
         "aidl/android/os/IAccessor.aidl",
     ],
     path: "aidl",
-}
-
-// TODO(b/353492849): Make this interface private to libbinder.
-aidl_interface {
-    name: "android.os.accessor",
-    srcs: [":libbinder_accessor_aidl"],
-    unstable: true,
-    backend: {
-        rust: {
-            enabled: true,
-            apex_available: [
-                "com.android.virt",
-            ],
-        },
-    },
-    visibility: [
-        ":__subpackages__",
-        "//system/tools/aidl:__subpackages__",
-        "//packages/modules/Virtualization:__subpackages__",
-    ],
+    visibility: [":__subpackages__"],
 }
 
 aidl_interface {
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 77b80ef..32388db 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -386,7 +386,7 @@
         ALOGE("Binder is null");
         return BAD_VALUE;
     }
-    sp<IAccessor> accessor = interface_cast<IAccessor>(binder);
+    sp<IAccessor> accessor = checked_interface_cast<IAccessor>(binder);
     if (accessor == nullptr) {
         ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str());
         return BAD_TYPE;
@@ -420,6 +420,28 @@
     return binder;
 }
 
+status_t delegateAccessor(const String16& name, const sp<IBinder>& accessor,
+                          sp<IBinder>* delegator) {
+    LOG_ALWAYS_FATAL_IF(delegator == nullptr, "delegateAccessor called with a null out param");
+    if (accessor == nullptr) {
+        ALOGW("Accessor argument to delegateAccessor is null.");
+        *delegator = nullptr;
+        return OK;
+    }
+    status_t status = validateAccessor(name, accessor);
+    if (status != OK) {
+        ALOGE("The provided accessor binder is not an IAccessor for instance %s. Status: "
+              "%s",
+              String8(name).c_str(), statusToString(status).c_str());
+        return status;
+    }
+    // validateAccessor already called checked_interface_cast and made sure this
+    // is a valid accessor object.
+    *delegator = sp<android::os::IAccessorDelegator>::make(interface_cast<IAccessor>(accessor));
+
+    return OK;
+}
+
 #if !defined(__ANDROID_VNDK__)
 // IPermissionController is not accessible to vendors
 
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 2b23276..81f7cdb 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -291,6 +291,28 @@
  * \return OK if the binder is an IAccessor for `instance`
  */
 LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder);
+
+/**
+ * Have libbinder wrap this IAccessor binder in an IAccessorDelegator and return
+ * it.
+ *
+ * This is required only in very specific situations when the process that has
+ * permissions to connect the to RPC service's socket and create the FD for it
+ * is in a separate process from this process that wants to service the Accessor
+ * binder and the communication between these two processes is binder RPC. This
+ * is needed because the binder passed over the binder RPC connection can not be
+ * used as a kernel binder, and needs to be wrapped by a kernel binder that can
+ * then be registered with service manager.
+ *
+ * \param instance name of the Accessor.
+ * \param binder to wrap in a Delegator and register with service manager.
+ * \param outDelegator the wrapped kernel binder for IAccessorDelegator
+ *
+ * \return OK if the binder is an IAccessor for `instance` and the delegator was
+ * successfully created.
+ */
+LIBBINDER_EXPORTED status_t delegateAccessor(const String16& name, const sp<IBinder>& accessor,
+                                             sp<IBinder>* delegator);
 #endif // __TRUSTY__
 
 #ifndef __ANDROID__
diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp
index 3c32a39..07b8c40 100644
--- a/libs/binder/ndk/binder_rpc.cpp
+++ b/libs/binder/ndk/binder_rpc.cpp
@@ -302,6 +302,28 @@
     }
 }
 
+binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* instance, AIBinder* accessor,
+                                                     AIBinder** outDelegator) {
+    LOG_ALWAYS_FATAL_IF(outDelegator == nullptr, "The outDelegator argument is null");
+    if (instance == nullptr || accessor == nullptr) {
+        ALOGW("instance or accessor arguments to ABinderRpc_Accessor_delegateBinder are null");
+        *outDelegator = nullptr;
+        return STATUS_UNEXPECTED_NULL;
+    }
+    sp<IBinder> accessorBinder = accessor->getBinder();
+
+    sp<IBinder> delegator;
+    status_t status = android::delegateAccessor(String16(instance), accessorBinder, &delegator);
+    if (status != OK) {
+        return PruneStatusT(status);
+    }
+    sp<AIBinder> binder = ABpBinder::lookupOrCreateFromBinder(delegator);
+    // This AIBinder needs a strong ref to pass ownership to the caller
+    binder->incStrong(nullptr);
+    *outDelegator = binder.get();
+    return OK;
+}
+
 ABinderRpc_ConnectionInfo* ABinderRpc_ConnectionInfo_new(const sockaddr* addr, socklen_t len) {
     if (addr == nullptr || len < 0 || static_cast<size_t>(len) < sizeof(sa_family_t)) {
         ALOGE("Invalid arguments in ABinderRpc_Connection_new");
diff --git a/libs/binder/ndk/include_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h
index 7132554..9fe5d78 100644
--- a/libs/binder/ndk/include_platform/android/binder_rpc.h
+++ b/libs/binder/ndk/include_platform/android/binder_rpc.h
@@ -265,6 +265,35 @@
         __INTRODUCED_IN(36);
 
 /**
+ * Wrap an ABinderRpc_Accessor proxy binder with a delegator binder.
+ *
+ * The IAccessorDelegator binder delegates all calls to the proxy binder.
+ *
+ * This is required only in very specific situations when the process that has
+ * permissions to connect the to RPC service's socket and create the FD for it
+ * is in a separate process from this process that wants to serve the Accessor
+ * binder and the communication between these two processes is binder RPC. This
+ * is needed because the binder passed over the binder RPC connection can not be
+ * used as a kernel binder, and needs to be wrapped by a kernel binder that can
+ * then be registered with service manager.
+ *
+ * \param instance name of the service associated with the Accessor
+ * \param binder the AIBinder* from the ABinderRpc_Accessor from the
+ *        ABinderRpc_Accessor_asBinder. The other process across the binder RPC
+ *        connection will have called this and passed the AIBinder* across a
+ *        binder interface to the process calling this function.
+ * \param outDelegator the AIBinder* for the kernel binder that wraps the
+ *        'binder' argument and delegates all calls to it. The caller now owns
+ *        this object with one strong ref count and is responsible for removing
+ *        that ref count with with AIBinder_decStrong when the caller wishes to
+ *        drop the reference.
+ */
+binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* _Nonnull instance,
+                                                     AIBinder* _Nonnull binder,
+                                                     AIBinder* _Nullable* _Nonnull outDelegator)
+        __INTRODUCED_IN(36);
+
+/**
  * Create a new ABinderRpc_ConnectionInfo with sockaddr. This can be supported socket
  * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets).
  *
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index c885816..4d691f8 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -257,6 +257,7 @@
     ABinderRpc_registerAccessorProvider; # systemapi
     ABinderRpc_unregisterAccessorProvider; # systemapi
     ABinderRpc_Accessor_new; # systemapi
+    ABinderRpc_Accessor_delegateAccessor; #systemapi
     ABinderRpc_Accessor_delete; # systemapi
     ABinderRpc_Accessor_asBinder; # systemapi
     ABinderRpc_Accessor_fromBinder; # systemapi
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 0e8e388..f7f3f35 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -123,7 +123,7 @@
 #[cfg(not(trusty))]
 pub use state::{ProcessState, ThreadState};
 #[cfg(not(any(android_vendor, android_vndk)))]
-pub use system_only::{Accessor, ConnectionInfo};
+pub use system_only::{delegate_accessor, Accessor, 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 a91d84d..08582ab 100644
--- a/libs/binder/rust/src/system_only.rs
+++ b/libs/binder/rust/src/system_only.rs
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+use crate::binder::AsNative;
+use crate::error::{status_result, Result};
 use crate::proxy::SpIBinder;
 use crate::sys;
 
@@ -185,3 +187,27 @@
         }
     }
 }
+
+/// Register a new service with the default service manager.
+///
+/// Registers the given binder object with the given identifier. If successful,
+/// this service can then be retrieved using that identifier.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
+pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder> {
+    let instance = CString::new(name).unwrap();
+    let mut delegator = ptr::null_mut();
+    let status =
+    // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
+    // string pointers. Caller retains ownership of both pointers.
+    // `AServiceManager_addService` creates a new strong reference and copies
+    // the string, so both pointers need only be valid until the call returns.
+        unsafe { sys::ABinderRpc_Accessor_delegateAccessor(instance.as_ptr(),
+            binder.as_native_mut(), &mut delegator) };
+
+    status_result(status)?;
+
+    // Safety: `delegator` is either null or a valid, owned pointer at this
+    // point, so can be safely passed to `SpIBinder::from_raw`.
+    Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") })
+}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index bdb7e4a..489fa0a 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -945,6 +945,43 @@
         assert!(deleted.load(Ordering::Relaxed));
     }
 
+    #[test]
+    fn test_accessor_delegator_new_each_time() {
+        let get_connection_info = move |_instance: &str| None;
+        let accessor = Accessor::new("foo.service", get_connection_info);
+        let delegator_binder =
+            binder::delegate_accessor("foo.service", accessor.as_binder().unwrap());
+        let delegator_binder2 =
+            binder::delegate_accessor("foo.service", accessor.as_binder().unwrap());
+
+        // The delegate_accessor creates new delegators each time
+        assert!(delegator_binder != delegator_binder2);
+    }
+
+    #[test]
+    fn test_accessor_delegate_the_delegator() {
+        let get_connection_info = move |_instance: &str| None;
+        let accessor = Accessor::new("foo.service", get_connection_info);
+        let delegator_binder =
+            binder::delegate_accessor("foo.service", accessor.as_binder().unwrap());
+        let delegator_binder2 =
+            binder::delegate_accessor("foo.service", delegator_binder.clone().unwrap());
+
+        assert!(delegator_binder.clone() == delegator_binder);
+        // The delegate_accessor creates new delegators each time. Even when they are delegators
+        // of delegators.
+        assert!(delegator_binder != delegator_binder2);
+    }
+
+    #[test]
+    fn test_accessor_delegator_wrong_name() {
+        let get_connection_info = move |_instance: &str| None;
+        let accessor = Accessor::new("foo.service", get_connection_info);
+        let delegator_binder =
+            binder::delegate_accessor("NOT.foo.service", accessor.as_binder().unwrap());
+        assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND));
+    }
+
     #[tokio::test]
     async fn reassociate_rust_binder_async() {
         let service_name = "testing_service";
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 077a33a..506fc71 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -75,6 +75,8 @@
 constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0";
 #endif
 
+constexpr char kKnownAidlService[] = "activity";
+
 static std::string WaitStatusToString(int wstatus) {
     if (WIFEXITED(wstatus)) {
         return "exit status " + std::to_string(WEXITSTATUS(wstatus));
@@ -1549,22 +1551,47 @@
     EXPECT_EQ(nullptr, ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&addr), 0));
 }
 
-TEST_P(BinderRpcAccessor, ARpcGetService) {
+TEST_F(BinderARpcNdk, ARpcDelegateAccessorWrongInstance) {
+    AccessorProviderData* data = new AccessorProviderData();
+    ABinderRpc_Accessor* accessor = getAccessor(kARpcInstance, data);
+    ASSERT_NE(accessor, nullptr);
+    AIBinder* localAccessorBinder = ABinderRpc_Accessor_asBinder(accessor);
+    EXPECT_NE(localAccessorBinder, nullptr);
+
+    AIBinder* delegatorBinder = nullptr;
+    binder_status_t status =
+            ABinderRpc_Accessor_delegateAccessor("bar", localAccessorBinder, &delegatorBinder);
+    EXPECT_EQ(status, NAME_NOT_FOUND);
+
+    AIBinder_decStrong(localAccessorBinder);
+    ABinderRpc_Accessor_delete(accessor);
+    delete data;
+}
+
+TEST_F(BinderARpcNdk, ARpcDelegateNonAccessor) {
+    auto service = defaultServiceManager()->checkService(String16(kKnownAidlService));
+    ASSERT_NE(nullptr, service);
+    ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(service));
+
+    AIBinder* delegatorBinder = nullptr;
+    binder_status_t status =
+            ABinderRpc_Accessor_delegateAccessor("bar", binder.get(), &delegatorBinder);
+
+    EXPECT_EQ(status, BAD_TYPE);
+}
+
+inline void getServiceTest(BinderRpcTestProcessSession& proc,
+                           ABinderRpc_AccessorProvider_getAccessorCallback getAccessor) {
     constexpr size_t kNumThreads = 10;
     bool isDeleted = false;
 
-    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
-    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
     AccessorProviderData* data =
             new AccessorProviderData{proc.proc->sessions[0].addr, proc.proc->sessions[0].addrLen,
                                      &isDeleted};
-
     ABinderRpc_AccessorProvider* provider =
             ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
                                                 kARpcNumSupportedServices, data,
                                                 accessorProviderDataOnDelete);
-
     EXPECT_NE(provider, nullptr);
     EXPECT_FALSE(isDeleted);
 
@@ -1580,6 +1607,45 @@
     waitForExtraSessionCleanup(proc);
 }
 
+TEST_P(BinderRpcAccessor, ARpcGetService) {
+    constexpr size_t kNumThreads = 10;
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    getServiceTest(proc, getAccessor);
+}
+
+// Create accessors and wrap each of the accessors in a delegator
+ABinderRpc_Accessor* getDelegatedAccessor(const char* instance, void* cookie) {
+    ABinderRpc_Accessor* accessor = getAccessor(instance, cookie);
+    AIBinder* accessorBinder = ABinderRpc_Accessor_asBinder(accessor);
+    // Once we have a handle to the AIBinder which holds a reference to the
+    // underlying accessor IBinder, we can get rid of the ABinderRpc_Accessor
+    ABinderRpc_Accessor_delete(accessor);
+
+    AIBinder* delegatorBinder = nullptr;
+    binder_status_t status =
+            ABinderRpc_Accessor_delegateAccessor(instance, accessorBinder, &delegatorBinder);
+    // No longer need this AIBinder. The delegator has a reference to the
+    // underlying IBinder on success, and on failure we are done here.
+    AIBinder_decStrong(accessorBinder);
+    if (status != OK || delegatorBinder == nullptr) {
+        ALOGE("Unexpected behavior. Status: %s, delegator ptr: %p", statusToString(status).c_str(),
+              delegatorBinder);
+        return nullptr;
+    }
+
+    return ABinderRpc_Accessor_fromBinder(instance, delegatorBinder);
+}
+
+TEST_P(BinderRpcAccessor, ARpcGetServiceWithDelegator) {
+    constexpr size_t kNumThreads = 10;
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    getServiceTest(proc, getDelegatedAccessor);
+}
+
 #endif // BINDER_WITH_KERNEL_IPC
 
 #ifdef BINDER_RPC_TO_TRUSTY_TEST
@@ -1845,7 +1911,7 @@
     ASSERT_NE(nullptr, sm);
     // Any Java service with non-empty getInterfaceDescriptor() would do.
     // Let's pick activity.
-    auto binder = sm->checkService(String16("activity"));
+    auto binder = sm->checkService(String16(kKnownAidlService));
     ASSERT_NE(nullptr, binder);
     auto descriptor = binder->getInterfaceDescriptor();
     ASSERT_GE(descriptor.size(), 0u);