虽可儿的小窝

Thoughts, stories and ideas.

0%

三 获取服务(getService)

三 获取服务(getService)

同样以 Media 为例,讲解如何获取服务。

类图在注册服务那一节已经讲解,不再过多赘述。

1 获取 Media 服务

路径在 frameworks/av/media/libmedia/IMediaDeathNotifier.cpp,这个是 Android 媒体框架中获取 MediaPlayerService 的统一入口。

例如一个媒体客户端想获取到 Media 服务,那么就要这样:sp<IMediaPlayerService> service = IMediaDeathNotifier::getMediaPlayerService();

如下:

// 获取 MediaPlayerService 的静态成员函数
// 这是客户端获取媒体播放服务的统一入口点
IMediaDeathNotifier::getMediaPlayerService()
{
    // 输出 verbose 级别日志,用于调试跟踪
    ALOGV("getMediaPlayerService");
    
    // 创建线程安全锁,使用 RAII 模式确保锁在作用域结束时自动释放
    // sServiceLock 是静态互斥锁,保护共享资源 sMediaPlayerService
    Mutex::Autolock _l(sServiceLock);
    
    // 单例模式:检查服务代理是否已经创建
    // sMediaPlayerService 是静态成员变量,存储创建的服务代理
    if (sMediaPlayerService == 0) {
        
        // 获取 ServiceManager 的代理对象
        // ServiceManager 是 Android 系统的"服务管家",管理所有系统服务的注册表
        sp<IServiceManager> sm = defaultServiceManager();
        
        // 从 ServiceManager 获取 MediaPlayerService 的 Binder 代理
        // waitForService 是同步调用,会阻塞直到服务可用
        // "media.player" 是 MediaPlayerService 注册时使用的服务名称
        sp<IBinder> binder = sm->waitForService(String16("media.player"));
        
        // 检查是否成功获取服务代理
        // 如果服务不可用或获取失败,返回空指针
        if (binder == nullptr) {
            return nullptr;
        }
        
        // 创建死亡通知器(DeathNotifier)的单例实例
        // DeathNotifier 继承自 IBinder::DeathRecipient,用于监听服务进程的死亡事件
        // 只在首次调用时创建,所有客户端共享同一个实例
        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        
        // 将死亡通知器绑定到服务的 Binder 对象
        // 当 MediaPlayerService 进程异常退出时:
        //   1. Binder 驱动会检测到死亡事件
        //   2. 触发 DeathNotifier::binderDied() 回调
        //   3. 清理失效的服务代理并通知所有客户端
        binder->linkToDeath(sDeathNotifier);
        
        // 使用 interface_cast 将通用的 IBinder 转换为具体的 IMediaPlayerService 接口
        // 实际创建的是 BpMediaPlayerService(代理类),提供类型安全的方法调用
        // 转换后可以像调用本地方法一样调用远程服务方法
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    
    // 错误检查:如果服务代理仍然为空,输出错误日志
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    
    // 返回 IMediaPlayerService 的智能指针
    // 调用者可以使用它调用服务方法,如 create(), setDataSource() 等
    // 智能指针自动管理引用计数,防止内存泄漏
    return sMediaPlayerService;
}

首先就还是获取到 ServiceManager,然后通过 ServiceManager 获取到我们需要的 "media.player" 服务。

2 waitForService

接下来看看 sm->waitForService(String16("media.player")) 这个是怎么获取到的。

路径是在 frameworks/native/libs/binder/IServiceManager.cpp。

sp<IBinder> CppBackendShim::waitForService(const String16& name16) {
	// 内部 Waiter 类,服务注册成功之后的回调,用于唤醒等待的进程。
    class Waiter : public android::os::BnServiceCallback {
        Status onRegistration(const std::string& /*name*/,
                              const sp<IBinder>& binder) override {
            std::unique_lock<std::mutex> lock(mMutex);
            mBinder = binder;
            lock.unlock();
            // Flushing here helps ensure the service's ref count remains accurate
            IPCThreadState::self()->flushCommands();
            mCv.notify_one();
            return Status::ok();
        }
    public:
        sp<IBinder> mBinder;
        std::mutex mMutex;
        std::condition_variable mCv;
    };

    // Simple RAII object to ensure a function call immediately before going out of scope
    class Defer {
    public:
        explicit Defer(std::function<void()>&& f) : mF(std::move(f)) {}
        ~Defer() { mF(); }
    private:
        std::function<void()> mF;
    };

    const std::string name = String8(name16).c_str();

    // 首次尝试获取服务
    sp<IBinder> out;
    if (Status status = realGetService(name, &out); !status.isOk()) {
		// status nok,代表 sm 有问题。返回 null
        ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(),
              status.toString8().c_str());
        sp<ProcessState> self = ProcessState::selfOrNull();
        if (self && 0 == self->getThreadPoolMaxTotalThreadCount()) {
            ALOGW("Got service, but may be racey because we could not wait efficiently for it. "
                  "Threadpool has 0 guaranteed threads. "
                  "Is the threadpool configured properly? "
                  "See ProcessState::startThreadPool and "
                  "ProcessState::setThreadPoolMaxThreadCount.");
        }
        return nullptr;
    }
    if (out != nullptr) return out; // 服务已存在

    // 创建 Waiter 对象,用于接收回调,然后注册通知
    sp<Waiter> waiter = sp<Waiter>::make();
    if (Status status = mUnifiedServiceManager->registerForNotifications(name, waiter);
        !status.isOk()) {
        ALOGW("Failed to registerForNotifications in waitForService for %s: %s", name.c_str(),
              status.toString8().c_str());
        return nullptr;
    }
    Defer unregister([&] { mUnifiedServiceManager->unregisterForNotifications(name, waiter); });

    // 无限循环,获取服务
    while(true) {
        {
            // It would be really nice if we could read binder commands on this
            // thread instead of needing a threadpool to be started, but for
            // instance, if we call getAndExecuteCommand, it might be the case
            // that another thread serves the callback, and we never get a
            // command, so we hang indefinitely.
			// 等待通知,直到获得了有效的 Binder 对象或者超时
            std::unique_lock<std::mutex> lock(waiter->mMutex);
            waiter->mCv.wait_for(lock, 1s, [&] {
                return waiter->mBinder != nullptr;
            });
            if (waiter->mBinder != nullptr) return waiter->mBinder;
        }

        sp<ProcessState> self = ProcessState::selfOrNull();
        ALOGW("Waited one second for %s (is service started? Number of threads started in the "
              "threadpool: %zu. Are binder threads started and available?)",
              name.c_str(), self ? self->getThreadPoolMaxTotalThreadCount() : 0);

        // Handle race condition for lazy services. Here is what can happen:
        // - the service dies (not processed by init yet).
        // - sm processes death notification.
        // - sm gets getService and calls init to start service.
        // - init gets the start signal, but the service already appears
        //   started, so it does nothing.
        // - init gets death signal, but doesn't know it needs to restart
        //   the service
        // - we need to request service again to get it to start
        if (Status status = realGetService(name, &out); !status.isOk()) {
            ALOGW("Failed to getService in waitForService on later try for %s: %s", name.c_str(),
                  status.toString8().c_str());
            return nullptr;
        }
        if (out != nullptr) return out;
    }
}

这个代码是怎么获取通知的呢,主要流程是这样的。

首先定义一个 Waiter 类,他就是一个回调接收器,用来接收需要等待的那个服务是否已经注册的通知。然后向 sm 注册监听,就是让 sm 检测需要的服务是否已经注册,如果已经注册则回调 Waiter 对象。然后通过参数将服务 IBinder 传递了过来。最后通过 mCv.wait_for 来返回获得的服务。

如果等待超时,会使用 realGetService 来主动获取一次。

流程图如下:

3 registerForNotifications

我们来继续看一下 mUnifiedServiceManager->registerForNotifications(name, waiter) 注册通知的方法。

路径在:frameworks/native/cmds/servicemanager/ServiceManager.cpp

中间其实还经过 IServiceManager.cpp → CppBackendShim::registerForNotifications(),客户端永远不能直接调用 ServiceManager 进程里的代码,必须经过一层代理中转,中间还经过 Binder 驱动,是通过 AIDL 实现的。不过此处不过多赘述了。

Status ServiceManager::registerForNotifications(
        const std::string& name, const sp<IServiceCallback>& callback) {
    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));

	// 获取调用者身份,并进行权限检查
    auto ctx = mAccess->getCallingContext();

    // TODO(b/338541373): Implement the notification mechanism for services accessed via
    // IAccessor.
    std::optional<std::string> accessorName;
    if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) {
        return status;
    }

	// 隔离应用检查
    // note - we could allow isolated apps to get notifications if we
    // keep track of isolated callbacks and non-isolated callbacks, but
    // this is done since isolated apps shouldn't access lazy services
    // so we should be able to use different APIs to keep things simple.
    // Here, we disallow everything, because the service might not be
    // registered yet.
    if (is_multiuser_uid_isolated(ctx.uid)) {
        return Status::fromExceptionCode(Status::EX_SECURITY, "isolated app");
    }

	// 服务名合法性检查
    if (!isValidServiceName(name)) {
        ALOGE("%s Invalid service name: %s", ctx.toDebugString().c_str(), name.c_str());
        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name.");
    }

	// 空指针检查
    if (callback == nullptr) {
        return Status::fromExceptionCode(Status::EX_NULL_POINTER, "Null callback.");
    }

	// 死亡通知注册
    if (OK !=
        IInterface::asBinder(callback)->linkToDeath(
                sp<ServiceManager>::fromExisting(this))) {
        ALOGE("%s Could not linkToDeath when adding %s", ctx.toDebugString().c_str(), name.c_str());
        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't link to death.");
    }

	// 存储 callback
    mNameToRegistrationCallback[name].push_back(callback);

	// 即时回调
    if (auto it = mNameToService.find(name); it != mNameToService.end()) {
        const sp<IBinder>& binder = it->second.binder;

        // never null if an entry exists
        CHECK(binder != nullptr) << name;
        callback->onRegistration(name, binder);
    }

    return Status::ok();
}

重点在最后的即时回调部分,首先获取查找服务是否已存在,mNameToService 就是个 map,这个在注册服务的时候讲过,从这里获取服务。

如果存在,就取出 binder,然后检查一下 binder 是否为空,最后触发回调,也就是 onRegistration。

如果不存在,则什么都不做,等待 addService 那边进行通知。

4 realGetService

最后再来看一下 realGetService 是怎么实现的吧,这个在 waitForService 中出现了两次,第一次是快速路径,也就是先主动向 ServiceManager 查一次这个服务是否存在,如果服务已存在就直接返回,不需要再查询了。

另一次是出现在最后,也就是等待超时之后。再主动查询一次,是用来兜底的。

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

virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
        Service service;
        Status status = mUnifiedServiceManager->getService2(name, &service);
        auto serviceWithMetadata = service.get<Service::Tag::serviceWithMetadata>();
        *_aidl_return = serviceWithMetadata.service;
        return status;
}

可以看到是通过 mUnifiedServiceManager->getService2(name, &service) 来发起的查询,其实和上面一样,也是通过 AIDL 来实现的,最终调用的是 frameworks/native/cmds/servicemanager/ServiceManager.cpp 路径的 getService2

Status ServiceManager::getService2(const std::string& name, os::Service* outService) {
    SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
            PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));

    *outService = tryGetService(name, true);
    // returns ok regardless of result for legacy reasons
    return Status::ok();
}

这个很简单就是通过 tryGetService 来查询服务是否存在,但是不管存不存在都会返回 ok。

服务不存在不是错误,结果保存在 outService 中了,如果为 null 就是不存在。

os::Service ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
    // 检查是否有 accessor 代理
	std::optional<std::string> accessorName;
#ifndef VENDORSERVICEMANAGER
    accessorName = getVintfAccessorName(name);
#endif
    if (accessorName.has_value()) {
	// 通过 accessor 代理访问的服务
        auto ctx = mAccess->getCallingContext();
        if (!mAccess->canFind(ctx, name)) {
            return os::Service::make<os::Service::Tag::accessor>(nullptr);
        }
        return os::Service::make<os::Service::Tag::accessor>(
                tryGetBinder(*accessorName, startIfNotFound).service);
    } else {
		// 普通服务 —— 绝大多数情况走这里
        return os::Service::make<os::Service::Tag::serviceWithMetadata>(
                tryGetBinder(name, startIfNotFound));
    }
}

再往下就是 tryGetBinder 了。

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())));

    auto ctx = mAccess->getCallingContext();

    sp<IBinder> out;
    Service* service = nullptr;
    if (auto it = mNameToService.find(name); it != mNameToService.end()) {
        service = &(it->second);

        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 os::ServiceWithMetadata();
        }
        out = service->binder;
    }

    if (!mAccess->canFind(ctx, name)) {
        return os::ServiceWithMetadata();
    }

    if (!out && startIfNotFound) {
        tryStartService(ctx, name);
    }

    if (out) {
        // Force onClients to get sent, and then make sure the timerfd won't clear it
        // by setting guaranteeClient again. This logic could be simplified by using
        // a time-based guarantee. However, forcing onClients(true) to get sent
        // right here is always going to be important for processes serving multiple
        // lazy interfaces.
        service->guaranteeClient = true;
        CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false));
        service->guaranteeClient = true;
    }
    os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
    serviceWithMetadata.service = out;
    serviceWithMetadata.isLazyService =
            service ? service->dumpPriority & FLAG_IS_LAZY_SERVICE : false;
    return serviceWithMetadata;
}

太多了,先只看是怎么查找服务的吧

sp<IBinder> out;
Service* service = nullptr;

if (auto it = mNameToService.find(name); it != mNameToService.end()) {
    service = &(it->second);

	// allowIsolated 是否允许隔离应用访问,大多都不行
    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 os::ServiceWithMetadata();
    }
    out = service->binder;
}

前面准备了两个变量,out 一个空指针,用来存放结果。service 一个指针,用来指向 mNameToService 中的 Service 条目。

有两个的原因是因为 out 是为了返回给客户端的结果,service 是后面需要用到,例如创建客户端回调。

可以看到其实就是 map 查询,还是 mNameToService,如果存在使用 out 来保存结果。

流程图:

5 总结

获取服务的流程不复杂,简单概括就是:客户端 -> SM 插 map -> 有就返回,没有就注册回调等通知 -> 回调或超时兜底再查一次。

Suikeer

关于作者