标签(空格分隔): art android5.1 启动流程 jvm
我们都已经知道,Android系统是基于Linux内核,而应用程序大都由Java语言实现的一个操作系统,包含一套C/C++ Framework和Java Framework以及其他的库支持文件和Hal层的一些东西。Android的启动过程也是从/system/core/init/init.c的main函数开始(这里忽略了bootloader的引导以及Linux Kernel的启动)。init.c这个文件做的事情比较多,这里我们只关注和Java层有关的东西。init.c中解析init.rc文件,在init.rc中和Java世界相关的是zygote,它在一个脚本文件中被系统创建出来,如下
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 media
onrestart restart netd
在Linux系统下,app_process是一个bin类型的可执行文件,它的源码在/frameworks/base/cmds/app_process中,其程序入口为main函数。在分析之前,我们先将这个过程的时序图和涉及到的一些类信息简单看看,有个宏观的感知。
时序图如下:
相关类图:
JavaVM:进程相关,每个虚拟机进程有持有一个JavaVM对象
JNIEnv:线程相关,每个虚拟机线程有持有一个JNIEnv对象
Runtime:Java程序运行时环境
Thread:Java Thread对象
Step1: app_process.main (/frameworks/base/cmds/app_process)
由命令行./system/bin/app_process -Xzygote /system/bin –zygote –start-system-server调用。
int main(int argc, char* const argv[])
{
....
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
argc--;
argv++;
int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
runtime.addOption(strdup(argv[i]));
}
....
// Parse runtime arguments. Stop at first unrecognized option.
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
....
if (!className.isEmpty()) {
....
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
...
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}
代码先是创建了一个AppRuntime对象,它继承自AndroidRuntime,构造函数参数分别是命令行字符串的首地址和字符串的总长度,然后将这两个值存放到其父类的成员变量mArgBlockStart和mArgBlockLength中,这里分析下AndroidRuntime成员变量mOptions,相关定义为
Vector<JavaVMOption> mOptions;
typedef struct JavaVMOption {
const char* optionString;
void* extraInfo;
} JavaVMOption;
可知mOptions就是用来保存这些JavaVMOption参数的,其成员函数addOption负责往mOptions中添加元素,main函数中首先将命令行中第一个以”-“开头的字符串加入到mOptions中,这里即是”-Xzygote”,继续解析命令行参数,while循环完成后,此时zygote和startSystemServer为true niceName为“zygote”,表示当前是在zygote模式下,接下来调用maybeCreateDalvikCache方法,创建这个/data/dalvik-cache/x86文件(我这里是x86的架构,还有arm等),存放字节码的缓存文件。接下来设置abi的相关信息,args最终存放的就是[“start-system-server”, “–abi-list=x86”]。此时niceName非空,接下来调用runtime.setArgv0,同时设置当前进程的name为niceName。
void AndroidRuntime::setArgv0(const char* argv0) {
memset(mArgBlockStart, 0, mArgBlockLength);
strlcpy(mArgBlockStart, argv0, mArgBlockLength);
}
这个函数调用memeset清除这块内存区,同时将niceName copy放置到mArgBlockStart的地址空间处。最后由于zygote为true,会进入runtime.start函数,此时args参数为”start-system-server”, “–abi-list=x86”。
Step2: AppRuntime::start (/frameworks/base/core/jni/AndroidRuntime.cpp)
AppRuntime继承至AndroidRuntime,其start方法实现如下:
void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
....
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
这个方法控制了整个启动的流程,主要由以下几步:
->创建JniInvocation,加载art虚拟机so文件(libart.so)。
->调用函数startVM,创建JavaVM和JNIEnv
->注册Android jni方法
->启动到Java世界
下面分段阅读这几个过程。
Step3: JniInvocation::Init (/libnativehelper/JniInvocation.cpp)
该函数中首先获取要加载的library名字,默认是libart.so库文件,并打开这个动态库并解析出所有未定义符号,同时返回动态链接库的句柄给handle_指针变量。接下来继续解析,将JNI_GetDefaultJavaVMInitArgs_、JNI_CreateJavaVM_、JNI_GetCreatedJavaVMs_三个函数指针进行初始化。生成libart.so的源代码位于/art/runtime,其中在jni_internal.cc中定义有这三个函数。
bool JniInvocation::Init(const char* library) {
....
library = GetLibrary(library, buffer);
handle_ = dlopen(library, RTLD_NOW);
....
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
函数执行完毕之后,返回至AndroidRuntime的start,将控制权归还,接着执行start中的startVM函数。
Step4: AndroidRuntime::startVm (/frameworks/base/core/jni/AndroidRuntime.cpp)
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
int result = -1;
JavaVMInitArgs initArgs;
....
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
result = 0;
bail:
return result;
}
这个函数中,通过property_get获取系统属性文件,设置大量关于虚拟机的一些参数信息,addOption、parseExtraOpts、parseRuntimeOption、parseCompilerRuntimeOption这四个函数均是往mOptions这个容器中添加元素,经过一些列的参数设置,在6-9行将mOptions信息保存至结构体initArgs中,initArgs是一个JavaVMInitArgs结构体对象
typedef struct JavaVMInitArgs {
jint version; /* use JNI_VERSION_1_2 or later */
jint nOptions;
JavaVMOption* options;
jboolean ignoreUnrecognized;
} JavaVMInitArgs;
继续往下,接着调用JNI_CreateJavaVM去进一步创建JavaVM对象。
Step5: JniInvocation.JNI_CreateJavaVM (/libnativehelper/JniInvocation.cpp)
extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
}
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)