Android Framwork ---App进程启动(中)

94 阅读4分钟

3. ZygoteConnection.runOnce

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    String args[];
    Arguments parsedArgs = null;
    try {
        //读取socket客户端发送过来的参数列表
        args = readArgumentList();
    } catch (IOException ex) {
        closeSocket();
        return true;
    }
    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;
    try {
        //将binder客户端传递过来的参数,解析成Arguments对象格式
        parsedArgs = new Arguments(args);
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    } catch (Exception e) {
        ...
    }
    try {
        if (pid == 0) {
            //子进程执行
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            // 不应到达此处,子进程预期的是抛出异常ZygoteInit.MethodAndArgsCaller或者执行exec().
            return true;
        } else {
            //父进程执行
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

4. forkAndSpecialize

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) {
    VM_HOOKS.preFork(); 
    int pid = nativeForkAndSpecialize(
              uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
              instructionSet, appDataDir); 
    ...
    VM_HOOKS.postForkCommon(); 
    return pid;
}

VM_HOOKS.preFork()的主要功能便是停止Zygote的4个Daemon子线程的运行,等待并确保Zygote是单线程(用于提升fork效率),并等待这些线程的停止,初始化gc堆的工作, 并将线程转换为long型并保存到token

public void preFork() {
    Daemons.stop(); //停止4个Daemon子线程【见小节8.1】
    waitUntilAllThreadsStopped(); //等待所有子线程结束【见小节8.2】
    token = nativePreFork(); //完成gc堆的初始化工作【见小节8.3】
}

nativeForkAndSpecialize()调用fork()创建新进程,设置新进程的主线程id,重置gc性能数据,设置信号处理函数等功能。

com_android_internal_os_Zygote_nativeForkAndSpecialize()
	ForkAndSpecializeCommon()
		fork() //fork子进程
		//等价于调用zygote.callPostForkChildHooks()
		env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,is_system_server ? NULL : instructionSet); 

fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型。

  • 父进程中,fork返回新创建的子进程的pid;
  • 子进程中,fork返回0;
  • 当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)

fork()的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote进程是所有Android进程的母体,包括system_server和各个App进程。zygote利用fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A。其中下图中Zygote进程的libc、vm、preloaded classes、preloaded resources是如何生成的

image.png copy-on-write过程:当父子进程任一方修改内存数据时(这是on-write时机),才发生缺页中断,从而分配新的物理内存(这是copy操作)。

copy-on-write原理:写时拷贝是指子进程与父进程的页表都所指向同一个块物理内存,fork过程只拷贝父进程的页表,并标记这些页表是只读的。父子进程共用同一份物理内存,如果父子进程任一方想要修改这块物理内存,那么会触发缺页异常(page fault),Linux收到该中断便会创建新的物理内存,并将两个物理内存标记设置为可写状态,从而父子进程都有各自独立的物理内存。

VM_HOOKS.postForkCommon的主要功能是在fork新进程后,启动Zygote的4个Daemon线程,java堆整理,引用队列,以及析构线程。

Zygote.forkAndSpecialize时序图

image.png 到此App进程已完成了创建的所有工作,接下来开始新创建的App进程的工作。在前面ZygoteConnection.runOnce方法中,zygote进程执行完forkAndSpecialize()后,新创建的App进程便进入handleChildProc()方法,下面的操作运行在App进程。

三. 新进程运行

在前面runOnce()过程中调用forkAndSpecialize()创建完新进程后,返回值pid=0(即运行在子进程)继续开始执行handleChildProc()方法。

1.handleChildProc

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller {
    //关闭Zygote的socket两端的连接
    closeSocket();
    ZygoteInit.closeServerSocket();
    if (parsedArgs.niceName != null) {
        //设置进程名
        Process.setArgV0(parsedArgs.niceName);
    }
    if (parsedArgs.invokeWith != null) {
        //这是用于检测进程内存泄露或溢出时场景而设计
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.remainingArgs);
    } else {
        //执行目标类的main()方法
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                parsedArgs.remainingArgs, null);
    }
}

2. zygoteInit

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    redirectLogStreams(); //重定向log输出
    commonInit(); // 通用的一些初始化
    nativeZygoteInit(); // zygote初始化 
    applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化
}
2.1 commonInit
private static final void commonInit() {
    // 设置默认的未捕捉异常处理方法
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
    // 设置市区,中国时区为"Asia/Shanghai"
    TimezoneGetter.setInstance(new TimezoneGetter() {
        public String getId() {
            return SystemProperties.get("persist.sys.timezone");
        }
    });
    TimeZone.setDefault(null);
    //重置log配置
    LogManager.getLogManager().reset();
    new AndroidConfig();
    // 设置默认的HTTP User-agent格式,用于 HttpURLConnection。
    String userAgent = getDefaultUserAgent();
    System.setProperty("http.agent", userAgent);
    // 设置socket的tag,用于网络流量统计
    NetworkManagementSocketTagger.install();
}
2.2 nativeZygoteInit
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {
    //此处的gCurRuntime为AppRuntime,是在AndroidRuntime.cpp中定义的
    gCurRuntime->onZygoteInit();
}
virtual void onZygoteInit() {
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //启动新binder线程
}
  • ProcessState::self():主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver().
  • startThreadPool(): 启动Binder线程池,
2.3 applicationInit
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    //true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用
    nativeSetExitWithoutCleanup(true);
    //设置虚拟机的内存利用率参数值为0.75
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    final Arguments args;
    try {
        args = new Arguments(argv); //解析参数
    } catch (IllegalArgumentException ex) {
        return;
    }
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    //调用startClass的static方法 main()
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

此处args.startClass为”android.app.ActivityThread”。

Android Framwork ---App进程启动(上)

Android Framwork ---App进程启动(中)

Android Framwork ---App进程启动(下)