Android启动过程(一)

安卓架构图

(转自:https://www.jianshu.com/p/657336b545bd

loader>kernel>native>framework>app

作为安卓的第一个进程init(pid =1),init将通过解析init.rc来陆续启动其他关键服务进程(ServiceManager,Zygote和SystemServer)

如果你本地看不了源码的话,可以通过在线查看源码(https://www.androidos.net.cn/android/5.1.0_r3/xref/system/core/rootdir/init.rc

/system/core/rootdir/init.rc

healthd  电池服务进程

zygote   卵进程

media    多媒体进程

surfaceflinger  suface进程

drm  Digital Rights Managemen,也就是数字版权加密保护技术。

servicemanager 是一个Linux 程序。它在设备中的存储路径是 /system/bin/servicemanager/  所属的class 为core 根据该特性,这些进程会同时被启动或停止。cirtical 表示的是系统的关键进程-意味着如果进程不幸在4分钟内异常退出超出4次,这设备将重启并进入还原模式。当servicemanager 每次重启时,其他关键进程如Zygote,media,surfaceflinger等也会被restart。

zygote   卵进程

卵进程干什么用的?

其实Android中大部分的进程和系统进程都是通过Zygote 来生成的

接下来分析一下Zygote是如何启动的

其实跟servicemanager一样也是通过init进程解析init.rc脚本启动的。早期版本android中的Zygote的启动命令是在init.rc中,但是随着硬件的不断升级换代,Android系统不得不面对32位和64位机器同时存在的情况,因而对Zygote的启动也需要根据不同的情况区分对待。

一般会有不同的Zygote的脚本,比如

现以init.zygote64.rc为例查看一下相关代码

从上面可以看出

servicename 为zygote

path:/system/bin/app_process64

属性-Xzygote /system/bin --zygote --start-system-server

Zygote 所属于的class 为main 而不是core 

从路径上来看他所在的进程名叫app_process64 而不像servicemanager 一样在一个独立的进程中。通过指定的--zygote参数,app_process可以识别用户是否需要启动zygote,接下来看一下这个app_process到底是什么

先看一下Android.mk文件

上述是构建32位和64位系统的一个编译脚本。其中LOCAL_MULTILTB 表示同时编译32位和64位

接下来分析一下app_process的主函数就知道其内部逻辑

int main(int argc, char* const argv[])
{
       ...
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
      ...
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {    //判断当前进程是否用于承载zygote
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {  //是否需要启动system server
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
     ...
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

这个函数用于解析app_process 时传入的参数,具体如下

--zygote: 表示当前进程用于承载zygote

--start-system-server:是否需要启动system server

--application: 启动进入独立的程序模式

--nice-name: 此进程的“别名”

对于非zygote的情况下,在上述参数的末尾会跟上main class 的名称,而后的其他参数则属于这个class 的主函数入参;对于zygote的情况,所有参数则会作为它的主函数入参使用。

init.rc指定了--zygote选项,因而app_process 接下来将启动"ZygoteInit“”并传入“start-system-server”,之后ZygoteInit会运行与java虚拟机上,为什么?

原因就是runtime这个变量实际是一个AndroidRuntime对象,其start函数源码如下

void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
 if (startVm(&mJavaVM, &env) != 0) { //启动虚拟机
        return;
    }
    onVmCreated(env);  //虚拟机启动后的回调
    ...
}

当虚拟机成功启动,并进入ZygoteInit的执行中:

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
 public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;  //需要启动Sytem server
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            registerZygoteSocket(socketName);   //注册一个Socket
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            preload();  //预加载各类资源
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            gc(); //执行gc操作

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            if (startSystemServer) {
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

Zygote主要完成两项工作

注册一个Socket

Zygote是”孵化器”,一旦有新程序需要运行时,系统会通过这个Socket(完整的名称为ANDROID_SOCKET_zygote)在第一时间通知“总管家”,并由它负责实际的进程孵化过程。

预加载各类资源

函数preload用于加载虚拟机运行时所需的各类资源,包括:

preloadClassed();  //负责加载和初始化常用的一些classed

preloadResources();//负责加载和初始化常用的一些资源文件

preloadOpenGL();//负责加载和初始化OpenGL

preloadSharedLibraries();//负责加载和初始化共享库

启动System Server

如果app_process的调用参数中带有“--start-system-server”,那么此时就会通过startSystemServer来启动System Server.

Zygote前期主要担任启动系统服务的工作,后期则又担当"程序孵化”的重任。但是Zygote只在init.rc中被启动一次,它是如何协调好这两项工作的关系呢?我们可以推断一下,上述的startSystemServer应该会新建一个专门的进程来承载系统服务的运行,而后app_process 所在的进程则转变为Zygote的“孵化器”守护进程。那么是不是这样子呢?

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

 private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        /* 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,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;
        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

上述代码段出现了我们熟悉的fork流程-forkSystemServer 在内部利用UNIX的fork机制创建了一个新的进程;而这个“新生儿”(即 pid ==0 分支)会在随后的执行过程中通过handleSystemServerProcess来启动各个支撑系统运行的System Server

在跟踪System Server 的具体启动过程之前,我们先来为Zygote接下来的工作做一个分析,startSystemServer中并没有为父进程专门开辟一个代码分支。因而这个函数最后会通过return ture 而返回到Zygoteinit 的主函数中。紧随其后的语就是

runSelectLoop(abiList);

查看源码:

static final int GC_LOOP_COUNT = 10;

 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        FileDescriptor[] fdArray = new FileDescriptor[4];

        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);  //添加null是为了保持fds 和peers的一致性

        int loopCount = GC_LOOP_COUNT; 设定多少次循环才调用垃圾回收函数gc(),
        while (true) {  //确实是死循环
            int index; 
            if (loopCount <= 0) {
                gc();  //gc操作
                loopCount = GC_LOOP_COUNT;
            } else {
                loopCount--;
            }


            try {
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray);

            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }

            if (index < 0) { //出错的情况
                throw new RuntimeException("Error in select()");
            } else if (index == 0) { //有新的连接请求
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDescriptor());
            } else {  //已建立的连接中有客户端发过来的数据需要处理
                boolean done;
                done = peers.get(index).runOnce();

                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }

从程序中可以看到,runSelectLoop的主体的确是一个while死循环,它将作为zygote的守护体存在,因为zygote此时运行在虚拟机环境中,所以它需要考虑垃圾回收的问题。不过这是一项非常耗时的操作,如果操作频繁,每次收回的垃圾并不会很多,那么就得不偿失。所以上述函数中设定了GC_LOOP_COUNT 为10,意味着while每循环十次才会调用一次gc()。那么while执行一轮都完成了那些工作呢?

我们从sServerSocket.getFileDescriptor() 获取到的是前面通过registerZygoteSocket 创建的Server Socket的文件描述符,它会被添加到一个ArrayList<FileDescriptor> 类型的fds变量中。这同时也意味着zygote中不光只有一个socket产生。具体而言,while循环中会先通过如下两个语句来判断当前哪个fd处于可读状态

fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);

当fds这个ArrayList指示的某个文件有可读数据时,返回的index值就代表此文件对应的file descriptor在队列中的序列。另外,这个函数还有一个特殊的返回值:0.。因为fds中的第一个元素为Zygote的Server Socket,所以index为0代表了有新的连接请求。这和网络连接中的Socket概念是一致的。

index = 0

此时我们需要通过acceptCommandPeer 来接受来自客户端的连接,产生一个新的ZygoteConnection,然后分别更新peers 和fds.为了保证这两个列表中的对象序列号保持一致,可以看到peers在初始化时专门添加了一个null,对应的是Zygote Server Socket这个“监听者”

index > 0

此时说明已经建立的Socket连接中有来自客户端的数据需要处理,完成具体的工作的是runOnce,下面我们详细分析一下这个函数:

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        ...
        try {                 
            checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize");
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
            checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize");
        } catch (IOException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }

        try {
            if (pid == 0) {
                // in child
                IoUtils.closeQuietly(serQverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                // should never get here, the child is expected to either
                // throw ZygoteInit.MethodAndArgsCaller or exec().
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

有两点需要重点注意:

创建承载应用程序的新进程

这是在意料之中的,zygote需要为每个新启动的应用程序生成自己独立的进程。不过runOnce中并没有直接使用fork来完成这一工作,而是调用了forkAndSpecialize,稍后会分析这个函数的实现。另外,新的创建的进程中一定需要运行应用程序本身的代码,这一部分工作是在handlerChildProc中展开的。

父进程的“扫尾”工作

执行完上述的任务之后,父进程还需要做一些清尾的工作才算“大功告成”。包括:将子进程加入进程组;正确关闭文件;调用返回结果值等。

Specialize的字面意思是“专门化”,表达了forkAndSpecialize在“孵化”的同时也把它转变为Android应用程序的目标。函数forkAndSpecialize的处理分为3个阶段,即preFork,nativeForkAndSpecialize 以及postForkCommon.

/frameworks/base/core/java/com/android/internal/os/Zygote.java 
 public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          String instructionSet, String appDataDir) {
        long startTime = SystemClock.elapsedRealtime();
        VM_HOOKS.preFork();
        checkTime(startTime, "Zygote.preFork");
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  instructionSet, appDataDir);
        checkTime(startTime, "Zygote.nativeForkAndSpecialize");
        VM_HOOKS.postForkCommon();
        checkTime(startTime, "Zygote.postForkCommon");
        return pid;
    }

接下来直接分析preForkZygote中对应的实现

/art/runtime/native/dalvik_system_ZygoteHooks.cc
static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
  Runtime* runtime = Runtime::Current();
  CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";

  runtime->PreZygoteFork();

  // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
  Thread* self = Thread::Current();
  return reinterpret_cast<jlong>(self);
}

这里的Runtime实例具体而言指的是Zygote进程中的运行环境,  runtime->PreZygoteFork()又会间接的调用Headp::PreZygoteFork,从而完全堆空间的初始操作。

函数nativeForkAndSpecialize 是一个native方法,具体对应的实现是com_android_internal_os_Zygote_nativeForkAndSpecialize ,后者则又进一步调用了ForkAndSpecializeCommon

/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities,
                                     jint mount_external,
                                     jstring java_se_info, jstring java_se_name,
                                     bool is_system_server, jintArray fdsToClose,
                                     jstring instructionSet, jstring dataDir) {
  uint64_t start = MsTime();
  SetSigChldHandler();
  ckTime(start, "ForkAndSpecializeCommon:SetSigChldHandler");

  pid_t pid = fork();   //这里才是真正孵化出一个新进程

  if (pid == 0) {//子进程中
    ...
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server ? NULL : instructionSet);
    ckTime(start, "ForkAndSpecializeCommon:PostForkChildHooks returns");
    ...
  } else if (pid > 0) {
    // the parent process 这里什么也不做因为父进程有处理
  }
  return pid;
}
}  

这个函数首先会fork一个新进程,并在pid == 0这一分支中为孵化的进程完成一系列初始化操作,而后执行CallStaticVoidMethod.其中gZygoteClass对应的是“com/android/internal/os/Zygote”,而gPostForkChildHooks则是Zygote这个类中的成员变量函数callPostForkChildHooks --从名称可以看出用于执行孵化后的一些处理工作。ForkAndSpecializeCommon也还没有设计与应用程序相关的具体业务,这部分工作会由runOnce中的handleChildProc 来完成,核心代码如下:

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
 private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        ...
        if (parsedArgs.niceName != null) {//子进程的别名
            Process.setArgV0(parsedArgs.niceName);
        }

        if (parsedArgs.runtimeInit) {
           ...
        } else {//应用程序的ActivityThread将在这里执行
            String className;
            try {
                className = parsedArgs.remainingArgs[0];
            } catch (ArrayIndexOutOfBoundsException ex) {
                logAndPrintError(newStderr,
                        "Missing required class name argument", null);
                return;
            }

            String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
            System.arraycopy(parsedArgs.remainingArgs, 1,
                    mainArgs, 0, mainArgs.length);  //className 主函数参数

            if (parsedArgs.invokeWith != null) {      //invokeWith的情况
                WrapperInit.execStandalone(parsedArgs.invokeWith,
                        parsedArgs.classpath, className, mainArgs);
            } else {
                ClassLoader cloader;
                if (parsedArgs.classpath != null) {
                    cloader = new PathClassLoader(parsedArgs.classpath,
                            ClassLoader.getSystemClassLoader());
                } else {
                    cloader = ClassLoader.getSystemClassLoader();
                }

                try { //执行main函数
                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
                } catch (RuntimeException ex) {
                    logAndPrintError(newStderr, "Error starting.", ex);
                }
            }
        }
    }

这个函数的任务用一句话来概括,就是找到并执行目标进程的入口函数。Android系统中所有的应用程序理论上都是由Zygote启动的;而且我们不难发现Zygote会为新启动的应用fork一个进程。不过和传统的内核中的fork+exec的做法不同的地方是,Zygote中并不会执行exec().。这在某些情况下就会造成一些障碍,比如无法使用valgrind来检测程序的内存泄漏情况。为了响应开发人员的类似需求,Android系统特别提供了一种Wrapper实现,并通过parsedArgs.invokeWith来加以控制

handleChildProc这个函数中,最重要的参数之一是className。可以看到,handleChildProc会把className对应的类加载到内存中,然后执行其中的main函数。那么这个className具体指的是什么呢?

其实是后续ActivityManagerServer,它会向Zygote发起的一个创建新进程的请求,代码如下

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
  private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
  Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);//这些参数将被转化为Arguments中的成员变量
                    ...
}

Process的字面意思虽然是进程,但其实它属于“进程类”,或者成为“进程管家”会贴切些。Process.jar显然是去启动一个新的进程来继承业务,而函数的第一个参数entryPoint,即我们在handleChildProc中看到的className。这是因为ActivityManagerService传递过来的字符串形式列表会被Arguments.paseArgs解析成Arguments中的各个成员变量,

各成员变量
  参数格式    对应的成员变量
“--setuid=”uid
"--setgid="gid
"--target--sdk-version="targetSdkVersion
"--runtime-init"runtimeInit
"-classpath"classPath

"--nice-name="

nicename
剩余的参数remainingArgs

 

现在问题转化为,ActivityManagerService 中的entryPoint是如何得来的呢?它的来源简单来讲就是下面的这个语句。

if (entryPoint == null) entryPoint = "android.app.ActivityThread";

换句话说,Zygote中主动执行的类是ActivityThread,这同时也是我们熟知的Acitivity应用程序的“主线程”:

  /frameworks/base/core/java/android/app/ActivityThread.java
  public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        ...
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

到目前为止,我们已经分析了Zygote作为守护进程时,如何为Android应用程序的启动而服务的。接下来要了解引导系统各个重要服务的启动过程。

从前面可以知道,System Server的启动是在startSystemServer中完成的。Zygote首先会利用Zygote.forkSystemServer来孵化处一个子进程,然后在pid==0的分支中调用handleSystemServerProcess,后者在函数的末尾又会进一步调用RuntimeInit.zygoteInit:

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
  public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        ...
        commonInit();
        nativeZygoteInit();

        applicationInit(targetSdkVersion, argv, classLoader);
    }

函数zygoteInit通过3个方面来完成初始化,分别是:

commonInit

通用部分的初始化,包括设置默认的uncaught exeception handler;为HttpURLConnection准备好默认的Http User_Agent;开启trace模式(只在emulator下才有必要)等。

nativeZygoteInit

这是一个本地初始化函数,也是zygoteInit中的重点,我们稍后会做重点分析。

applicationInit

这个函数的声明为:private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader);从中可以看出它是程序运行的“起点”。在我们这个场景中,程序指的是SystemServers,而"入口"是什么呢?这就和第二个参数argv有关系.。这个Sting[]实际上包含了两个重要的成员变量,即startClass 和startArgs。而这两个变量的赋值可以追溯到startSystemServer中,具体代码如下:
String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };

换句话说,startClass 对应的就是com.android.server.SystemServer。因而applicationInit最终将调用main@SystemServer:

public static void main(String[] args){

       new SystemServer().run();

}

经过上面的初始化后,程序现在会有两个分支,其一是nativeZygoteInit 主导的本地系统服务的启动:另一个则是applicationInit负责的java层系统服务的启动。

(1)本地系统服务的启动

在JNI机制中,Native函数在java层会有一个声明,然后在本地层得到真正的实现。那么当我们调用了java层的函数后,系统是如何找到Native中与之对应的函数的呢?通常情况下,Native中的C++文件名称是以java层的package为基础的,如java层的包名为com.android.internal.XX,那么其对应的JNI层文件则是com_android_internal_XX。不过这种对应关系并不是绝对不变的,可以根据开发人员的需求进行调整。譬如我们上面讲的ZygoteInit所在的java包是com.android.initernal,而实际上JNI的实现则为AndroidRuntime.cpp。

AndroidRuntime 表明这个class的任务是“负责Android的运行时环境”。当我们调用了nativeZygoteInit后,实际上是执行了 com_android_internal_os_RuntimeInit_nativeZygoteInit@AndroidRuntime.cpp,代码如下:

/frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

全局变量gCurRuntime是一个AndroidRuntime的对象,结合之前能想象到AndroidRuntime是一个父类,真正的实现则在App_main.cpp中的AppRuntime。当我们新建AppRuntime对象时,它的父类的构造函数会被调用,并为gCurRuntime赋值。上述的onZygoteInit也在这个App_main.cpp文件中,如下所示:

 /frameworks/base/cmds/app_process/app_main.cpp
 virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

上面这段代码是Binder机制中的重要组成部分,其中startThreadPool将开启Binder线程池以保证其他进程可以正确访问到Zygote所提供的服务。Zyogte通过JNI和回调的方式非常巧妙地把本地层和java层,SystemServer和App process关联起来了。

(2)java层系统服务的启动

java层的系统服务比较多,它们各司其职,缺一不可。我们知道,Zygote会为System Server的运行启动和初始化虚拟机,并通过入口main@System.java 开启 “系统服务之旅”。不过main函数只起到“门”的作用,它又会直接调用SystemServer().run(),后者才是真正实现服务的地方:

private void run() {
        try {            
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
            ...
            // Mmmmmm... more memory!
            VMRuntime.getRuntime().clearGrowthLimit();       

            // Prepare the main looper thread (this thread).
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();  //准备主循环体
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

            // Initialize native services.
            System.loadLibrary("android_servers");  //加载本地服务库        
            ...
            // Initialize the system context.
            createSystemContext();

            // Create the system service manager.
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

        // Start services.
        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();
        }

        StrictMode.initVmDefaults(null);
        // Loop forever.
        Looper.loop();  //进入死循环,直到设备关机
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

System Server 在启动前首先需要做很多初始化设置,包括将VM的版本记录到系统变量中,设置线程优先级,设置堆的使用率等。我们知道,Android系统服务会被分为两类,其一就是java层的,其二就是本地层的。后者具体事由System.loadLibrary("android_servers")实现的

通过以上我们可以看到app_process就是系统服务的“根据地”。它在init进程的帮助下,通过Zygote逐步建立起各SystemServer的运行环境,继而为上层的“繁殖壮大”提供“土壤环境”。

流程图转自:(https://blog.csdn.net/wgheng2011/article/details/79420451

全文借鉴《Android内核设计思想》

后续分析SystemServer以及ActivityManagerService

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万子开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值