目录

前言

一、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的pidtry {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作用就是下面的判断条件第二个,设置为tureif (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.runFinalizationSyncSystem.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,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。

AOSP 8.0 系统启动之三--Zygote启动(二)相关推荐

  1. Android10.0系统启动之Zygote进程-[Android取经之路]

    [Android取经之路] 的源码都基于Android-Q(10.0) 进行分析 [Android取经之路] 系列文章: <系统启动篇> Android系统架构 Android是怎么启动的 ...

  2. AOSP 8.0 系统启动之四ART虚拟机启动(一)

    目录 前言 一.创建虚拟机 1.1 JniInvocation.Init 1.2 startVm 1.2.1 JNI_CreateJavaVM 1.2.2 Runtime::Create 1.2.3  ...

  3. Android10.0系统启动之Zygote进程

    Android学习之路 文章目录 1. zygote架构 1.1 rc 1.1.1 init.zygote64_32.rc 1.1.2 Zygote什么时候被重启 1.2 启动后逻辑 1.3 主要函数 ...

  4. android system_server中的dump_Android 10.0系统启动之SystemServer进程(二)

    感谢您的阅读与点赞!欢迎点击右上角关注:「大猫玩程序」 微信公众号:大猫玩程序 上一节讲解了SystemServer的架构以及被Zygote 进程fork的流程,这一节重点讲解SystemServer ...

  5. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

  6. Android 10.0 系统服务之ActivityMnagerService-AMS启动流程-[Android取经之路]

    摘要:上一节我们讲完了SystemServer的启动过程,这一节接着上一节的步骤,来讲解ActivityManagerService的启动过程. ActivityManagerService简称AMS ...

  7. Android 10.0 系统启动之SystemServer进程-[Android取经之路]

    摘要:上一节讲解了Zygote进程的整个启动流程.Zygote是所有应用的鼻祖.SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来.Zygote fork的第一 ...

  8. Android 10.0系统启动之init进程-[Android取经之路]

    摘要:init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取ini ...

  9. Android 7.0系统启动流程分析

    随着Android版本的升级,aosp项目中的代码也有了些变化,本文基于Android 7.0分析Android系统启动流程.当我们按下电源键后,整个Android设备大体经过了一下过程:  今天我们 ...

最新文章

  1. 皮一皮:谁来解释下一无所有的字典含义?
  2. viewPager开启界面导航之旅
  3. 牛顿法 Newton Method
  4. VTK:图表之SelectedVerticesAndEdgesObserver
  5. vue笔记(一)基本使用、数据检测
  6. rss spring 接口_spring mvc: rss(xml)输出
  7. myEclipse怎样将程序部署到tomcat(附录MyEclipse调试快捷键)
  8. 怎样让手机立马变空号?
  9. 突击计划——给定大写字母,输出小写字母
  10. 产品经理业务流程图的绘制流程分享
  11. Please either set ERLANG_HOME to point to your Erlang installation or place
  12. NR/5G - 一种TDD+FDD场景下Type I codebook size分析
  13. 【 OpenCV】——图像平移
  14. Bron-kerbosch算法-求图的最大团,极大团
  15. 石像鬼 openwrt chinadns dns-forwarder 开机无法自动启动
  16. IE和标准下有哪些兼容性的写法
  17. MySQL比较两张表数据相同、不同结果记录
  18. PDMS插件_三维地形工具
  19. STM32F103时钟系统讲解(精)
  20. 初学深度学习笔记(小土堆和霹雳吧啦)

热门文章

  1. 小米官网设计php分析,小米网秒杀系统设计经验与问题解析.ppt
  2. java邮箱登录学习笔记
  3. 关于市盈率,答大海先生
  4. FireFox浏览器不能正常导出文件
  5. 合并两个有序单链表,使得合并后的链表仍然有序
  6. 西门子PLC S7-1200硬件故障ERROR灯常亮处理一例---附“未决的启动禁止项 重置为出厂设置”方法
  7. ISO质量认证范围和审核范围的简要解说
  8. 城市智能停车系统解决方案介绍
  9. OpenGL 4.0的Tessellation Shader(细分曲面着色器)
  10. PPT(一) PPT课程:PPT排版中的视觉化表达