Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85d8eaae authored by Devin Moore's avatar Devin Moore
Browse files

Allow other processes to implement a UDS servicemanager

Another process can serve IServiceManager over
/dev/socket/rpc_servicemanager.

Once the servicemanager.ready property is set, IServiceManager clients
will look for the kernel binder servicemanager if kernel binder is
supported, and fall back to checking for the UDS servicemanager.

This is useful for systems without kernel binder, with unix domain
sockets, to provide the same experience for binder clients trough the
IServiceManager client APIs.

Flag: EXEMPT Clients of this new functionality will be flagged
Test: atest vm_accessor_test
Bug: 358427181
Change-Id: I78e85fb62c67f6b7a085fda9a681e569bf32ed01
parent c662c5ed
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "frameworks_native_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["frameworks_native_license"],
}

rust_library {
    name: "librpc_servicemanager",
    crate_name: "rpc_servicemanager",
    srcs: ["rpc_servicemanager.rs"],
    rustlibs: [
        "android.system.virtualmachineservice-rust",
        "libanyhow",
        "libbinder_rs",
        "liblibc",
        "liblog_rust",
        "librpcbinder_rs",
        "librustutils",
        "libvsock",
        "rpc_servicemanager_aidl-rust",
        "servicemanager_aidl-rust",
    ],
}
+177 −0
Original line number Diff line number Diff line
// Copyright 2025, 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.

//! Implementation of the AIDL interface `IServiceManager`.

use anyhow::Result;
use binder::{Accessor, BinderFeatures, Interface, Strong};
use libc::{sa_family_t, sockaddr_vm, AF_VSOCK};
use log::{error, info};
use rpc_servicemanager_aidl::aidl::android::os::IRpcProvider::{
    IRpcProvider, ServiceConnectionInfo::ServiceConnectionInfo,
};
use rpcbinder::{FileDescriptorTransportMode, RpcServer};
use rustutils::sockets::android_get_control_socket;
use servicemanager_aidl::aidl::android::os::IServiceManager::{
    BnServiceManager, CallerContext::CallerContext, IServiceManager,
};
use servicemanager_aidl::aidl::android::os::{
    ConnectionInfo::ConnectionInfo, IClientCallback::IClientCallback,
    IServiceCallback::IServiceCallback, Service::Service, ServiceDebugInfo::ServiceDebugInfo,
};
use vsock::VMADDR_CID_HOST;

// Name of the socket that libbinder is expecting IServiceManager to be served from
const RPC_SERVICEMANAGER_UDS_NAME: &str = "rpc_servicemanager";

/// Implementation of `IServiceManager`.
pub struct RpcServiceManager {
    provider_service: Strong<dyn IRpcProvider>,
}

impl IServiceManager for RpcServiceManager {
    fn getService(&self, _name: &str) -> binder::Result<Option<binder::SpIBinder>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn getService2(&self, name: &str) -> binder::Result<Service> {
        let provider_service = self.provider_service.clone();

        let get_connection_info = move |inst: &str| {
            let connection_info = provider_service.getServiceConnectionInfo(inst).unwrap();
            match connection_info {
                ServiceConnectionInfo::Vsock(info) => {
                    let addr = sockaddr_vm {
                        svm_family: AF_VSOCK as sa_family_t,
                        svm_reserved1: 0,
                        svm_port: info.port as u32,
                        svm_cid: VMADDR_CID_HOST,
                        svm_zero: [0u8; 4],
                    };
                    Some(binder::ConnectionInfo::Vsock(addr))
                }
                #[allow(unreachable_patterns)]
                _ => {
                    error!("Unexpected ServiceConnectionInfo type!");
                    None
                }
            }
        };

        let accessor = Accessor::new(name, get_connection_info);

        Ok(Service::Accessor(accessor.as_binder()))
    }
    fn checkService(&self, _name: &str) -> binder::Result<Option<binder::SpIBinder>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn checkService2(&self, _name: &str) -> binder::Result<Service> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn addService(
        &self,
        _name: &str,
        _service: &binder::SpIBinder,
        _allow_isolated: bool,
        _dump_priority: i32,
    ) -> binder::Result<()> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn listServices(&self, _dump_priority: i32) -> binder::Result<Vec<String>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn registerForNotifications(
        &self,
        _name: &str,
        _callback: &binder::Strong<dyn IServiceCallback>,
    ) -> binder::Result<()> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn unregisterForNotifications(
        &self,
        _name: &str,
        _callback: &binder::Strong<dyn IServiceCallback>,
    ) -> binder::Result<()> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn isDeclared(&self, _name: &str) -> binder::Result<bool> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn getDeclaredInstances(&self, _iface: &str) -> binder::Result<Vec<String>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn updatableViaApex(&self, _name: &str) -> binder::Result<Option<String>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn getUpdatableNames(&self, _apex_name: &str) -> binder::Result<Vec<String>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn getConnectionInfo(&self, _name: &str) -> binder::Result<Option<ConnectionInfo>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn registerClientCallback(
        &self,
        _name: &str,
        _service: &binder::SpIBinder,
        _callback: &binder::Strong<dyn IClientCallback>,
    ) -> binder::Result<()> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn tryUnregisterService(
        &self,
        _name: &str,
        _service: &binder::SpIBinder,
    ) -> binder::Result<()> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn getServiceDebugInfo(&self) -> binder::Result<Vec<ServiceDebugInfo>> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
    fn checkServiceAccess(&self, _: &CallerContext, _: &str, _: &str) -> binder::Result<bool> {
        Err(binder::ExceptionCode::UNSUPPORTED_OPERATION.into())
    }
}

impl Interface for RpcServiceManager {}

impl RpcServiceManager {
    /// Creates a new `RpcServiceManager` instance from the `IServiceManager` reference.
    fn new(provider_service: Strong<dyn IRpcProvider>) -> RpcServiceManager {
        Self { provider_service }
    }
}

/// Registers the `IServiceManager` service.
pub fn register_rpc_servicemanager(provider_service: Strong<dyn IRpcProvider>) -> Result<()> {
    let rpc_servicemanager_binder = BnServiceManager::new_binder(
        RpcServiceManager::new(provider_service),
        BinderFeatures::default(),
    );

    let servicemanager_fd = android_get_control_socket(RPC_SERVICEMANAGER_UDS_NAME)?;
    let server =
        RpcServer::new_bound_socket(rpc_servicemanager_binder.as_binder(), servicemanager_fd)?;
    // Required for the FD being passed through libbinder's accessor binder
    server.set_supported_file_descriptor_transport_modes(&[FileDescriptorTransportMode::Unix]);

    info!("The RPC server '{}' is running.", RPC_SERVICEMANAGER_UDS_NAME);
    if let Err(e) = rustutils::system_properties::write("servicemanager.ready", "true") {
        error!("failed to set ro.servicemanager.ready {:?}", e);
    }

    // Move server reference into a background thread and run it forever.
    std::thread::spawn(move || {
        server.join();
    });
    Ok(())
}
+45 −3
Original line number Diff line number Diff line
@@ -469,7 +469,6 @@ release_libbinder_binder_observer_config {
    },
}


soong_config_module_type {
    name: "libbinder_remove_cache_static_list_config",
    module_type: "cc_defaults",
@@ -857,7 +856,7 @@ cc_library_static {
    ],
}

// AIDL interface between libbinder and framework.jar
// ServiceManager AIDL interface between libbinder and framework.jar
filegroup {
    name: "libbinder_aidl",
    srcs: [
@@ -881,6 +880,15 @@ filegroup {
    visibility: [":__subpackages__"],
}

filegroup {
    name: "libbinder_rpc_aidl",
    srcs: [
        "aidl/android/os/IRpcProvider.aidl",
    ],
    path: "aidl",
    visibility: [":__subpackages__"],
}

aidl_interface {
    name: "packagemanager_aidl",
    unstable: true,
@@ -904,12 +912,19 @@ aidl_interface {
}

aidl_interface {
    name: "libbinder_aidl_test_stub",
    name: "servicemanager_aidl",
    unstable: true,
    local_include_dir: "aidl",
    srcs: [":libbinder_aidl"],
    vendor_available: true,
    backend: {
        cpp: {
            // libbinder exports this type itself so use that
            enabled: false,
        },
        rust: {
            enabled: true,
        },
        java: {
            enabled: false,
        },
@@ -917,6 +932,33 @@ aidl_interface {
    visibility: [
        ":__subpackages__",
        "//system/tools/aidl:__subpackages__",
        "//frameworks/native/cmds/servicemanager/rpc_servicemanager",
    ],
}

aidl_interface {
    name: "rpc_servicemanager_aidl",
    unstable: true,
    local_include_dir: "aidl",
    srcs: [":libbinder_rpc_aidl"],
    vendor_available: true,
    backend: {
        rust: {
            enabled: true,
            apex_available: [
                "com.android.virt",
                "com.android.compos",
            ],
        },
        java: {
            enabled: false,
        },
    },
    visibility: [
        ":__subpackages__",
        "//system/tools/aidl:__subpackages__",
        "//frameworks/native/cmds/servicemanager/rpc_servicemanager",
        "//packages/modules/Virtualization:__subpackages__",
    ],
}

+32 −4
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <android/os/IAccessor.h>
#include <android/os/IServiceManager.h>
#include <binder/RpcSession.h>
#include <cutils/sockets.h>
#include <sys/socket.h>
#include <sys/un.h>

#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
#include <android-base/properties.h>
@@ -26,6 +29,10 @@

namespace android {

// This is similar to the kernel binder servicemanager's context 0. It's the
// known socket that we expect the Unix Domain Socket servicemanager to be listening on.
const char kUdsServiceManagerName[] = ANDROID_SOCKET_DIR "/rpc_servicemanager";

#ifdef LIBBINDER_CLIENT_CACHE
constexpr bool kUseCache = true;
#else
@@ -499,6 +506,16 @@ static bool hasOutOfProcessServiceManager() {
#endif // BINDER_WITH_KERNEL_IPC
}

static sp<AidlServiceManager> getUdsServiceManager() {
    auto session = RpcSession::make();
    session->setFileDescriptorTransportMode(RpcSession::FileDescriptorTransportMode::UNIX);
    auto status = session->setupUnixDomainClient(kUdsServiceManagerName);
    if (status == OK) {
        return interface_cast<AidlServiceManager>(session->getRootObject());
    }
    return nullptr;
}

sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() {
    std::call_once(gUSmOnce, []() {
#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
@@ -514,11 +531,22 @@ sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() {

        sp<AidlServiceManager> sm = nullptr;
        while (hasOutOfProcessServiceManager() && sm == nullptr) {
            sm = interface_cast<AidlServiceManager>(
                    ProcessState::self()->getContextObject(nullptr));
            // There is either a kernel binder service manager, or an RPC binder
            // service manager
            sp<ProcessState> ps = ProcessState::selfIfKernelBinderEnabled();
            if (ps) {
                // Service management over kernel binder
                sm = interface_cast<AidlServiceManager>(ps->getContextObject(nullptr));
            } else {
                // Check for service management over Unix Domain Sockets
                sm = getUdsServiceManager();
            }

            if (sm == nullptr) {
                ALOGE("Waiting 1s on context object on %s.",
                      ProcessState::self()->getDriverName().c_str());
                std::string contextObjectName = ps
                        ? ps->getDriverName() + ", " + kUdsServiceManagerName
                        : kUdsServiceManagerName;
                ALOGE("Waiting 1s on context object(s) on %s.", contextObjectName.c_str());
                sleep(1);
            }
        }
+5 −0
Original line number Diff line number Diff line
@@ -117,6 +117,11 @@ sp<ProcessState> ProcessState::selfOrNull()
    return init(nullptr, false /*requireDefault*/);
}

sp<ProcessState> ProcessState::selfIfKernelBinderEnabled() {
    if (access(kDefaultDriver, R_OK) == -1) return nullptr;
    return init(kDefaultDriver, false /*requireDefault*/);
}

[[clang::no_destroy]] static sp<ProcessState> gProcess;
[[clang::no_destroy]] static std::mutex gProcessMutex;

Loading