Android 13 - binder阅读(2)- ServiceManager的启动与获取

ServiceManager作为Android系统中的服务管理器,其启动涉及打开binder驱动、注册自身为服务管理者,并通过`BINDER_SET_CONTEXT_MGR_EXT`通知内核。然后,它监听binder驱动的消息,通过`talkWithDriver`与驱动通信,接收数据。获取ServiceManager的代理通常通过`defaultServiceManager`,该方法利用`getContextObject`和`getStrongProxyForHandle`创建ServiceManager的远程代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 ServiceManager的启动

1.1 服务的启动与注册

上一篇笔记中有说到,ServiceManager是一个特殊的binder service,所以它和普通的service一样需要打开binder驱动,在驱动中创建一个属于ServiceManager进程的binder_proc

int main(int argc, char** argv) {
    const char* driver = argc == 2 ? argv[1] : "/dev/binder";
    // 打开Binder驱动,mmap
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    ps->setThreadPoolMaxThreadCount(0);
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
	// 创建ServiceManager对象
    sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
    // 将ServiceManager自身先加入到服务列表当中
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
        LOG(ERROR) << "Could not self register servicemanager";
    }
    IPCThreadState::self()->setTheContextObject(manager);
    // 通知binder driver,我就是servicemanager
    ps->becomeContextManager();
    // 监听消息
    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);
    while(true) {
        looper->pollAll(-1);
    }
    return EXIT_FAILURE;
}

那它和普通service不一样的地方在哪里呢?就在于ServiceManager需要告诉binder驱动它就是servicemanager,这通过调用becomeContextManager完成。

bool ProcessState::becomeContextManager()
{
    AutoMutex _l(mLock);
    flat_binder_object obj {
        .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
    };
    int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
    return result == 0;
}

接下来我们到内核态中看看ioctl对应做了什么:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	case BINDER_SET_CONTEXT_MGR_EXT: {
		struct flat_binder_object fbo;
		// 将cmd从用户态copy过来
		if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {
			ret = -EINVAL;
			goto err;
		}
		ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
		if (ret)
			goto err;
		break;
	}
}

static int binder_ioctl_set_ctx_mgr(struct file *filp,
				    struct flat_binder_object *fbo)
{
	int ret = 0;
	// 1. 获取binder_proc
	struct binder_proc *proc = filp->private_data;
	// 2. 获取binder_proc 中保存的 binder_context
	struct binder_context *context = proc->context;
	// 创建一个binder_node
	struct binder_node *new_node;
	kuid_t curr_euid = current_euid();

	mutex_lock(&context->context_mgr_node_lock);
	// 判断是否已经注册有servicemanager
	if (context->binder_context_mgr_node) {
		pr_err("BINDER_SET_CONTEXT_MGR already set\n");
		ret = -EBUSY;
		goto out;
	}
	ret = security_binder_set_context_mgr(proc->cred);

	if (uid_valid(context->binder_context_mgr_uid)) {
	} else {
		context->binder_context_mgr_uid = curr_euid;
	}
	// 3. 用binder_proc实例化binder_node
	new_node = binder_new_node(proc, fbo);
	if (!new_node) {
		ret = -ENOMEM;
		goto out;
	}
	binder_node_lock(new_node);
	// 强弱引用计数加 1 
	new_node->local_weak_refs++;
	new_node->local_strong_refs++;
	new_node->has_strong_ref = 1;
	new_node->has_weak_ref = 1;
	// 4. 将binder_context中的binder_context_mgr_node 指向 servicemanager进程对应的binder_node 
	context->binder_context_mgr_node = new_node;
	binder_node_unlock(new_node);
	binder_put_node(new_node);
out:
	mutex_unlock(&context->context_mgr_node_lock);
	return ret;
}

binder_ioctl处理BINDER_SET_CONTEXT_MGR_EXT这条cmd主要做了以下几件事情:

  1. fd中获取binder_procbinder_proc指代的是ServiceManager所在进程;
  2. 获取binder_proc 中的 binder_context成员,从上一篇我们可以知道binder_context 指向的是binder_device中的binder_context成员(ServiceManager),只不过在ServiceManager进程起来前该binder_context成员为空;
  3. binder_proc实例化binder_node
  4. binder_context中的binder_context_mgr_node 指向 servicemanager进程对应的;binder_node,到这里binder_device中的binder_context成员就不为空了,binder驱动也就指定了ServiceManager。

1.2 服务的监听

ServiceManager注册完成之后,就会开始监听binder驱动,查看是否有消息发给自己,接下来我们一起看看它是如何监听消息的。

class BinderCallback : public LooperCallback {
public:
    static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
        sp<BinderCallback> cb = sp<BinderCallback>::make();
        int binder_fd = -1;
        IPCThreadState::self()->setupPolling(&binder_fd);
        int ret = looper->addFd(binder_fd,
                                Looper::POLL_CALLBACK,
                                Looper::EVENT_INPUT,
                                cb,
                                nullptr /*data*/);
        return cb;
    }

    int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
        IPCThreadState::self()->handlePolledCommands();
        return 1;  // Continue receiving callbacks.
    }
};

ServiceManager监听的是打开binder驱动时返回的fd,如果有事件则调用IPCThreadStatehandlePolledCommands方法来处理。

status_t IPCThreadState::handlePolledCommands()
{
    do {
        result = getAndExecuteCommand();
    } while (mIn.dataPosition() < mIn.dataSize());
}

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;
	// 1. 与binder驱动进行通信
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        size_t IN = mIn.dataAvail();
        cmd = mIn.readInt32();
		// 2. 收到数据执行命令
        result = executeCommand(cmd);
    }
    return result;
}

一路追过去我们发现,ServiceManager会调用talkWithDriver与binder驱动进行通信,如果有数据就调用executeCommand执行命令。

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
	// 1. 创建binder_write_read对象
    binder_write_read bwr;
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();
	// servicemanager中的监听指的接收,所以这里的doReceive为true
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        // 将binder_write_read的buffer指向mIn的buffer
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
	// 初始化其他成员
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
    	// 2. 调用ioctl与binder驱动通讯,传入参数为binder_write_read
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
    } while (err == -EINTR);

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
            else {
                mOut.setDataSize(0);
                processPostWriteDerefs();
            }
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        return NO_ERROR;
    }
    return err;
}

talkWithDriver主要做了如下几件事情:

  1. 构建并初始化binder_write_read,如果是发送(doReceive=true),则将binder_write_read中的参数用mIn初始化,否则用mOut初始化;
  2. 调用ioctl与binder驱动通讯读取数据,传入参数为刚刚构建的binder_write_read,cmd为BINDER_WRITE_READ

接下来我们一起进入内核态看看binder_ioctl中对应BINDER_WRITE_READ的分支做了什么。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	case BINDER_WRITE_READ:
		ret = binder_ioctl_write_read(filp, cmd, arg, thread);
		if (ret)
			goto err;
		break;
}

static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread)
{
	int ret = 0;
	struct binder_proc *proc = filp->private_data;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;
	struct binder_write_read bwr;
	// 1. 从用户态拷贝binder_write_read
	if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}

	// 这里是给binder驱动发送数据,暂时不看
	if (bwr.write_size > 0) {
		ret = binder_thread_write(proc, thread,
					  bwr.write_buffer,
					  bwr.write_size,
					  &bwr.write_consumed);
		trace_binder_write_done(ret);
		if (ret < 0) {
			bwr.read_consumed = 0;
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			goto out;
		}
	}
	// 这里是从binder驱动收取数据,先看这里
	if (bwr.read_size > 0) {
	    // 2. 读取数据
		ret = binder_thread_read(proc, thread, bwr.read_buffer,
					 bwr.read_size,
					 &bwr.read_consumed,
					 filp->f_flags & O_NONBLOCK);
	}
	// 3. 将数据拷贝到用户空间
	if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}
out:
	return ret;
}

读取数据主要调用了binder_ioctl_write_read,做了如下事情:

  1. 创建binder_write_read对象bwr,并且从将用户态的数据拷贝到该对象中;
  2. 调用binder_thread_read读取数据到bwr;
  3. 将bwr中的数据重新拷贝会用户态。

因为还没有数据传过来,所以binder_thread_read我们暂不分析,后面看到数据发送后我们再一起看。

同样的,返回用户态之后executeCommand我们暂时也先不看。

题外话:做笔记的时候不可避免的贴了很多代码,这是我很不愿意做的,因为对不了解代码的同学来说,虽然有注释但是看来依旧非常困难。我更希望能够从全局的角度了解代码执行的流程,所以我可能会在每一节最后做一个总结,尽管可能会和前文内容有重复。

总结起来ServiceManager监听binder驱动的动作如下:

  1. 用户态中,执行talkWithDriver与binder驱动做通信,首先构建binder_write_read,执行iotcl发送BINDER_WRITE_READ命令读取数据;内核态中,先将用户态的cmd参数拷贝到内核态,接着调用binder_thread_read读取数据,最后将数据拷贝回用户态;
  2. 用户态中,收到返回的数据后执行executeCommand处理数据。

2 获取ServiceManager

使用ServiceManager之前,我们肯定要从binder驱动中获取到它,最常用的获取方式如下:

    // 获取servicemanager
    sp<IServiceManager> sm(defaultServiceManager());

可以看到获取ServiceManager代理的方式和获取普通服务代理有一些不一样,普通服务代理需要通过ServiceManager来查询并获取,例如:

sp<IBinder> binder = sm->getService(String16("media.camera"));

ServiceManager的远程代理要通过什么来获得呢?那android自然是开了后门的,一起来看看吧。

sp<IServiceManager> defaultServiceManager()
{
    std::call_once(gSmOnce, []() {
        sp<AidlServiceManager> sm = nullptr;
        while (sm == nullptr) {
            sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
        }
        gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
    });

    return gDefaultServiceManager;
}

通过ProcessStategetContextObject方法,并且将参数设置为NULL即可获取ServiceManager的代理。

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

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    // 1. 查询是否有handle对应的远程代理,如果没有则创建一个
    handle_entry* e = lookupHandleLocked(handle);
    if (e != nullptr) {
        IBinder* b = e->binder;
        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
        	// 这个判断中的代码可以不用看
            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;
            }
			// 用Handle创建一个远程代理对象BpXXX
            sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
            e->binder = b.get();
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

这里贴了比较长的代码,核心就是getStrongProxyForHandle,从名字来看意为,用从binder驱动获取的handle来创建一个强引用对象。

ServiceManager创建这个强引用对象时,用的handle为0,这是预先设定好的,意思是handle为0的代理就是ServiceManager。这要如何理解呢?我们要看看一个方法lookupHandleLocked

ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
    const size_t N=mHandleToObject.size();
    if (N <= (size_t)handle) {
        handle_entry e;
        e.binder = nullptr;
        e.refs = nullptr;
        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
        if (err < NO_ERROR) return nullptr;
    }
    return &mHandleToObject.editItemAt(handle);
}

getStrongProxyForHandle一开始就调用了这个方法lookupHandleLocked,有一个比较有意思的点,里面使用handle和mHandleToObject中元素的数量做对比。为什么可以这样对比,解释大概如下:每个进程中的handle都是从0开始计数增加的,mHandleToObject中元素的数量代表的是该进程中引用了几个服务,由于获取其他服务前需要先获取ServiceManager的代理,所以ServiceManager必须是第一个被引用的服务,所以handle值为0。

handle值计数的设定由是如何设定的这里暂不讨论,另外这里还要留下一个问题,创建Bpxxx时引用计数需要如何处理?后面会继续研究。

到这里ServiceManager的远程服务代理就获取结束了。


天气越来越热,但是心要保持平静~

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值