而能够访问Java端的thread需要跟JVM进行绑定,下面是具体的实现函数
#AndroidRuntime.cpp
int AndroidRuntime::javaCreateThreadEtc(
android_thread_func_t entryFunction,
void* userData,
const char* threadName,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t* threadId)
{
args[0] = (void*) entryFunction; //将entryFunc 暂存在args[0]
args[1] = userData;
args[2] = (void*) strdup(threadName);
result =AndroidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args, threadName, threadPriority, threadStackSize, threadId); //entryFunc变成javaThreadShell.
return result;
}
int AndroidRuntime::javaThreadShell(void* args) {
void* start = ((void**)args)[0];
void* userData = ((void **)args)[1];
char* name = (char*) ((void **)args)[2]; // we own this storage
JNIEnv* env;
/* 跟 VM 绑定 */
if (javaAttachThread(name, &env) != JNI_OK)
return -1;
/* 运行真正的’entryFunc’ */
result = (*(android_thread_func_t)start)(userData);
/* unhook us */
javaDetachThread();
…
return result;
}
attachVM() 到底做什么事情? 篇幅有限无法展开,这里只需要知道这么几点:
-
- 一个进程里有一个Java 虚拟机,Java 虚拟机内部有很多线程,如上面列到的 GC, FinalizeDaemon, 以及用户创建的线程等等.
-
每个Java线程都维护一个JNIEnvExt对象,里面存放一个指向DVM 内部Thread对象的指针,也就是说,所有从native到Java端的调用,都会引用到这个对象。
-
所有通过JVM创建的线程都会在VM内部记录在案,但是当前,我们还没有进入Java世界,本地创建的线程VM自然就不知道,因此我们需要通过attach来通知VM来创建相应的内部数据结构。
看看下面代码,你就知道,其实Attach()做的一件重要的事情就是 创建thread和JNIEnvExt.
bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon)
{
Thread* self = NULL;
…
self = allocThread(gDvm.stackSize);
…
self->jniEnv = dvmCreateJNIEnv(self);
…
gDvm.threadList->next = self;
…
threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);
vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
…
self->threadObj = threadObj;
…
}
完了,就开始注册本地的JNI接口函数了- register_jni_procs(), 这个函数其实就是对一个全局数组gRegJni[] 进行遍历调用,这个数组展开可以得到以下的结果
static const RegJNIRec gRegJNI[] = {
{register_android_debug_JNITest},
{register_com_android_internal_os_RuntimeInit}.
…
}
每个 register_xxx是一个函数指针
int jniRegisterNativeMethods(
C_JNIEnv* env,
const char* className,
const JNINativeMethod* gMethods,
int numMethods);
RegisterNativeMethods 在VM内部到底发生了什么? 同样,这里只需要知道以下几点即可:
gRegJni[]
好了,经过了千辛万苦,Android的运行时环境都已经准备就绪了,让我们再回顾一下AndroidRuntime的初始化都做了哪些工作,
-
创建了Dalvik VM.
-
获取Native 访问Java的两个接口对象,JavaVM 和 JNIENV。
-
注册了一批 (见gRegJni[]) native接口给VM。
这些操作都是相对耗时的工作,如果每个进程都做同样的工作势必会影响到启动速度,这也是为什么我们需要通过Zygote来创建Android 应用,因为通过Linux fork 的 copy_on_write的机制,子进程可以将这些初始化好的内存空间直接映射到自己的进程空间里,不在需要做重复的工作,从而提高了应用启动的速度。
可以是,Android系统只需要基本的运行时环境就够了吗? 答案显然是No。AndriodRuntime 只是提供了语言层面的基础支持,在一个多任务,多用户的图形操作系统上快速的孵化和运行应用程序,我们需要更多。这就是Zygote,这就是为什么在图2中,ZygoteInit会比RuntimeInit做更多的事情。那接下来,让我们真正进入Zygote的世界。
3. ZygoteInit
==============
当VM准备就绪,就可以运行Java代码了,系统也将在此第一次进入Java世界,还记得app_main.cpp里面调到的 Runtime.start()的参数吗, 那就是我们要运行的Java类。Android支持两个类做为起点,一个是‘com.android.internal.os.ZygoteInit’, 另一个是’com.android.internal.os.RuntimeInit’。
此外Runtime_Init 类里还定义了一个ZygoteInit() 静态方法。它在Zygote 创建一个新的应用进程的时候被创建,它和RuntimeInit 类的main() 函数做了以下相同的事情:
-
redirectLogStreams(): 将System.out 和 System.err 输出重定向到Android 的Log系统(定义在 android.util.Log).
-
commonInit(): 初始化了一下系统属性,其中最重要的一点就是设置了一个未捕捉异常的handler,当代码有任何未知异常,就会执行它,调试过Android代码的同学经常看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自这里:
Runtime_init.java
…
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
…
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
// Don’t re-enter – avoid infinite loops if crash-reporting crashes.
if (mCrashing) return;
mCrashing = true;
if (mApplicationObject == null) {
Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
}
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
…
} finally {
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}
接下来,RuntimeInit::main() 和 RuntimeInit::ZygoteInit() 分别调用里nativeFinishInit() 和 nativeZygoteInit(), 由此开始分道扬镳,RuntimeInit 的nativeFinishInit() 最终会调用到 app_main.cpp 里的 onStarted() 函数,里面调用Java类的main() 函数,然后结束进程退出。
virtual void onStarted()