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驱动,mmapsp<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,我就是servicemanagerps->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_procstruct binder_proc *proc = filp->private_data;// 2. 获取binder_proc 中保存的 binder_contextstruct binder_context *context = proc->context;// 创建一个binder_nodestruct binder_node *new_node;kuid_t curr_euid = current_euid();mutex_lock(&context->context_mgr_node_lock);// 判断是否已经注册有servicemanagerif (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_nodenew_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主要做了以下几件事情:
- 从fd中获取
binder_proc
,binder_proc
指代的是ServiceManager所在进程; - 获取
binder_proc
中的binder_context
成员,从上一篇我们可以知道binder_context
指向的是binder_device
中的binder_context
成员(ServiceManager),只不过在ServiceManager进程起来前该binder_context
成员为空; - 用
binder_proc
实例化binder_node
; - 将
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,如果有事件则调用IPCThreadState
的handlePolledCommands方法来处理。
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为trueif (doReceive && needRead) {bwr.read_size = mIn.dataCapacity();// 将binder_write_read的buffer指向mIn的bufferbwr.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_readif (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)err = NO_ERROR;elseerr = -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主要做了如下几件事情:
- 构建并初始化
binder_write_read
,如果是发送(doReceive=true),则将binder_write_read
中的参数用mIn初始化,否则用mOut初始化; - 调用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_readif (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,做了如下事情:
- 创建
binder_write_read
对象bwr,并且从将用户态的数据拷贝到该对象中; - 调用binder_thread_read读取数据到bwr;
- 将bwr中的数据重新拷贝会用户态。
因为还没有数据传过来,所以binder_thread_read我们暂不分析,后面看到数据发送后我们再一起看。
同样的,返回用户态之后executeCommand我们暂时也先不看。
题外话:做笔记的时候不可避免的贴了很多代码,这是我很不愿意做的,因为对不了解代码的同学来说,虽然有注释但是看来依旧非常困难。我更希望能够从全局的角度了解代码执行的流程,所以我可能会在每一节最后做一个总结,尽管可能会和前文内容有重复。
总结起来ServiceManager
监听binder驱动的动作如下:
- 用户态中,执行talkWithDriver与binder驱动做通信,首先构建
binder_write_read
,执行iotcl发送BINDER_WRITE_READ命令读取数据;内核态中,先将用户态的cmd参数拷贝到内核态,接着调用binder_thread_read读取数据,最后将数据拷贝回用户态; - 用户态中,收到返回的数据后执行executeCommand处理数据。
2 获取ServiceManager
使用ServiceManager
之前,我们肯定要从binder驱动中获取到它,最常用的获取方式如下:
// 获取servicemanagersp<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;
}
通过ProcessState
的getContextObject方法,并且将参数设置为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创建一个远程代理对象BpXXXsp<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的远程服务代理就获取结束了。
天气越来越热,但是心要保持平静~