Dalvik                                                           (1)                                 @kishima             ...
(            )                Zygote                     fork                VM                     dex                   ...
dalvik/                 dalvikvm/                   DalvikVM main()                 dexdump/                  dex         ...
dalvik/            vm/             alloc/                 GC                analysis/                arch/                ...
Zygote       init.rc       service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-       serv...
Zygote  frameworks/base/cmds/app_process/app_main.cpp   int main(int argc, const char* const argv[])   {   ---            ...
Zygote  frameworks/base/core/jni/AndroidRuntime.cpp       /*        * Start the Android runtime. This involves starting th...
Zygote                                       AndroidRuntime.cpp                   JNI       frameworks/base/core/java/com/...
dvz                dalvik/dvz                int main (int argc, const char **argv) {                ---                  ...
system/core/libcutils/zygote.c       static int send_request(int fd, int sendStdio, int argc, const char **argv)       {  ...
VM frameworks/base/core/jni/AndroidRuntime.cpp       int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)       { ...
VM       dalvik/vm/Jni.c           jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)             VM     ...
VM           JavaVM             VM                libnativehelper/include/nativehelper/jni.h                struct JNIInvo...
VM                struct JavaVMExt;                typedef struct JNIEnvExt {                   const struct JNINativeInte...
dex                         1       dalvik/vm/JarFile.c       /*                                                          ...
dex                              2             dalvik/vm/JarFile.c                  /*                                    ...
dex                             3           dalvik/vm/JarFile.c       ---               /*                * Map the cached...
dex           dalvik/vm/analysis/DexPrepare.c  /*                                                                         ...
dex           dalvik/vm/analysis/DexPrepare.c bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,     const c...
1(   )       dalvik/        vm/         mterp/                gen-mterp.py                config-xxx              xxx      ...
dalvik/vm/mterp/out/InterpC-portstd.c                                                                             (     C ...
(              )                Zygote                 fork                dexopt                VM        ->fork->dex    ...
Upcoming SlideShare
Loading in...5
×

Dalvik Source Code Reading

5,064

Published on

横浜AndroidPF部で発表しようとして、できなかったときの資料です。
http://silentworlds.info/pukiwiki/?%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E3%83%AA%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
5,064
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
77
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Dalvik Source Code Reading

  1. 1. Dalvik (1) @kishima http://silentworlds.info/ 2011/6/5 AndroidPF ( )2011 6 12 1
  2. 2. ( ) Zygote fork VM dex dexopt2011 6 12 2
  3. 3. dalvik/ dalvikvm/ DalvikVM main() dexdump/ dex dexlist/ frameworks/base/cmds/app_process/ ? dexopt/ Zygote(system-server) dex dex docs/ dvz/ zygote system/core/libcutils/zygote.c dx/ zygote dex hit/ ? libdex/ dex (vm ) libnativehelper/ ? tests/ tools/ vm/ VM2011 6 12 3
  4. 4. dalvik/ vm/ alloc/ GC analysis/ arch/ compiler/ JIT hprof/ interp/ mterp jdwp/ mterp/ native/ JNI oo/ reflect/ test/ VM2011 6 12 4
  5. 5. Zygote init.rc service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system- server2011 6 12 5
  6. 6. Zygote frameworks/base/cmds/app_process/app_main.cpp int main(int argc, const char* const argv[]) { --- init // Next arg is startup classname or "--zygote" if (i < argc) { Zygote arg = argv[i++]; if (0 == strcmp("--zygote", arg)) { bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0 : false; setArgv0(argv0, "zygote"); set_process_name("zygote"); runtime.start("com.android.internal.os.ZygoteInit", startSystemServer); ---2011 6 12 6
  7. 7. Zygote frameworks/base/core/jni/AndroidRuntime.cpp /* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". */ void AndroidRuntime::start(const char* className, const bool startSystemServer) { --- /* start the virtual machine */ VM if (startVm(&mJavaVM, &env) != 0) --- /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ --- “com.android.internal.os.ZygoteInit” startClass = env->FindClass(slashClassName); --- startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); --- env->CallStaticVoidMethod(startClass, startMeth, strArray); --- } JNI Java main2011 6 12 7
  8. 8. Zygote AndroidRuntime.cpp JNI frameworks/base/core/java/com/android/internal/os/ZygoteInit.java public static void main(String argv[]) { if (argv[1].equals("true")) { try { startSystemServer(); VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024); } else if (!argv[1].equals("false")) { throw new RuntimeException(argv[0] + USAGE_STRING); // Start profiling the zygote initialization. } SamplingProfilerIntegration.start(); Log.i(TAG, "Accepting command socket connections"); registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, if (ZYGOTE_FORK_MODE) { SystemClock.uptimeMillis()); runForkMode(); preloadClasses(); PreLoad } else { Fork? preloadResources(); runSelectLoopMode(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, } SystemClock.uptimeMillis()); closeServerSocket(); // Finish profiling the zygote initialization. } catch (MethodAndArgsCaller caller) { SamplingProfilerIntegration.writeZygoteSnapshot(); caller.run(); } catch (RuntimeException ex) { // Do an initial gc to clean up after startup Log.e(TAG, "Zygote died with exception", ex); gc(); closeServerSocket(); throw ex; // If requested, start system server directly from Zygote } if (argv.length != 2) { } throw new RuntimeException(argv[0] + USAGE_STRING); }2011 6 12 8
  9. 9. dvz dalvik/dvz int main (int argc, const char **argv) { --- err = zygote_run_wait(argc - 1, argv + 1, post_run_func); system/core/libcutils/zygote.c int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int)) /dec/socket/zygote { fd = socket_local_client(ZYGOTE_SOCKET, ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL); --- // The command socket is passed to the peer as close-on-exec // and will close when the peer dies zygote newargv[0] = "--peer-wait"; memcpy(newargv + 1, argv, argc * sizeof(*argv)); pid = send_request(fd, 1, argc + 1, newargv); --- }2011 6 12 9
  10. 10. system/core/libcutils/zygote.c static int send_request(int fd, int sendStdio, int argc, const char **argv) { --- struct msghdr msg; --- ret = sendmsg(fd, &msg, MSG_NOSIGNAL); sendmsg --- // replace any newlines with spaces and send the args 1.stdio For (i = 0; i < argc; i++) { --- 2.argv toprint = argv[i]; --- 3.PID ivs[0].iov_base = (char *)toprint; ivs[0].iov_len = strlen(toprint); ( fork PID ivs[1].iov_base = (char *)newline_string; // ”¥n” ) ivs[1].iov_len = 1; msg.msg_iovlen = 2; do { ret = sendmsg(fd, &msg, MSG_NOSIGNAL); } while (ret < 0 && errno == EINTR); --- // Read the pid, as a 4-byte network-order integer ivs[0].iov_base = &pid; --- ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL);2011 6 12 10
  11. 11. VM frameworks/base/core/jni/AndroidRuntime.cpp int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) { --- if (executionMode == kEMIntPortable) { JIT opt.optionString = "-Xint:portable"; mOptions.add(opt); } else if (executionMode == kEMIntFast) { opt.optionString = "-Xint:fast"; mOptions.add(opt); #if defined(WITH_JIT) } else if (executionMode == kEMJitCompiler) { opt.optionString = "-Xint:jit"; mOptions.add(opt); #endif --- /* * 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) { VM --- }2011 6 12 11
  12. 12. VM dalvik/vm/Jni.c jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) VM { /* * Set up structures for JNIEnv and VM. */ pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt)); memset(pVM, 0, sizeof(JavaVMExt)); pVM->funcTable = &gInvokeInterface; pVM->envList = pEnv; --- VM /* set this up before initializing VM, so it can create some JNIEnvs */ gDvm.vmList = (JavaVM*) pVM; ※ /* * Create an env for main thread. We need to have something set up * here because some of the class initialization we do when starting * up the VM will call into native code. */ JNI pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL); --- /* initialize VM */ gDvm.initializing = true; if (dvmStartup(argc, argv, args->ignoreUnrecognized, (JNIEnv*)pEnv) != 0) { --- } --- *p_env = (JNIEnv*) pEnv; *p_vm = (JavaVM*) pVM; --- }2011 6 12 12
  13. 13. VM JavaVM VM libnativehelper/include/nativehelper/jni.h struct JNIInvokeInterface{ jint (*DestroyJavaVM)(JavaVM*); jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*); jint (*DetachCurrentThread)(JavaVM*); jint (*GetEnv)(JavaVM*, void**, jint); jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); } JNIEnv JNI libnativehelper/include/nativehelper/jni.h struct JNINativeInterface{} VM2011 6 12 13
  14. 14. VM struct JavaVMExt; typedef struct JNIEnvExt { const struct JNINativeInterface* funcTable; /* must be first */ const struct JNINativeInterface* baseFuncTable; /* pointer to the VM we are a part of */ struct JavaVMExt* vm; u4 envThreadId; Thread* self; /* if nonzero, we are in a "critical" JNI call */ int critical; /* keep a copy of this here for speed */ bool forceDataCopy; struct JNIEnvExt* prev; struct JNIEnvExt* next; } JNIEnvExt; typedef struct JavaVMExt { const struct JNIInvokeInterface* funcTable; /* must be first */ const struct JNIInvokeInterface* baseFuncTable; /* if multiple VMs are desired, add doubly-linked list stuff here */ /* per-VM feature flags */ bool useChecked; bool warnError; bool forceDataCopy; /* head of list of JNIEnvs associated with this VM */ JNIEnvExt* envList; pthread_mutex_t envListLock; } JavaVMExt;2011 6 12 14
  15. 15. dex 1 dalvik/vm/JarFile.c /* classes.dex * Open a Jar file. Its okay if its just a Zip archive without all of * the Jar trimmings, but we do insist on finding "classes.dex" inside .odex * or an appropriately-named ".odex" file alongside. * * If "isBootstrap" is not set, the optimizer/verifier regards this DEX as * being part of a different class loader. */ int dvmJarFileOpen(const char* fileName, const char* odexOutputName, JarFile** ppJarFile, bool isBootstrap) { --- /* First, look for a ".odex" alongside the jar file. It will * have the same name/path except for the extension. .odex */ fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName); .odex --- /* * Pre-created .odex absent or stale. Look inside the jar for a * "classes.dex". */ classes.dex entry = dexZipFindEntry(&archive, kDexInJarName);2011 6 12 15
  16. 16. dex 2 dalvik/vm/JarFile.c /* classes.dex * Weve found the one we want. See if theres an up-to-date copy * in the cache. * * On return, "fd" will be seeked just past the "opt" header. ( fd opt * * If a stale .odex file is present and classes.dex exists in ) * the archive, this will *not* return an fd pointing to the ( odex * .odex file; the fd will point into dalvik-cache like any classes.dex fd odex * other jar. */ jar ) if (odexOutputName == NULL) { cachedName = dexOptGenerateCacheFileName(fileName, kDexInJarName); --- /* * If fd points to a new file (because there was no cached version, * or the cached version was stale), generate the optimized DEX. * The file descriptor returned is still locked, and is positioned * just past the optimization header. */ if (newFile) { --- DEX result = dvmOptimizeDexFile(fd, dexOffset, dexGetZipEntryUncompLen(&archive, entry), ( odex?) fileName, dexGetZipEntryModTime(&archive, entry), dexGetZipEntryCrc32(&archive, entry), odex isBootstrap); ---2011 6 12 16
  17. 17. dex 3 dalvik/vm/JarFile.c --- /* * Map the cached version. This immediately rewinds the fd, so it * doesnt have to be seeked anywhere in particular. mmap */ if (dvmDexFileOpenFromFd(fd, &pDvmDex) != 0) { seek --- *ppJarFile = (JarFile*) calloc(1, sizeof(JarFile)); (*ppJarFile)->archive = archive; (*ppJarFile)->cacheFileName = cachedName; (*ppJarFile)->pDvmDex = pDvmDex; --- ( ) dalvik/libdex/SysUtil.c } fd dalvik/DvmDex.c dvmDexFileOpenFromFd() (writable read-only) pDvmDex mmap { mmap prot=PROT_READ | PROT_WRITE SHA-1 flags=MAP_FILE | MAP_PRIVATE (copy-on-write) mprotect } PROT_READ2011 6 12 17
  18. 18. dex dalvik/vm/analysis/DexPrepare.c /* fd * Given a descriptor for a file with DEX data in it, produce an * optimized version. * * The file pointed to by "fd" is expected to be a locked shared resource OK * (or private); we make no efforts to enforce multi-process correctness * here. * * "fileName" is only used for debug output. "modWhen" and "crc" are stored * in the dependency set. * bootstrap * The "isBootstrap" flag determines how the optimizer and verifier handle * package-scope access checks. When optimizing, we only load the bootstrap ※ * class DEX files and the target DEX, so the flag determines whether the * target DEX classes are given a (synthetic) non-NULL classLoader pointer. * This only really matters if the target DEX contains classes that claim to * be in the same package as bootstrap classes. dex * * The optimizer will need to load every class in the target DEX file. * This is generally undesirable, so we start a subprocess to do the * work and wait for it to complete. * * Returns "true" on success. All data will have been written to "fd". ※ */ bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength, const char* fileName, u4 modWhen, u4 crc, bool isBootstrap) fd2011 6 12 18
  19. 19. dex dalvik/vm/analysis/DexPrepare.c bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength, const char* fileName, u4 modWhen, u4 crc, bool isBootstrap) { --- pid = fork(); if (pid == 0) { static const int kUseValgrind = 0; static const char* kDexOptBin = "/bin/dexopt"; ※fork static const char* kValgrinder = "/usr/bin/valgrind"; --- strcpy(execFile, androidRoot); dexopt strcat(execFile, kDexOptBin); execv() --- if (kUseValgrind) dexopt execv(kValgrinder, argv); else execv(execFile, argv); --- } else { ※fork --- /* * Wait for the optimization process to finish. We go into VMWAIT * mode here so GC suspension wont have to wait for us. */ VM VMWAIT oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT); ※GC --- } }2011 6 12 19
  20. 20. 1( ) dalvik/ vm/ mterp/ gen-mterp.py config-xxx xxx config-yyy yyy config-portstd rebuild.sh xxx/ xxx xxx yyy/ yyy yyy c/ C out/ OP out2011 6 12 20
  21. 21. dalvik/vm/mterp/out/InterpC-portstd.c ( C ) /* File: portable/entry.c */ * Main interpreter loop. bool INTERP_FUNC_NAME(Thread* self, InterpState* interpState) { #define FETCH(_offset) (pc[(_offset)]) --- #define INST_INST(_inst) ((_inst) & 0xff) /* copy state in */ # define HANDLE_OPCODE(_op) case _op: curMethod = interpState->method; # define ADJUST_PC(_offset) do { pc = interpState->pc; pc += _offset; fp = interpState->fp; EXPORT_EXTRA_PC(); --- } while (false) methodClassDex = curMethod->clazz->pDvmDex; # define FINISH(_offset) { ADJUST_PC(_offset); break; } --- while (1) { --- /* fetch the next 16 bits from the instruction stream */ inst = FETCH(0); switch (INST_INST(inst)) { PC( ) (instruction) --- /* File: c/OP_NOP.c */ HANDLE_OPCODE(OP_NOP) OP FINISH(1); OP_END OP case --- PC --- } JNI2011 6 12 21
  22. 22. ( ) Zygote fork dexopt VM ->fork->dex -> JNI JIT ↓ http://silentworlds.info/pukiwiki/2011 6 12 22
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×