安卓手机启动时发生的那些事儿——下篇

上篇文章我们谈到进入安卓系统的启动流程,大致梳理了从Native到Framework的流程,到达Framework阶段后,到应用程序启动,这之间仍然有一些工作需要处理,这次,我们就一起学习这部分的工作。

一、概览

上篇文章学习到了Zygote进程,但并未有具体分析Zygote进程的工作,本篇文章,我们就一起学习Zygote进程的具体工作,以及第一个App——Launcher的启动过程。

二、Zygote进程的工作

ZygoteInit的main方法方法大概就做了六件事情:

  1. 创建 ZygoteServer,Android O 上把与 Socket 的操作都封装到了ZygoteServer 类中
  2. 解析app_main.cpp传来的参数 。
  3. 创建一个 Server 端的 Socket,作用是当 Zygote 进程将SystemServer 进程启动后,就会在这个 Socket 上来等待ActivityManagerService 请求,即请求创建我们自己 APP 应用程序进程
  4. 预加载类和资源,包括颜色、R文件、drawable 、 类等
  5. 启动 system_server 进程 这是上层 framework 的运行载体,ActivityManagerService 就是运行在这个进程里面的
  6. 开启一个循环,等待着接收ActivityManagerService 的请求,随时待命,当接收到创建新进程的请求时立即唤醒并执行相应工作

我们主要学习其中的这几个步骤:

  1. 创建 Server 端的 Socket
  2. 启动SystemServer进程
  3. SystemServer处理过程
  4. 资源预加载
  5. 等待AMS请求创建新的应用程序进程

2.1 创建 Server 端的 Socket

在ZygoteInit.java的main方法,是这样来创建 Server 端的 Socket的:

zygoteServer.registerServerSocket(socketName);

那我们就来看看ZygoteServer的registerServerSocket方法到底做了什么。关键代码如下:

void registerServerSocket(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            //拼接Socket的名称
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                 //得到Socket的环境变量的值
                String env = System.getenv(fullSocketName);
                //将Socket环境变量的值转换为文件描述符的参数
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
                //创建文件描述符
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                //创建服务器端 Socket
                mServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

拼接Socket的名称时,socketName的值是传进来的“zygote”,因此fullSocketName的值是“ANDROID_SOCKET_zygote”,然后将这个值转换为环境变量的值,再转换为文件描述符的参数。之后创建文件描述符,并传入此前的文件描述符参数,最后创建LocalServerSocket(fd),也就是服务器端 Socket,并将文件描述符传进去。再Zygote进程将SystenServer进程启动后,就会在这个服务器端的Socket上等待AMS请求zygote进程创建新的应用程序进程。

2.2 启动SystemServer进程

ZygoteInit进程是通过startSystemServer(abiList, socketName, zygoteServer)函数来启动SystemServer进程的,接下来我们学习此部分关键代码:

private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
            throws Zygote.MethodAndArgsCaller, RuntimeException {
······
        //创建args数组,这个数组用来保存启动SystemServer的启动参数
        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);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            //创建SystemServer子线程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        //以下代码运行在子线程中
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            zygoteServer.closeServerSocket();
            //处理SystemServer进程
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

可以看到,这个函数首先创建args数组,保存启动参数,并封装Arguments对象供forkSystemServer调用,而forkSystemServer函数内部会调用nativeSystemServer的这个Native方法,最终通过fork函数在当前进程创建一个子进程,也就是SystemServer进程,并执行pid == 0的代码,也就是关键的handleSystemServerProcess(parsedArgs)函数。

2.3 SystemServer处理过程

这一节紧接上节,主要学习handleSystemServerProcess()函数发生的事情。主要代码如下:

    private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
            throws Zygote.MethodAndArgsCaller {
       ······
        if (parsedArgs.invokeWith != null) {
            ······
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                //创建PathClassLoader
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }
            //调用ZygoteInit的zygoteInit方法
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
    }

这里重点是调用了ZygoteInit的zygoteInit方法,关键代码如下:

public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();
        RuntimeInit.commonInit();
        //启动binder线程池
        ZygoteInit.nativeZygoteInit();
        //进入SystemServer的main方法
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

这里主要调用了nativeZygoteInit()方法,作用是调用Native层的代码,来启动Binder线程池,这样SystemServer就可以使用Binder与其他进程进行通信。然后进入SystemServer的main方法。下面分别介绍这两部分:

int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

nativeZygoteInit()是一个Native方法,需要查找其对应的JNI文件,通过JNI的gMethods数组,可以看到其对应的是AndroidRuntime.cpp的com_android_internal_os_ZygoteInit_nativeZygoteInit函数,如下:

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

这里gCurRuntime是AndroidRuntime类型的指针,指向AppRuntime,在app_main_cpp中定义,关键代码如下:

    virtual void onZygoteInit()
    {
        sp proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
       //启动一个Binder线程池
        proc->startThreadPool();
    }

看到这里,我们大致就了解了nativeZygoteInit方法主要是启动Binder线程池的。

再回到ZygoteInit的zygoteInit方法,我们还没结束这段代码:

public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();
        RuntimeInit.commonInit();
        //启动binder线程池
        ZygoteInit.nativeZygoteInit();
        //进入SystemServer的main方法
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

第二部分,调用了RuntimeInit的applicationInit方法,来进入SystemServer的main方法,applicationInit关键代码如下:

    protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
       ······
        // Remaining arguments are passed to the start class's static main
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

看到,在其中调用了invokeStaticMain方法,这个方法启动SystemServer的main方法过程比较复杂,为了清除堆栈帧,使用了抛出异常然后捕获异常的方法,总之会经过一串过程,最终进入SystemServer的main方法中。那么我们就看看这个main方法:

     public static void main(String[] args) {
        new SystemServer().run();
    }

里面只有一行run方法,run方法主要代码如下:

    private void run() {
        try {
            ······
            //创建消息Looper
            Looper.prepareMainLooper();
            // 加载动态库libandroid_servers.so
            System.loadLibrary("android_servers");
            performPendingShutdown();
            // 创建系统的contex
            createSystemContext();
            // 创建SystemServiceManager
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }
        try {
            traceBeginAndSlog("StartServices");
            //启动引导服务
            startBootstrapServices();
            //启动核心服务
            startCoreServices();
            //启动其他服务
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
        ······
    }

可以看到,这段代码主要启动系统的各种服务,这些服务大致如下:

  • 引导服务:AMS,PowerMS,PachageMS
  • 核心服务:DropBoxManagerService,BatteryService,UsageStateService和web ViewUpdateService
  • 其他服务:Camera、Alarm、VrManager等等

服务的总数有100多个,这里就不在详细讨论了。这些服务的启动逻辑是类似的,直接调用SystemServiceManager的startService方法,会将服务注册到服务列表中,然后调用服务的onStart函数完成启动。
下面总结下SystemServer进程的工作:

  • 启动Binder线程池,可以与其他进程通信
  • 创建SystemServiceManager,用于对系统的服务进行创建、启动和生命周期管理
  • 启动各种系统服务

2.4 资源预加载

好,现在让我们回到ZygoteInit进程,接下来是资源的预加载过程,那么预加载是什么呢?Android 系统资源加载分两种方式,预加载和使用进程中加载。 预加载是指在 zygote 进程启动的时候就加载,这样系统只在 zygote 执行一次加载操作,所有 APP 用到该资源不需要再重新加载,减少资源加载时间,加快了应用启动速度,一般情况下,系统中 App 共享的资源会被列为预加载资源。

预加载的原理很简单,就是在 zygote 进程启动后将资源读取出来,保存到 Resources 一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。这主要靠 zygoteInit.java 类的man方法调用preload()方法完成,下面我们来看看这部分关键代码:

static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
        beginIcuCachePinning();
        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        //预加载类
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("PreloadResources");
        //预加载资源
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
        //预加载图形接口
        preloadOpenGL();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();
        //预加载文字资源
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        endIcuCachePinning();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

可以看到,这个方法主要是通过调用各种预加载方法去实现预加载的,具体的方法预加载方法在这里就不在细究,等有机会再深入学习。

2.5 等待AMS请求创建新的应用程序进程

启动SystemServer进程后,会执行ZygoteServer的zygoteServer.runSelectLoop(abiList)方法:

zygoteServer.runSelectLoop(abiList);

这个方法无限循环,等待AMS的请求,主要代码如下:

    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ArrayList fds = new ArrayList();
        ArrayList peers = new ArrayList();
        //之前创建的服务器端Socket,获得该Socket的fd字段,并添加到列表
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);
        //无限循环等待AMS请求
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            //遍历fds,将信息转移到pollFds数组
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            //遍历pollFds数组
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                //i等于0,说明服务器端Socket与客户端连接上了,即当前Zygote与AMS建立连接
                if (i == 0) {
                    //得到ZygoteConnection并添加到连接列表
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    //添加fd列表,以便可以接收到AMS的请求
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //i不等于0,说明AMS向Zygote发送了请求,则创建新的应用程序进程
                    //调用runOnce函数创建新的应用程序进程
                    boolean done = peers.get(i).runOnce(this);
                    //成功后,在Socket连接列表和fds中清除这个请求
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

根据上述代码,可以看到这个函数是通过无限循环来处理AMS的请求,每次成功创建新的应用程序进程,就将其从列表清除。

三、Lanucher启动过程

Laucher启动较为复杂,放在另外一篇文章中进行学习。

四、总结

结合这几篇文章,就可以总结出安卓启动的完整流程,主要有下列几部分:

  1. 启动电源以及系统启动
    按下电源,引导芯片代码从预设位置(ROM)执行。加载BootLoader到RAM,然后执行。
  2. 引导程序BootLoader
    拉起OS。
  3. Linux内核启动
    设置缓存、被保护寄存器、计划列表、加载驱动,完成系统设置后,在系统文件中寻找Init.rc文件,并启动init进程。
  4. init进程启动
    初始化和启动属性服务,启动Zygote进程
  5. Zygote进程启动
    创建java虚拟机并注册JNI方法,创建服务器端Socket,启动SystenmServer进程。
  6. SystemServer进程启动
    启动Binder线程池和SystemServiceManager,启动各种系统服务。
  7. Launcher启动
    AMS启动Launcher,将安装应用程序的快捷图标显示到界面上。

给出图示如下:


安卓系统启动流程

文笔简陋,如有错误,还请见谅。

你可能感兴趣的:(安卓手机启动时发生的那些事儿——下篇)