深入了解Android读书笔记——深入理解zygote

zygote概述

zygote是由init进程通过解析init.zygote.rc文件创建的。应用程序的进程和java虚拟机的启动是由它负责创建和启动的。

启动zygote

init进程解析的zygote文件是system/core/rootdir/init.zygote64_32.rc。init进程解析rc文件获取Service对象(定义在system/core/init/service.h中),调用system/core/init/service.cpp中的start方法启动 zygote 服务。

由于start方法是通过forkexec来启动进程的,由此可知,zygote 的启动方式是 fork + exec

zygote启动过程

zygote所对应的可执行程序app_process,所对应的源文件是frameworks/base/cmds/app_process/app_main.cpp,进程名为zygote。

//传入的参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
int main(int argc, char* const argv[])
{
    ...
    
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 忽略第一个参数
    argc--;
    argv++;

    ...

    // 参数解析
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i; 
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            //对于64位系统nice_name为zygote64; 32位系统为zygote
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            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;
        }
    }

   ...

    //将进程名设置为 zygote
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
    
    if (zygote) {
        // 调用AppRuntime的start方法
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

AppRuntime

AppRuntime的定义和声明都在frameworks/base/cmds/app_process/app_main.cpp中。它继承AndroidRuntime,重载了onStart、onZygoteInitonExit函数。调用的start函数是 AndroidRuntime 中定义的,代码位置在 frameworks/base/core/jni/AndroidRuntime.cpp

//className 是 com.android.internal.os.ZygoteInit
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
   
    ...


    //创建java虚拟机
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    //jni方法注册
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    ...

    //将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
        } else {
            //调用 ZygoteInit.main 方法,正式进入java世界
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    //释放相应对象的内存空间
    free(slashClassName);

    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}        

startVm

创建java虚拟机,主要工作是关于虚拟机参数的设置

startReg

int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    
    //设置线程创建方法为javaCreateThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    /*
     * Every "register" function calls one or more things that return
     * a local reference (e.g. FindClass).  Because we haven't really
     * started the VM yet, they're all getting stored in the base frame
     * and never released.  Use Push/Pop to manage the storage.
     */
    env->PushLocalFrame(200);

    //注册JNI函数
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}

ZygoteInit

通过上面的调用,最后走到java层的frameworks/base/core/java/com/android/internal/os/ZygoteInit.java类的main方法

    @UnsupportedAppUsage
    public static void main(String[] argv) {
        
        ZygoteServer zygoteServer = null;

        ...

        Runnable caller;
        try {    
        ...
            if (!enableLazyPreload) {
                ...
                //预加载资源        
                preload(bootTimingsTraceLog);
                ...
            }

            //执行垃圾回收
            gcAndFinalize();
            //用于zygote进程的socket服务
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                //启动SystemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

               ...
            }

            //开启循环等待和处理 socket 请求
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        //SystemServer相关
        if (caller != null) {
            caller.run();
        }
    }

预加载资源

    static void preload(TimingsTraceLog bootTimingsTraceLog) {
        ...
        // 预加载 /system/etc/preloaded-classes 文件里面定义的常用类(比如我们用到的 Activity,Fragment 等)
        preloadClasses();
        ...
        // 预加载系统资源
        preloadResources();
        ...
        // 硬件抽象层
        nativePreloadAppProcessHALs();
        ...
        //图像驱动
        maybePreloadGraphicsDriver();
        ...
        //库资源
        preloadSharedLibraries();
        ...
        //语言相关文本信息
        preloadTextResources();
        ...
        //webview
        WebViewFactory.prepareWebViewInZygote();
        ...
    }

预加载的作用

  1. Android通过 zygote fork 的方式创建子进程。zygote预先加载的类和资源在fork时会复制到子进程中,这样就减少了子进程加载资源的时间
  2. forkcopy-on-write机制在子进程不改变父进程的类时,会与父进程共享这部分数据,从而节省内存

创建socket服务

预加载完成后,会通过ZygoteServer创建socket服务,由此可见zygote是通过socket通信的

启动SystemServer

zygote创建socket服务后,会通过fork启动SystemServer进程。

开启循环等待和处理 socket 请求

zygote通过runSelectLoop方法开启循环等待和处理 socket 请求??突Ф擞?code>ZygoteConnection来表示,客户端的请求则由它的processCommand方法来处理。

总结

image.png

SystemServer

从上面我们知道SystemServer是通过forkSystemServer来启动的,其内部会一直调用到Zygote#forkSystemServe,到frameworks/base/core/jni/com_android_internal_os_Zygote.cpp的
com_android_internal_os_Zygote_nativeForkSystemServer方法。当SystemServer创建失败时,会重启zygote

当进程创建成功时,会先关闭父进程zygote复制而来的Socket,再调用ZygoteInit#handleSystemServerProcess方法

    private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        
        ...
        if (parsedArgs.mNiceName != null) {
            Process.setArgV0(parsedArgs.mNiceName);//设置进程名字为system_server
        }

        ...

        if (parsedArgs.mInvokeWith != null) {
            
            ...
            //启动应用程序
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);

            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else {
            ClassLoader cl = getOrCreateSystemServerClassLoader();
            if (cl != null) {
                Thread.currentThread().setContextClassLoader(cl);
            }

            //启动SystemServer
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, cl);
        }
    }

ZygoteInit的zygoteInit的方法如下

    public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        ...
        RuntimeInit.redirectLogStreams();//重定向log输出

        RuntimeInit.commonInit();//通用的一些初始化
        ZygoteInit.nativeZygoteInit();//与Binder系统建立联系
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

RuntimeInit的applicationInit方法如下

    protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        ...
        //最后调用了 findStaticMain
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
    
    protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?> cl;

    ...
    //创建MethodAndArgsCaller
    return new MethodAndArgsCaller(m, argv);
}

static class MethodAndArgsCaller implements Runnable {

    public void run() {
        try {
            // 调用 com.android.server.SystemServer 的 main()
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
        } catch (InvocationTargetException ex) {
        }
    }
}

com.android.server.SystemServermain 方法很简单,就是调用 SystemServer 他自己的 run 方法

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

run 方法如下

    private void run() {
        try {
            ...
            //准备Looper
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

            // 加载 android_servers.so 库
            //该库包含的源码位于 frameworks/base/services/core/jni 下
            System.loadLibrary("android_servers");

            ...

            // 创建 system context.
            createSystemContext();

            // 创建 SystemServiceManager
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            ...
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

        // 启动服务
        try {
            ...
            //启动引导服务
            startBootstrapServices();
            //启动核心服务
            startCoreServices();
            //启动其他服务
            startOtherServices();
            ...
        } catch (Throwable ex) {
            ...
        } finally {
            traceEnd();
        }

        ...
        
        // 进入 loop() 循环等待和处理请求
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

参考

http://08643.cn/p/c1ee303620c0
http://08643.cn/p/ce686a88e3bc

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

推荐阅读更多精彩内容