Dalvik虚拟机进程和线程的创建过程分析
我们知道,在Android系统中,Dalvik虚拟机是运行Linux内核之上的。如果我们把Dalvik虚拟机看作是一台机器,那么它也有进程和线程的概念。事实上,我们的确是可以在Java代码中创建进程和线程,也就是Dalvik虚拟机进程和线程。那么,这些Dalvik虚拟机所创建的进程和线程与其宿主Linux内核的进程和线程有什么关系呢?本文将通过Dalvik虚拟机进程和线程的创建过程来回答这个问题。
此外,从前面Dalvik虚拟机的运行过程分析一文可以知道,Dalvik虚拟机除了可以执行Java代码之外,还可以执行Native代码,也就是C/C++函数。这些C/C++函数在执行的过程中,又可以通过本地操作系统提供的系统调用来创建本地操作系统进程或者线程,也就是Linux进程和线程。如果在Native代码中创建出来的进程又加载有Dalvik虚拟机,那么它实际上又可以看作是一个Dalvik虚拟机进程。另一方面,如果在Native代码中创建出来的线程能够执行Java代码,那么它实际上又可以看作是一个Dalvik虚拟机线程。
这样事情看起来似乎很复杂,因为既有Dalvik虚拟机进程和线程,又有Native操作系统进程和线程,而且它们又可以同时执行Java代码和Native代码。为了理清它们之间的关系,我们将按照以下四个情景来组织本文:
1. Dalvik虚拟机进程的创建过程;
2. Dalvik虚拟机线程的创建过程;
3. 只执行C/C++代码的Native线程的创建过程;
4. 能同时执行C/C++代码和Java代码的Native线程的创建过程。
对于上述进程和线程,Android系统都分别提供有接口来创建:
1. Dalvik虚拟机进程可以通过android.os.Process类的静态成员函数start来创建;
2. Dalvik虚拟机线程可以通过java.lang.Thread类的成员函数start来创建;
3. 只执行C/C++代码的Native线程可以通过C++类Thread的成员函数run来创建;
4. 能同时执行C/C++代码和Java代码的Native线程也可以通过C++类Thread的成员函数run来创建;
接下来,我们就按照上述四个情况来分析Dalvik虚拟机进程和线程和Native操作系统进程和线程的关系。
一. Dalvik虚拟机进程的创建过程
Dalvik虚拟机进程实际上就是通常我们所说的Android应用程序进程。从前面Android应用程序进程启动过程的源代码分析一文可以知道,Android应用程序进程是由ActivityManagerService服务通过android.os.Process类的静态成员函数start来请求Zygote进程创建的,而Zyogte进程最终又是通过dalvik.system.Zygote类的静态成员函数forkAndSpecialize来创建该Android应用程序进程的。因此,接下来我们就从dalvik.system.Zygote类的静态成员函数forkAndSpecialize开始分析Dalvik虚拟机进程的创建过程,如图1所示:
图1 Dalvik虚拟机进程的创建过程
这个过程可以分为3个步骤,接下来我们就详细分析每一个步骤。
Step 1. Zygote.forkAndSpecialize
[java]
public class Zygote {
......
native public static int forkAndSpecialize(int uid, int gid, int[] gids,
int debugFlags, int[][] rlimits);
......
}
public class Zygote {
......
native public static int forkAndSpecialize(int uid, int gid, int[] gids,
int debugFlags, int[][] rlimits);
......
} 这个函数定义在文件libcore/dalvik/src/main/java/dalvik/system/Zygote.java中。
Zygote类的静态成员函数forkAndSpecialize是一个JNI方法,它是由C++层的函数Dalvik_dalvik_system_Zygote_forkAndSpecialize来实现的,如下所示:
[cpp]
/* native public static int forkAndSpecialize(int uid, int gid,
* int[] gids, int debugFlags);
*/
static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
JValue* pResult)
{
pid_t pid;
pid = forkAndSpecializeCommon(args, false);
RETURN_INT(pid);
}
/* native public static int forkAndSpecialize(int uid, int gid,
* int[] gids, int debugFlags);
*/
static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
JValue* pResult)
{
pid_t pid;
pid = forkAndSpecializeCommon(args, false);
RETURN_INT(pid);
}
这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.c中。
注意,参数args指向的是一个u4数组,它里面包含了所有从Java层传递进来的参数,这是由Dalvik虚拟机封装的。另外一个参数pResult用来保存JNI方法调用结果,这是通过宏RETURN_INT来实现的。
函数Dalvik_dalvik_system_Zygote_forkAndSpecialize的实现很简单,它通过调用另外一个函数forkAndSpecializeCommon来创建一个Dalvik虚拟机进程。
Step 2. forkAndSpecializeCommon
[cpp]
/*
* Utility routine to fork zygote and specialize the child process.
*/
static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
{
pid_t pid;
uid_t uid = (uid_t) args[0];
gid_t gid = (gid_t) args[1];
ArrayObject* gids = (ArrayObject *)args[2];
u4 debugFlags = args[3];
ArrayObject *rlimits = (ArrayObject *)args[4];
int64_t permittedCapabilities, effectiveCapabilities;
if (isSystemServer) {
/*
* Don't use GET_ARG_LONG here for now. gcc is generating code
* that uses register d8 as a temporary, and that's coming out
* scrambled in the child process. b/3138621
*/
//permittedCapabilities = GET_ARG_LONG(args, 5);
//effectiveCapabilities = GET_ARG_LONG(args, 7);
permittedCapabilities = args[5] | (int64_t) args[6] << 32;
effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
} else {
permittedCapabilities = effectiveCapabilities = 0;
}
if (!gDvm.zygote) {
......
return -1;
}
......
pid = fork();
if (pid == 0) {
 
补充:移动开发 , Android ,