| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android Zygote -> 正文阅读 |
|
[移动开发]Android Zygote |
1.Zygote Zygote译为“受精卵”。在Android中,负责孵化新进程的这个进程就叫Zygote,安卓上其他的应用进程都是由它孵化的。由于安卓是Linux内核,安卓系统上运行的一切程序都是放在Dalvik虚拟机上的,Zygote也不例外,事实上,它是安卓运行的第一个Dalvik虚拟机进程。既然Zygote负责孵化其他的安卓进程,那么它自己是由谁孵化的呢?因为Android是基于Linux内核,那么Zygote当然就是Linux内核启动的用户级进程Init创建的了。 Zygote进程在启动时会创建一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使每一个应用程序进程都有一个独立的Dalvik虚拟机实例。试想,如果每个应用程序在启动时都要单独运行和初始化一个虚拟机,会大大降低系统性能,因此Android首先创建一个zygote虚拟机,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样就大幅度提高了应用程序的启动和运行速度。 ? zygote的作用: ?①创建并启动SystemServer进程 ②fork新的应用进程 ? 2.zygote的启动 zygote是由Init进程(pid=0)解析init.rc脚本启动的。Zygote进程在Init进程启动过程中被以service服务的形式启动。 从rc文件中可以看出: ①zygote的进程优先级是最高的,priority被设成-20,主要是因为Android的启动非常依赖于SystemServer的启动,而SystemServer也是zygote fork出来的,因此需要将zygote优先级设成最高的。 ②zygote在启动时创建了两个socket(zygote和usap_pool_primary),用于进程间的通信。 ③zygote是Android非常重要的核心服务之一,当其因异常退出后,Init会将其重新启动,并将一些相关的节点和服务重新设置。 zygote的启动实际上分成了两部分:SystemServer的启动、ZygoteServer的启动。两者前面是在同一个进程中执行的,当虚拟机创建完成后才正式分离。 ? zygote是通过app_process启动,入口就是app_process的main函数: #frameworks/base/cmds/app_process/app_main.cpp int main(int argc, char* const argv[]) { ? ? AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); ? ? … ? ??runtime.start( "com.android.internal.os.ZygoteInit", args, zygote); ? ? … } 创建AndroidRuntime对象(AndroidRuntime继承自AppRuntime),这里面主要的动作就是启动虚拟机。然后在虚拟机中运行ZygoteInit,ZygoteInit是java写的,即这一步Zygote就从native世界进入到了Java世界。接下来的流程如下图: ?Zygote的java世界入口就是ZygoteInit类的main方法: #frameworks/base/core/java/com/android/internal/os/ZygoteInit.java: public static void main(String argv[]) {? ? ? …… ? ? zygoteServer = new ZygoteServer( isPrimaryZygote); //1.创建ZygoteServer ? ? ??zygoteServer.registerServerSocket( socketName);?//2.创建一个Server端的Socket ? ? preload(bootTimingsTraceLog); //3.加载进程的资源和类 ? ? if (startSystemServer) { ? ? ? ? Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); //4.启动SystemServer ? ? ? ? if (r != null) { ? ? ? ? ? ? r.run(); ? ? ? ? ?? ?return; ? ? ? ? } ? ??} ? ? //5.启动一个死循环监听来自Client端的消息 ? ? caller = zygoteServer.runSelectLoop(abiList); ? ? if (caller != null) { ? ? ? ? caller.run(); ? ? } } ZygoteInit的main()方法是Android启动中的第一个Java进程的主方法。它主要完成几件事情: ①注册一个socket 在main方法里,通过registerServerSocket方法来创建一个Server端的socket,这个name为zygote的socket用于等待ActivityManagerService请求Zygote来创建新的应用程序进程。 Zygote作为孵化器,跟其他进程间的通讯不是通过binder,而是通过socket。一旦有新进程需要运行,系统会通过这个socket跟Zygote通讯,由zygote完成进程孵化过程。 ②预加载各类资源 preload函数用于加载虚拟机运行时所需的各类资源。 在ZygoteInit中,一般无特殊原因,都会调用preload()方法将Android Java层应用常用的资源预加装,其原因是: 1)Android是基于Linux系统开发的,底层就是Linux操作系统,而Linux进程的fork机制有一个特点,就是写时拷贝机制,即fork出来的进程最初是共用一块内存,只有当发生写操作时,才会将对应的内存块进行拷贝修改,而一些只读的内存块则会所有fork出来的进程共享。 2)preload()方法所加装的东西主要有以下几类:常用类文件、Resources资源、HALs资源、opengl、webview等。这些资源一般都是只读的,不会进行修改,而且是很多应用都可能会用到的。因此预先加载后所有由zygote fork出来的应用进程都能共用一块内存。 ?通过上图可以很容易理解在Zygote进程预加载系统资源后,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样大幅度提高应用程序的启动和运行速度。 ③启动SystemServer ? ?SystemServer是通过forkSystemServer()方法fork出来并开始执行。 private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { ? ? int pid; ? ? pid = Zygote.forkSystemServer( ? ? ? ? ? ? ? ? parsedArgs.mUid, parsedArgs.mGid, ? ? ? ? ? ? ? ? parsedArgs.mGids, ? ? ? ? ? ? ? ? parsedArgs.mRuntimeFlags, ? ? ? ? ? ? ? ? null, ? ? ? ? ? ? ? ? parsedArgs.mPermittedCapabilities, ? ? ? ? ? ? ? ? parsedArgs.mEffectiveCapabilities); ? ? if (pid == 0) { //子进程 ? ? ? ? zygoteServer.closeServerSocket(); ? ? ? ? return handleSystemServerProcess( parsedArgs); ? ? } ? ? return null; } forkSystemServer()中主要做了两件事:①调用Zygote.forkSystemServer()方法fork一个新的进程出来。②fork()后的子进程是SystemServer进程,等待zygote的启动完成,然后执行真正的SystemServer代码。 // Zygote.java public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ? ? ZygoteHooks.preFork(); //将Daemons线程关掉,虚拟机进行一些copy前的处理 ? ? // Resets nice priority for zygote process. ? ? resetNicePriority(); //将进程的优先级设回普通的级别 ? ? int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities); //调用native层方法fork一个新的进程。该方法主要调用Linux的fork系统调用,fork一个新的进程,子进程的pid为0,父进程返回子进程的pid值 ? ? if (pid == 0) { //子进程 ? ? ? ? Trace.setTracingEnabled(true, runtimeFlags); ? ? } ? ? ZygoteHooks.postForkCommon(); //重新启动Daemons线程,虚拟机进行copy后的处理 ? ? return pid; } 注:fork操作是不会将进程中所有线程拷贝的,只会拷贝当前线程。 Daemons线程是指:①HeapTaskDaemon;②ReferenceQueueDaemon;③FinalizerDaemon;④FinalizerWatchdogDaemon。平时在trace文件(ANR或者其他方式获取的trace文件)中看到Java应用进程都会有这4个线程,这4个线程就是在这里创建的。 再回到ZygoteInit.forkSystemServer()方法,此时两个进程都会返回到此处,然后两个进程到这就分道扬镳了。SystemServer进程将ZygoteServer的socket关闭,然后调用handleSystemServerProcess()方法去执行SystemServer的源码。 handleSystemServerProcess()方法的核心代码: createSystemServerClassLoader(); ClassLoader cl = sCachedSystemServerClassLoader; ?if (cl != null) { ? ? ? Thread.currentThread().setContextClassLoa der(cl); ?} ?return ZygoteInit.zygoteInit( parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, cl); 先获取classloader,并将其设置为root classloader。然后调用ZygoteInit.zygoteInit()方法去执行。 public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,?ClassLoader classLoader) { ? ? RuntimeInit.commonInit(); ? ? ZygoteInit.nativeZygoteInit(); //为进程创建Binder的环境(ProcessStatae) ? ? return RuntimeInit.applicationInit( targetSdkVersion, argv, classLoader); //执行传参进来的类的main()方法,这里传进来的类就是com.android.server.SystemServer } ZygoteInit.forkSystemServer()返回一个runnable,返回到ZygoteInit.main()方法后,SystemServer进程就会继续执行这个runnable。 zygote在fork进程后,使用runnable的方式返回到main()方法后才执行的原因?减少线程堆栈的长度,因为fork后进行执行的内容与之前zygote的堆栈内容并无关系,因此不需要为每个进程都保留前面的堆栈信息,而且还能减少进程的堆栈容量限制。 ④进入Loop循环 ZygoteServer.runSelectLoop 当zygote进程返回到main()方法后,就会继续执行ZygoteServer.runSelectLoop()方法,这个方法是一个死循环,是不断进行循环执行命令的方法。执行runSelectLoop()方法是为了等待消息去创建应用进程。 runSelectLoop()方法主要做两件事: ①每次循环都重新构建监听文件列表,主要是ZygoteServer的socket文件(ZygoteServer的socket和其他应用进程连接过来的socket)和usap文件节点。 ②监听文件列表,并从中获取命令执行。 ? 一张图看看Zygote的启动流程: ? 3.总结 Zygote创建Java世界的步骤: ①第一天:创建AppRuntime对象,并调用它的start。此后的活动则由AppRuntime来控制。 ②第二天:调用startVm创建Java虚拟机,然后调用startReg来注册JNI函数。 ③第三天:通过JNI调用com.android.internal.os.ZygoteInit类的main函数,从此进入了Java世界。然而在这个世界刚开创的时候,什么东西都没有。 ④第四天:调用registerZygoteSocket,通过这个函数,它可以响应子孙后代的请求。同时Zygote调用preloadClasses和preloadResources,为Java世界添砖加瓦。 ⑤第五天:Zygote觉得自己工作压力太大,便通过调用startSystemServer分裂一个子进程system_server来为Java世界服务。 ⑥第六天:Zygote完成了Java世界的初创工作,它已经很满足了。下一步该做的就是调用runSelectLoopMode后,便沉沉地睡去了。 ⑦以后的日子:Zygote随时守护在我们的周围,当接收到子孙后代的请求时,它会随时醒来,为它们工作。 ⑧有一天,他的孩子SystemServer发送了个请求,Zygote苏醒,Zygote调用ZygoteConnection的runOnce函数。在runOnce方法中Zygote分裂了一个子进程(App进程),然后在调用handleChildProc方法在子进程中进行处理。 ⑨然后继续沉睡,等待请求进行下一次分裂。 ? ? ? |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 2:25:22- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |