*注:基于Android11源码

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

// 文件路径: system/core/init/main.cpp

int 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 hwservicemanager
start vndservicemanager

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

#此脚本文件描述了启动servicemanager进程时的一些细节
#service用于通知init进程创建名为servicemanager的进程,这个进程执行程序的路径是/system/bin/servicemanager
#在手机系统中是能找到这个文件的
service servicemanager /system/bin/servicemanager
class core animation
#表明此进程是以system身份运行的
user system
group system readproc
#说明servicemanager是系统中的关键服务,关键服务是不会退出的,若退出系统则会重启,系统重启则会重启
#以下onrestart修饰的进程,也可以说明这些进程是依赖于servicemanager进程的
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
onrestart restart keystore
onrestart restart gatekeeperd
onrestart restart thermalservice
writepid /dev/cpuset/system-background/tasks
shutdown 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);
//实例化ServiceManager
sp<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); //注释3
ClientCallbackCallback::setupTo(looper, manager); while(true) {
looper->pollAll(-1);
} // should not be reached
return EXIT_FAILURE;
}

先看注释1:

//frameworks\native\libs\binder\ProcessState.cpp

sp<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 Storage
if (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,作为存放线程本地变量的key
int 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设置为true
gHaveTLS.store(true, std::memory_order_release);
}
pthread_mutex_unlock(&gTLSMutex);
// 回到gHaveTLS为true的case
goto restart;
} sp<BBinder> the_context_object; void IPCThreadState::setTheContextObject(sp<BBinder> obj)
{
//赋值给一个BBinder类型的成员变量,即传进来的这个manager就是服务端的BBinder
the_context_object = obj;
}

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

下面来到注释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接口的实体类,它实现了接口中的所有方法。

android系统启动流程- ServiceManager进程启动流程的更多相关文章

  1. ORACLE11G R2 RAC的进程启动流程

    简要说明ORACLE11GR2 RAC的进程启动流程: 1.启动流程概览图: 二.RAC启动流程的梳理: 第一层:OHASD 启动:(OHASD派生) 1.CSSDAGENT负责启动CSSD的AGEN ...

  2. Android Activity启动流程, app启动流程,APK打包流程, APK安装过程

    1.Activity启动流程 (7.0版本之前) 从startActivity()开始,最终都会调用startActivityForResult() 在该方法里面会调用Instrumentation. ...

  3. broadcom代码中httpd进程启动流程介绍

    Broadcom代码中包含WEB配置管理媒介, 在嵌入式WEB服务器min_httpd基础上改造实现, 其bin名称为httpd,此httpd可以由管理进程有连接后动态启动,并且当一段时间内没有连接到 ...

  4. Chromium的GPU进程启动流程

    转载请注明出处:http://www.cnblogs.com/fangkm/p/3960327.html 硬件渲染依赖计算机的GPU,GPU种类繁多,兼容这么多种类的硬件,稳定性是个大问题,虽然Chr ...

  5. ARM-Linux移植之(三)——init进程启动流程分析

    我们通常使用Busybox来构建根文件系统的必要的应用程序.Busybox通过传入的参数来决定执行何种操作.当init进程启动时,实际上调用的是Busybox的init_main()函数,下面我们来分 ...

  6. Android的Launcher启动流程 “Launcher部分启动流程”

    研究代码从:AndroidManifest.xml.自定义的Application.java开始. Android系统启动时,系统需要一个Home应用程序来负责将这些应用程序展示出来:也就是该应用的目 ...

  7. Android四大组件与进程启动的关系(转)

    一. 概述 Android系统将进程做得很友好的封装,对于上层app开发者来说进程几乎是透明的. 了解Android的朋友,一定知道Android四大组件,但对于进程可能会相对较陌生. 一个进程里面可 ...

  8. 【Chromium】GPU进程启动流程

    本篇文档以gpu进程的创建和启动为例,讲述chormium如何启动一个browser进程的子进程 PS:本文使用的chromium代码版本为71 前言 GPU进程的启动时机是由browser进程负责的 ...

  9. Android系统开机启动流程及init进程浅析

    Android系统启动概述 Android系统开机流程基于Linux系统,总体可分为三个阶段: Boot Loader引导程序启动Linux内核启动Android系统启动,Launcher/app启动 ...

  10. Tiny4412 Android 启动流程

    Android系统的启动主要包括三个阶段: ①BootLoader启动 ②Linux Kernel启动 ③Android系统启动 前面我们大致分析了前面两个步骤,即u-boot和内核的启动流程(内核启 ...

随机推荐

  1. springboot简单正确的使用构造函数注入

    一个一个写构造函数太麻烦了,而且代码会显得非常多,这里我们可以采用lombok快捷注入 但是我们并不是所有的成员变量都需要进行注入,所以使用 @RequiredArgsConstrucotr 需要构造 ...

  2. Scrapy模块入门与实战:笔趣阁小说网爬取

    scrapy框架基本使用 创建项目(爬取笔趣阁小说网) scrapy startproject novels 创建spider cd novels scrapy genspider bqgui.cc ...

  3. 如何通过PowerShell批量修改O365用户的office phone属性值

    我的博客园:https://www.cnblogs.com/CQman/ 如何通过PowerShell批量修改O365用户的office phone属性值? 需求信息: 组织中的O365用户在创建时, ...

  4. 【PostgreSQL】下载安装PgSQL

    官网下载地址: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads Windows平台 官网直接提供exe安装包, ...

  5. 【H5】16 表单 其五 表单验证

    在将数据提交到服务器之前,重要的是确保以正确的格式填写所有必需的表单控件.这称为客户端表单验证,可帮助确保所提交的数据符合各种表单控件中规定的要求.本文将引导您通过基本概念和客户端表单验证示例. 先决 ...

  6. 【Redis】01 NoSQL概述 & Redis

    NoSQL概述: 1.什么是NoSQL NoSQL 是 Not Only SQL 的缩写,意即"不仅仅是SQL"的意思,泛指非关系型的数据库.强调Key-Value Stores和 ...

  7. 国产操作系统 deepin —— UOS 系统下使用蓝牙音箱或蓝牙耳机不能正常工作

    近日搞来了一个国产CPU的电脑,自带系统为UOS,具体可见: https://www.cnblogs.com/devilmaycry812839668/p/14828130.html 忽然发现这个系统 ...

  8. git 如何在本地同步远程已经删除的分支

    背景 因为分支管理,release/*是被保护的,除非是已经合并到master才会被删除.所以这个时候本地存在已经删除的releas/*分支. 此时会发现,怎么都删除不了这些保护分支.留着也没意思,该 ...

  9. git在idea中的冲突解决(非常重要)

    1.什么是冲突 冲突是指当你在提交或者更新代码时被合并的文件与当前文件不一致.读起来有点绕,结合下面的案例理解. 从上面对冲突的定义来看,冲突时发生在同一个文件上的. 2.生产上冲突的场景 常见冲突的 ...

  10. Centos7安装mysql8.0教程

    1.背景 centos7安装mysql8.0 2.安装步骤 步骤一:安装准备工作 1.查看是否有安装过mysql rpm -qa | grep -i mysql 2.删除mysql yum -y re ...