SystemServer进程启动分析

2024-02-02 07:48

本文主要是介绍SystemServer进程启动分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在前面关于Zygote启动的文章分析过,Zygote进程启动后会去启动SystemServer进程,本篇就来分析下SystemServer启动流程。

//ZygoteInit.java
public static void main(String argv[]) {....if (startSystemServer) {startSystemServer(abiList, socketName, zygoteServer);}}
//ZygoteInit.java
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)throws Zygote.MethodAndArgsCaller, RuntimeException {//启动system server进程的一些参数/* Hardcoded command line to start the system server */String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {//解析参数parsedArgs = new ZygoteConnection.Arguments(args);//fork子进程pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);}/* For child process *///子进程也就是SystemServer进程会执行到这个分支if (pid == 0) {//SystemServer进程不需要要从父进程(zygote)继承来的ServerSocketzygoteServer.closeServerSocket();//执行子进程相关代码handleSystemServerProcess(parsedArgs);}return true;}

startSystemServer主要干了3件事:

  • 设置了一些启动system server进程的参数,比如用户id,组id,还有进程创建后要执行的类com.android.server.SystemServer。
  • fork出SystemServe进程
  • 执行子进程相关代码,最终会执行com.android.server.SystemServer的main函数。

首先分析Zygote.forkSystemServer,看看是如何fork子进程的。

//Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {int pid = nativeForkSystemServer(uid, gid, gids...);return pid;}native private static int nativeForkSystemServer(int uid, int gid, int[] gids...);

调用到native层的com_android_internal_os_Zygote.cpp的nativeForkSystemServer方法。

//com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,jlong effectiveCapabilities) {//调用了ForkAndSpecializeCommon方法pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,debug_flags, rlimits,permittedCapabilities, effectiveCapabilities,MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,NULL, NULL, NULL);return pid;
}static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid...) {//直接通过fork函数来创建一个子进程pid_t pid = fork();//...return pid;
}

关于fork函数可以查看我的Linux博客,这样一个进程就创建出来了,接着分析handleSystemServerProcess。

//ZygoteInit.java
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)throws Zygote.MethodAndArgsCaller {//从启动进程的参数可知没有设置--invoke-with,因此parsedArgs.invokeWith为空if (parsedArgs.invokeWith != null) {} else {ClassLoader cl = null;if (systemServerClasspath != null) {cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);}//走到这ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);}}

handleSystemServerProcess的代码不多,主要是创建了systemServer的类加载器,然后调用ZygoteInit.zygoteInit方法,把parsedArgs遗留的参数以及类加载器传进去了。

//ZygoteInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {//这个方法最终会启动当前进程的binder线程池,本篇暂不分析ZygoteInit.nativeZygoteInit();RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);}

接着调用了 RuntimeInit.applicationInit方法。

//RuntimeInit.java
protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)throws Zygote.MethodAndArgsCaller {final Arguments args;try {args = new Arguments(argv);} catch (IllegalArgumentException ex) {return;}//调用了invokeStaticMain方法invokeStaticMain(args.startClass, args.startArgs, classLoader);}private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)throws Zygote.MethodAndArgsCaller {Class<?> cl;//获取com.android.server.SystemServer的class对象,这个className就是之前参数配置的try {cl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {}Method m;try {//获取SystemServer的main方法m = cl.getMethod("main", new Class[] { String[].class });}//这个注释很有意思,所以我没删/** This throw gets caught in ZygoteInit.main(), which responds* by invoking the exception's run() method. This arrangement* clears up all the stack frames that were required in setting* up the process.*///抛出异常,并且把SystemServer的main方法和argv传进去了throw new Zygote.MethodAndArgsCaller(m, argv);}

这个异常是在哪里捕获的呢?注释已经很清楚了ZygoteInit.main()方法。

public static void main(String argv[]) {try {if (startSystemServer) {startSystemServer(abiList, socketName, zygoteServer);}} catch (Zygote.MethodAndArgsCaller caller) {caller.run();} catch (Throwable ex) {}}

捕获了这个异常后就会调用它的run方法,为什么要这么干呢,主要是为了清除所有的堆栈帧,这样调用SystemServer的入口main方法时,之前的堆栈帧都会被清除,看起来更像一个入口函数,当然可能也有其他好处。继续往下分析:

//Zygote.java
public static class MethodAndArgsCaller extends Exceptionimplements Runnable {/** method to call */private final Method mMethod;/** argument array */private final String[] mArgs;public MethodAndArgsCaller(Method method, String[] args) {mMethod = method;mArgs = args;}public void run() {try {//直接调用了SystemServer的main方法mMethod.invoke(null, new Object[] { mArgs });} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} }}

到这里新创建的进程就去执行SystemServer类的main方法了。

//SystemServer.java
public static void main(String[] args) {//调用了SystemServer类的run方法new SystemServer().run();}private void run() {try {// Here we go!Slog.i(TAG, "Entered the Android system server!");//SystemServer的Looper消息循环Looper.prepareMainLooper();// Initialize native services.//加载动态库libandroid_servers.soSystem.loadLibrary("android_servers");// Initialize the system context.createSystemContext();// Create the system service manager.//创建SystemServiceManager,它会对系统的服务进行创建、启动和生命周期管理。mSystemServiceManager = new SystemServiceManager(mSystemContext);mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);} // Start services.try {//引导服务:ActivityManagerService、PowerMandiaoagerService、PackageManagerService等startBootstrapServices();//核心服务:BatteryService、UsageStatsService和WebViewUpdateService等startCoreServices();//其他服务:AlarmManagerService、VrManagerService等startOtherServices();SystemServerInitThreadPool.shutdown();} catch (Throwable ex) {throw ex;}// Loop forever.Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

可以看到SystemServer的run方法,启动了很多系统服务,而系统根据服务的特性分为了三类。引导服务、核心服务以及其他服务。

到这里SystemServer的启动流程其实就分析完成了,SystemServer在启动时回去创建许多的系统服务,包括我们经常打交道的ActivityManagerService主要用来管理四大组件的生命周期调度、PowerManagerService 是设备电源管理的系统服务 、PackageManagerService 管理所有和 package 相关的工作,比如安装、卸载应用。

有些系统服务并不是通过SystemServiceManager来完成启动的。这里挑几个常见的系统服务看看是如何在SystemServer中被启动的。

//SystemServer.java
private void startBootstrapServices() {//启动了AMSmActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();//启动了PowerManagerServicemPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);//PKMSmPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);//把AMS加入到ServiceManager中mActivityManagerService.setSystemProcess();}

SystemServiceManager的startService方法如下

//SystemServiceManager.java//通过类名启动系统服务
public SystemService startService(String className) {final Class<SystemService> serviceClass;try {serviceClass = (Class<SystemService>)Class.forName(className);} return startService(serviceClass);}//通过类名创建系统服务
public <T extends SystemService> T startService(Class<T> serviceClass) {try {final String name = serviceClass.getName();final T service;try {Constructor<T> constructor = serviceClass.getConstructor(Context.class);//直接通过反射创建了系统服务的实例service = constructor.newInstance(mContext);} //然后调用startService方法把服务的实例传入startService(service);return service;} }public void startService(@NonNull final SystemService service) {// Register it.mServices.add(service);//直接调用了SystemService的onStart方法service.onStart();}

SystemServiceManager的startService很简单,通过反射创建实例,然后调用onStart方法。

而启动ActivityManagerService时传入了ActivityManagerService.Lifecycle.class

//ActivityManagerService.java
public static final class Lifecycle extends SystemService {private final ActivityManagerService mService;public Lifecycle(Context context) {super(context);//在构造方法中传入了创建了ActivityManagerServicemService = new ActivityManagerService(context);}@Overridepublic void onStart() {//调用ActivityManagerService的start方法,启动ActivityManagerServicemService.start();}public ActivityManagerService getService() {return mService;}}

创建并启动了ActivityManagerService之后会把他加入到ServiceManager中。

//ActivityManagerService.java
public void setSystemProcess() {//把AMS的IBinder注册到ServiceManager中ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);}

可以看到这里把服务注册到ServiceManager了,ServiceManager属于一个单独的进程,也是由init进程启动的,它的角色相当于服务的路由器(DNS)。当然了ServiceManager那边绑定的是服务名称和对应的handle值,不过,目前只需要简单理解通过这个方法把服务注册到ServiceManager,其他进程可以通过服务的名称来查询对应的服务就好了。

接着分析下PowerManagerService的启动注册,根据前面分析知道,调用startService传入PowerManagerService.class必然会创建它的实例,然后调用它的onStart方法。

//PowerManagerService.java
public void onStart() {//BinderService是PowerManagerService的内部类,继承自IPowerManager.StubpublishBinderService(Context.POWER_SERVICE, new BinderService());}

调用了publishBinderService,传入了BinderService实例,BinderService继承自IPowerManager.Stub,了解AIDL的一眼就看出来了吧。

这个publishBinderService是父类SystemService的方法。

//SystemService.java
protected final void publishBinderService(String name, IBinder service) {publishBinderService(name, service, false);}protected final void publishBinderService(String name, IBinder service,boolean allowIsolated) {//可以看到最终还是被添加到ServiceManager了ServiceManager.addService(name, service, allowIsolated);}

最后来看下PKMS的启动,它只是调用了PackageManagerService.main就完成了PackageManagerService的启动,其实本质还是一样的。

//PackageManagerService.java
public static PackageManagerService main(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {// Self-check for initial settings.PackageManagerServiceCompilerMapping.checkProperties();PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);ServiceManager.addService("package", m);return m;}

是不是很简单,最终还是被注册到ServiceManager中。

finsh~~~

这篇关于SystemServer进程启动分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/669981

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud