zygote启动过程

init进程通过解析init.zygote.rc文件fork出zygote进程,然后会执行app_main.cpp的main方法, 这个函数有两种启动模式:

  1. 一种是zygote模式,也就是初始化zygote进程,传递的参数有--start-system-server --socket�name=zygote,前者表示启动SystemServer,后者指定socket的名称
  2. 一种是application模式,也就是启动普通应用程序,传递的参数有class名字以及class带的参数
    两者最终都是调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个Java类,并将之前整理的参数传入进去
// \frameworks\base\cmds\app_process\app_main.cpp main() 
 if (strcmp(arg, "--zygote") == 0) { 
         zygote = true; 
         niceName = ZYGOTE_NICE_NAME; 
     } else if (strcmp(arg, "--start-system-server") == 0) { 
                 startSystemServer = true; 
     } else if (strcmp(arg, "--application") == 0) {
                application = true; 
     } 
 if (zygote) { 
     //这些Java的应用都是通过 AppRuntime.start(className)开始的 
     //其实AppRuntime是AndroidRuntime的子类,它主要实现了几个回调函数,
     //而start()方 法是实现在AndroidRuntime这个方法类里 
      runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 
   } else if (className) { 
      runtime.start("com.android.internal.os.RuntimeInit", args, zygote); 
   }

app_process 里面定义了三种应用程序类型:

  1. Zygote: com.android.internal.os.ZygoteInit
  2. System Server, 不单独启动,而是由Zygote启动
  3. 其他指定类名的Java 程序

上面的runtime 指的AppRuntime, AppRuntime继承AndroidRuntime,所以我们来看看AndroidRuntime 的 start方法

// \frameworks\base\core\jni\androidRuntime.cpp start() L1091
  void AndroidRuntime::start(const char* className,
      const Vector<String8>& options, bool zygote) { 
     ... 
     JNIEnv* env;
     //JNI_CreateJavaVM L1015
 
     if (startVm(&mJavaVM, &env, zygote) != 0) { 
        return; 
      }
     onVmCreated(env);
     if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return; 
   } 
  ... 
 }

startVm()方法主要是创建java 虚拟机

Java虚拟机的启动大致做了以下一些事情:
 1. 从property读取一系列启动参数。
 2. 创建和初始化结构体全局对象(每个进程)gDVM
    ,及对应与JavaVM和JNIEnv的内部结构体JavaVMExt, JNIEnvExt.
 3. 初始化java虚拟机,并创建虚拟机线程
 4. 注册系统的JNI,Java程序通过这些JNI接口来访问底层的资源。
 5. 为Zygote的启动做最后的准备,包括设置SID/UID, 以及mount 文件系统
 6. 返回JavaVM 给Native代码,这样它就可以向上访问Java的接口

除了系统的JNI接口(”javacore”, “nativehelper”), android framework 还有大量的Native实现,
Android将所有这些接口一次性的通过startReg()来完成

上述代码执行完后,会通过反制执行到java端的ZygotInit.java 的main()方法

 public static void main(String argv[]) {
        //新建Zygote服务器端
        //1 重点
        ZygoteServer zygoteServer = new ZygoteServer();

        ...

        final Runnable caller;
        try {
            ...

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                //还记得app_main.cpp中传的start-system-server参数吗,在这里总有用 到了
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } 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.");
            }

           //注册Socket 
           //2 重点
         zygoteServer.registerServerSocketFromEnv(socketName);
            // 在有些情况下我们需要在第一个fork之前进行预加载资源
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                 //3 重点
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
             //主动进行一次资源GC
              //4 重点
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd();

            bootTimingsTraceLog.traceEnd(); 
   
            Trace.setTracingEnabled(false, 0);

            Zygote.nativeSecurityInit();

         
            Zygote.nativeUnmountStorageOnInit();

            ZygoteHooks.stopZygoteNoThreadCreation();
             //5 重点
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

    
                if (r != null) {
                    r.run();
                    return;
                }
            }

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

    
            //6 重点
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
             //7 重点
            zygoteServer.closeServerSocket();
        }

   
        if (caller != null) {
            //8 重点
            caller.run();
        }
    }
首先总结一下main()主要做的事情,然后再具体分析上面的8个重点
  1.注册一个name为zygote 的socket,用来与其他进程通信,
    这里的其他进程主要指systemserver进程,
    用来接收AMS发送的socket消息,fork出用户app进程
  2.预加载安卓系统资源。
  3.fork systemserver 进程
  4.循环从socket里面取消息

重点1和2 :新建Zygote服务器端,注册Socket
重点3 : preload(bootTimingsTraceLog);
preload() 的作用就是提前将需要的资源加载到VM中,比如class、resource等

static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
        beginIcuCachePinning();
        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        //加载指定的类到内存并且初始化,使用的Class.forName(class, true, null);方式
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("PreloadResources");
        //加载Android通用的资源,比如drawable、color...
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
        //加载OpenGL...
        preloadOpenGL();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        //加载共用的Library
        preloadSharedLibraries();
        //加载Text资源,字体等
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        // 为了内存共享,WebViewFactory进行任何初始化都要在Zygote进程中
        WebViewFactory.prepareWebViewInZygote();
        endIcuCachePinning();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。
而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间,所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一

重点4 gcAndFinalize()

static void gcAndFinalize() {
        final VMRuntime runtime = VMRuntime.getRuntime();

        /* runFinalizationSync() lets finalizers be called in Zygote,
         * which doesn't have a HeapWorker thread.
         */
        System.gc();
        runtime.runFinalizationSync();
        System.gc();
    }

gc()调用只是通知VM进行垃圾回收,是否回收,什么时候回收全由VM内部算法决定。GC的回收有一个
复杂的状态机控制,通过多次调用,可以使得尽可能多的资源得到回收。gc()必须在fork之前完成(接下
来的StartSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没
有释放

重点5 forkSystemServer

 private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
          
             ...

            /* Request to fork the system server process */
            //fork出SystemServer进程,返回pid,这里的pid为0, 后续代码运行在SystemServer进程
        
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            //下面代码运行在SystemServer进程
            //fork会将父进程的主线程的一切都复制过来
            // Socket 也复制过来了,SystemServer进程进程间通信使用binder,
            // 所以关掉Socket 
           
            zygoteServer.closeServerSocket();
            //处理SystemServer进程
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

handleSystemServerProcess()用来处理SystemServer进程

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
   
        ····
      
          if (parsedArgs.invokeWith != null) {
             ····
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
               // 为systemServer创建了一个类加载器PathClassLoader
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }

        /* should never reach here */
    }

接下来分析ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl)

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

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        //1
        ZygoteInit.nativeZygoteInit();
        //2
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

接下来分析上面的1,2处
ZygoteInit.nativeZygoteInit()方法是一个本地方法,会调用到 natvie层,在AndroidRuntime.cpp类中可以查看到nativeZygoteInit()方法对应的native函数:

/*
* JNI registration.
*/
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(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方面为com_android_internal_os_ZygoteInit_nativeZygoteInit

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

gCurRuntime指向AppRuntime,所以我们来看AppRuntime的onZygoteInit()方法

virtual void onZygoteInit()
    {
         // 创建ProcessState对象,用来打开Binder 驱动,创建Binder线程池,让其进程里面的所有线程都能通过Binder通信
         sp<ProcessState> proc = ProcessState::self();
         ALOGV("App process: starting thread pool.\n");
        // 启动Binder线程池,最终会调用到
        //IPCThreadState实例的joinThreadPool()函数,
        //进行Binder线程池相关的处理
        proc->startThreadPool();
    }

RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader)

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        ...
           //findStaticMain来运行args的startClass的main方法
          return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

findStaticMain从名字就可以看出来,是用来寻找方法名为main()的静态方法,我们这里寻找到的其实是SystemServer.Java的main()方法,通过参数确定的

protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            //通过反射获取到class对象
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
          ...
        }
        Method m;
        try {
            //通过反射获取到main()方法
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
          ...
        } catch (SecurityException ex) {
          ...
        }

        ...
        return new MethodAndArgsCaller(m, argv);
    }

返回 new MethodAndArgsCaller(m, argv) 对象,继承自 Runnable

static class MethodAndArgsCaller implements 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 {
            //从上面可以知道mMethod是SystemServer.Java的main()           方法
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }

MethodAndArgsCaller最终会返回到重点5的r对象,r就是MethodAndArgsCaller
所以r.run()会调用到MethodAndArgsCaller的run()方法,
里面会调用到SystemServer.main(),启动SystemServer进程,SystemServer进程的分析请看下一篇文章。

重点6循环socket,从里面获取到fork 用户进来的消息,fork出app进程

 Runnable runSelectLoop(String abiList) {
         ...
     while (true) {
          ...
        ZygoteConnection connection = peers.get(i);
          ...
        final Runnable command =  connection.processOneCommand(this);
            ....
            if (mIsForkChild) {
                return command;
           } 
        ...
        }
         ...
    }

//分析这个connection.processOneCommand(this)

 Runnable processOneCommand(ZygoteServer zygoteServer) {
    
         ...
       //fork出孩子进程,返回pid=0
      pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);

        try {
          //
            if (pid == 0) {
                // in child
              
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                 //处理孩子进程
                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.startChildZygote);
            } else {
               ...
            }
        } finally {
            ...
        }
    }

在分析 handleChildProc方法

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
 
        ....
            if (!isZygote) {
           
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,          parsedArgs.remainingArgs,
                        null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }
        ...
    }

从上面可以看出来,接下来的过程和SystemServer一样,会返回到重点8
执行run()方法,这里的run 方法会执行ActivityThreed的main()方法,这是我们用户app的入口。

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