android系统启动流程- ServiceManager进程启动流程

news/2024/9/20 7:25:28/文章来源:https://www.cnblogs.com/linhaostudy/p/18301854

*注:基于Android11源码

ServiceManager进程是在init进程创建的,所以我们从init进程的main()开始分析:

// 文件路径: system/core/init/main.cppint main(int argc, char** argv) {...if (!strcmp(argv[1], "second_stage")) {  //TODO  根据条件会走到这个分支return SecondStageMain(argc, argv);}}int SecondStageMain(int argc, char** argv) {...//用来存放解析出的内容ActionManager& am = ActionManager::GetInstance();ServiceList& sm = ServiceList::GetInstance();//在这个方法中会对 /system/core/rootdir/init.rc 脚本文件文件进行解析LoadBootScripts(am, sm);//循环处理init.rc脚本中的command命令,处理完就进入等待while (true) {if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {//内部遍历执行每个action中携带的command对应的执行函数am.ExecuteOneCommand();}}
}static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {//创建解析器Parser parser = CreateParser(action_manager, service_list);std::string bootscript = GetProperty("ro.boot.init_rc", "");if (bootscript.empty()) {//解析init.rc ,这个是手机设备上的路径,和源码中system/core/init/init.rc是一个文件parser.ParseConfig("/system/etc/init/hw/init.rc");if (!parser.ParseConfig("/system/etc/init")) {late_import_paths.emplace_back("/system/etc/init");}// late_import is available only in Q and earlier release. As we don't// have system_ext in those versions, skip late_import for system_ext.parser.ParseConfig("/system_ext/etc/init");if (!parser.ParseConfig("/product/etc/init")) {late_import_paths.emplace_back("/product/etc/init");}if (!parser.ParseConfig("/odm/etc/init")) {late_import_paths.emplace_back("/odm/etc/init");}if (!parser.ParseConfig("/vendor/etc/init")) {late_import_paths.emplace_back("/vendor/etc/init");}} else {parser.ParseConfig(bootscript);}
}

下面是init.rc中启动servicemanager进程相关的部分:

on init# Start essential services.start servicemanager  #启动servicemanager进程start hwservicemanagerstart vndservicemanager

有关servicemanager进程启动的细节配置被放在了 frameworks\native\cmds\servicemanager\servicemanager.rc

#此脚本文件描述了启动servicemanager进程时的一些细节
#service用于通知init进程创建名为servicemanager的进程,这个进程执行程序的路径是/system/bin/servicemanager
#在手机系统中是能找到这个文件的
service servicemanager /system/bin/servicemanagerclass core animation#表明此进程是以system身份运行的user systemgroup system readproc#说明servicemanager是系统中的关键服务,关键服务是不会退出的,若退出系统则会重启,系统重启则会重启#以下onrestart修饰的进程,也可以说明这些进程是依赖于servicemanager进程的criticalonrestart restart healthdonrestart restart zygoteonrestart restart audioserveronrestart restart mediaonrestart restart surfaceflingeronrestart restart inputflingeronrestart restart drmonrestart restart cameraserveronrestart restart keystoreonrestart restart gatekeeperdonrestart restart thermalservicewritepid /dev/cpuset/system-background/tasksshutdown critical

当执行到 start servicemanager 这条命令,就会运行android设备(比如手机)中 /system/bin/servicemanager这个可执行文件,而这个可执行程序就是servicemanager进程,他由 frameworks\native\cmds\servicemanager\main.cpp 文件编译生成的。什么?你不信?打开frameworks\native\cmds\servicemanager\Android.bp,这就是证据:

...
# cc_binary表示编译成一个二进制文件
cc_binary {name: "servicemanager", #文件名defaults: ["servicemanager_defaults"],init_rc: ["servicemanager.rc"],  #配置详情srcs: ["main.cpp"],   #要编译的源文件
}...

这样我们就知道运行servicemanager这个可执行文件就是运行到了frameworks\native\cmds\servicemanager\main.cpp这个文件了。

int main(int argc, char** argv) {if (argc > 2) {LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";}//此时要使用的binder驱动为 "/dev/binder",同样这个路径也是android设备上的路径const char* driver = argc == 2 ? argv[1] : "/dev/binder";//打开binder驱动文件并将此进程与binder驱动进行内存映射,ProcessState是用来保存进程状态的一个类sp<ProcessState> ps = ProcessState::initWithDriver(driver); //注释1//设置最大线程数ps->setThreadPoolMaxThreadCount(0);ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);//实例化ServiceManagersp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());//将自身作为服务添加if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {LOG(ERROR) << "Could not self register servicemanager";}//创建服务端Bbinder对象IPCThreadState::self()->setTheContextObject(manager); //注释2//设置称为binder驱动的context manager,称为上下文的管理者ps->becomeContextManager(nullptr, nullptr);//通过Looper epoll机制处理binder事务sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);//Binder驱动中数据变化的监听BinderCallback::setupTo(looper); //注释3ClientCallbackCallback::setupTo(looper, manager); while(true) { looper->pollAll(-1);}// should not be reachedreturn EXIT_FAILURE;
}

先看注释1:

//frameworks\native\libs\binder\ProcessState.cppsp<ProcessState> ProcessState::initWithDriver(const char* driver)
{Mutex::Autolock _l(gProcessMutex);if (gProcess != nullptr) {// Allow for initWithDriver to be called repeatedly with the same// driver. 允许使用同一驱动程序重复调用initWithDriver()if (!strcmp(gProcess->getDriverName().c_str(), driver)) {//若当前ProcessState对象的驱动与传参不同return gProcess;  //直接返回现有的ProcessState对象}LOG_ALWAYS_FATAL("ProcessState was already initialized.");}if (access(driver, R_OK) == -1) {ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);driver = "/dev/binder";}//第一次调用gProcess为空,走这里gProcess = new ProcessState(driver); //创建新对象return gProcess;
}//ProcessState类的构造函数
ProcessState::ProcessState(const char *driver): mDriverName(String8(driver))  //以下都是成员变量初始化赋值,设置驱动名, mDriverFD(open_driver(driver)) //打开驱动文件,拿到驱动文件的文件描述符, mVMStart(MAP_FAILED), mThreadCountLock(PTHREAD_MUTEX_INITIALIZER), mThreadCountDecrement(PTHREAD_COND_INITIALIZER), mExecutingThreadsCount(0), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mStarvationStartTimeMs(0), mBinderContextCheckFunc(nullptr), mBinderContextUserData(nullptr), mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE)
{if (mDriverFD >= 0) { //大于0,说明打开binder驱动成功// mmap内存映射,提供一块虚拟地址空间来接收事务(即从客户端发送的请求(数据))。// BINDER_VM_SIZE 地址空间大小BINDER_VM_SIZE = 1M - 8k
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();}}...
}static int open_driver(const char *driver)
{//得到驱动的文件描述符int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd >= 0) {int vers = 0;//binder驱动版本检查status_t result = ioctl(fd, BINDER_VERSION, &vers);if (result == -1) {ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));close(fd);fd = -1;}if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {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;//给驱动设置最大线程数result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);if (result == -1) {ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));}} else {ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));}return fd;
}

接下来到注释2部分:

//	frameworks\native\libs\binder\IPCThreadState.cpp//IPCThreadState是线程单例
IPCThreadState* IPCThreadState::self()
{//不是初次调用的情况,TLS的全称为Thread Local Storageif (gHaveTLS.load(std::memory_order_acquire)) {
restart://初次调用,生成线程私有变量key后//TLS 表示线程本地存储空间,和java中的ThreadLocal是一个意思const pthread_key_t k = gTLS;IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);if (st) return st;//没有的话就实例化一个return new IPCThreadState;}// Racey, heuristic test for simultaneous shutdown.// IPCThreadState shutdown后不能再获取if (gShutdown.load(std::memory_order_relaxed)) {ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");return nullptr;}// 首次获取时gHaveTLS为false,会先走这里pthread_mutex_lock(&gTLSMutex);if (!gHaveTLS.load(std::memory_order_relaxed)) {//创建一个key,作为存放线程本地变量的keyint key_create_value = pthread_key_create(&gTLS, threadDestructor);if (key_create_value != 0) {pthread_mutex_unlock(&gTLSMutex);ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",strerror(key_create_value));return nullptr;}//创建完毕,gHaveTLS设置为truegHaveTLS.store(true, std::memory_order_release);}pthread_mutex_unlock(&gTLSMutex);// 回到gHaveTLS为true的casegoto restart;
}sp<BBinder> the_context_object;void IPCThreadState::setTheContextObject(sp<BBinder> obj)
{   //赋值给一个BBinder类型的成员变量,即传进来的这个manager就是服务端的BBinderthe_context_object = obj;
}

为了更好的理解ServiceManager这个类,下面是一张它的继承关系图:

image

下面来到注释3:

static sp<BinderCallback> setupTo(const sp<Looper>& looper) {sp<BinderCallback> cb = new BinderCallback;int binder_fd = -1;//向binder驱动发送BC_ENTER_LOOPER事务请求,并获得binder驱动的文件描述符IPCThreadState::self()->setupPolling(&binder_fd);LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);// Flush after setupPolling(), to make sure the binder driver// knows about this thread handling commands.// 检查写缓存是否有可写数据,有的话发给binder驱动IPCThreadState::self()->flushCommands();// 监听binder文件描述符int ret = looper->addFd(binder_fd,Looper::POLL_CALLBACK,Looper::EVENT_INPUT,cb,nullptr /*data*/);LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");return cb;}// 当binder驱动发来消息后,就可以通过次函数接收处理了int handleEvent(int /* fd */, int /* events */, void* /* data */) override {//处理消息IPCThreadState::self()->handlePolledCommands();return 1;  // Continue receiving callbacks.}
};

servicemanager进程启动过程中,主要做了以下四件事:

1)初始化binder驱动

2)将自身以“manager” 添加到servicemanager中的map集合中

3)注册成为binder驱动的上下问管理者

  1. 给Looper设置callback,进入无限循环,处理client端发来的请求

总结:

1.ServiceManager是一个独立的进程,由init进程创建,且在创建zygote进程之前被创建。

2.IBinder是什么?它是实现了AIDL接口的实体类,它实现了接口中的所有方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/743629.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jdk22

1、下载JDK22 2、安装JDK22选择路径后,一路默认安装。3、Windows 系统下配置环境变量点击我的电脑-属性-高级系统设置 新增配置 JAVA_HOME,为 jdk 的安装路径D:\Java22\jdk22 编辑配置 Path 变量,配置 jdk 的 bin 的目录%JAVA_HOME%\bin 验证安装结果 java -version

第一章 FFmpeg初体验:在Centos7.9下编译FFmpeg!

FFmpeg 官方网站:https://ffmpeg.org//download.html#build-linux 1.下载源码 1.1 第一种方式,官网上面下载源码包: 截至目前最新的版本是7.0.1,对应的地址是:https://ffmpeg.org//releases/ffmpeg-7.0.1.tar.gz 下载 curl -o ffmpeg-7.0.1.tar.gz https://ffmpeg.org//re…

Camstar 生成本地SSL證書

1.登录已经安装 Camstar 服务器,通过管理员启动 Windows PowerShell,需要注意的一定要使用管理员身份启动 2.生成 SSL 证书 在启动的 Windows PowerShell 窗口中输入以下命令代码。代码输入后点,击回车即可创建 SSL 证书New-SelfSignedCertificate -DnsName "localhos…

tryhackme-Gatekeeper(守门人)

信息收集 首先使用nmap进行端口扫描,结果如下 nmap -sT -p- --min-rate 10000 -oA openPort nmap -sV -O -A -p port1,port2,portN -oA version nmap --script=smb.. -p 135,139,445 -oA 445Port# Nmap 7.94SVN scan initiated Sat Jul 13 23:05:09 2024 as: nmap -sT -p- --…

CmsEasy7.6支付逻辑漏洞

最近在学习支付逻辑漏洞相关的知识,利用一些测试思路来复现一下靶场,顺便做一下笔记,不过这个靶场比较老了,供新手学习练练手 靶场源码下载链接:https://ftp.cmseasy.cn/CmsEasy7.x/CmsEasy_7.6.3.2_UTF-8_20200422.zip靶场部署自行百度,用我大学老师的一句话————要学…

element-plus 如何点击其它位置触发文件上传

原文链接: https://www.xiandanplay.com/article/view?id=16925669181947904&articleCategoryId=16078840161206272 https://www.xiandanplay.com/是我的一个自建的网站,,欢迎大家来踩,多多给些建议,开源不易ElementPlus虽然为我们提供了文件上传的组件,但是每次使用…

Nuxt.js 错误侦探:useError 组合函数

title: Nuxt.js 错误侦探:useError 组合函数 date: 2024/7/14 updated: 2024/7/14 author: cmdragon excerpt: 摘要:文章介绍Nuxt.js中的useError组合函数,用于统一处理客户端和服务器端的错误,提供statusCode、statusMessage和message属性,示例展示了如何在组件中使用它…

模糊综合评价

对于模糊的概念,如确定一个人是秃子吗,我们不能确认少于多少根头发的人是秃子,所以需要模糊综合评价法。 层次分析法 上一页层次分析法所求为各个影响因素的分立权重。那现在我们更进一步,通过之前利用层次分析法求得的权重来求出一个评价函数。 模型建立 根据之前所得影响…

[Unity] Dreamteck Splines实现沿路径移动功能

Dreamteck Splines实现沿路径移动功能 最近有一个“让物体沿固定路径移动”的需求,因此接触到了Dreamteck Splines插件。 Dreamteck Splines可以很方便地绘制各种插值曲线,但在实现物体移动的时候却遇到了很多坑,因此在这里记录一下。 1. 绘制路径线 首先,让我们在场景上创…

银河麒麟V10SP1搭建oracle19c(单库)

遇到的坑:1.PRVG-0282问题解决:在先决条件检查步骤,PRVG-0282:无法检索操作系统分发ID的报错,该问题是由于字符集和环境变量问题,只需在执行安装前:使用oracle用户登录,不要root跳到oracle用户下 export CV_ASSUME_DISTID=RHEL7.6 export LANG=en_US 然后刷新环境变量 …