最近因工作需要,阅读了一些Dalvik虚拟机代码,整理输出一波。本文整理Dalvik虚拟机在启动流程和初始化流程,为下篇分析Dalvik的内存分配流程和gc流程打一个基础。
本系列代码均基于4.4.2分析。
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
AppRuntime runtime;
// 解析参数
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
} else if (className) {
runtime.mClassName = className;
runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool");
}
}
// Start the Android runtime.
void AndroidRuntime::start(const char* className, const char* 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) {
return;
}
}
// Start the Dalvik Virtual Machine.
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) {
// 拼接一大堆虚拟机初始化参数
// adb shell getprop | grep dalvik 通过该命令可以查看一些
/*
* 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:
free(stackTraceFile);
return result;
}
libnativehelper/JniInvocation.cpp
4.x的代码里获取libdvm.so,再获取到JNI_CreateJavaVM、JNI_GetCreatedJavaVMs等的实现。
#ifdef HAVE_ANDROID_OS
static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib";
#endif
static const char* kLibraryFallback = "libdvm.so";
bool JniInvocation::Init(const char* library) {
#ifdef HAVE_ANDROID_OS
char default_library[PROPERTY_VALUE_MAX];
property_get(kLibrarySystemProperty, default_library, kLibraryFallback);
#else
const char* default_library = kLibraryFallback;
#endif
if (library == NULL) {
library = default_library;
}
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;
}
dalvik/vm/Jni.cpp
/*
* Create a new VM instance.
*
* The current thread becomes the main VM thread. We return immediately,
* which effectively means the caller is executing in a native method.
*/
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
// 初始化gDvm全局变量
memset(&gDvm, 0, sizeof(gDvm));
// 初始化JavaVmExt
JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
pVM->funcTable = &gInvokeInterface; // jni表
// Create a JNIEnv for the main thread.
JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
// 启动虚拟机
dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
return JNI_OK;
}
在dalvik/vm/Init.cpp中做Dalvik虚拟机初始化操作。
/*
* VM initialization. Pass in any options provided on the command line.
* Do not pass in the class name or the options for the class.
*
* Returns 0 on success.
*/
std::string dvmStartup(int argc, const char* const argv[], bool ignoreUnrecognized, JNIEnv* pEnv) {
/*
* Initialize components.
*/
// 初始化Davlik的内存分配记录模块AllocTracker。
dvmAllocTrackerStartup();
// 初始化Dalvik的垃圾回收模块。内部包含堆初始化
dvmGcStartup();
// 初始化Davlik的线程管理模块。Dalvik线程就是Linux的线程,线程管理模块只是用Thread类来记录Dalvik与线程相关的数据。所有Thread类会形成一个链表。这里除了初始化链表外,还会为主线程创建一个Thread类,并把它加入到链表中。
dvmThreadStartup();
// 初始化Davlik的内部native函数模块
dvmInlineNativeStartup();
// 初始化Dalvik的寄存器映射模块Register Map
dvmRegisterMapStartup();
// 初始化Dalvik的instanceof操作符缓存模块
dvmInstanceofStartup();
// 初始化Dalvik的类装载模块,类装载模块主要负责装载和查找Java类
dvmClassStartup();
// 初始化gDvm中定义的所有Java关键字的类
dvmFindRequiredClassesAndMembers()
// 初始化Dalvik的常量字符串模块。Dalvik在装载类时,会把类中定义的各种字符串都放入gDvm的两个hash表internedStrings和literalStrings中。Dalvik内部创建相同字符串的对象时只会产生引用而不再创建对象了,这样就能节约重复字符串占用的内存。
dvmStringInternStartup();
// 初始化Dalvik的native函数管理模块
dvmNativeStartup();
// 初始化Dalvik内部类的native函数模块。这个模块定义了所有Dalvik的内部类的native函数表。如DexFile、VMRuntime、DexFile等
dvmInternalNativeStartup();
// 初始化Dalvik的JNI模块。主要是创建了全局引用表和全局弱引用表
dvmJniStartup();
// 这个函数的作用是初始化类java.lang.Class
dvmInitClass();
// 注册com.android.dex.Dex的native方法getDex()。同时装载JNI库libjavacore.so以及libnativehelper.so
registerSystemNatives();
// 。创建一些异常对象,包括OutOfMemoryError、InternalError和NoClassDefFoundError,保存在gDvm中
dvmCreateStockExceptions();
// 执行java.lang.Daemons的start()方法来启动和初始化垃圾回收线程
dvmGcStartupClasses();
// 虚拟机OK了,zygote再继续启动
initZygote();
}
在dalvik/vm/Globals.h头文件中定义,里面参数太多了,列出了如下一般开发涉及的重要变量。
这种变量是全局变量,可以通过dlsys获取到,再获取其内部的参数,在hook时经常用到。
/* global state */
struct DvmGlobals gDvm;
/*
* All fields are initialized to zero.
*
* Storage allocated here must be freed by a subsystem shutdown function.
*/
struct DvmGlobals {
// 几个最基本的jar包的路径。包括core.jar、ext.jar、framework,jar、services.jar和android.policy.jar
char* bootClassPathStr;
// 存放系统jar包的路径。通常为/system/framework
char* classPathStr;
// 堆初始化参数,下篇再讲
size_t heapStartingSize;
size_t heapMaximumSize;
size_t heapGrowthLimit;
bool lowMemoryMode;
double heapTargetUtilization;
size_t heapMinFree;
size_t heapMaxFree;
size_t stackSize;
size_t mainThreadStackSize;
/*
* Loaded classes, hashed by class name. Each entry is a ClassObject*,
* allocated in GC space.
*/
HashTable* loadedClasses;
/* Hash table of strings interned by the user. */
HashTable* internedStrings;
/* Hash table of strings interned by the class loader. */
HashTable* literalStrings;
/*
* Thread list. This always has at least one element in it (main),
* and main is always the first entry.
*/
Thread* threadList;
/*
* JNI global reference table.
*/
IndirectRefTable jniGlobalRefTable;
IndirectRefTable jniWeakGlobalRefTable;
pthread_mutex_t jniGlobalRefLock;
pthread_mutex_t jniWeakGlobalRefLock;
/*
* Native shared library table.
*/
HashTable* nativeLibs;
/*
* GC heap lock. Functions like gcMalloc() acquire this before making
* any changes to the heap. It is held throughout garbage collection.
*/
pthread_mutex_t gcHeapLock;
/*
* Condition variable to queue threads waiting to retry an
* allocation. Signaled after a concurrent GC is completed.
*/
pthread_cond_t gcHeapCond;
/* Opaque pointer representing the heap. */
GcHeap* gcHeap;
/* Monitor list, so we can free them */
/*volatile*/ Monitor* monitorList;
}
extern struct DvmGlobals gDvm;