[TOC]
概述
文章参考:https://blog.csdn.net/itachi85/article/details/104205274
上一篇文章Android进程间通信(IPC)机制Binder简要介绍和学习计划简要介绍了Android系统进程间通信机制Binder的总体架构,它由Client、Server、Service Manager和驱动程序Binder四个组件构成。
本文着重介绍组件Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能。ServiceManager本身也是一个Binder服务,但并没有采用libbinder中的多线程模型来与Binder驱动通信,而是自行编写了binder.c直接和Binder驱动来通信,并且只有一个循环binder_loop来进行读取和处理事务,这样的好处是简单而高效。
既然Service Manager组件是用来管理Server并且向Client提供查询Server远程接口的功能,那么,Service Manager就必然要和Server以及Client进行通信了。我们知道,ServiceManger、Client和Server三者分别是运行在独立的进程当中,这样它们之间的通信也属于进程间通信了,而且也是采用Binder机制进行进程间通信,因此,Service Manager在充当Binder机制的守护进程的角色的同时,也在充当Server的角色,然而,它是一种特殊的Server,下面我们将会看到它的特殊之处。
与Service Manager相关的源代码较多,这里不会完整去分析每一行代码,主要是带着Service Manager是如何成为整个Binder机制中的守护进程这条主线来一步一步地深入分析相关源代码,包括从用户空间到内核空间的相关源代码。
ServiceManager的启动
ServiceManager是init进程负责启动的,具体是在解析init.rc配置文件时启动的,init进程是在系统启动时启动的,因此ServiceManager亦是如此。
1 2 3 4 5
| // 启动必不可少的服务 # Start essential services. start servicemanager start hwservicemanager start vndservicemanager
|
rc文件内部由Android初始化语言编写(Android Init Language)编写的脚本,它主要包含五种类型语句:Action、Commands、Services、Options和Import。
在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。ServiceManager的启动脚本在servicemanager.rc中:
frameworks/native/cmds/servicemanager/servicemanager.rc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
service servicemanager /system/bin/servicemanager class core animation user system group system readproc critical file /dev/kmsg w onrestart setprop servicemanager.ready false onrestart restart apexd onrestart restart audioserver onrestart restart gatekeeperd onrestart class_restart --only-enabled main onrestart class_restart --only-enabled hal onrestart class_restart --only-enabled early_hal task_profiles ServiceCapacityLow shutdown critical
|
service用于通知init进程创建名为servicemanager的进程,这个servicemanager进程执行程序的路径为/system/bin/servicemanager。
注释1的关键字user说明servicemanager是以用户system的身份运行的,注释2处的critical说明servicemanager是系统中的关键服务,关键服务是不会退出的,如果退出了,系统就会重启,当系统重启时就会启动用onrestart关键字修饰的进程,比如zygote、media、surfaceflinger等等。
servicemanager的入口函数在service_manager.c中,具体的启动流程图如下:
我们看一下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
int main(int argc, char** argv) { android::base::InitLogging(argv, android::base::KernelLogger);
if (argc > 2) { LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; }
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
LOG(INFO) << "Starting sm instance on " << driver;
sp<ProcessState> ps = ProcessState::initWithDriver(driver); ps->setThreadPoolMaxThreadCount(0); ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>()); if (!manager->addService("manager", manager, false , IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { LOG(ERROR) << "Could not self register servicemanager"; }
IPCThreadState::self()->setTheContextObject(manager); ps->becomeContextManager();
sp<Looper> looper = Looper::prepare(false );
BinderCallback::setupTo(looper); ClientCallbackCallback::setupTo(looper, manager);
#ifndef VENDORSERVICEMANAGER if (!SetProperty("servicemanager.ready", "true")) { LOG(ERROR) << "Failed to set servicemanager ready property"; } #endif
while(true) { looper->pollAll(-1); }
return EXIT_FAILURE; }
|
binder_state结构体用来存储binder的三个信息:
1 2 3 4 5 6
| struct binder_state { int fd; //binder设备的文件描述符 void *mapped; //binder设备文件映射到进程的地址空间 size_t mapsize; //内存映射后,系统分配的地址空间的大小,默认为128KB };
|