Android zygote启动流程详解

对zygote的理解

在Android系统中,zygote是一个native进程,是所有应用进程的父进程。而zygote则是Linux系统用户空间的第一个进程——init进程,通过fork的方式创建并启动的。

作用

zygote进程在启动时,会创建一个Dalvik虚拟机实例,每次孵化新的应用进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面,从而使得每个应用程序进程都有一个独立的Dalvik虚拟机实例。

zygote进程的主要作用有两个:

启动SystemServer。
孵化应用进程。

启动流程

启动入口

Zygote进程在init进程中,通过解析init.zygote.rc配置文件,以service(服务)的方式启动并创建的。

以init.zygote32.rc为例来看下:

脚本讲解

//  system\core\rootdir\init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
  class main
  priority -20
  user root
  group root readproc reserved_disk
  socket zygote stream 660 root system
  socket usap_pool_primary stream 660 root system
  onrestart write /sys/power/state on
  onrestart restart audioserver
  onrestart restart cameraserver
  onrestart restart media
  onrestart restart netd
  onrestart restart wificond
  writepid /dev/cpuset/foreground/tasks

这段脚本要求 init 进程创建一个名为 zygote 的进程,该进程要执行的程序是“/system/bin/app_process”。并且为 zygote 进程创建一个 socket 资源 (用于进程间通信,ActivityManagerService 就是通过该 socket 请求 zygote 进程 fork 一个应用程序进程)。

后面的**--zygote**是参数,表示启动的是zygote进程。在app_process的main函数中会依据该参数决定执行ZygoteInit还是Java类。

启动过程

zygote要执行的程序便是system/bin/app_process,它的源代码在frameworks/base/cmds/app_process/app_main.cpp

App_main::main

int main(int argc, char* const argv[])
{
  ...
  while (i < argc) {
    const char* arg = argv[i++];
    if (strcmp(arg, "--zygote") == 0) {//是否有--zygote参数。这个是启动zygote进程的时候的参数
      zygote = true;
			//进程名称,设置为zygote
      niceName = ZYGOTE_NICE_NAME;
    } else if (strcmp(arg, "--start-system-server") == 0) {//是否有--start-system-server
      startSystemServer = true;
	....
  if (zygote) {
		//最最重要方法。。。如果是zygote进程,则启动ZygoteInit。
    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.");
  }
}

AndroidRuntime::start

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
  ...
  JNIEnv* env;
	//重点方法   创建VM虚拟机,参数是指针,可以用于获取返回的值,可以使用env来和Java层来做交互
  if (startVm(&mJavaVM, &env, zygote) != 0) {
    return;
  }
  onVmCreated(env);
  //重点方法   给虚拟机注册一些JNI函数,(系统so库、用户自定义so库 、加载函数等。)
  if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
  }

  	//找到类的main方法,并调用。如果是zygote的话,这里就会启动ZygoteInit类的main方法
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
      "([Ljava/lang/String;)V");
    if (startMeth == NULL) {
      ALOGE("JavaVM unable to find main() in '%s'\n", className);
      /* keep going */
    } else {
    	//调用main方法。这里通过JNI调用Java方法之后,Zygote(Native层)就进入了Java的世界,从而开启了Android中Java的世界。
      env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
App_main.main
 AndroidRuntime.start
  startVm//创建虚拟机
  startReg//注册JNI函数
  ZygoteInit.main//这里就进入到了Java层了
    registerZygoteSocket//建立IPC的通讯机制
    preload//预加载类和资源
    startSystemServer//启动system_server
    runSelectLoop//等待进程创建的请求

对应的源码地址: /frameworks/base/cmds/app_process/App_main.cpp (内含AppRuntime类) /frameworks/base/core/jni/AndroidRuntime.cpp /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java /frameworks/base/core/java/com/android/internal/os/Zygote.java /frameworks/base/core/java/android/net/LocalServerSocket.java

Zygote进程的启动过程中,除了会创建一个Dalvik虚拟机实例之外,还会将Java运行时库加载到进程中,以及注册一些Android核心类的JNI方法到创建的Dalvik虚拟机实例中。

zygote进程初始化时启动虚拟,并加载一些系统资源。这样zygote fork出子进程之后,子进程也会继承能正常工作的虚拟机和各种系统资源,剩下的只需要装载APK文件的字节码就可以运行程序,。

Java应用程序不能以本地进程的形态运行,必须在一个独立的虚拟机中运行。如果每次都重新启动虚拟机,肯定就会拖慢应用程序的启动速度。

注意:APK应用程序进程被zygote进程孵化出来以后,不仅会获得Dalvik虚拟机实例拷贝,还会与Zygote一起共享Java运行时库。

以上就是Android zygote启动流程详解的详细内容,更多关于Android zygote启动流程的资料请关注我们其它相关文章!

时间: 2021-03-30

详细分析Android中实现Zygote的源码

概述 在Android系统中,所有的应用程序进程,以及用来运行系统关键服务的System进程都是由zygote进程负责创建的.因此,我们将它称为进程孵化器.zygote进程是通过复制自身的方式来创建System进程和应用程序进程的.由于zygote进程在启动时会在内部创建一个虚拟机实例,因此,通过复制zygote进程而得到的System进程和应用程序进程可以快速地在内部获得一个虚拟机实例拷贝. zygote进程在启动完成之后,会马上将System进程启动起来,以便它可以将系统的关键服务启动起来.

详细分析Android中onTouch事件传递机制

onTach介绍 ontach是Android系统中整个事件机制的基础.Android中的其他事件,如onClick.onLongClick等都是以onTach为基础的. onTach包括从手指按下到离开手机屏幕的整个过程,在微观形式上,具体表现为action_down.action_move和action_up等过程. onTach两种主要定义形式如下: 1.在自定义控件中,常见的有重写onTouchEvent(MotionEvent ev)方法.如在开发中经常可以看到重写的onTouchEv

简略分析Android的Retrofit应用开发框架源码

面对一个项目,对于Android应用开发框架的选择,我想过三种方案: 1.使用Loader + HttpClient + GreenDao + Gson + Fragment,优点是可定制性强,由于使用Google家自己的Loader和LoaderManager,代码健壮性强. 缺点是整套代码学习成本较高,使用过程中样板代码较多,(比如每一个Request都需要产生一个新类) 2.Volley,作为Google在IO大会上得瑟过的一个网络库,其实不算什么新东西(2013 IO发布),使用较为简单

分析Android中应用的启动流程

前言 在我们开始之前,希望您能最好已经满足以下条件: 1.有一份编译后的Android源码(亲自动手实践才会有更深入的理解) 2.对Binder机制有一定的了解 本文启动流程分析基于Android 5.1的源码.为什么是5.1的源码呢?因为手边编译完的代码只有这个版本-另外,用什么版本的源码并不重要,大体的流程并无本质上的区别,仅仅是实现细节的调整,找一个你熟悉的版本就好. 1.启动时序图 作为一个轻微强迫症的人,整理的时序图,相信大家按图索骥,一定能搞明白整个启动流程: 说明:为了让大家更清楚

详细分析sqlserver中的小数类型(float和decimal)

在SQL Server中实际上只有两种小数数值类型,分别是float(近似数值)和decimal(精确数值),这两种类型能表示所有的小数数值类型. float(近似数值类型) float表示的是近似数值,存在一定的精度缺失. float(n) 这里的n是以科学计数法存储浮点数尾数的位数,因此此参数决定了精度和存储的大小.其是可选的,默认值是53,即float等价于float(53),占用8bytes.如果指定了n,则它必须是介于1至53之间的值.实际上,虽然n的取值范围定义是1至53,但实际上f

自定义Android六边形进度条(附源码)

本文实例讲述了Android自定义圆形进度条,分享给大家供大家参考.具体如下: 大家也可以参考这两篇文章进行学习: <自定义Android圆形进度条(附源码)>   <Android带进度的圆形进度条> 运行效果截图如下: 主要代码: package com.sxc.hexagonprogress; import java.util.Random; import android.content.Context; import android.content.res.ColorSta

android的消息处理机制(图文+源码分析)—Looper/Handler/Message

这篇文章写的非常好,深入浅出,关键还是一位大三学生自己剖析的心得.这是我喜欢此文的原因.下面请看正文: 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设 计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android的消息处理机 制,我看了Looper,Handler,Message这几个类的源码,结果又

代码实例分析android中inline hook

以下内容通过1.实现目标注入程序,2.实现主程序,3.实现注入函数,4.thumb指令集实现等4个方面详细分析了android中inline hook的用法,以下是全部内容: 最近终于沉下心来对着书把hook跟注入方面的代码敲了一遍,打算写几个博客把它们记录下来. 第一次介绍一下我感觉难度最大的inline hook,实现代码参考了腾讯GAD的游戏安全入门. inline hook的大致流程如下: 首先将目标指令替换为跳转指令,跳转地址为一段我们自己编写的汇编代码,这段汇编代码先是执行用户指定的

实例分析Android中HandlerThread线程用法

一.HandlerThread的介绍及使用举例      HandlerThread是什么鬼?其本质就是一个线程,但是HandlerThread在启动的时候会帮我们准备好一个Looper,并供外界使用,说白了就是使我们在子线程中更方便的使用Handler,比如没有HandlerThread我们要在子线程使用Handler,写法如下: private Handler mHandler;    @Override     public void run() {        super.run();

详细分析JavaScript中的深浅拷贝

在说JS中深浅拷贝之前,我们需要对JS中的数据类型有所了解,分为基本数据类型与引用数据类型,对于基本数据类型并没有深浅拷贝的说法,深浅拷贝主要针对引用数据类型. 一.浅拷贝 浅拷贝只复制了引用,并没有复制值.在JS中最简单的浅拷贝就是利用"="赋值操作符来实现. var obj1 = { a:1, b:[2,3,4], c:{name:'tanj'}, fun:function(){ console.log('fun') } } var obj2 = obj1 obj2.a = 666