ServiceManager在init进程启动之后启动,用来管理系统中的service,那么首先理解一下在init进程启动之后启动这句话类:
一般开机过程分为三个阶段:
1. OS级别,由bootloader载入linux内核后,内核开始初始化,并载入built-in的驱动程序,内核完成开机后,载入init process,切换至user-space后,结束内核的循序过程,进入排成模式。
2. Android-level,由init process开始,读取init.rc,Mative服务启动,并启动重要的外部程序,例如servicemanager、zygote以及system service。
3. Zygote-Mode,Zygote启动完System Service后,进入Zygote Mode,在Socket等候命令,随后,使用者将看到一个桌面环境,桌面环境由一个名为Launcher的应用程序负责提供。
在ServiceManager中有两个比较重要的方法:add_service和check_service,系统的service需要通过add_service把自己的信息注册到servicemanager中,当需要使用时,通过check_service检查该service是否存在。看它的main函数的源码:
三件事:
1. 打开Binder设备,并在内存中映射128k的空间
首先看一下struct binder_state这个结构体
struct binder_state{
int fd; //文件描述符,打开/dev/binder设备
void* mapped; //把设备文件/dev/binder映射到进程空间的起始地址
unsigned mapsize; //映射内存空间的大小
}
2. 告诉Binder驱动程序,自己是Binder上下文管理者
3.进入循环,不停去读Binder设备,看是否有对service的请求,如果有的话就去调用svcmgr_handller函数回调处理请求。
下面就来看一下servicemanager是怎么循环等待客户端的请求,并进行注册服务、服务获取这一系列活动的。
等待客户端请求
ServiceManager进程通过binder_loop方法进入循环等待客户端的请求中,当有客户端请求时,进程ServiceManager被唤醒并调用svcmgr_handler来处理客户端的请求。 1. ServiceManager进程在进入循环前,调用binder_write()方法,通过ioctl系统调用设置Binder线程的运行状态为BINDER_LOOPER_STATE_ENTERED,看下binder_write()方法的源码: 首先设置binder_write_read结构体变量的值,然后通过ioctl传递到Binder驱动程序中,此时控制命令为BINDER_WRITE_READ,binder_ioctl函数中对BINDER_WRITE_READ命令的处理过程为: 在binder_thread_write方法中,对BC_ENTER_LOOPER Binder协议的处理如下: 此处仅仅设置了binder_thread结构体变量中的线程运行状态looper为BINDER_LOOPER_STATE_ENTERED,表示当前的binder线程进入循环状态。
2. 睡眠等待客户端请求
在没有客户端请求时,当前进程就进入休眠状态,等待请求到来再唤醒。
总结一哈?
ServiceManager进程的启动首先打开binder驱动并开辟内核缓存区,同时将缓存区的物理页面同时映射到内核虚拟地址空间及进程虚拟地址空间中,然后在内核中创建属于servicemanager进程的binder_node实体节点,接着设置处理客户端请求的binder线程运行状态,由于此时没有客户端的请求,servicemanager进程进入睡眠等待中,直到客户端请求的到来时,唤醒servicemanager进程,再继续往下执行。
服务注册
直接来看,当有service请求时,调用的回到函数svcmgr_handler函数。 如果请求注册,就执行红色框中的代码,我们再来看一下具体实现do_add_service()方法是怎么实现的: 看代码中的三个红框,首先会检查是否有权限注册service,如果没有权限就直接返回不能注册;然后去检查该service是否已经注册过了,如果已经注册过,那就不能再注册;再判断内存是否够用。如果都没有问题,就会注册该service,加入到svcList中来,(在servicemanager中维护service信息的地方就是svcList,里面存了service的name和handler)。通过以上几步,service就算注册成功了。服务获取
如果是服务获取,就会执行代码中的黄色框,并将返回的数据写入reply,返回给客户端,do_find_service函数中主要执行service的查找,看源码:
纪念我的第一篇MarkDown文章
写了这么久的博客,一开始的时候就对文字输入表示怀疑,为啥人家输入代码的时候输入的这么溜,还能复制,而我只能截图发上去,偶然让我发现了MarkDown编译器,感觉当时的自己。。。。好白痴啊。。。。。