系列文章目录
目录
2.4 ProcessState::initWithDriver
2.6 ProcessState::ProcessState
2.10 设置binder最大线程数binder_ioctl
2.13 setThreadPoolMaxThreadCount
2.15 ServiceManager::addService
2.18 IPCThreadState::IPCThreadState
2.20 IPCThreadState::setTheContextObject
2.21 ProcessState::becomeContextManager
2.28 Looper::rebuildEpollLocked
2.31 IPCThreadState::setupPolling
2.33 IPCThreadState::flushCommands
2.34 IPCThreadState::talkWithDriver
2.38 ClientCallbackCallback::setupTo
1.简介
经过上一篇,我们已经知道servermanager的框架,那么本篇便从源码的角度分析servermangaer服务的启动流程。
1.1 流程介绍
第一步:首先init进程启动后会读取各个进程的rc启动文件,然后会去启动servermanager服务。
第二步:在servermanager服务的main函数中,首先会打开/dev/binder驱动,并申请一块内存,通过mmap的进行内存映射,将servermanager服务的用户空间映射到驱动中,从而会减少数据的拷贝。
第三步:在servermanager服务的main函数中,创建servicemanager服务的对象,并将ServiceManager对象注册到自身的Map表保存起来。
第四步:becomeContextManager通知驱动成为binder的管理者。
第五步:servermanager服务的主线程进入死循环,调用epoll_wait() 监听/dev/binder是否有数据可读,如有则调用回调执行指令,根据client传入的code,从而调用get()\add()\ 等接口,来查询、注册binder服务。
1.2 时序图

(为了保证流程的完整性,较为模糊,可放大观看)
2.源码分析
2.1 servicemanager的启动
1.在init.rc中,当init进程启动后,会去启动servicemanager、hwservicemanager、vndservicemanager 三个binder的守护进程。
[/system/core/rootdir/init.rc]
on init
...
start servicemanager //启动sericemanager服务
start hwservicemanager
start vndservicemanager
2.2 servicemanager.rc
1.init进程启动后,会从指定路径加载进程的rc文件,然后启动servicemanager服务。
service servicemanager /system/bin/servicemanager
class core animation //服务的类为core和animation
user system //在启动服务前将用户切换为system
group system readproc //在启动前将用户组切换为system和readproc
critical //表明这个服务是至关重要的服务,如果它在四分钟内退出超过四次,则设备将重启进入恢复模式
onrestart restart apexd //当此服务重启后,重启apexd服务
onrestart restart audioserver //当此服务重启后,重启audioserver服务
onrestart restart gatekeeperd //当此服务重启后,重启gatekeeperd服务
onrestart class_restart main //当此服务重启后,重启所有class为main的服务
onrestart class_restart hal //当此服务重启后,重启所有class为 hal的服务
onrestart class_restart early_hal //当此服务重启后,重启所有class为early_hal的服务
writepid /dev/cpuset/system-background/tasks //写入当前servicemanager进程的pid到/dev/cpuset/system-background/tasks文件中
shutdown critical //设置Service进程的关闭行为。在关机期间,当前服务在shutdown超时之前不会被关闭。
2.3 main.cpp
主要作用为:
1.打开/dev/binder驱动,并完成mmap的内存映射,然后向设置最大线程数。
2.创建servicemanager服务的对象。
3.将ServiceManager对象注册到自身的Map表中。
4.becomeContextManager通知驱动成为binder的管理者。
5.进入死循环,调用epoll_wait() 监听/dev/binder是否有数据可读,如有则调用回调执行指令,根据client传入的code,从而调用get()\add()\ 等接口,来查询、注册binder服务。
int main(int argc, char** argv) {//servicemanager入口,与/dev/binder交互,vndservicemanager也是走这个口,只是init时,会传入/dev/vndbinder值
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
}
const char* driver = argc == 2 ? argv[1] : "/dev/binder";//因为没传入值所以driver值是/dev/binder
sp<ProcessState> ps = ProcessState::initWithDriver(driver);//传入的值是/dev/binder,创建了ProcessState对象,里面主要是通过mmap内存映射一块地址空间
ps->setThreadPoolMaxThreadCount(0);//设置最大线程数为0
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());//创建了一个ServiceManager对象
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {//将自身注册到ServiceManager当中
LOG(ERROR) << "Could not self register servicemanager";
}
IPCThreadState::self()->setTheContextObject(manager);
ps->becomeContextManager();//成为管理者
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);
while(true) {//死循环,
looper->pollAll(-1);//阻塞在此处,等待监听的fd有消息的到来
}
// should not be reached
return EXIT_FAILURE;
}
2.4 ProcessState::initWithDriver
sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
return init(driver, true /*requireDefault*/);
}
2.5 ProcessState::init
1.创建了ProcessState对象。此对象用于打开binder驱动,并完成内存的映射,将用户空间的一块内存映射到内核空间,映射关系建立后,用户对这块内存区域的修改可直接反映到内核空间,反之内核空间对其修改也能反映到用户空间。
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
[[clang::no_destroy]] static sp<ProcessState> gProcess;
[[clang::no_destroy]] static std::mutex gProcessMutex;
/**
if (driver == nullptr) {//此时不为空,不执行
std::lock_guard<std::mutex> l(gProcessMutex);
return gProcess;
}
*/
[[clang::no_destroy]] static std::once_flag gProcessOnce;//call_once的flag
std::call_once(gProcessOnce, [&](){//call_once表示这个函数只执行一次
if (access(driver, R_OK) == -1) {//access判断/dev/binder文件是否存在
ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
driver = "/dev/binder";
}
std::lock_guard<std::mutex> l(gProcessMutex);
gProcess = sp<ProcessState>::make(driver);//此处使用的是安卓智能指针的构造,内部会调用new ProcessState
});
if (requireDefault) {//传入的是true,打印log
LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,
"ProcessState was already initialized with %s,"
" can't initialize with %s.",
gProcess->getDriverName().c_str(), driver);
}
return gProcess;
}
2.6 ProcessState::ProcessState
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))//driver是/dev/binder
, mDriverFD(open_driver(driver))//打开binder驱动返回的fd文件描述符
, mVMStart(MAP_FAILED)//
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)//保护线程数量的锁,pthread_mutex_t mThreadCountLock;
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)//条件变量。pthread_cond_t mThreadCountDecrement;
, mExecutingThreadsCount(0)
, mWaitingForThreads(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)//最大线程数15
, mStarvationStartTimeMs(0)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
// mmap binder,内存映射。128k的内存地址,申请128k的内存地址用来接收事务,对应binder驱动的binder_mmap函数。
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
/**
if (mVMStart == MAP_FAILED) {//如果内存映射失败
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
*/
}
}
2.7 open_driver
主要作用为:
1.open打开binder驱动,通过系统调用_open,最后会调用到binder_open,陷入内核态。获取fd。
2.通过ioctl,获取binder驱动版本号,用vers保存。然后对比版本号是否一致。
3.通过ioctl设置binder驱动最大线程数。
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);//driver值是/dev/binder,打开binder驱动,陷入内核,此
//open对应_open,然后对应binder驱动层的binder_open,binder_open中主要是为/dev/binder这个驱动设备节点,创建
//对应的proc对象,然后通过fd返回。这样就可以和驱动进行通信。
if (fd >= 0) {//大于0代表打开成功
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);//获取binder驱动的版本信息,用vers保存
/**正常不执行
if (result == -1) {//如果获取信息失败,则关闭binder驱动
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
*/
/**
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {//如果获取的版本信息不匹配,则关闭binder驱动
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
*/
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;//设置最大线程数15
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//设置binder驱动最大线程数
/**
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
*/
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;//DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION值是1,表示默认启用更新垃圾检测
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);//设置到binder驱动中
/**
if (result == -1) {
ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
*/
}
/**
else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
*/
return fd;
}
2.8 binder_open
1.为当前sm服务进程分配保存binder_proc的对象。binder_proc结构体保存的是sm服务的进程的信息。
2.对sm服务的binder_proc的对象进行初始化,如初始化todo队列,设置进程优先级等。
3.将sm服务的binder_proc添加到binder_procs队列中,驱动有一个全局的binder_procss的列表,用于存储所有进程的binder_proc对象。
//主要作用:binder驱动为用户进程创建了用户进程自己的binder——proc实体
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;//proc表示驱动中binder进程
proc = kzalloc(sizeof(*proc), GFP_KERNEL);//为binder_proc结构体在分配kernel内存空间
if (proc == NULL)
return -ENOMEM;
//下面是对binder_proc进行初始化,binder_proc用于管理数据的记录体
get_task_struct(current);
proc->tsk = current;//current代表当前线程。当前线程此时是servicemanager的主线程,当前线程的task保存在binder进程的tsk
INIT_LIST_HEAD(&proc->todo);//初始化to列表
init_waitqueue_head(&proc->wait);//初始化wait列表
proc->default_priority = task_nice(current);//当前进程的nice值转化为进程优先级
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);//BINDER_PROC对象创建+1
hlist_add_head(&proc->proc_node, &binder_procs);//将proc_node节点添加到binder_procs为表头的队列
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;//将 proc 保存到filp中,这样下次可以通过filp找到此proc
binder_unlock(__func__);
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
}
return 0;
}
//进程相关的参数
struct binder_proc {
struct hlist_node proc_node;//hlist_node表示哈希表中的一个节点。哈希表中的一个节点,用于标记该进程
struct rb_root threads;// rb_root表示红黑树。Binder线程池每一个Binder进程都有一个线程池,
//由Binder驱动来维护,Binder线程池中所有线程由一个红黑树来组织,RB树以线程ID为关键字 */
//上述红黑树的根节点
struct rb_root nodes;// 一系列Binder实体对象(binder_node)和Binder引用对象(binder_ref) */
//在用户空间:运行在Server端称为Binder本地对象,运行在Client端称为Binder代理对象*/
//在内核空间:Binder实体对象用来描述Binder本地对象,Binder引用对象来描述Binder代理对象 */
//Binder实体对象列表(RB树),关键字 ptr
struct rb_root refs_by_desc;//记录binder引用, 便于快速查找,binder_ref红黑树的根节点(以handle为key),它是Client在Binder驱动中的体现。
//Binder引用对象,关键字 desc
struct rb_root refs_by_node;//记录binder引用, 便于快速查找,binder_ref红黑树的根节点(以ptr为key),它是Client在Binder驱动中的体现,
//Binder引用对象,关键字 node
struct list_head waiting_threads;
int pid;//进程组pid
struct task_struct *tsk;//任务控制模块
const struct cred *cred;
struct hlist_node deferred_work_node;
int deferred_work;
bool is_dead;
struct list_head todo;//待处理队列,进程每接收到一个通信请求,Binder将其封装成一个工作项,保存在待处理队列to_do中 */
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;// Binder驱动程序最多可以请求进程注册线程的最大数量,
//进程可以调用ioctl注册线程到Binder驱动程序中,当线程池中没有足够空闲线程来处理事务时,Binder驱动可以主动要求进程注册更多的线程到Binder线程池中 */
// Binder驱动程序最多可以请求进程注册线程的最大数量
int requested_threads;
int requested_threads_started;
int tmp_ref;
long default_priority;
struct dentry *debugfs_entry;
struct binder_alloc alloc;
struct binder_context *context;//存储binder_node和binder_context_mgr_uid以及name
spinlock_t inner_lock;
spinlock_t outer_lock;
struct dentry *binderfs_entry;
};
2.9 获取版本号binder_ioctl
主要作用为:
1.此时用于获取版本号,存在一次拷贝行为。
//获取binder版本号分析
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;//binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//binder_stop_on_user_error值是0,
//binder_stop_on_user_error < 2为假时,休眠,故此处不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取当前sm的proc实体对象的binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_VERSION://获取版本号
if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
//将驱动程序的BINDER_CURRENT_PROTOCOL_VERSION变量地址,拷贝sizeof(*ptr)的ubuf用户空间地址。
//分析,此处是有一次拷贝的。
ret = -EINVAL;
goto err;
}
break;
default:
ret = -EINVAL;
goto err;
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.10 设置binder最大线程数binder_ioctl
//设置binder最大线程数分析
//ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);maxThreads值为15
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;//binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//ubuf是15的地址
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取当前sm的proc实体的binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_SET_MAX_THREADS://设置binder最大线程数量
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {//拷贝用户空间的地址到内核空间
ret = -EINVAL;
goto err;
}
break;
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_ev

https://blog.youkuaiyun.com/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501
最低0.47元/天 解锁文章
632

被折叠的 条评论
为什么被折叠?



