android java进程管理(二)之zygote

来源:互联网 发布:浙大软件工程硕士 编辑:程序博客网 时间:2024/06/14 09:51

app_process命令

app_process是c++本地程序,源码目录为 frameworks/base/cmds/app_process/
app_process是可以执行java代码的命令(因为它启动了一个java虚拟机),它有两种启动模式:

  • 1.zygote 模式:通常情况下,在–start-system-server启动参数的配置下,app_process启动之后,直接fork system_server 子进程,拉起整个android系统,之后用来孵化apk进程
  • 2.非zygote模式:分两种子模式
    • (1).application模式:这种模式是zygote 创建进程后通过shell来重新加载app_process命令再执行的
    • (2).tool模式:这个模式主要是用来执行调试命令(如am\pm\wm等等)

zygote 模式app_process命令的启动

service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks

以上是rc脚本中zygote模式启动的命令:

  • 1.service zygote /system/bin/app_process:启动app_process命令,将进程名设置为zygote
  • 2.–zygote: 这个启动参数指定app_process命令以zygote 模式启动
  • 3.–start-system-server:zygote进程自动启动system_server子进程
  • 4.socket zygote stream 660 root system:/dev/socket/目录下创建zygote 文件, system_server进程通过这个socket文件发送请求(例如创建apk进程)给zygote

非zygote模式app_process命令的启动

  • (1).application模式:这种模式是zygote 创建进程后通过shell来重新加载app_process命令再执行的
    • 请关注下面(zygote创建进程)小结中的详细调用描述
  • (2).tool模式:这个模式主要是用来执行调试命令(如am\pm\wm等等)
    • adb shell am –help

不同启动模式下的区别

app_process的c++代码很简单,没有任何逻辑可言(大家基于android 7.0的代码浏览一下就可以),就是解析启动参数、启动配置虚拟机,然后跳转到java代码执行,无论是zygote模式还是非zygote模式,本地代码的逻辑基本一样,但是从进入java代码的入口就开始不一样了。

if (zygote) {
runtime.start(“com.android.internal.os.ZygoteInit”, args, zygote);
} else if (className) {
runtime.start(“com.android.internal.os.RuntimeInit”, args, zygote);
} else {
………
return 10;
}
说明:runtime是AppRuntime对象(它是AndroidRuntime的子类,代表虚拟机运行环境,代码实现也是在app_main.cpp文件中),start函数的第一个参数指定的java的入口

zygote 模式下java的入口是ZygoteInit 的main方法,main方法主要做了如下事:

  • 1.打开/dev/socket/zygote socket文件,创建服务端对象LocalServerSocket
  • 2.预加载资源
  • 3.启动system_server
  • 4.监测socket, 建立链接(ZygoteConnection代表一个客户端的连接),循环处理客户端的请求,目前支持两种请求,一是创建进程,二是查询abi列表,在android系统上的客户端就是指system_server进程

非zygote模式下java的入口是RuntimeInit的main方法,main方法进行如下操作:

  • 1.调用commonInit()进行简单的通用初始化
  • 2.调用native方法nativeFinishInit(),这个方法的本地实现在AndroidRuntime中,对应的函数是com_android_internal_os_RuntimeInit_nativeFinishInit()
  • 3.调用AndroidRuntime的子类AppRuntime中的onStarted()函数
  • 4.调用启动参数指定类的main方法:
    • a.tool模式:例如am 命令,这个时候调用的就是Am.java的main方法(代码路径为frameworks/base/cmds/am)
    • b.application模式:WrapperInit::main()

zygote预加载资源

预加载属于拿空间换时间的策略,上一节我们提到过,zygote是作为一个java虚拟机的环境,通过写时复制机制达到快速启动apk进程的,既然如此,那么只要zygote环境配置的越健全越通用,apk进程需要单独做的事情就越少,对于jni层次来说就是提前注册jni函数,对于java来说,就是资源的预加载,zygote主要预加载如下资源:

  • 1.类的预加载
    zygote在启动的时候通过解析/system/etc/preloaded-classes这个文件来预加载类,这个文件的源码目录是frameworks/base,想要增加预加载类,直接在这个文件中添加即可
  • 2.图片资源的预加载
  • 3.共享库的预加载
    目前android N 上预加载了三个库:libandroid.so | libcompiler_rt.so | libjnigraphics.so, 如果想要增加自己的库的话,只需要在ZygoteInit::preloadSharedLibraries()方法中增加即可

ZygoteInit、ZygoteConnection、Zygote对象之间的关系

ZygoteInit对象是zygote进程的java入口
ZygoteConnection对象在zygote进程中代表一个socket链接,目前就是指system_server的链接,其中的runOnce()方法负责处理system_server的一次请求,那么在客户端system_server进程中socket的客户端具体是哪个对象呢?这个功能是由Process.ZygoteState内部类实现的,也就可以说实现socket的通信的服务端和客户端就是:ZygoteConnection(服务端)对象和Process.ZygoteState(客户端)对象
Zygote对象负责孵化system_server和通用进程

  • 1.forkSystemServer()方法:负责创建system_server()进程
  • 2.forkAndSpecialize()方法:负责创建通用进程

这三个对象都很简单,public和package的权限的方法很少,大家有时间的时候可以随便看看。

zygote创建进程

zygote启动两种进程,一个是system_server进程,这个是android的老大,所有的服务基本都在这个被控制,另一个就是通用进程,负责apk运行,每种进程在启动之后还有两种运行方式,一种是直接运行,另一种是通过shell 重新加载app_process命令开始执行。

  • 1.启动system_server进程

    • a.直接运行的调用流程(目前android系统system_server使用的是这种模式)
      ZygoteInit::handleSystemServerProcess()

       -->RuntimeInit::zygoteInit()    -->RuntimeInit::redirectLogStreams()    -->RuntimeInit::commonInit()    -->RuntimeInit::nativeZygoteInit()    -->RuntimeInit::applicationInit()       -->SystemServer::main()
    • b.shell重新加载 app_process命令调用流程
      ZygoteInit::handleSystemServerProcess()

       -->WrapperInit::execApplication()    -->Zygote::execShell()       -->shell重新加载app_process          -->RuntimeInit::main()             -->RuntimeInit::redirectLogStreams()             -->RuntimeInit::commonInit()             -->RuntimeInit::nativeFinishInit()                -->AppRuntime::onStarted()                    -->WrapperInit::main()                        -->RuntimeInit::wrapperInit()                           -->RuntimeInit::applicationInit()                              -->SystemServer::main()
  • 2.启动通用进程

    • a.直接运行通用进程(目前我们启动apk进程都是这种模式)
      ZygoteConnection::handleChildProc()

       -->RuntimeInit::zygoteInit()    -->RuntimeInit::redirectLogStreams()    -->RuntimeInit::commonInit()    -->RuntimeInit::nativeZygoteInit()    -->RuntimeInit::applicationInit()       -->ActivityThread::main()
    • b.shell重新加载 app_process命令调用流程
      ZygoteConnection::handleChildProc()

       -->WrapperInit::execApplication()    -->Zygote::execShell()       -->shell重新加载app_process          -->RuntimeInit::main()             -->RuntimeInit::redirectLogStreams()             -->RuntimeInit::commonInit()             -->RuntimeInit::nativeFinishInit()                -->AppRuntime::onStarted()                    -->WrapperInit::main()                        -->RuntimeInit::wrapperInit()                           -->RuntimeInit::applicationInit()                              -->ActivityThread::main()    

system_server和apk进程crash过程

从以上调用流程来看,无论是启动system_server进程还是apk进程,都会运行RuntimeInit::commonInit()方法,在这个方法中包含一个很重要的调用Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()),这行代码注册了一个全局的异常处理handler,只要进程中存在无法捕获的异常,虚拟机就会调用UncaughtHandler::uncaughtException()方法

public void uncaughtException(Thread t, Throwable e) {

             ......            if(mApplicationObject == null) {                Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);            } else {                StringBuilder message = new StringBuilder();                message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");            ......            ActivityManagerNative.getDefault().handleApplicationCrash(                    mApplicationObject, new ApplicationErrorReport.CrashInfo(e));

}

以上代码中FATAL EXCEPTION字样是不是很熟悉?!对头,就是apk进程和system_server进程crash掉后打印的堆栈信息,打印完堆栈信息后,调用AMS的handleApplicationCrash()方法,AMS处理完,进程才会kill自己,主动退出,再之后AMS中进程记录表注册的讣告收到消息,调用AppDeathRecipient::binderDied()方法(这个方法在调用handleAppDiedLocked()方法),一个进程的crash才算处理完,所以对于crash来说,在events日志中,会有两个事件:am_crash和am_proc_died,这里给大家留一个小疑问;crash的进程是如上的处理方法,那么被系统主动回收的进程是怎么处理的呢??

zygote启动system_server

在android平台上,system_server进程是zygote启动后直接启动的,通过Zygote.forkSystemServer()方法实现

参数列表
1.uid :unix uid
2.gid :unix gid
3.gids : unix gids
4.debugFlags : 调试标志
5.rlimits :资源限制
6.permittedCapabilities :unix cap
7.effectiveCapabilities : unix cap

zygote启动apk进程

apk的创建是由system_server进程发送请求给zygote进程,通过ZygoteConnection::runOnce() 调用Zygote.forkAndSpecialize()启动apk进程

参数列表
1.uid :unix uid
2.gid :unix gid
3.gids : unix gids
4.debugFlags : 调试标志
5.rlimits :资源限制
6.mountExternal :
7.seInfo : SELinux information
8.niceName :the process name
9.fdsToClose :需要关闭的zygote打开的文件
10.instructionSet :the instruction set
11.appDataDir :apk的数据目录

调试标志(debugFlags)

  • 1.DEBUG_ENABLE_DEBUGGER:启动虚拟机调试

  • 2.DEBUG_ENABLE_CHECKJNI :检查jni参数

  • 3.DEBUG_ENABLE_ASSERT :启动assert,通过debug.assert属性控制

  • 4.DEBUG_ENABLE_SAFEMODE:启动AOT compiler 和 JIT,通过Application 的属性vmSafeMode控制

  • 5.DEBUG_ENABLE_JNI_LOGGING :启动第三方jni activity logging,通过debug.jni.logging属性控制

  • 6.DEBUG_GENERATE_DEBUG_INFO :生成本地调试信息,通过debug.generate-debug-info属性控制,如果通过START_FLAG_NATIVE_DEBUGGING标志启动的话(Am命令使用),这个debug标志也是被置位的

  • 7.DEBUG_ALWAYS_JIT:总是启动JIT,通过START_FLAG_NATIVE_DEBUGGING标志控制(Am命令使用)

  • 8.DEBUG_NATIVE_DEBUGGABLE:关闭优化,调试代码,通过START_FLAG_NATIVE_DEBUGGING标志控制(Am命令使用)

java入口小结

下面我们来简单总结一下各个进程的java入口:

  • 1.zygote模式下app_process进程的java入口:ZygoteInit::main()
  • 2.system_server进程的java 入口:SystemServer::main()
  • 3.apk进程的java入口:ActivityThread::main()
  • 4.非zygote模式下app_process各个调试命令的入口:
    • (1) am 的java入口: RuntimeInit::main()->Am::main()
    • (2)wm 的java入口: RuntimeInit::main()->Wm::main()
    • (3)pm 的java入口:RuntimeInit::main()->Pm::main()
  • 5.非zygote模式下application子模式的入口:RuntimeInit::main()->WrapperInit::main()

socket的创建和使用

socket的创建和使用需要三步,非常简单:

  • 1.创建socket文件,这个是在rc脚本中定义的,又init进程来创建,并且作为服务端进程的配置子项,例如上面的zygote socket的创建

    socket zygote stream 660 root system
    zygote socket文件名,660是文件权限,root 是用户 system是用户组
    这条命令会创建/dev/socket/zygote文件

  • 2.服务端的创建

    • (1).java服务端的创建
      打开/dev/socket目录下的对应文件,绑定监听,这个功能是通过LocalServerSocket类实现的,只要使用socket名字构造LocalServerSocket对象尽可,非常简单
    • (2)c/c++服务端的创建
      主要问题是打开socket文件,这个通过android_get_control_socket(“socket文件名字”)函数返回文件描述符fd,之后的操作就和网络编程接口一样了
  • 3.客户端的创建

    • (1)java客户端的创建
      客户端的创建连接如下代码:

      socket = new LocalSocket();
      LocalSocketAddress address = new LocalSocketAddress(“socket文件名字”, LocalSocketAddress.Namespace.RESERVED);
      socket.connect(address);

    • (2)c/c++客户端的创建
      主要问题是打开socket文件,这个通过android_get_control_socket(“socket文件名字”)函数返回文件描述符fd,之后的操作就和网络编程接口一样了

1 0