上一篇文章我们已经分析到调用com.android.internal.os.ZygoteInit类的main函数。

今天分析一下com.android.internal.os.ZygoteInit类的main函数。

public static void main(String argv[]) {
// 注册zygote的socket
    registerZygoteSocket();

    //加载Android Application Framework使用的类与资源
    preloadClasses();
    preloadResources();     //启动SystemServer
    if(argv[1].equals("true")) {
      startSystemServer();
    }
/**
* 处理客户端连接及请求。由zygoteConnection的runOnce函数来处理。
    */
runSelectLoopMode();
}

在main函数我们就主要看registerZygoteSocket()与runSelectLoopMode()。

  • registerZygoteSocket():就是创建一个localsocket,也就是说注册了一个zygote的服务端socket。
  • runSelectLoopMode():就是一直无限循环,等待客户端socket的连接,然后通过zygoteConnection的runOnce函数来处理对应的请求。
  • PreloadClass(): 读取framework/base/tools/preload/preload_class文件约1268类。

  • PreloadResources(): 加载framework-res.apk中的资源。

  • gc():执行垃圾收集。

那么我们就看一下registerZygoteSocket()

private static void registerZygoteSocket() {

       String env = System.getenv(ANDROID_SOCKET_ENV);
  fileDesc = Integer.parseInt(env); if (sServerSocket == null) {
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));
}
}

很简单就是创建一个LocalServerSocket。

建立IPC通信服务器,从环境变量中获取(System.getenv(ANDROID_SOCKET_ENV);)socket的fd,之前用sig的fd来调用handle去创建的zygote。

我们在来看一下runSelectLoopMode()

private static void runSelectLoopMode() throws MethodAndArgsCaller {
    …
while (true) {
int index; fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray); if(index == ) {
//连接客户端发送的请求(Command)
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//处理客户端发送的请求(Command)
boolean done;
done = peers.get(index).runOnce();
}
}
}

这个函数也很简单等待客户端发来的请求,当接收到请求时就运行run0nce函数去处理请求即可。

客户端可以理解成AMS或SystemServer。

在这里简单说明一下AMS与SystemServer

  • SystemServer

    Zygote的子进程,为JAVA世界做服务。

    Java世界系统Service,此进程是framework的核心,此server挂掉了,zygote会自杀。

     Zygote.forkSystemServer()而诞生。

  • AMS

    ActivityManagerService是由SystemServer创建。

    当一个Acitvity开启的时候,是由AMS中开启一个新的Process,而在Process类中最终会创建一个LocalSocket去连接ZYGOTE_SOCKET。

      而在AMS中的startProcessLocked()中调用Process.start()函数中会传入一个参数-android.app.ActivityThread。最终会通过socket传入zygote处理。

我们继续看以下done = peers.get(index).runOnce();

boolean runOnce( ) {
Arguments parsedArgs = null;
FileDescriptor[] descriptors; //Reads command socket.
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors(); try {
parsedArgs = new Arguments(args);
...... pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);

} catch (IOException ex) {
......
} catch (ErrnoException ex) {
......
} catch (IllegalArgumentException ex) {
......
} catch (ZygoteSecurityException ex) {
......
}     //新创建的进程 pid == 0
if (pid == ) {
// in child
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else { // in parent,也就是Zygote进程执行过程
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
}

我们分析一下以下几个函数

  • readArgumentList()与parsedArgs = new Arguments(args) 是用来获取command和解析command的。
  • Zygote.forkAndSpecialize()是很简单的,就是去调用native函数来fork的。
  • handleChildProc()是处理子进程。
  • handleParentProc()是处理父进程。也就是zygote进程,此函数会原路返回,通过socket的写入返还给systemserver最终到AMS,然后重新进入runSelectLoopMode。

首先我们来看一下forkAndSpecialize()

这个函数定义在文件libcore/dalvik/src/main/java/dalvik/system/Zygote.java中。

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName) {
preFork();
int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName);
postFork();
return pid;
}

很简单就是调用native的ForkAndSpecialize函数。
JNI函数nativeForkAndSpecialize的由Dalvik_dalvik_system_Zygote_forkAndSpecialize函数来实现。

那我们就去看一下。

这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。

static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args, JValue* pResult)
{

pid_t pid;

  //args指向的一块内存中
pid = forkAndSpecializeCommon(args, false); RETURN_INT(pid);
}

Dalvik_dalvik_system_Zygote_forkAndSpecialize函数通过调用forkAndSpecializeCommon函数来执行创建进程,

实现如下所示:

这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。

static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
{
pid_t pid; uid_t uid = (uid_t) args[];
gid_t gid = (gid_t) args[];
......
char *seInfo = NULL;
char *niceName = NULL; if (isSystemServer) {
      //参数isSystemServer表示true时创建的是System Server进程。
  ......
} else {
      //参数isSystemServer表示true时创建的是应用程序进程。
  ......
} ...... pid = fork();
  //表示当前是新创建的进程
if (pid == ) {
...... err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);
......
} ...... return pid;
}

我们不去看具体代码实现,主要了解一下主要是干什么的就可以了。
我们要知道的是zygote是负责应用程序进程与SystemServer的进程就可以了。

接下来我们回到之前的handleParentProc()

private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
if (pid > ) {
setChildPgid(pid);
}
if (descriptors != null) {
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
}
boolean usingWrapper = false;
if (pipeFd != null && pid > ) {
DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
int innerPid = -;
try {
innerPid = is.readInt();
} catch (IOException ex) {
Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
} finally {
try {
is.close();
} catch (IOException ex) {
}
}
// Ensure that the pid reported by the wrapped process is either the
// child process that we forked, or a descendant of it.
if (innerPid > ) {
int parentPid = innerPid;
while (parentPid > && parentPid != pid) {
parentPid = Process.getParentPid(parentPid);
}
if (parentPid > ) {
Log.i(TAG, "Wrapped process has pid " + innerPid);
pid = innerPid;
usingWrapper = true;
} else {
Log.w(TAG, "Wrapped process reported a pid that is not a child of "
+ "the process that we forked: childPid=" + pid
+ " innerPid=" + innerPid);
}
}
}
//将创建的应用程序进程ID返回给SystemServer进程的ActivityManagerService服务
try {
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error reading from command socket", ex);
return true;
}
/*
* If the peer wants to use the socket to wait on the
* newly spawned process, then we're all done.
*/
if (parsedArgs.peerWait) {
try {
mSocket.close();
} catch (IOException ex) {
Log.e(TAG, "Zygote: error closing sockets", ex);
}
return true;
}
return false;
}

也就是创建失败会进入此函数,也就是处理zygote进程的函数,此函数会原路返回,通过socket的写入返还给systemserver最终到AMS,然后重新进入runSelectLoopMode。继续监听客户端的请求。

如果我们新创建进程成功了,会调用handleChildProc()。

代码如下

private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
/*
* Close the socket, unless we're in "peer wait" mode, in which
* case it's used to track the liveness of this process.
*/ if (parsedArgs.peerWait) {
try {
ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
sPeerWaitSocket = mSocket;
} catch (IOException ex) {
Log.e(TAG, "Zygote Child: error setting peer wait "
+ "socket to be close-on-exec", ex);
}
} else {//关闭从Zygote进程复制过来的Socket连接
closeSocket();
ZygoteInit.closeServerSocket();
}
if (descriptors != null) {
try {
//为新创建的应用程序进程重新打开标准输入输出控制台
ZygoteInit.reopenStdio(descriptors[],descriptors[], descriptors[]);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (IOException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
//设置新进程名称
if (parsedArgs.niceName != null) {
    //设置新进程名称niceName是指systemServer
Process.setArgV0(parsedArgs.niceName);
}
//重新初始化Runtime
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
//为应用程序进程启动Binder线程池
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs);
}
} else {
String className;
try {
//读取新进程执行的类名,在Process.start()函数中,传过来的类名为:"android.app.ActivityThread"
className = parsedArgs.remainingArgs[];
} catch (ArrayIndexOutOfBoundsException ex) {
logAndPrintError(newStderr,"Missing required class name argument", null);
return;
}
String[] mainArgs = new String[parsedArgs.remainingArgs.length - ];
System.arraycopy(parsedArgs.remainingArgs, ,mainArgs, , mainArgs.length);
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,parsedArgs.classpath, className, mainArgs);
} else {
//获取类加载器
ClassLoader cloader;
if (parsedArgs.classpath != null) {
cloader = new PathClassLoader(parsedArgs.classpath,ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
//加载并执行"android.app.ActivityThread"类
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
}
}

由于应用程序启动参数中已经设置了"--runtime-init"标志位,因此新创建的应用程序进程将调用RuntimeInit.zygoteInit()函数来初始化运行时库,为应用程序启动Binder线程池,完成这些准备工作后,调用应用程序进程的入口函数ActivityThread.main()为应用程序进程创建消息循环。

接下来我们就看一下RuntimeInit.zygoteInit()

此函数在/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java中

public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
//重定向Log输出流
redirectLogStreams();
//初始化运行环境
commonInit();
//启动Binder线程池
nativeZygoteInit();
//调用程序入口函数
applicationInit(targetSdkVersion, argv);
}

接下来我们看一下applicationInit()

private static void applicationInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true); // We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
} // Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs);
}

在这里我们重点要看一下invokeStaticMain()
通过调用invokeStaticMain来调用args.startClass这个类的main()方法。

说明开启又一个新世界。

在之前提过zygote的socket的客户端可以是AMS,下一节我们分析如何开启一个Activity。

ZygoteInit 相关分析的更多相关文章

  1. 多视图学习利器----CCA(典型相关分析)及MATLAB实现

    Hello,我是你们人见人爱花见花开的小花.又和大家见面了,今天我们来聊一聊多视图学习利器------CCA. 一 典型相关分析的基本思想 当我们研究两个变量x和y之间的相关关系的时候,相关系数(相关 ...

  2. SPSS数据分析—基于最优尺度变换的典型相关分析

    传统的典型相关分析只能考虑变量之间的线性相关情况,且必须为连续变量,而我们依然可以使用最优尺度变换来拓展其应用范围,使其可以分析非线性相关.数据为分类数据等情况,并且不再仅限于两个变量间的分析, 虽然 ...

  3. SPSS数据分析—典型相关分析

    我们已经知道,两个随机变量间的相关关系可以用简单相关系数表示,一个随机变量和多个随机变量的相关关系可以用复相关系数表示,而如果需要研究多个随机变量和多个随机变量间的相关关系,则需要使用典型相关分析. ...

  4. com.android.internal.os.ZygoteInit$MethodAndArgsCaller 解决

    好久没写博客了,带着点小愧疚来,添上几个字: 这是今天遇到的一个bug,之前也遇到过,为了后面方便,就记下. bug提示:com.android.internal.os.ZygoteInit$Meth ...

  5. SPSS数据分析—相关分析

    相关系数是衡量变量之间相关程度的度量,也是很多分析的中的当中环节,SPSS做相关分析比较简单,主要是区别如何使用这些相关系数,如果不想定量的分析相关性的话,直接观察散点图也可以. 相关系数有一些需要注 ...

  6. 中国各城市PM2.5数据间的相关分析

    code{white-space: pre;} pre:not([class]) { background-color: white; }if (window.hljs && docu ...

  7. Zygote(app_process)相关分析2

    在前一篇文章中已经分析了从init.c到Zygote(app_process)的启动流程. 今天开始分析frameworks/base/cmds/app_process/app_main.cpp. s ...

  8. Jordan Lecture Note-12: Kernel典型相关分析(Kernel Canonical Correlation Analysis, KCCA).

    Kernel典型相关分析 (一)KCCA 同样,我们可以引入Kernel函数,通过非线性的坐标变换达到之前CCA所寻求的目标.首先,假设映射$\Phi_X: x\rightarrow \Phi_X(x ...

  9. Jordan Lecture Note-11: 典型相关分析(Canonical Correlation Analysis, CCA).

    典型相关分析 (一)引入 典型相关分析(Canonical Correlation Analysis)是研究两组变量之间相关关系的一种多元统计方法.他能够揭示出两组变量之间的内在联系. 我们知道,在一 ...

随机推荐

  1. Linux 串口使用

    1. 安装串口调试工具minicom sudo apt-get install minicom 2. 查看串口端口 cfm@cfm880:~$ dmesg | grep tty[ 0.000000] ...

  2. form表单 无法提交js动态添加的表单元素问题。。

    第一种情况, 这种情况js动态添加的表单元素是不能提交到服务器端的 <table> <form method="post" action=" url   ...

  3. Solaris网络配置

    /etc/hostname.interface:物理端口,里面包含一个主机名或主机的IP/etc/nodename:计算机名/etc/defaultdomain:主机域名/etc/defaultrou ...

  4. Solaris磁盘设备

    Solaris的磁盘分区称为分片(slice),在磁盘上,一个环形就是一个分区分片的命名通常是c#t#d#s#c:Controller number,控制器标号,c0就是第一个控制器t:Taget n ...

  5. javaSE第十二天

    第十二天    64 1. Scanner的使用(了解)    64 (1)在JDK5以后出现的用于键盘录入数据的类.    64 (2)构造方法:    64 (4)要掌握的两个方法    65 ( ...

  6. backBarButtonItem 颜色/文字修改

    iOS7之后. 默认的返回按钮字体颜色是蓝色的, 显示内如是父VC(上一级界面)的title 如果要做修改, 可以通过下面的办法: 1. 修改字体颜色 (1) 在plist里面, 加上View con ...

  7. cpack

    一. 简介 CPack是CMake 2.4.2之后的一个内置工具,主要作用就是生成制定类型的安装包.它可以脱离cmake单独运行. 二. 基本设置 (mandatory) 设置包类型set(CPACK ...

  8. 解决Linux中遇到No such device

    虚拟机备份转移后,网络启动异常,提示“SIOCSIFADDR: No such device” he problem lies in the fact that ethernet MAC addres ...

  9. subpage和secondary page的区别

    Hi,  Can you tell me the differences between subpage and secondary  page and when to use which ? I n ...

  10. DataGridView 控件用法(可能不是很全面,因为这是自己常常用到的一些小总结):

    一.DataGridView属性设置 1.我们单击选中行的时候,默认是选择一个单元格,不能选择一整行,我们只需设置DataGridView的属性SelectionMode为FullRowSelect ...