SystemServer
1.简介
systemServer是一个进程,能运行java,也能运行c。他是由zygote进程创建出的,zygote也是都能运行。
systemServer的uid是1000。
uid是应用唯一代码,安装时时分配,不卸载不会变化。uid为0的权限最大。
init进程创建了zygote进程,systemServer是zygote创建出的第一个进程,zygote负责创建进程,system负责管理进程。
Android中可运行的java代码进程都要依靠system,比如想启动Activity,就需要ActivityTaskManagerService服务。
1.1 拥有的service
installer
与安装有关系
PowerStatsService
电源状态服务
DisplayManagerService
显示相关,屏幕亮灭,旋转,多窗口等
UserManagerService
管理设备用户,默认一个设备只有一个用户,uid是0,用户之间的数据是隔离的
1.2 service工作环境
根据service的复杂度与特点,有的service会启动自己的线程,有的会与其他service共享线程,有的在server主线程工作。
1.3 service如何被调用
通过binder调用来实现
IXXXManager
它是一个接口,定义了该service提供的能力,它继承了IInterface接口。每个service都有自己的对应接口,比如ActivityManagerService对应的是IActivityManager接口、ActivityTaskManagerService对应的是IActivityTaskManager。
IXXXManager.Stub
一个抽象类,它实现了IXXXManager接口,同时也继承了Binder类。
XXXService
该类就是每个service了,每个service又继承了IXXXManager.Stub,也就是说每个service其实又是Binder的子类。
IXXXManager.Stub.Proxy
该类如它的名字就是一个代理类,它实现了IXXXManager接口,该类有一个属性mRemote它一般是BinderProxy类型的。而该类是让使用者来使用的,调用该类的相应方法,就可以通过binder通信最终调用到对应service的能力了。
同样每个service都有自己对应的IXXXManager.Stub.Proxy,比如ActivityManagerService对应的是IActivityManager.Stub.Proxy、ActivityTaskManagerService对应的是IActivityTaskManager.Stub.Proxy
这样一来,每一个service都是一个binder。service会把自己注册在ServiceManager中。
使用者从ServiceManager中获取对应Service的BinderProxy对象来构建代理对象,从而使用Service的能力。
# 向ServiceManager注册服务
XXXService service = new XXXService()
ServiceManager.addService("XXXService",service)
BinderProxy bp = ServiceManager.getService("XXXService")
IXXX.Stub.Proxy proxy = new IXXX.Stub.Proxy(bp)
# 就可以调用proxy对象来使用service的功能了
2.SystemServer的创建
它的创建是被动的,其他大部分进程是主动创建的,比如 logd 进程会自动配饰rc脚本并交给init进程。
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进程,从而增强了系统的安全性。
就是说非root用户进程也可以通过设置capabilities,来让该进程具有相应的root特权。
比如systemServer杀死别的应用特权,就是通过该方式:
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 );
2.2 创建中
之前已经把参数信息之类的配置好了,调用fork方法创建,创建成功后,将会传递上面的参数并设置。
fork机制采用了 写时复制 如果子进程没有对父子进程的共享进程进行写操作的话,这篇区域都是共享的
systemserver进程就把zygote进程中的jvm实例,Resoures资源,预加载class完全共享过来。
2.3 创建后
创建后会有关闭socket,创建ClassLoader,打开binder,进入入口类。
关闭socket
因为fork机制创建子进程,会把父进程打开的socket对应的fd也继承过来,因此需要把继承过来的socket对应的fd关闭掉。zygote是会启动一个ServerSocket,如果想要孵化子进程,则其他进程与该ServerSocket建立连接即可。因此systemserver进程需要把继承过来的ServerSocket关闭掉。
fd
(File Descriptor,文件描述符)是一个用于表示打开文件、套接字(socket)、管道(pipe)或其他I/O资源(如终端)的抽象指标。它是一个非负整数,系统内核用它来访问这些资源。每个进程都有自己的一组文件描述符,这些描述符在进程的生命周期内是唯一的。在Android系统中,当使用
fork()
系统调用来创建一个新的子进程时,父进程中几乎所有的资源都会被复制到子进程中,包括打开的文件描述符。这意味着,如果父进程(如Zygote进程)打开了一个ServerSocket并与之关联了一个文件描述符(比如fd为3),那么当Zygote通过fork()
创建子进程(如SystemServer进程)时,这个ServerSocket的文件描述符也会被复制到子进程中。在很多情况下,这种继承并不是我们想要的。例如,在Android的启动过程中,Zygote进程会启动并监听一个ServerSocket,等待其他进程(如SystemServer)通过该ServerSocket与其建立连接。但是,当SystemServer进程被fork出来时,它并不需要继续监听这个ServerSocket,因为它不是负责接受新连接的进程。因此,SystemServer进程需要关闭它从Zygote进程继承来的ServerSocket的文件描述符,以避免不必要的资源占用或潜在的冲突。
创建ClassLoader
当前被创建出的systemserver进程,它与zygote共享一个BootClassLoader对象,而该ClassLoader只是加载了进程之间公用的classes,
而systemserver自己特有的各种classes在共享的BootClassLoader对象中是找不到的,比如入口类SystemServer在BootClassLoader找不到。
为什么需要创建? 于是创建自己的ClassLoader,并且把自己的各种jar、so文件路径设置给ClassLoader,同时该ClassLoader的parent是共享的BootClassLoader对象。这样通过自己的创建的ClassLoader就可以找到systemserver进程自己特有的classes,同时也能找到zygote之前预加载的classes。
打开binder
打开Binder驱动
在Android的源代码中,Binder的初始化通常是通过
ProcessState
类来完成的。这个类封装了与Binder驱动交互的底层细节。当你看到sp<ProcessState> proc = ProcessState::self();
这行代码时,它实际上是在获取当前进程的ProcessState
实例。如果这个实例还不存在,那么self()
方法会创建一个新的实例,并在这个过程中打开与Binder驱动的连接。Binder驱动
Binder驱动是Android内核中的一个特殊组件,它提供了进程间通信的底层支持。通过Binder驱动,Android系统能够高效地实现跨进程通信,而不需要像传统UNIX系统那样通过套接字(sockets)或管道(pipes)等机制进行通信。
启动Binder线程池
在
ProcessState
实例被创建并成功打开Binder驱动之后,proc->startThreadPool();
这行代码会启动一个Binder线程池。这个线程池负责处理来自Binder驱动的请求,包括接收来自其他进程的IPC调用请求,并将这些请求分发到相应的处理函数中去。Zygote与SystemServer中的Binder初始化
在
Zygote
进程孵化SystemServer
进程的过程中,SystemServer
进程会继承Zygote
进程的环境,包括已经打开的Binder连接。但是,为了确保SystemServer
进程能够正确地使用Binder机制,它仍然需要执行上述的Binder初始化步骤。这是因为虽然连接是继承的,但是SystemServer
进程需要有自己的Binder线程池来处理IPC请求。总结
通过
ProcessState::self()
和startThreadPool()
这两个步骤,SystemServer
进程成功地打开了Binder驱动并启动了Binder线程池,从而具备了与其他进程进行Binder通信的能力。这是Android系统启动过程中非常关键的一步,因为它确保了系统服务能够高效地与其他组件进行交互。进入入口类
最后一步,也是systemserver进入自己代码的起始点,还记得入口类是SystemServer,而这一步就是要进入SystemServer的main方法。
3.SystemServer的启动
3.1 太多service问题
SystemServer有很多service,这会导致出现service启动相互依赖的情况,通过 管理service,对service分类,分发启动阶段信号,这三种方式解决。
3.1.1 管理service
SystemService
每个service如果要作为service被systemserver管理的话,需要继承SystemServer类。
该类是一个抽象类,定义了service都会用到的方法如publishBinderService,它可以吧service注册到ServiceManager中。
还有一些onStart(),onBootPhase()特别类似Activity的生命周期方法。
onstart()
被调用的话,则代表当前的service可以调用publishBinderService方法,把自己注册到ServiceManager中。
onBootPhase()
systemserver会通过onBootPhase方法告知service当前启动到了哪一步了。
onUserStarting()
通过该方法告知service当前是哪个用户正在启动,其他的onUserXXX方法也是类似作用。
SystemServiceManager
该类的主要作用就是管理所有的SystemService,它的mService属性存储了所有启动的SystemService。同时它拥有几个简化创建service流程的方法:
startService(Class)
该方法把构建service对象、添加service对象、调用service的onStart方法这几个步骤都集中起来。启动一个service只需要调用该方法,service只需要实现自己的onStart方法逻辑,onStart方法具体啥时候调用,service不需要关心。
3.1.2 对service分类
把service分为bootstrap services、core services、other services:
bootstrap services代表别的service对它们的依赖最多,因此需要最先启动。
3.1.3 分发启动阶段信号
就是告知每个service当前处于启动的哪个阶段了,service根据相应的阶段信号可以做一些自己的事情。
分发启动阶段信号这个词如果不好理解的话,那用个例子来解释:在下载文件的时候,是不是会显示下载进度,而启动阶段信号其实与下载进度非常类似,就是告知service当前的启动进度是啥样。
3.2 启动
启动过程分为启动前、启动bootstrap services、启动core services、启动other services、进入无休工作模式。
3.2.1 启动前
设置binder线程池个数、开启Looper、加载android_servers可执行文件、创建Context,那就依次来介绍下。
设置binder线程池个数
普通进程打开binder进程之后,最多能启动15个binder线程,但是systemserver最多可以启动31个。
开启Looper
开启了Looper后,其他的线程或者当前线程就可以通过Handler把Message传递到当前线程。
加载android_servers可执行文件
android_servers可执行文件中包含了jni方法和很多native方法,使用System.loadLibrary方法可以把android_servers可执行文件加载到内存中,这样就可以保证jni方法可用。
创建Context
会创建两个Context,一个用来做业务逻辑等处理,另一个用来做UI显示,在systemserver也是会显示一些UI的 (比如关机对话框)。
3.2.2 启动bootstrap services
已经对service进行了分类,该阶段就是对bootstrap services进行启动,在此阶段同时还会启动一个Watchdog类,它的作用是监控systemserver进程的对应线程是否发生了锁等待情况.
此阶段,会发出第一个启动阶段信号PHASE_WAIT_FOR_DEFAULT_DISPLAY (它的值为100),此信号的意思是现在进入等待获取默认显示屏阶段,已经启动的service都会收到该信号,只不过只有DisplayManagerService才关心此信号。DisplayManagerService会尝试获取是否有可用的显示屏,有的话则进入下阶段;否则等待一定时间后还是没有可用的显示屏,则整个启动过程失败。
3.2.3 启动core services
主要是启动类别为core的所有service
3.2.4 启动other services
会启动剩下的service,在这个阶段还会启动systemui进程,并且还会启动launcher,在这里介绍下几个关键的启动阶段信号。
PHASE_WAIT_FOR_SENSOR_SERVICE (它的值是200),此信号的意思是进入等待传感器服务阶段,同样所有启动的service都会收到此信号,只有SensorService才会关心它,SensorService在等待期间会阻塞启动过程。
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收到此信号后就可以做自己该做的事情了。
3.2.5 进入无休工作模式
在ActivityManagerService发出PHASE_BOOT_COMPLETED信号.
其实就是调用了Looper.loop()方法,该方法作用是让当前线程会一直循环下去。