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,进入入口类。

  1. 关闭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的文件描述符,以避免不必要的资源占用或潜在的冲突。

  2. 创建ClassLoader

    当前被创建出的systemserver进程,它与zygote共享一个BootClassLoader对象,而该ClassLoader只是加载了进程之间公用的classes,

    systemserver自己特有的各种classes在共享的BootClassLoader对象中是找不到的,比如入口类SystemServer在BootClassLoader找不到。

    为什么需要创建? 于是创建自己的ClassLoader,并且把自己的各种jar、so文件路径设置给ClassLoader,同时该ClassLoader的parent是共享的BootClassLoader对象。这样通过自己的创建的ClassLoader就可以找到systemserver进程自己特有的classes,同时也能找到zygote之前预加载的classes。

  3. 打开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系统启动过程中非常关键的一步,因为它确保了系统服务能够高效地与其他组件进行交互。

  4. 进入入口类

    最后一步,也是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 servicescore servicesother 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()方法,该方法作用是让当前线程会一直循环下去。