Merge "[rpc_binder] Implement RPC binder over init-managed Unix domain socket"

GitOrigin-RevId: 213454462ca60ec8af20f69a797bbef19712b85b
Change-Id: Idb5bbf5d20c362bb9b20953130ade759bdf802bf
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2362580..28369d6 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -501,6 +501,7 @@
         "libbase",
         "libbinder",
         "libbinder_ndk",
+        "libcutils_sockets",
         "liblog",
         "libutils",
     ],
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 83d0de7..399667d 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -564,6 +564,29 @@
     return OK;
 }
 
+status_t RpcServer::setupRawSocketServer(base::unique_fd socket_fd) {
+    RpcTransportFd transportFd(std::move(socket_fd));
+    if (!transportFd.fd.ok()) {
+        int savedErrno = errno;
+        ALOGE("Could not get initialized Unix socket: %s", strerror(savedErrno));
+        return -savedErrno;
+    }
+    // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
+    // the backlog is increased to a large number.
+    // TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
+    //  to 1.
+    if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
+        int savedErrno = errno;
+        ALOGE("Could not listen initialized Unix socket: %s", strerror(savedErrno));
+        return -savedErrno;
+    }
+    if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
+        ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
+        return status;
+    }
+    return OK;
+}
+
 void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
     const std::vector<uint8_t>& id = session->mId;
     LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID");
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 81ae26a..4ad0a47 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -71,6 +71,16 @@
     [[nodiscard]] status_t setupUnixDomainServer(const char* path);
 
     /**
+     * Sets up an RPC server with a raw socket file descriptor.
+     * The socket should be created and bound to a socket address already, e.g.
+     * the socket can be created in init.rc.
+     *
+     * This method is used in the libbinder_rpc_unstable API
+     * RunInitUnixDomainRpcServer().
+     */
+    [[nodiscard]] status_t setupRawSocketServer(base::unique_fd socket_fd);
+
+    /**
      * Creates an RPC server at the current port.
      */
     [[nodiscard]] status_t setupVsockServer(unsigned int port);
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index e4a9f99..dd177af 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -42,6 +42,20 @@
 
 AIBinder* VsockRpcClient(unsigned int cid, unsigned int port);
 
+// Starts a Unix domain RPC server with a given init-managed Unix domain `name` and
+// a given root IBinder object.
+// The socket should be created in init.rc with the same `name`.
+//
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+bool RunInitUnixDomainRpcServer(AIBinder* service, const char* name,
+                                void (*readyCallback)(void* param), void* param);
+
+// Gets the service via the RPC binder with Unix domain socket with the given
+// Unix socket `name`.
+// The final Unix domain socket path name is /dev/socket/`name`.
+AIBinder* UnixDomainRpcClient(const char* name);
+
 // Connect to an RPC server with preconnected file descriptors.
 //
 // requestFd should connect to the server and return a valid file descriptor, or
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 1f38bb9..ae07aee 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,6 +19,7 @@
 #include <android/binder_libbinder.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <cutils/sockets.h>
 #include <linux/vm_sockets.h>
 
 using android::OK;
@@ -30,6 +31,17 @@
 
 extern "C" {
 
+void RunRpcServer(android::sp<RpcServer>& server, AIBinder* service,
+                  void (*readyCallback)(void* param), void* param) {
+    server->setRootObject(AIBinder_toPlatformBinder(service));
+
+    if (readyCallback) readyCallback(param);
+    server->join();
+
+    // Shutdown any open sessions since server failed.
+    (void)server->shutdown();
+}
+
 bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
                                   void* factoryContext, unsigned int port) {
     auto server = RpcServer::make();
@@ -60,13 +72,7 @@
                    << " error: " << statusToString(status).c_str();
         return false;
     }
-    server->setRootObject(AIBinder_toPlatformBinder(service));
-
-    if (readyCallback) readyCallback(param);
-    server->join();
-
-    // Shutdown any open sessions since server failed.
-    (void)server->shutdown();
+    RunRpcServer(server, service, readyCallback, param);
     return true;
 }
 
@@ -84,6 +90,31 @@
     return AIBinder_fromPlatformBinder(session->getRootObject());
 }
 
+bool RunInitUnixDomainRpcServer(AIBinder* service, const char* name,
+                                void (*readyCallback)(void* param), void* param) {
+    auto server = RpcServer::make();
+    auto fd = unique_fd(android_get_control_socket(name));
+    if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
+                   << " error: " << statusToString(status).c_str();
+        return false;
+    }
+    RunRpcServer(server, service, readyCallback, param);
+    return true;
+}
+
+AIBinder* UnixDomainRpcClient(const char* name) {
+    std::string pathname(name);
+    pathname = ANDROID_SOCKET_DIR "/" + pathname;
+    auto session = RpcSession::make();
+    if (status_t status = session->setupUnixDomainClient(pathname.c_str()); status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC client with path: " << pathname
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
 AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
     auto session = RpcSession::make();
     auto request = [=] { return unique_fd{requestFd(param)}; };
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index 347831a..f9c7bcf 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -3,6 +3,8 @@
     RunVsockRpcServer;
     RunVsockRpcServerCallback;
     VsockRpcClient;
+    RunInitUnixDomainRpcServer;
+    UnixDomainRpcClient;
     RpcPreconnectedClient;
   local:
     *;
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 5ebc27f..9771cc9 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -20,6 +20,7 @@
         "libbinder_rs",
         "libdowncast_rs",
         "liblibc",
+        "liblog_rust",
     ],
     apex_available: [
         "com.android.compos",
diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs
index 4343ff4..48c787b 100644
--- a/libs/binder/rust/rpcbinder/src/client.rs
+++ b/libs/binder/rust/rpcbinder/src/client.rs
@@ -15,6 +15,7 @@
  */
 
 use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong};
+use std::ffi::CString;
 use std::os::{
     raw::{c_int, c_void},
     unix::io::RawFd,
@@ -35,6 +36,27 @@
     interface_cast(get_vsock_rpc_service(cid, port))
 }
 
+/// Connects to an RPC Binder server over Unix domain socket.
+pub fn get_unix_domain_rpc_service(socket_name: &str) -> Option<SpIBinder> {
+    let socket_name = match CString::new(socket_name) {
+        Ok(s) => s,
+        Err(e) => {
+            log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+            return None;
+        }
+    };
+    // SAFETY: AIBinder returned by UnixDomainRpcClient has correct reference count,
+    // and the ownership can safely be taken by new_spibinder.
+    unsafe { new_spibinder(binder_rpc_unstable_bindgen::UnixDomainRpcClient(socket_name.as_ptr())) }
+}
+
+/// Connects to an RPC Binder server for a particular interface over Unix domain socket.
+pub fn get_unix_domain_rpc_interface<T: FromIBinder + ?Sized>(
+    socket_name: &str,
+) -> Result<Strong<T>, StatusCode> {
+    interface_cast(get_unix_domain_rpc_service(socket_name))
+}
+
 /// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
 /// file descriptors already connected to it.
 pub fn get_preconnected_rpc_service(
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index fb6b90c..89a49a4 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -20,7 +20,9 @@
 mod server;
 
 pub use client::{
-    get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface,
-    get_vsock_rpc_service,
+    get_preconnected_rpc_interface, get_preconnected_rpc_service, get_unix_domain_rpc_interface,
+    get_unix_domain_rpc_service, get_vsock_rpc_interface, get_vsock_rpc_service,
 };
-pub use server::{run_vsock_rpc_server, run_vsock_rpc_server_with_factory};
+pub use server::{
+    run_init_unix_domain_rpc_server, run_vsock_rpc_server, run_vsock_rpc_server_with_factory,
+};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 8009297..b350a13 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -18,7 +18,7 @@
     unstable_api::{AIBinder, AsNative},
     SpIBinder,
 };
-use std::{os::raw, ptr::null_mut};
+use std::{ffi::CString, os::raw, ptr::null_mut};
 
 /// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
 /// port.
@@ -35,7 +35,28 @@
     F: FnOnce(),
 {
     let mut ready_notifier = ReadyNotifier(Some(on_ready));
-    ready_notifier.run_server(service, port)
+    ready_notifier.run_vsock_server(service, port)
+}
+
+/// Runs a binder RPC server, serving the supplied binder service implementation on the given
+/// socket file name. The socket should be initialized in init.rc with the same name.
+///
+/// If and when the server is ready for connections, `on_ready` is called to allow appropriate
+/// action to be taken - e.g. to notify clients that they may now attempt to connect.
+///
+/// The current thread is joined to the binder thread pool to handle incoming messages.
+///
+/// Returns true if the server has shutdown normally, false if it failed in some way.
+pub fn run_init_unix_domain_rpc_server<F>(
+    service: SpIBinder,
+    socket_name: &str,
+    on_ready: F,
+) -> bool
+where
+    F: FnOnce(),
+{
+    let mut ready_notifier = ReadyNotifier(Some(on_ready));
+    ready_notifier.run_init_unix_domain_server(service, socket_name)
 }
 
 struct ReadyNotifier<F>(Option<F>)
@@ -46,7 +67,7 @@
 where
     F: FnOnce(),
 {
-    fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
+    fn run_vsock_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
         let service = service.as_native_mut();
         let param = self.as_void_ptr();
 
@@ -64,6 +85,31 @@
         }
     }
 
+    fn run_init_unix_domain_server(&mut self, mut service: SpIBinder, socket_name: &str) -> bool {
+        let socket_name = match CString::new(socket_name) {
+            Ok(s) => s,
+            Err(e) => {
+                log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+                return false;
+            }
+        };
+        let service = service.as_native_mut();
+        let param = self.as_void_ptr();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // RunInitUnixDomainRpcServer does not retain a reference to `ready_callback` or `param`;
+        // it only uses them before it returns, which is during the lifetime of `self`.
+        unsafe {
+            binder_rpc_unstable_bindgen::RunInitUnixDomainRpcServer(
+                service,
+                socket_name.as_ptr(),
+                Some(Self::ready_callback),
+                param,
+            )
+        }
+    }
+
     fn as_void_ptr(&mut self) -> *mut raw::c_void {
         self as *mut _ as *mut raw::c_void
     }
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
index 4cdeac4..aac4b04 100644
--- a/libs/binder/tests/BinderRpcTestServerConfig.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -22,5 +22,6 @@
     int serverVersion;
     int vsockPort;
     int unixBootstrapFd; // Inherited from parent
+    int socketFd;
     @utf8InCpp String addr;
 }
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 004dea3..79bd9d4 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -129,6 +129,15 @@
     return vsockPort++;
 }
 
+static base::unique_fd initUnixSocket(std::string addr) {
+    auto socket_addr = UnixSocketAddress(addr.c_str());
+    base::unique_fd fd(
+            TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX)));
+    CHECK(fd.ok());
+    CHECK_EQ(0, TEMP_FAILURE_RETRY(bind(fd.get(), socket_addr.addr(), socket_addr.addrSize())));
+    return fd;
+}
+
 // Destructors need to be defined, even if pure virtual
 ProcessSession::~ProcessSession() {}
 
@@ -243,13 +252,18 @@
                                                    singleThreaded ? "_single_threaded" : "",
                                                    noKernel ? "_no_kernel" : "");
 
-    base::unique_fd bootstrapClientFd, bootstrapServerFd;
+    base::unique_fd bootstrapClientFd, bootstrapServerFd, socketFd;
     // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
     // This is because we cannot pass ParcelFileDescriptor over a pipe.
     if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
         int savedErrno = errno;
         LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
     }
+    auto addr = allocateSocketAddress();
+    // Initializes the socket before the fork/exec.
+    if (socketType == SocketType::UNIX_RAW) {
+        socketFd = initUnixSocket(addr);
+    }
 
     auto ret = std::make_unique<LinuxProcessSession>(
             Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) {
@@ -265,8 +279,9 @@
     serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
     serverConfig.serverVersion = serverVersion;
     serverConfig.vsockPort = allocateVsockPort();
-    serverConfig.addr = allocateSocketAddress();
+    serverConfig.addr = addr;
     serverConfig.unixBootstrapFd = bootstrapServerFd.get();
+    serverConfig.socketFd = socketFd.get();
     for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
         serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
                 static_cast<int32_t>(mode));
@@ -312,6 +327,7 @@
                     return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
                 });
                 break;
+            case SocketType::UNIX_RAW:
             case SocketType::UNIX:
                 status = session->setupUnixDomainClient(serverConfig.addr.c_str());
                 break;
@@ -1042,7 +1058,8 @@
 }
 
 static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
-    std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET};
+    std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET,
+                                   SocketType::UNIX_RAW};
 
     if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
 
@@ -1284,6 +1301,17 @@
                     mAcceptConnection = &Server::recvmsgServerConnection;
                     mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); };
                 } break;
+                case SocketType::UNIX_RAW: {
+                    auto addr = allocateSocketAddress();
+                    auto status = rpcServer->setupRawSocketServer(initUnixSocket(addr));
+                    if (status != OK) {
+                        return AssertionFailure()
+                                << "setupRawSocketServer: " << statusToString(status);
+                    }
+                    mConnectToServer = [addr] {
+                        return connectTo(UnixSocketAddress(addr.c_str()));
+                    };
+                } break;
                 case SocketType::VSOCK: {
                     auto port = allocateVsockPort();
                     auto status = rpcServer->setupVsockServer(port);
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index dc7d264..654e16c 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -69,6 +69,7 @@
     PRECONNECTED,
     UNIX,
     UNIX_BOOTSTRAP,
+    UNIX_RAW,
     VSOCK,
     INET,
 };
@@ -81,6 +82,8 @@
             return "unix_domain_socket";
         case SocketType::UNIX_BOOTSTRAP:
             return "unix_domain_socket_bootstrap";
+        case SocketType::UNIX_RAW:
+            return "raw_uds";
         case SocketType::VSOCK:
             return "vm_socket";
         case SocketType::INET:
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 721fbfe..5a78782 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -108,7 +108,8 @@
     bool supportsFdTransport() const {
         return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
                 (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
-                 socketType() == SocketType::UNIX_BOOTSTRAP);
+                 socketType() == SocketType::UNIX_BOOTSTRAP ||
+                 socketType() == SocketType::UNIX_RAW);
     }
 
     void SetUp() override {
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index a922b21..cc40995 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -54,6 +54,9 @@
         case SocketType::UNIX_BOOTSTRAP:
             CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd)));
             break;
+        case SocketType::UNIX_RAW:
+            CHECK_EQ(OK, server->setupRawSocketServer(base::unique_fd(serverConfig.socketFd)));
+            break;
         case SocketType::VSOCK:
             CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
             break;
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index 1e8d93d..f960442 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -86,7 +86,7 @@
 
     SocketType type = std::get<0>(GetParam());
     if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
-        type == SocketType::UNIX_BOOTSTRAP) {
+        type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
         // we can't get port numbers for unix sockets
         return;
     }