当前位置: 首页 > 工具软件 > Dalvik > 使用案例 >

Android Dalvik虚拟机 启动和初始化

汝承载
2023-12-01

前言

最近因工作需要,阅读了一些Dalvik虚拟机代码,整理输出一波。本文整理Dalvik虚拟机在启动流程和初始化流程,为下篇分析Dalvik的内存分配流程和gc流程打一个基础。
本系列代码均基于4.4.2分析。

Android Rumtime.cpp Jni.cpp init.cpp JNI_CreateJavaVM dvmCreateJNIEnv dvmStartup dvmGcStartup、dvmThreadStartup... initZygote Android Rumtime.cpp Jni.cpp init.cpp

Dalvik启动

zogyte启动app_main.cpp

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");
    }
}

AndroidRuntime.cpp

// 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;
}

JniInvocation.cpp

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;
}

Jni.cpp

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初始化

init.cpp

在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();
}

重要变量gDvm

在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;
 类似资料: