AOSP 8.0 系统启动之三--Zygote启动(二)

目录

前言

一、Art虚拟机启动

二、首次进入Java世界

2.1 禁用子线程创建

2.2 创建zygote socket并监听

2.3 加载系统资源

2.4 GC初始化并启动

2. 5启动System server进程

2.6 Zygote进入Looper处理socket消息

三 关于Zygote的一些疑问


前言

虚拟机创建完成后,接下去就可以用JNI反射调用Java了,其实接下来的语法用过JNI的都应该比较熟悉了,直接是CallStaticVoidMethod反射调用ZygoteInit的main函数,进入Java世界;

相关源码文件

platform/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
platform/frameworks/base/core/java/com/android/internal/logging/MetricsLogger.java
platform/frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
platform/system/core/logcat/event.logtags
platform/build/tools/java-event-log-tags.py
platform/frameworks/base/core/jni/android_util_EventLog.cpp
platform/frameworks/base/core/java/android/os/Trace.java
platform/frameworks/base/core/jni/android_os_Trace.cpp
platform/system/core/libcutils/trace-dev.c

一、Art虚拟机启动

main(){
    ...

    //这里的runtime.start的实现是在 frameworks/base/core/jni/AndroidRuntime.cpp 中的AndroidRuntime对象
    if (zygote) {
        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.");
    }
}


//frameworks/base/core/jni/AndroidRuntime.cpp 中的AndroidRuntime对象
// 参数 className 等于 "com.android.internal.os.ZygoteInit"
// 参数 options 就是虚拟机的各种args
void start(const char* className, const char* options){
       // start the virtual machine Java在虚拟机中运行的
       JNIEnv* env;
       if (startVm(&mJavaVM, &env) != 0) {
              return;
       }

       //向刚刚新建的虚拟机注册JNI本地接口
       if (startReg(env) < 0) {
              return;
       }

    // jni 调用 java 方法,获取对应类的静态main方法
    jmethodID startMeth = env->GetStaticMethodID(startClass,
         "main","([Ljava/lang/String;)V");

       // jni调用 java方法,调用到ZygoteInit类的main函数
       char* slashClassName = toSlashClassName(className);//将字符中的.转换为/
       jclass startClass = env->FindClass(className);

       //终于进入Java世界
       env->CallStaticVoidMethod(startClass, startMeth, strArray);
       
       //正常情况,如果zygoteInit.main 函数并不会退出,内部是实现死循环,后面的代码并不会执行,一旦main函数退出,那么就需要及时释放虚拟机占有的相关的内存资源
       free(slashClassName);
       

       ALOGD("Shutting down VM\n");
        if (mJavaVM->DetachCurrentThread() != JNI_OK)//退出当前线程
            ALOGW("Warning: unable to detach main thread\n");
        if (mJavaVM->DestroyJavaVM() != 0) //创建一个DestroyJavaVM线程,该线程会等待所有子线程结束后关闭虚拟机
            ALOGW("Warning: VM did not shut down cleanly\n");
}

二、首次进入Java世界

  • 保证在Zygote主进程init过程中无法通过Java中的Thread类创建子线程
  • 创建zygote socket并监听
  • preload Android资源
  • GC初始化并启动
  • 移除Zygote进程中创建线程限制
  • 启动System server进程
  • 运行zygote进程的select loop
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
    
    //当前是zygote 主线程, GC相关的子线程其实已经是创建ok了;

    // Mark zygote start. This ensures that thread creation will throw an error.
    // 后续的代码逻辑中试图通过new Thread() 会抛出异常;除非接触这个限制
    // Zygote Init处理的时候无法java类Thread类来创建子线程;
    ZygoteHooks.startZygoteNoThreadCreation();  

    // Zygote goes into its own process group.
    // 设置zygote进程组id为zygote的pid
    try {
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }

    try {
        ......

        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        ......

        zygoteServer.registerServerSocket(socketName);
        // In some configurations, we avoid preloading resources and classes eagerly.
        // In such cases, we will preload things prior to our first fork.
        if (!enableLazyPreload) { //走这个分支
            preload(bootTimingsTraceLog); //加载各种系统资源
        } else {
            Zygote.resetNicePriority();
        }
        gcAndFinalize();

        ......
        //解除创建子线程限制
        ZygoteHooks.stopZygoteNoThreadCreation();

        if (startSystemServer) { //创建system_server进程
            startSystemServer(abiList, socketName, zygoteServer);
        }
        //zygote进程等待AMS的socket请求,内部处理完之后,抛出异常Zygote.MethodAndArgsCaller,被catch后执行;
        zygoteServer.runSelectLoop(abiList);

        //下面的逻辑代码不会执行,zygote进程
        zygoteServer.closeServerSocket();
    } catch (Zygote.MethodAndArgsCaller caller) {
        caller.run();
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        zygoteServer.closeServerSocket();
        throw ex;
    }
}

2.1 禁用子线程创建

ZygoteHooks.startZygoteNoThreadCreation();  

严禁在zygote中创建多线程,除非后续放开

//Java中的通过Thread类的创建线程
static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,jboolean daemon) {
    // There are sections in the zygote that forbid thread creation.
    Runtime* runtime = Runtime::Current();
    //上面的ZygoteHooks_startZygoteNoThreadCreation作用就是下面的判断条件第二个,设置为ture
    if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) {
        jclass internal_error = env->FindClass("java/lang/InternalError");
        CHECK(internal_error != nullptr);
        env->ThrowNew(internal_error, "Cannot create threads in zygote");
        return;
    }

    Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
}

2.2 创建zygote socket并监听

void registerServerSocket(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }

        try {
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            //将对应的socket转换为fd, 作为server端,等待client 发送数据
            mServerSocket = new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

2.3 加载系统资源

在zygote init中,Android的相关资源被预加载到Zygote进程空间中。这些资源在后续所有的应用程序进程中都是共享的,因为Android Java层进程都是Zygote的子进程。

这里有个疑问, 为什么这些资源不放到init 进程,又或者说为什么不放到system_server进程呢?

可以思考下,欢迎大家追在评论中留言;

static void preload() {
    ...
    preloadClasses(); 
    preloadResources();
    preloadOpenGL();
    preloadSharedLibraries();
    preloadTextResources();
    WebViewFactory.prepareWebViewInZygote();
}
  • preloadClasses:加载class类到虚拟机中,需要加载的类是由/system/etc/preloaded-classes文件指定。它是由相关preloaded-classes文件生成,如:
  • \frameworks\base\preloaded-classes
  • \frameworks\base\compiled-classes-phone

虚拟机会通过classloader把preloaded-classes文件中指定的类都加载到虚拟机中,方便应用程序的调用处理。此处会涉及到手机内存空间和手机开机性能问题,手机性能优化方面可以进一步深入研究。

  • preloadResources:加载系统资源,比如 drawables colors
  • preloadOpenGL: 加载显示资源
  • preloadSharedLibraries: 加载共享库,包含android.so、compiler_rt.so和jnigraphics.so
  • preloadTextResources:加载语言库

2.4 GC初始化并启动

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

    /* runFinalizationSync() lets finalizers be called in Zygote,
     * which doesn't have a HeapWorker thread.
     */
    System.gc(); //先看GC部分
    runtime.runFinalizationSync(); //再分析VmRuntime.runFinalizationSync
    System.gc();
}


public static void gc() {
        boolean shouldRunGC;
        synchronized (LOCK) {
            shouldRunGC = justRanFinalization;
            if (shouldRunGC) {
                justRanFinalization = false;
            } else {
                runGC = true;
            }
        }
        if (shouldRunGC) {
            Runtime.getRuntime().gc(); // 
        }
    }



System.runFinalization();
///libcore/ojluni/src/main/java/java/lang/System.java
public static void runFinalization() {
    boolean shouldRunGC;
    synchronized (LOCK) {
        shouldRunGC = runGC;
        runGC = false;
    }
    if (shouldRunGC) {
        Runtime.getRuntime().gc();
    }
    Runtime.getRuntime().runFinalization();
    synchronized (LOCK) {
        justRanFinalization = true;
    }
}

/libcore/ojluni/src/main/java/java/lang/Runtime.java
private static native void runFinalization0();



2. 5启动System server进程

在startSystemServer()方法里,通过Zygote.forkSystemServer() native函数调用来创建system server 进程。从创建中可以看到,system server进程是zygote进程的子进程。内部调用fork函数

/* 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,1021,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);
 
    /* Request to fork the system server process */
    // 内部执行fork 函数,返回两次,其中pid = 0 表示子进程返回;
    pid = Zygote.forkSystemServer(
            parsedArgs.uid, parsedArgs.gid,
            parsedArgs.gids,
            parsedArgs.debugFlags,
            null,
            parsedArgs.permittedCapabilities,
            parsedArgs.effectiveCapabilities);
    
} catch (IllegalArgumentException ex) {
    throw new RuntimeException(ex);
}
.....
//后续执行com.android.server.SystemServer的main函数;

后续重点介绍下System_server 进程的启动流程;

2.6 Zygote进入Looper处理socket消息

在runSelectLoop()方法中

监听socket,通过Os.poll函数来等待POLLIN事件的到来。
通过ZygoteConnection来读取socket传过来的command并创建进程。
zygote进程在运行select loop后,zygote进程就进入无限循环,一直等待socket的command,并做处理。
  //zygote进程在此进入无限循环
 

while (true) {
  StructPollfd[] pollFds = new StructPollfd[fds.size()];
    for (int i = 0; i < pollFds.length; ++i) {
        pollFds[i] = new StructPollfd();
        pollFds[i].fd = fds.get(i);
        pollFds[i].events = (short) POLLIN;
    }
    try {
        //zygote进程被阻塞,直至以下条件达到时退出:
        //a file descriptor becomes ready;
        //the call is interrupted by a signal handler; or
        //the timeout expires.
        Os.poll(pollFds, -1);
    } catch (ErrnoException ex) {
        throw new RuntimeException("poll failed", ex);
    }
    for (int i = pollFds.length - 1; i >= 0; --i) {
        if ((pollFds[i].revents & POLLIN) == 0) {
            continue;
        }
        if (i == 0) {
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            //调用ZygoteConnection的runOnce()方法来fork进程。
            boolean done = peers.get(i).runOnce();
            if (done) {
                peers.remove(i);
                fds.remove(i);
            }
        }
    }
}


至此,zygote进程启动处理完成,最后一直停留在select loop中运行。

三 关于Zygote的一些疑问

3.1  孵化应用进程这种事为什么不交给SystemServer来做,而专门设计一个Zygote?

我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了。


3.2 Zygote的IPC通信机制为什么不采用binder?如果采用binder的话会有什么问题么?

网上大部分答案都是采用binder,引入线程池,但fork在多线程的情况下,可能会产生死锁问题,这部分解析目前还不是很理解,后续完善;

3.3 Zygote进程是多线程还是单线程呢?

是多线程,除了zygote主线程之外,还有和GC 相关的其他几个线程;

在主线程中调用fork之后,子进程只会保留一个线程,其他几个GC 线程没有克隆过来,是后续创建的;

3.4 对3.3 的追加问题: GC 几个线程是什么时候创建出来的呢?

/art/runtime/runtime.cc

在虚拟机的启动过程中, 创建GC相关的线程;

bool Runtime::Start() {    
        ...
        StartDaemonThreads();  //启动GC 相关的几个线程;
        ....
        return true;
}

void Runtime::StartDaemonThreads() {
        Thread* self = Thread::Current();
        //进入Java 世界, Daemons.java 似乎比ZygoteInit.java 
        env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,

                WellKnownClasses::java_lang_Daemons_start);
}

/libcore/libart/src/main/java/java/lang/Daemons.java
//启动4个GC 相关的线程
public static void start() {
        ReferenceQueueDaemon.INSTANCE.start();
        FinalizerDaemon.INSTANCE.start();
        FinalizerWatchdogDaemon.INSTANCE.start();
        HeapTaskDaemon.INSTANCE.start();
}

3.5 Zygote 进程启动的出现了GC,请问下System.gc() 和 Runtime. getRuntime(). gc()会做什么事情?

System.gc() 在内部调用 Runtime.gc()。
硬要说区别的话 Runtime.gc() 是 native method。存在于 /libcore/ojluni/src/main/native/Runtime.c
而 System.gc() 是非 native method,它依次调用 Runtime.gc();
System.gc 调用附带一个免责声明,无法保证垃圾收集器的调用。即gc()函数的作用只是提醒虚拟机,程序员希望进行一次垃圾回收。但是这次回收不能保证一定进行,具体什么时候回收取决于jvm。如果每次调用gc方法后想让gc必须执行,可以追加调用system. runFinalization方法。

调用gc方法在默认情况下,会显示触发full gc,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值