【Android面试题】Android Framework核心面试题——SystemServer进程的启动流程

SystemServer进程的启动流程

这道题想考察什么?

这道题想考察同学对SystemServer进程的了解。

考生应该如何回答

SystemServer进程是由zygote进程启动的,它作为zygote进程的大儿子,它被赋予了重要的职责,启动并管理app运行所需要的绝大多数服务,其中包含:AMS ,ATMS,WMS,PKMS,PMS等等大概有90多个服务,这些服务的启动和管理流程的细节请看后面的分析。

1.SystemServer是做什么的

SystemServer进程主要是用于创建和管理系统服务的,例如AMS、WMS、PMS。由于SystemServer进程和应用进程由Zygote进程启动,所以接下来分析Zygote如何处理的SystemServer进程。

2.Zygote处理SystemServer进程

继上一题《Zygote进程的启动流程》的代码,在zygote#main() 函数中通过调用forkSystemServer()函数 fork SystemServer 进程,那么我们看一下下面的代码:

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        try {
            // 1.创建SystemServer进程,并返回当前进程的pid
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        // 2.如果pid==0则说明Zygote进程创建SystemServer进程成功,当前运行在SystemServer进程中
        if (pid == 0) {
            // 3.由于SystemServer进程fork了Zygote进程的地址空间,所以会得到Zygote进程创建的Socket,
            // 而这个Socket对于SystemServer进程是无用的,因此,在此处关闭了该Socket。
            zygoteServer.closeServerSocket();
            // 4.启动SystemServer进程
            return handleSystemServerProcess(parsedArgs);
        }
    }

上面的代码执行过程会涉及到进程的fork,在代码1 处,Zygote.forkSystemServer()执行的过程中会创建一个进程,这个进程就是systemServer进程。那么fork完成后,此处的代码会返回两次,因为fork 会返回两次,一次返回是执行fork新创建的代码,另外一次是zygote自己的代码。第一次返回值如果是0 ,说明当前运行的是新的创建的进程的代码也就是systemServer进程的代码,第二次返回的值是一个大于0的值,说明当前运行的代码是zygote进程的代码。因此就有了后面的if判断也就是代码2处,如果 pid 等于0 ,说明当前进程是运行在systemServer进程中。systemServer进程是不需要zygoteServer的,于是就有了 closeServerSocket代码的存在。然后,再执行handleSystemServerProcess,运行systemServer进程。

private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        if (parsedArgs.mInvokeWith != null) {
            ...
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                // 1.使用了systemServerClassPath和targetSdkVersion创建了一个PathClassLoader
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
            }

            // 2.调用 ZygoteInit.zygoteInit 方法
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, cl);
        }
    }

以上代码做了两件事:1)基于sdk版本创建了一个ClassLoader;2)执行zygoteInit方法。

public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        // 1.进入native方法
        ZygoteInit.nativeZygoteInit();
        // 2.获取封装了SystemServer的main函数的runnable
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

在zygoteInit函数中,首先是调用nativeZygoteinit函数来初始化进程环境,然后再执行applicationInit函数获取封装了SystemServer的main函数的Runnable。

2-1.ZygoteInit.nativeZygoteInit

在上一题《zygote进程的启动流程》中我们知道有一个流程,那就是在zygote初始化的时候会注册JNI,其中就有将nativeZygoteInit()方法和native函数com_android_internal_os_ZygoteInit_nativeZygoteInit()建立了映射关系。所以此时调用nativeZygoteInit()会调用到AndroidRuntime的下面的代码。

static AndroidRuntime* gCurRuntime = NULL;

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

gCurRuntime是AndroidRuntime的指针,具体指向的是其子类AppRuntime,它在app_main.cpp中定义。代码如下:

// frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
    {
        // 1.创建了一个ProcessState实例
        sp<ProcessState> proc = ProcessState::self();
        // 2.启动了一个Binder线程池
        proc->startThreadPool();
    }

在这个代码中执行的是进程的初始化,首先在代码1处,创建了一个进程ProcessState,其中就会创建一个binder;然后在代码2处启动了Binder线程池,为Binder线程的运行提供了动力。

到目前为止SystemServer进程已经创建完成,那么接下来就需要运行systemServer进程了,所以我们回到RuntimeInit.applicationInit函数中进行分析。

2-2.RuntimeInit.applicationInit
// frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        return findStaticMain(args.startClass, args.startArgs, classLoader);
}
protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;
        try {
            // 1.通过反射得到了SystemServer类
            cl = Class.forName(className, true, classLoader);
        }

        Method m;
        try {
            // 2.找到了 SystemServer中的main方法
            m = cl.getMethod("main", new Class[] { String[].class });
        }

        // 3.将main()方法传入MethodAndArgsCaller()方法中
        return new MethodAndArgsCaller(m, argv);
    }

以上代码就是运用反射,拿到systemServer的main 函数,并且调用MethodAndArgsCaller,将main函数的调用封装到一个Runnable中,方便后期的执行。

static class MethodAndArgsCaller implements Runnable {
        private final Method mMethod;
        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
                // 执行SystemServer的main()方法
                mMethod.invoke(null, new Object[] { mArgs });
            }
        }
    }

这个Runnable的run方法是在ZygoteInit的main()方法中被执行。代码如下:

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
    try {
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                if (r != null) {
                    r.run();  //1 执行run
                    return;
                }
            }
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

如上面代码1处,执行run方法,这个时候就是执行方法main(),所以,接下来我们看systemServer main函数的执行。

3. SystemServer进程执行

// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
        new SystemServer().run();
}

main函数就一行代码执行SystemServer进程的润函数:

private void run() {
        try {
            Looper.prepareMainLooper();

            // 1.加载动态库libandroid_servers.so
            System.loadLibrary("android_servers");

            // 2.创建SystemServerManager
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            
            // 3.初始化系统上下文
            createSystemContext();

        }

        try {
            // 3.使用SystemServiceManager启动引导服务
            startBootstrapServices(t);
            // 4.启动核心服务
            startCoreServices(t);
            // 5.启动其他服务
            startOtherServices(t);
        }

        // Loop forever.
        Looper.loop();
}

通过上面的代码不难发现,启动过程中,在大流程上systemServer和app进程的启动很像,初始化了很多资源,也加载了很多资源,还创建了上下文,同时构建了进程的Looper 死循环确保进程不会退出。当然,在SystemServer中最重要的内容还是通过代码3,4,5启动了非常多的服务,大概有90多个服务,这些服务包括AMS,ATMS,WMS,PKMS,BMS等等一系列的服务。另外,在代码2处创建了一个systemServiceManager对象,这个对象是用于在SystemServer进程中管理90多个服务的启动的。

4.总结

SystemService进程被创建后,主要的处理如下:

  1. 启动Binder线程池,这样就可以与其他进程进行Binder跨进程通信。
  2. SystemServer在启动过程中,先初始化一些系统变量,加载类库,创建Context对象。
  3. 创建SystemServiceManager,它用来对系统服务进行创建、启动和生命周期管理。
  4. 启动各种系统服务:引导服务、核心服务、其他服务,共90多种。应用开发主要关注引导服务ActivityManagerService、PackageManagerService和其他服务WindowManagerService、InputManagerService即可。
  5. SystemServer在启动服务前,会尝试与Zygote建立Socket通信,通信成功后才去启动服务。
  6. 启动的服务都单独运行在SystemServer的各自线程中,同属于SystemServer进程

最后

有需要面试题的朋友可以关注一下哇哇,以上都可以分享!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容