您的位置:首页 > 移动开发 > Android开发

android java进程管理(二)之zygote

2017-04-17 13:21 351 查看

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,之后的操作就和网络编程接口一样了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: