虽可儿的小窝

Thoughts, stories and ideas.

0%

四 获取 ServiceManager

四 获取 ServiceManager

前面第二、三章,注册服务、获取服务的时候都是使用到了 ServiceManager,那么他是怎么获取的呢?

从前面可以知道,使用的是 defaultServiceManager() 方法,这个获取的就是 gDefaultServiceManager 对象。对于 gDefaultServiceManager 对象,如果存在则直接返回,如果不存在则需要创建该对象。

1 概述

1.1 流程图

1.2 defaultServiceManager

首先我们来看一下 defaultServiceManager 方法是怎么实现的,

路径在:frameworks/native/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()
{
	// std::call_once 保证全局只初始化一次,且线程安全
    std::call_once(gSmOnce, []() {
        gDefaultServiceManager = sp<CppBackendShim>::make(getBackendUnifiedServiceManager());
    });

    return gDefaultServiceManager;
}

获取 ServiceManager 对象采用单例模式,

然后通过 CppBackendShim + getBackendUnifiedServiceManager() 实现了后端统一抽象。

2 getBackendUnifiedServiceManager

路径是 frameworks/native/libs/binder/BackendUnifiedServiceManager.cpp

sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() {
	// 线程安全单例
    std::call_once(gUSmOnce, []() {
#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
        /* wait for service manager */
		// 读取属性 servicemanager.installed,判断是否存在独立的 servicemanager 进程
        if (hasOutOfProcessServiceManager()) {
            using std::literals::chrono_literals::operator""s;
            using android::base::WaitForProperty;
			// 轮询等待系统属性 servicemanager.ready 变为 "true",超时 1 秒
            while (!WaitForProperty("servicemanager.ready", "true", 1s)) {
                ALOGE("Waited for servicemanager.ready for a second, waiting another...");
            }
        }
#endif

        sp<AidlServiceManager> sm = nullptr;
        while (hasOutOfProcessServiceManager() && sm == 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) {
                std::string contextObjectName = ps
                        ? ps->getDriverName() + ", " + kUdsServiceManagerName
                        : kUdsServiceManagerName;
                ALOGE("Waiting 1s on context object(s) on %s.", contextObjectName.c_str());
                sleep(1);
            }
        }

        gUnifiedServiceManager = sp<BackendUnifiedServiceManager>::make(sm);
    });

    return gUnifiedServiceManager;
}

上面的逻辑可以分成三个部分,第一部分判断是否存在独立的 servicemanager 进程然后循环等待进程是否初始化完毕,也就是 wait for service manager 部分。第二部分阻塞式地获取 servicemanager 的实际通信引用。第三部分保存结果。

先看一下 hasOutOfProcessServiceManager 的实现,如下

static bool hasOutOfProcessServiceManager() {
// We don't currently support kernel binder service management or UDS
// service management on host or when libbinder is compiled without any
// kernel binder suport. Please use setDefaultServiceManager for host
// processes that want to use service manager APIs.
#if !defined(BINDER_WITH_KERNEL_IPC) || !defined(__BIONIC__)
    return false;
#else
#ifdef __ANDROID_VNDK__
    return true;
#else
    return android::base::GetBoolProperty("servicemanager.installed", true);
#endif
#endif
}

就是通过 servicemanager.installed 属性是否为 true 来判断是否存在 servicemanager 进程。

2.1 wait for service manager

    std::call_once(gUSmOnce, []() {
#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) // 运行在 Android 系统上,而非普通 Linux
        /* wait for service manager */
		// 读取属性 servicemanager.installed,判断是否存在独立的 servicemanager 进程
        if (hasOutOfProcessServiceManager()) {
            using std::literals::chrono_literals::operator""s;
            using android::base::WaitForProperty;
			// 轮询等待系统属性 servicemanager.ready 变为 "true",超时 1 秒
            while (!WaitForProperty("servicemanager.ready", "true", 1s)) {
                ALOGE("Waited for servicemanager.ready for a second, waiting another...");
            }
        }
#endif
	......
	});

来看上面的代码,首先是 call_once,老朋友了,线程安全单例,就是一个锁。

然后通过 hasOutOfProcessServiceManager 来判断是否存在,如果存在的话,轮询等待系统属性 servicemanager.ready,代表 ServiceManager 初始化完毕可以正常工作了,每次等待超时时间为 1 秒,会一直等待。

android::base::WaitForProperty 是 libbase 提供的函数,用来阻塞等待某个 Android 系统属性变为期望值。

可以看到第二部分在 ServiceManager 不存在时也不会执行,所以在初始化 BackendUnifiedServiceManager 这个单例时,必须阻塞等待 ServiceManager 真正就绪并可以通信后,才继续完成初始化。也就是第一部分必须成功之后才能执行第二部分和第三部分。

  • 如何启动的 ServiceManager 请看后面的讲解。

2.2 阻塞获取引用

		sp<AidlServiceManager> sm = nullptr;
        while (hasOutOfProcessServiceManager() && sm == 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) {
                std::string contextObjectName = ps
                        ? ps->getDriverName() + ", " + kUdsServiceManagerName
                        : kUdsServiceManagerName;
                ALOGE("Waiting 1s on context object(s) on %s.", contextObjectName.c_str());
                sleep(1);
            }
        }

在第一部分结束之后进行,也就是 ServiceManager 存在且已经初始化完毕。

这一部分的逻辑就是为了获取 AidlServiceManager 的代理对象 sm。轮询获取,保险起见每次也需要通过 hasOutOfProcessServiceManager 来再次判断 ServiceManager 是否存在。

而获取 AIdlServiceManager 有两个路径,一个是传统的 Kernel Binder,了一个是 UDS 路径。

整个流程如下:

2.2.1 ProcessState

sp<ProcessState> ps = ProcessState::selfIfKernelBinderEnabled();

首先是这个,获取 ps,ps 是一个 ProcessState 单例。

ProcessState 在注册服务中见过,路径在 frameworks/native/libs/binder/ProcessState.cpp

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

kDefaultDriver 是一个常量,定义在 ProcessState.h 中,值是 "/dev/binder"。

access() 是 POSIX 系统调用,就是检查路径节点是否存在且可读,可以返回 0,否则返回 -1。

如果存在的话,就初始化并返回 ProcessState 对象。

至于 init 方法在注册服务中有讲解,此处不过多赘述。

这个函数的真正意义是判断当前运行环境是否支持传统的内核 Binder 驱动。

2.2.2 Kernel Binder

如果支持的话,也就是 ps 存在,则走传统 Binder 路径。

sm = interface_cast<AidlServiceManager>(ps->getContextObject(nullptr));

ps->getContextObject(nullptr) 会返回 sp<IBinder>,前面的 interface_cast<AidlServiceManager> 可以将 IBinder 转换为 AIDL 定义的服务管理接口代理,本质上创建 BpServiceManager。

getContextObject 也是 ProcessState 的方法,如下:

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    sp<IBinder> context = getStrongProxyForHandle(0);

    if (context) {
        // The root object is special since we get it directly from the driver, it is never
        // written by Parcell::writeStrongBinder.
        internal::Stability::markCompilationUnit(context.get());
    } else {
        ALOGW("Not able to get context object on %s.", mDriverName.c_str());
    }

    return context;
}

这里逻辑比较简单,直接调用的是 getStrongProxyForHandle 方法。

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    std::function<void()> postTask;

    std::unique_lock<std::mutex> _l(mLock);

    if (handle == 0 && the_context_object != nullptr) return the_context_object;

    handle_entry* e = lookupHandleLocked(handle);

    if (e != nullptr) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  The
        // attemptIncWeak() is safe because we know the BpBinder destructor will always
        // call expungeHandle(), which acquires the same lock we are holding now.
        // We need to do this because there is a race condition between someone
        // releasing a reference on this BpBinder, and a new reference on its handle
        // arriving from the driver.
        IBinder* b = e->binder;
        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
			// 需要创建新的 BpBinder
            if (handle == 0) {
                // Special case for context manager...
                // The context manager is the only object for which we create
                // a BpBinder proxy without already holding a reference.
                // Perform a dummy transaction to ensure the context manager
                // is registered before we create the first local reference
                // to it (which will occur when creating the BpBinder).
                // If a local reference is created for the BpBinder when the
                // context manager is not present, the driver will fail to
                // provide a reference to the context manager, but the
                // driver API does not return status.
                //
                // Note that this is not race-free if the context manager
                // dies while this code runs.

                IPCThreadState* ipc = IPCThreadState::self();

                CallRestriction originalCallRestriction = ipc->getCallRestriction();
                ipc->setCallRestriction(CallRestriction::NONE);

                Parcel data;
                status_t status = ipc->transact(
                        0, IBinder::PING_TRANSACTION, data, nullptr, 0);

                ipc->setCallRestriction(originalCallRestriction);

                if (status == DEAD_OBJECT)
                   return nullptr;
            }

            sp<BpBinder> bp = BpBinder::PrivateAccessor::create(handle, &postTask);
            e->binder = bp.get();
            if (bp) e->refs = bp->getWeakRefs();
            result = bp;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    _l.unlock();

    if (postTask) postTask();

    return result;
}

这个方法的作用是,根据 handle 编号,查找或创建对应的 BpBinder 代理对象。

我们这里请求的是 handle = 0,也就是 servicemanager。

此时会触发快速路径,也就是

if (handle == 0 && the_context_object != nullptr) return the_context_object;

如果是获取的 servicemanager,且已经存在了,则直接返回。

如果没有的话,则往下执行 handle_entry* e = lookupHandleLocked(handle),这个是用来查找 handle 缓存表,用来判断是直接复用还是创建。不过 servicemanager 缓存上面已经确定没有了,所以这里必定是返回一个空槽位。

if (e != nullptr) {
    IBinder* b = e->binder;
    if (b == nullptr || !e->refs->attemptIncWeak(this)) {
        // 分支 A:创建新的 BpBinder
    } else {
        // 分支 B:复用已有的 BpBinder
    }
}

也就是在这里会进入到分支 A,

			if (handle == 0) {
                IPCThreadState* ipc = IPCThreadState::self();

                CallRestriction originalCallRestriction = ipc->getCallRestriction();
                ipc->setCallRestriction(CallRestriction::NONE);

                Parcel data;
                status_t status = ipc->transact(
                        0, IBinder::PING_TRANSACTION, data, nullptr, 0);

                ipc->setCallRestriction(originalCallRestriction);

                if (status == DEAD_OBJECT)
                   return nullptr;
            }

            sp<BpBinder> bp = BpBinder::PrivateAccessor::create(handle, &postTask);
            e->binder = bp.get();
            if (bp) e->refs = bp->getWeakRefs();
            result = bp;

servicemanager 进行了特殊处理,handle 为 0 时,必须确认 context manage 已经注册完成。否则未注册完成时创建 BpBinder(0),后续所有发往 handle = 0 的事务都会静默失败。

在内核 Binder 体系中,handle = 0 是隐式映射到 servicemanager 的 —— servicemanager 启动时通过 ioctl(BINDER_SET_CONTEXT_MGR) 声明自己为 context manager,驱动自动将其关联到 handle=0。

servicemanager 特殊处理之后,就是创建 BpBinder

sp<BpBinder> bp = BpBinder::PrivateAccessor::create(handle, &postTask);
e->binder = bp.get();
if (bp) e->refs = bp->getWeakRefs();
result = bp;

旧版是 new BpBinder(handle) 直接构造,Android 16 改用 BpBinder::PrivateAccessor::create(handle, &postTask)。这个是 BpBinder 的内部 friend class,通过它可以访问 BpBinder 的私有内部构造逻辑。create 接收一个输出参数 &postTask,用于返回一个需要在锁外执行的回调任务。

分支 B 复用已有的 BpBinder

} else {
    result.force_set(b);
    e->refs->decWeak(this);
}

最后,解锁加延迟任务执行

_l.unlock();
if (postTask) postTask();
return result;

为什么 postTask 要在锁外执行?

BpBinder::PrivateAccessor::create() 可能需要执行一些操作,比如向 IPCThreadState 注册新创建的 handle。这类操作可能涉及其他锁,如果在 mLock 持有期间执行,有死锁风险。

流程如下:

2.2.3 UDS

也就是使用的这个方法进行获取。

sm = getUdsServiceManager();

看看这个方法

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;
}

共四个步骤。

  1. 创建 RpcSession,这个是 Android libbinder 中新增的跨进程 RPC 框架,类似于 gRPC 的客户端会话。它的职责是管理一次跨进程连接的全生命周期。
  2. 设置文件描述符传输模式。
  3. 建立 Unix Domain Socket 连接。
  4. 获取远端根对象并转换为接口代理。

这个的设计意义在于 Android 16 通过 UDS 路径,使得在没有内核 Binder 驱动的环境中(如容器、虚拟机),仍然可以使用 ServiceManager 的完整功能,保持上层应用代码零修改。

先不过多赘述了。

3 总结

defaultServiceManager() 通过 std::call_once 以线程安全单例模式获取全局唯一的 gDefaultServiceManager 对象,其内部首先轮询等待系统属性 servicemanager.ready 变为 "true" 以确保独立 servicemanager 进程已初始化就绪。

随后通过双路径阻塞式获取 AidlServiceManager 代理:若存在 /dev/binder 则走传统 Kernel Binder 路径(通过 ProcessState 获取 handle=0 的 BpBinder,并先执行 PING_TRANSACTION 确认 context manager 已注册),否则回退到 UDS 路径(通过 RpcSession 建立 Unix Domain Socket 连接),最终保证在 ServiceManager 真正可通信后才向上层返回可用的服务管理代理,支撑后续服务的注册与查询。

Suikeer

关于作者