用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章,技术文章也可以有温度。
本文摘要
系统native进程的文章就先告一段落了,从这篇文章开始写Java层的文章,本文同样延续自述的方式来介绍systemserver进程,通过本文您将了解到systemserver进程是啥?它包含那么多的服务,是如何管理它们的?如何启动它们的?(文中代码基于Android13)
本文大纲
我是谁
我的出生
我的启动
总结
1. 我是谁
我是一个进程,是一个既可以运行Java代码也可以运行C和C++代码的全能型选手,不像我的“叔叔辈儿”如logd进程、lmkd进程只能运行C和C++代码。我拥有全能型能力还要感谢我的“父亲”zygote,因为他是全能型的,所以我才把这些能力继承了过来。
我的uid是1000,uid是啥呢?它与你们人类的身份证一样,每个安装到Android设备上的程序都有一个uid,只要apk被安装就分配一个唯一的uid,只要apk不卸载,这个uid是不会变化的。uid为0也就是root用户的程序它可是拥有无限超级能力。
我其实还有一个真名叫system_process,我觉得这个名字不霸气、不能体现我的职责,因此我对外让大家都称呼我为systemserver,你看这名字多好系统服务,这名字多霸气、多威武。
1.1 我的父亲
我的“爷爷”init进程有非常非常多的孩子,这或许是偶像的力量吧,我的“父亲”zygote也有非常非常多的孩子。凡是Android中能运行Java代码的进程都是zygote的孩子,并且它们也都是我的“弟弟”,为啥是弟弟呢?因为我是zygote的第一个孩子,也就是“长子”。
其实我对我的“父亲”zygote也是有蛮多怨言的,为啥这样说呢?因为他只负责孵化子进程,而孵化完毕后,他就做一个甩手掌柜的,对于子进程不管不顾,他甚至完全不知道自己孵化了多少子进程,而这些任务却偏偏都落在了我的身上,我还得负责管理这些子进程。这或许就是“”长兄如父“”的完美体现吧。
1.2 我的弟弟们
我所有的“弟弟们”,它们若想要“出生”的话,都需要经过我向zygote发送孵化它们的请求,zygote孵化出它们后,我负责来管理它们,比如当Android设备处于低内存状态时候,我会尝试把最不常用、处于后台的子进程杀掉。**不知道你们有没有发现个问题,我的uid是1000并非是0,那我怎么具有杀其他进程的能力的呢?**先卖个关子,在后面会介绍到我如何具有此能力。
我不单单充当“长子”的角色,我还把我自己比作Android的大脑,这可不是我骄傲事实确实是这样的,所有可运行Java代码进程都需要以我为中心,我离了它们是可以的,它们可是万万离不开我,比如这些进程想要启动Activity,那需要经过我的ActivityTaskManagerService服务的校验,再比如某个进程需要发出振动的话,那也需要经过我的VibratorManagerService服务进而由它发向hal层发出振动的命令。
(如下图展示app进程与systemserver进程的一些交互信息)
大家可别把我想象的如超人那样,我也不是事无巨细的“诸葛亮”,我能完成这么多复杂的工作,完全是靠我拥有的各种service (服务),这些service会处理各自擅长的事情,像上面提到的ActivityTaskManagerService和VibratorManagerService就是其中两个service,那来看下我拥有的service吧。
1.3 拥有的service
下图是我拥有的部分service
那就来简单介绍下部分service吧
Installer
在installd进程中介绍过它,它与apk的安装有关系,它对installd进程做了封装,这样就可以在Java层使用installd的功能了。
PowerStatsService
想要知道电量的使用情况,可以找它啊,它可是电量使用情况的专家
ActivityTaskManagerService
该服务与启动Activity有非常大的关系,进程中启动Activity必定要经过该服务
PowerManagerService
电源管理服务是一个非常重要的系统服务,它负责管理系统的电源状态,包括设备的唤醒、休眠、屏幕亮度调节、电池电量管理等
ThermalManagerService
该服务是温度监控服务,当温度超过一定阈值后,手机会做出一些策略比如cpu降频操作,保证手机温度不至于一直上升
DisplayManagerService
该服务负责管理设备上的所有显示相关的资源和操作。它负责屏幕的开启与关闭、屏幕亮度的调整、显示分辨率的变更、屏幕旋转以及多窗口管理等任务
UserManagerService
该服务主要是管理设备用户,一个设备默认情况下有一个主用户它的id是0,可以为设备增加用户,用户之间的数据是隔离的
好了,由于时间关系,我不可能把所有的service都介绍完毕,就先介绍以上这些service
service在什么环境下工作呢?
先来说下这里的环境一词,其实指的是在哪个线程工做。
首先需要肯定的一点是不可能所有的service都在我systemserver的唯一的一个主线程里面工作,如果是这样这些service肯定会出现各种问题,其次是性能低下。
其实对于这一点我是没有制定规则的,每个service的复杂程度不一样,因此有的service会启动自己的线程来做工作,而有的service是与别的service共享一个线程来做工作,有的service就在主线程里面做自己的工作。
1.4 service如何让使用者使用
我既然拥有这么多的service,那如何让使用者使用这些service的能力呢?
如果使用者都与我systemserver位于同一进程的话,这些事情就特别好办了,但却不是这样的使用者它们绝大多数都是位于别的进程,那这种情况就有些棘手了。
虽然棘手,但是是有解的,大家上眼了先看下下面这张类图
看了这张图是不是有一种似曾相识的感觉,没错这就是使用aidl生成的类图结构,大家都知道aidl其实是为binder通信设计的,那service如果让使用者使用的话那就是使用binder通信了,先暂停一下,继续把上面的类图交代清楚 (熟悉的小伙伴可以跳过这部分)
IXXXManager
它是一个接口,定义了该service提供的能力,它继承了IInterface接口。每个service都有自己的对应接口,比如ActivityManagerService对应的是IActivityManager接口、ActivityTaskManagerService对应的是IActivityTaskManager
IXXXManager.Stub
该类是一个抽象类,它实现了IXXXManager接口,同时也继承了Binder类。
XXXService
该类就是每个service了,每个service又继承了IXXXManager.Stub,也就是说每个service其实又是Binder的子类。下面是几个例子
public class ActivityTaskManagerService extends IActivityTaskManager.Stub public class ActivityManagerService extends IActivityManager.Stub
IXXXManager.Stub.Proxy
该类如它的名字就是一个代理类,它实现了IXXXManager接口,该类有一个属性mRemote它一般是BinderProxy类型的。而该类是让使用者来使用的,调用该类的相应方法,就可以通过binder通信最终调用到对应service的能力了。
同样每个service都有自己对应的IXXXManager.Stub.Proxy,比如ActivityManagerService对应的是IActivityManager.Stub.Proxy、ActivityTaskManagerService对应的是IActivityTaskManager.Stub.Proxy
上面的类图就是每个service让使用者使用的一个框架,说直白点就是使用了binder通信,因为binder通信是client/server模式,每个service是Binder的子类,那它就是server端,而使用者要想使用对应service的能力那就需要使用对应的IXXXManager.Stub.Proxy类了。
既然每个service是一个Binder,那就有必要把自己注册在ServiceManager中,只有注册了使用者才可以使用。(如下伪代码)
XXXService service = new XXXService()
ServiceManager.addService("XXXService",service)
使用者使用的话从ServiceManager中获取对应的service的BinderProxy对象,并把它作为IXXXManager.Stub.Proxy类的参数,来构造IXXXManager.Stub.Proxy这样的一个对象 ,通过该对象即可使用service的能力。(如下伪代码)
BinderProxy bp = ServiceManager.getService("XXXService")
IXXX.Stub.Proxy proxy = new IXXX.Stub.Proxy(bp)
# 就可以调用proxy对象来使用service的功能了
1.5 小结
我是一个既能运行Java代码又能运行C/C++代码的全能型进程,我在所有可运行Java代码的进程中的地位犹如人类的大脑,那可是妥妥的C位。我的地位虽然如此高贵,但我可不是一个集权者,我拥有很多的service,是它们替我分担了我的职责,它们有条不紊的处理着各种需求。其他可运行Java代码的进程要想使用这些service的能力,那就需要通过binder通信来使用。
好了,关于我就先介绍到此,作为C位的我,大家对我的出生一定很感兴趣,那就来讲下我的出生吧。
2. 我的出生
我的出生其实是被动的,为什么说是被动的呢?我的出生并不是我主动发起的,像我的“叔叔辈儿”、“弟弟们”他们的出生基本都是由他们主动发起的,比如logd进程会主动配置rc脚本文件,在把脚本文件交给init进程。而我的出生是在我完全不知晓的情况下由我的“父亲”zygote直接决定的。
我的出生大致分为三步:孵化前、孵化、孵化后,那就按这三步来讲下我的出生吧
2.1 孵化前
在孵化前,我的“父亲”zygote已经做了很多的工作的:加载JVM、加载公共的jni方法、提前预加载classes、预加载resource、预加载字体等。
其中预加载classes,会把这些classes加载到BootClassLoader.getInstance()对象中,该ClassLoader可是顶级ClassLoader,还有预加载的这些classes主要是framework.jar下面的类。预加载resource,会把这些resource加载到Resources.getSystem()对象中。
除了上面的工作,还有一个工作就是准备孵化时候要用到的参数,这些参数有几个是需要重点介绍下的。
setuid
--setuid=1000
如上设置了我systemserver进程的uid为1000
setgid
--setgid=1000
设置了我systemserver进程所属的组id是1000
capabilities
Linux Capabilities是Linux操作系统中的一种权限管理机制,它允许对进程的权限进行细粒度的控制,以实现最小特权原则。这一机制将root用户的特权划分为具体的功能集,允许将部分root特权授予非root进程,从而增强了系统的安全性。
Linux Capabilities是在Linux内核2.2之后引入的,它将传统上与超级用户root(UID=0)关联的特权细分为不同的功能组。这些功能组作为线程(Linux中并不真正区分进程和线程)的属性存在,每个功能组都可以独立启用和禁用。这样一来,权限检查的过程就变成了:在执行特权操作时,如果线程的有效身份不是root,就去检查其是否具有该特权操作所对应的capabilities,并以此为依据,决定是否可以执行特权操作
上面是capabilities功能的介绍,用一句话概括:就是说非root用户进程也可以通过设置capabilities,来让该进程具有相应的特权。
还记得我systemserver可以杀掉一些处于后台的进程来释放内存吗?杀掉其他进程的特权就是通过capabilities设置的,当然还设置了别的特权,如下相关代码:
long capabilities = posixCapabilitiesAsBits(//主要用于控制进程对共享内存片段的锁定能力 OsConstants.CAP_IPC_LOCK,//杀掉其他进程的能力OsConstants.CAP_KILL,//用于控制对网络配置和管理的访问权限OsConstants.CAP_NET_ADMIN,//它允许进程绑定到1024以下的端口号。这些端口号通常被认为是特权端口OsConstants.CAP_NET_BIND_SERVICE,//它允许进程发送广播消息到网络OsConstants.CAP_NET_BROADCAST,//它允许进程创建RAW和PACKET套接字以及进行任意地址的绑定OsConstants.CAP_NET_RAW,//它允许用户或进程加载(或卸载)内核模块OsConstants.CAP_SYS_MODULE,//它允许进程调整其他进程或自身进程的nice值,从而影响其调度优先级OsConstants.CAP_SYS_NICE,//它允许进程跟踪系统上的任何其他进程,这种能力通常与调试和安全审计相关OsConstants.CAP_SYS_PTRACE,//它允许进程设置系统时间OsConstants.CAP_SYS_TIME,//它允许进程进行TTY设备的配置任务。OsConstants.CAP_SYS_TTY_CONFIG,//它允许进程设置唤醒系统(或唤醒挂起系统)的定时器OsConstants.CAP_WAKE_ALARM,//它允许进程阻止系统进入挂起(suspend)状态OsConstants.CAP_BLOCK_SUSPEND);
在配置了上面的这些capabilities后,我systemserver也就具有了这些特权了。
入口类
com.android.server.SystemServer
入口类就是当systemserver进程被fork成功后,最先开始执行的类。如上这个类就是SystemServer类
这些参数配置完毕后,孵化前的准备工作就完成了。
下面是相关代码,请自行取阅:
//ZygoteInit类private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {long capabilities = posixCapabilitiesAsBits(OsConstants.CAP_IPC_LOCK,OsConstants.CAP_KILL,OsConstants.CAP_NET_ADMIN,OsConstants.CAP_NET_BIND_SERVICE,OsConstants.CAP_NET_BROADCAST,OsConstants.CAP_NET_RAW,OsConstants.CAP_SYS_MODULE,OsConstants.CAP_SYS_NICE,OsConstants.CAP_SYS_PTRACE,OsConstants.CAP_SYS_TIME,OsConstants.CAP_SYS_TTY_CONFIG,OsConstants.CAP_WAKE_ALARM,OsConstants.CAP_BLOCK_SUSPEND);省略代码······String[] args = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"+ "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,"com.android.server.SystemServer",};ZygoteArguments parsedArgs;int pid;try {ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);try {parsedArgs = ZygoteArguments.getInstance(commandBuffer);} catch (EOFException e) {throw new AssertionError("Unexpected argument error for forking system server", e);}commandBuffer.close();// 设置允许所有的app可以调试Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs);省略其他代码······} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}省略其他代码······}
2.2 孵化
现在进入最激动人心的阶段孵化,因为孵化前已经把参数等信息都准备好了,那孵化就是调用系统的fork方法来创建子进程,当然在调用fork方法的时候是需要把从zygote进程继承来的fd关闭掉的,否则会影响原先的父进程。在fork成功后,会把传递的这些参数设置给我systemserver进程。
因为fork机制采用的是写时复制,即如果子进程没有对父子进程共享的区域进行写操作的话,则这片区域是共享的。我的“父亲”zygote在孵化之前做的准备工作:如加载JVM、加载jni方法、预加载classes、预加载resource,都是我与我父亲共享的。
上面的话是不是有些懵,还是看下图吧,毕竟一图胜千言
在孵化之前zygote加载了JVM、预加载的classes加载到了BootClassLoader.getInstance()方法返回的BootClassLoader对象中、预加载的resources加载到了Resources.getSystem()方法返回的Resources对象中,当然还有别的。
而在孵化之后,systemserver进程就把zygote进程中的JVM实例、BootClassLoader.getInstance()返回的对象、Resources.getSystem()方法返回的Resources对象及其他的实例都完完全全的共享过来了。这也就是zygote提前做各种准备能在子进程中生效的具体原因。
2.3 孵化后
在孵化后会有关闭socket、创建ClassLoader、打开binder、进入入口类这几件事情要做,那接下来就介绍下。
2.3.1 关闭socket
因为fork机制创建子进程,会把父进程打开的socket对应的fd也继承过来,因此需要把继承过来的socket对应的fd关闭掉。zygote是会启动一个ServerSocket,如果想要孵化子进程,则其他进程与该ServerSocket建立连接即可。因此systemserver进程需要把继承过来的ServerSocket关闭掉。
相关的代码,请自行取阅:
//ZygoteInit类private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {省略代码······//在fork成功后,下面的代码会分别由zygote的线程和systemserver的线程执行,//pid==0 代表 systemserver的线程会执行if (pid == 0) {省略代码······//在systemserver进程把zygote socket关闭掉,因为systemserver进程不需要它//查看下面的closeServerSocket方法zygoteServer.closeServerSocket();return handleSystemServerProcess(parsedArgs);}return null;}//ZygoteServer类void closeServerSocket() {try {if (mZygoteSocket != null) {FileDescriptor fd = mZygoteSocket.getFileDescriptor();mZygoteSocket.close();if (fd != null && mCloseSocketFd) {Os.close(fd);}}} catch (IOException ex) {Log.e(TAG, "Zygote: error closing sockets", ex);} catch (ErrnoException ex) {Log.e(TAG, "Zygote: error closing descriptor", ex);}mZygoteSocket = null;}
2.3.2 创建ClassLoader
为啥要创建ClassLoader呢?
原因是这样的,当前被孵化出来的systemserver进程,它其实与zygote共享一个BootClassLoader对象,而该ClassLoader只是加载了进程之间公用的classes,而systemserver自己特有的各种classes在共享的BootClassLoader对象中是找不到的,比如入口类SystemServer在BootClassLoader找不到。那咋办呢,答案当然是创建自己的ClassLoader,并且把自己的各种jar、so文件路径设置给ClassLoader,同时该ClassLoader的parent是共享的BootClassLoader对象。这样通过自己的创建的ClassLoader就可以找到systemserver进程自己特有的classes,同时也能找到zygote之前预加载的classes。
下面是相关代码,请自行取阅:
//ZygoteInit类private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {省略代码······//在fork成功后,下面的代码会分别由zygote的线程和systemserver的线程执行,//pid==0 代表 systemserver的线程会执行if (pid == 0) {省略代码······//查看下面handleSystemServerProcess方法return handleSystemServerProcess(parsedArgs);}return null;}private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {省略代码······if (parsedArgs.mInvokeWith != null) {省略代码······} else { //创建ClassLoaderClassLoader cl = getOrCreateSystemServerClassLoader();if (cl != null) {//为当前线程设置ClassLoaderThread.currentThread().setContextClassLoader(cl);}省略代码······}/* should never reach here */}
3.2.3 打开binder
打开binder这可是非常重要的一步,只有执行了这步被孵化的进程才具有了binder通信的能力,直接看代码吧
//ZygoteInit类private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {省略代码······//在fork成功后,下面的代码会分别由zygote的线程和systemserver的线程执行,//pid==0 代表 systemserver的线程会执行if (pid == 0) {省略代码······//查看下面handleSystemServerProcess方法return handleSystemServerProcess(parsedArgs);}return null;}private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {省略代码······if (parsedArgs.mInvokeWith != null) {省略代码······} else { 省略代码······//查看下面 zygoteInit 方法return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);}}public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {省略代码······//nativeZygoteInit 方法会调用到下面的 com_android_internal_os_ZygoteInit_nativeZygoteInit 方法ZygoteInit.nativeZygoteInit(); }//core/jni/AndroidRuntime.cppstatic void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz){//会调用到下面的onZygoteInitgCurRuntime->onZygoteInit();}//cmds/app_process/app_main.cppvirtual void onZygoteInit(){//打开binder驱动sp<ProcessState> proc = ProcessState::self();//启动binder线程池proc->startThreadPool();}
3.2.4 进入入口类
这是孵化后的最后一步,也是systemserver进入自己代码的起始点,还记得入口类是SystemServer吧,而这一步就是要进入SystemServer的main方法。
下面是相关方法,请自行取阅:
//ZygoteInit类private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {省略代码······//在fork成功后,下面的代码会分别由zygote的线程和systemserver的线程执行,//pid==0 代表 systemserver的线程会执行if (pid == 0) {省略代码······//查看下面handleSystemServerProcess方法return handleSystemServerProcess(parsedArgs);}return null;}private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {省略代码······if (parsedArgs.mInvokeWith != null) {省略代码······} else { 省略代码······//查看下面 zygoteInit 方法return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);}}public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {省略代码······//查看下面的 applicationInit方法return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,classLoader);}//RuntimeInit类protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {省略代码······//查找 static main方法//查看下面的 findStaticMain 方法return findStaticMain(args.startClass, args.startArgs, classLoader);}protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {Class<?> cl;try {//查找SystemServer的Classcl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {省略代码······}Method m;try {//查找SystemServer的main方法m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {throw new RuntimeException("Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}//返回MethodAndArgsCaller实例,它持有找到的main方法的Method实例return new MethodAndArgsCaller(m, argv);}
2.4 小结
以上就是我的出生过程,我的“父亲”zygote为了加快子进程的启动速度,在孵化之前做了很多准备工作:加载JVM、加载通用jni方法、预加载classes、预加载resource等,而我systemserver进程在fork成功后与zygote共享在准备阶段产生的这些实例,同时我还打开了binder驱动,这样我才具有了binder通信能力,我还创建了自己的ClassLoader,并且进入了SystemServer类的main方法,至此我“出生”了。
3. 我的启动
我虽然“出生”了,但是我就像人类的婴儿一样,还没有任何的能力,因此我需要经历启动过程,只有经历了启动过程我才真正的“长大成人”。
3.1 解决多service带来的启动问题
大家都知道我有很多很多的service,而启动过程其实就是把所有的service启动起来,service多是好事也同时是坏事,这不在启动过程中就体现出来了,因为service多,在启动过程中肯定会出现某个service的启动要依赖于另外的service,而另外的service又要依赖于别的service;甚至会出现更复杂的情况,某个或多个service要依赖多个其他的service,这种依赖关系就像一团乱麻着实令人头疼。
针对这种情况,确实花费了我很多的脑细胞,想出了管理service、对service分类、分发启动阶段信号这三个办法来解决此问题。
3.1.1 管理service
管理service就是要对这些service进行管理,不管理确实会出现各种乱套,那该如何管理呢?
老规矩先看下我设计的类图吧
如图,我主要设计了SystemService和SystemServiceManager两个类,先来解释下这两个类
SystemService
每个service作为能力提供方的话是Binder类的子类,而要作为一个service被systemserver进程管理的话,那它需要继承SystemService类。
该类是一个抽象类,它定义了一些service都会用到的方法比如publishBinderService,它的主要作用就是service可以把自己注册到ServiceManager中。
还定义了一些一些抽象方法,其中onStart、onBootPhase特别类似Activity的生命周期方法。
onStart方法
onStart被调用的话,则代表当前的service可以调用publishBinderService方法,把自己注册到ServiceManager中。
onBootPhase方法
systemserver会通过onBootPhase方法告知service当前启动到了哪一步了。
onUserStarting方法
systemserver会通过该方法告知service当前是哪个用户正在启动,其他的onUserXXX方法也是类似作用。
图中ActivityManagerService类为啥没有继承SystemService呢?主要原因是Java只支持单继承,因为ActivityManagerService已经继承了IActivityManager.Stub类
SystemServiceManager
而该类的主要作用就是管理所有的SystemService,它的mService属性存储了所有启动的SystemService。同时它拥有几个简化创建service流程的方法,暂且拿下面这个方法举例子
startService(Class)
该方法把构建service对象、添加service对象、调用service的onStart方法这几个步骤都集中起来。启动一个service只需要调用该方法,service只需要实现自己的onStart方法逻辑,onStart方法具体啥时候调用,service不需要关心。
3.1.2 对service分类
对service进行分类,把service分为bootstrap services、core services、other services,如下图:
bootstrap services代表别的service对它们的依赖最多,因此需要最先启动。
3.1.3 分发启动阶段信号
分发启动阶段信号就是告知每个service当前处于启动的哪个阶段了,service根据相应的阶段信号可以做一些自己的事情。
分发启动阶段信号这个词如果不好理解的话,那用个例子来解释:在下载文件的时候,是不是会显示下载进度,而启动阶段信号其实与下载进度非常类似,就是告知service当前的启动进度是啥样。
3.1.4 小结
service继承SystemService,并且把它们都添加到SystemServiceManager,这样就可以把所有的service管理起来;再对service进行分类,按类别来分别启动它们;把启动阶段信号通过SystemServiceManager发送给所有的service,这样service根据启动阶段信号来做自己的事情。以上三种办法可以解决启动service混乱的问题。
3.2 启动
既然多service启动的问题解决了,那咱就进入正题开始介绍我的启动过程吧,我把启动过程分为启动前、启动bootstrap services、启动core services、启动other services、进入无休工作模式,当然还有启动Apex services这一步,因为它不是重点在这就不赘述了,那就从这几步来介绍启动。
3.2.1 启动前
启动前是需要做一些准备工作的设置binder线程池个数、开启Looper、加载android_servers可执行文件、创建Context,那就依次来介绍下。
设置binder线程池个数
普通进程打开binder驱动后,能启动最大的binder线程个数是15个,前面也一直在强调我可不是普通的进程,更何况我拥有非常多的service,这些service每个都是binder server,因此我启动的最大binder线程个数是31个。
不知道大家有没有考虑过这样的问题:最大binder线程个数少的话会有啥问题?
其中一个重要的问题就是性能降低。我举个例子比如工厂里面正常工作量的话,15个人刚好干完,但是由于工作量加大,15个人的话就干不完了,那这种情况该咋办呢?其中一种是15个人加班干,另外一种是增加工人个数。同样binder最大线程数小的话,就会导致大量的请求积压在队列中,这样就导致性能下降。
下面是相关代码,请自行取阅:
//SystemServer方法
public static void main(String[] args) {//run方法在下面new SystemServer().run();
}private void run() {省略代码······//sMaxBinderThreads的值为31,该方法设置开启binder线程的最大个数BinderInternal.setMaxThreads(sMaxBinderThreads);省略代码······
}
开启Looper
Looper在Android中的作用不必说,开启了Looper后,其他的线程或者当前线程就可以通过Handler把Message传递到当前线程。
加载android_servers可执行文件
android_servers可执行文件中包含了jni方法和很多native方法,使用System.loadLibrary方法可以把android_servers可执行文件加载到内存中,这样就可以保证jni方法可用
创建Context
Context在Android中的作用那可是非常重要,而在systemserver进程中也是需要Context对象的,会创建两个Context,一个用来做业务逻辑等处理,另一个用来做UI显示,在systemserver也是会显示一些UI的 (比如关机对话框)
下面是相关代码,请自行取阅:
//SystemServer方法
public static void main(String[] args) {//run方法在下面new SystemServer().run();
}private void run() {省略代码······//createSystemContext方法在下面createSystemContext();省略代码······
}private void createSystemContext() {//创建systemserver具有的ActivityThread对象ActivityThread activityThread = ActivityThread.systemMain();//获取系统Context对象mSystemContext = activityThread.getSystemContext();//为Context设置主题mSystemContext.setTheme(DEFAULT_SYSTEM_THEME); //该方法会根据mSystemContext创建UI类型的Context,它主要用来显示UIfinal Context systemUiContext = activityThread.getSystemUiContext(); //为systemUiContext设置主题systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
小结
启动前期主要是为后面启动各种service做准备,接下来看剩下的步骤吧。
3.2.2 启动bootstrap services
还记得我已经对service进行了分类,该阶段就是对bootstrap services进行启动,在此阶段同时还会启动一个Watchdog类,它的作用是监控systemserver进程的对应线程是否发生了锁等待情况,后面会再次详细介绍它。
在此阶段,会发出第一个启动阶段信号PHASE_WAIT_FOR_DEFAULT_DISPLAY (它的值为100),此信号的意思是现在进入等待获取默认显示屏阶段,已经启动的service都会收到该信号,只不过只有DisplayManagerService才关心此信号。DisplayManagerService会尝试获取是否有可用的显示屏,有的话则进入下阶段;否则等待一定时间后还是没有可用的显示屏,则整个启动过程失败。
下面是相关代码,请自行取阅:
//DisplayManagerService
//下面方法会阻塞整个启动流程
public void onBootPhase(int phase) {//收到 PHASE_WAIT_FOR_DEFAULT_DISPLAY 信号if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {synchronized (mSyncRoot) {//获取超时时间long timeout = SystemClock.uptimeMillis()+ mInjector.getDefaultDisplayDelayTimeout();//若没有可用显示屏,则进行等待while (mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY) == null|| mVirtualDisplayAdapter == null) {long delay = timeout - SystemClock.uptimeMillis();//若超时依然没有获取到可用显示屏,则抛异常if (delay <= 0) {throw new RuntimeException("Timeout waiting for default display "+ "to be initialized. DefaultDisplay="+ mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY)+ ", mVirtualDisplayAdapter=" + mVirtualDisplayAdapter);}省略代码······try {mSyncRoot.wait(delay);} catch (InterruptedException ex) {}}}} 省略代码······}
3.2.3 启动core services
该阶段主要是启动类别为core的所有service,启动的service确实很多,我在这就不给大家一一介绍了,咱们进入下个阶段。
3.2.4 启动other services
同样此阶段会启动剩下的service,由于启动的service多,也不在此一一赘述了,当然在这个阶段还会启动systemui进程,并且还会启动launcher,在这里介绍下几个关键的启动阶段信号。
PHASE_WAIT_FOR_SENSOR_SERVICE (它的值是200),此信号的意思是进入等待传感器服务阶段,同样所有启动的service都会收到此信号,只有SensorService才会关心它,SensorService在等待期间会阻塞启动过程。
下面是相关代码,请自行取阅:
//SensorService
public void onBootPhase(int phase) {if (phase == SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE) {ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart,START_NATIVE_SENSOR_SERVICE);synchronized (mLock) {mSensorServiceStart = null;}}
}
PHASE_LOCK_SETTINGS_READY (它的值是480),此信号的意思是settings相关的数据你们各service可以使用了,因此已经启动的service,收到该信号后若需要读取settings的数据就可以读取了。
PHASE_SYSTEM_SERVICES_READY (它的值是500),此信号的意思是core services可以被安全的使用了,比如PowerManagerService、PackageManagerService等可以被别的service使用了。
PHASE_ACTIVITY_MANAGER_READY (它的值是550),此信号的意思是ActivityManagerService已经准备好了,广播等都可以使用了。
PHASE_BOOT_COMPLETED (它的值是1000),此信号的意思是启动阶段完成,那啥时候发该信号呢?launcher界面展示成功后才会发出该信号,所有已经启动的service收到此信号后就可以做自己该做的事情了。
下面是相关代码,请自行取阅:
//ActivityManagerService//下面的方法是launcher界面做完动画后会调用
final void finishBooting() {省略代码······//让所有的service都知道启动完成了mSystemServiceManager.startBootPhase(t, SystemService.PHASE_BOOT_COMPLETED);省略代码······}
3.2.5 进入无休工作模式
在ActivityManagerService发出PHASE_BOOT_COMPLETED信号后,所有的service都欢腾了起来,每个service身上紧绷着的弦也终于放松了,从此刻开始我和我的service小伙伴们就进入了无休工作模式,人类啊千万别在抱怨你们的工作时长长了,在长能有我长吗?
进入无休工作模式的代码也特别简单,如下
//SystemServer
private void run() {省略代码······Looper.loop(); 省略代码·····
}
其实就是调用了Looper.loop()方法,该方法作用是让当前线程会一直循环下去。
3.2.6 小结
我的启动其实就是启动所有的service,而由于service很多它们之间又存在复杂的依赖,导致启动过程很复杂,为了解决此问题,我使用SystemService和SystemServiceManager来管理这些service;并且对这些service进行分类,这样启动过程就可以按照分类来依次启动它们;在启动过程中某些service肯定要依赖于别的service或者别的事件,针对这种情况我想了分发启动阶段信号这么个办法,发出相应的信号后,对该信号关心的service就可以着手处理相关的事情,其中PHASE_BOOT_COMPLETED阶段信号是最关键信号,代表整个启动完成,而发该信号的时机是launcher界面展示完成。收到该信号后,我和我的service就完全准备好了,我们进入无休的工作模式
总结
我是systemserver进程,我虽然是zygote进程的“长子”,但我同时也当担着“父亲”的职责,我会管理由zygote孵化的所有进程。我把我比作Android的大脑,App进程如果想启动Activity那需要找我的ActivityTaskManagerService,如果需要让设备振动那也需要找我的VibratorManagerService,当然还有很多很多的事情都需要找我的service。
这就是我一个独一无二的进程。