源码版本:Android-4.4.4_r2
提示:大部分分析直接注释在代码内。
接着上一篇【分析】dalvik虚拟机启动过程(一)
JNI_CreateJavaVM
函数调用dvmCreateJNIEnv
创建JNIEnv后,接着又调用了dvmStartup
函数初始化VM:
/* * VM 初始化。 * 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. * * argc:参数个数。 * argv:参数数组。 */ std::string dvmStartup(int argc, const char* const argv[], bool ignoreUnrecognized, JNIEnv* pEnv) { ScopedShutdown scopedShutdown; assert(gDvm.initializing); ALOGV("VM init args (%d):", argc); for (int i = 0; i < argc; i++) { ALOGV(" %d: '%s'", i, argv[i]); } // 设置默认值。 setCommandLineDefaults(); // 处理选项标志(如果有的话)。 /* * Process the option flags (if any). */ int cc = processOptions(argc, argv, ignoreUnrecognized); if (cc != 0) { if (cc < 0) { dvmFprintf(stderr, "\n"); usage("dalvikvm"); } return "syntax error"; } ...... // 验证系统页大小。 /* verify system page size */ if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) { return StringPrintf("expected page size %d, got %d", SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE)); } // 验证用于mterp解释器的常量。 /* mterp setup */ ALOGV("Using executionMode %d", gDvm.executionMode); dvmCheckAsmConstants(); // 初始化组件。 /* * Initialize components. */ dvmQuasiAtomicsStartup(); if (!dvmAllocTrackerStartup()) { return "dvmAllocTrackerStartup failed"; } if (!dvmGcStartup()) { return "dvmGcStartup failed"; } // 初始化线程。 if (!dvmThreadStartup()) { return "dvmThreadStartup failed"; } ...... }
dvmSartup函数中调用了dvmThreadStartup
函数初始化了线程,这个函数在dalvik/vm/Thread.cpp
文件中:
/* * 初始化线程列表和主线程的环境。 * 我们需要设置一些东西,当我们开始加载类时dvmThreadSelf()将会工作。 * * Initialize thread list and main thread's environment. We need to set * up some basic stuff so that dvmThreadSelf() will work when we start * loading classes (e.g. to check for exceptions). */ bool dvmThreadStartup() { Thread* thread; // 分配一个线程局部存储。 /* allocate a TLS slot */ if (pthread_key_create(&gDvm.pthreadKeySelf, threadExitCheck) != 0) { ALOGE("ERROR: pthread_key_create failed"); return false; } /* test our pthread lib */ if (pthread_getspecific(gDvm.pthreadKeySelf) != NULL) ALOGW("WARNING: newly-created pthread TLS slot is not NULL"); // 准备与线程相关的锁和条件。 /* prep thread-related locks and conditions */ dvmInitMutex(&gDvm.threadListLock); pthread_cond_init(&gDvm.threadStartCond, NULL); pthread_cond_init(&gDvm.vmExitCond, NULL); dvmInitMutex(&gDvm._threadSuspendLock); dvmInitMutex(&gDvm.threadSuspendCountLock); pthread_cond_init(&gDvm.threadSuspendCountCond, NULL); // 专用于监听Thread.sleep()。 // /* * Dedicated monitor for Thread.sleep(). * TODO: change this to an Object* so we don't have to expose this * call, and we interact better with JDWP monitor calls. Requires * deferring the object creation to much later (e.g. final "main" * thread prep) or until first use. */ gDvm.threadSleepMon = dvmCreateMonitor(NULL); /* 创建线程Id映射。 * 返回的BitVector结构可以保存的数据为 (kMaxThreadId + 31) >> 5 个位, * 详见下面的dvmAllocBitVector函数说明。 * * gDvm.threadIdMap中保存所有线程的线程Id。 * 如果线程Id为1,那么第1位置1,如果线程Id为而,则第2位置1,以此类推。 * 位索引从0开始。保留0作为无效的线程Id。 * 这里所说的线程Id,与pthread_self()的返回值不是一回事。 * * gettid()是内核中的线程的ID。(linux使用进程模拟线程,gettid 函数返回实际的进程ID,这么展开话就长了……) * pthread_self()获取的是POSIX thread ID。 * 所以我认为,gDvm.threadIdMap内的线程Id,代表的是Android虚拟机内的线程Id。 * * #define kMaxThreadId ((1 << 16) - 1),即65535 * kMaxThreadId表示线程id的最大个数。 */ gDvm.threadIdMap = dvmAllocBitVector(kMaxThreadId, false); // 动态分配和初始化一个Thread结构。 thread = allocThread(gDvm.mainThreadStackSize); if (thread == NULL) return false; // 线程状态:正在运行。 /* switch mode for when we run initializers */ thread->status = THREAD_RUNNING; // 完成一个Thread结构的初始化。 /* * We need to assign the threadId early so we can lock/notify * object monitors. We'll set the "threadObj" field later. */ prepareThread(thread); gDvm.threadList = thread; #ifdef COUNT_PRECISE_METHODS gDvm.preciseMethods = dvmPointerSetAlloc(200); #endif return true; }
dvmAllocBitVector函数:
/* * Allocate a bit vector with enough space to hold at least the specified * number of bits. * * expandable:当BitVector中的位使用完以后,是否扩展。true:扩展。false:不扩展。 */ BitVector* dvmAllocBitVector(unsigned int startBits, bool expandable) { BitVector* bv; unsigned int count; assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */ bv = (BitVector*) malloc(sizeof(BitVector)); // count代表数组元素个数。 count = (startBits + 31) >> 5; bv->storageSize = count; bv->expandable = expandable; bv->storage = (u4*) calloc(count, sizeof(u4)); return bv; }
allocThread函数动态分配和初始化一个Thread,这个函数在dalvik/vm/Thread.cpp
文件中:
/* * 分配和初始化一个线程结构。 * Alloc and initialize a Thread struct. * * 不要创建任何对象,...... * Does not create any objects, just stuff on the system (malloc) heap. */ static Thread* allocThread(int interpStackSize) { Thread* thread; u1* stackBottom; // 从堆中分配内存给Thread结构。 thread = (Thread*) calloc(1, sizeof(Thread)); if (thread == NULL) return NULL; /* Check sizes and alignment */ assert((((uintptr_t)&thread->interpBreak.all) & 0x7) == 0); assert(sizeof(thread->interpBreak) == sizeof(thread->interpBreak.all)); ...... return thread; }
prepareThread函数完成一个Thread结构的初始化,这个函数在dalvik/vm/Thread.cpp
文件中:
/* * 完成一个Thread结构的初始化。 * Finish initialization of a Thread struct. * * 必须同时在新的线程中执行调用,但是在线程被添加到线程列表之前。 * This must be called while executing in the new thread, but before the * thread is added to the thread list. * * 注意:threadListLock必须由调用者维护(需要assignThreadId())。 * NOTE: The threadListLock must be held by the caller (needed for * assignThreadId()). */ static bool prepareThread(Thread* thread) { assignThreadId(thread); // 分配一个线程Id。其实就是为thread->threadId赋值。 thread->handle = pthread_self(); thread->systemTid = dvmGetSysThreadId(); //ALOGI("SYSTEM TID IS %d (pid is %d)", (int) thread->systemTid, // (int) getpid()); // 将thread设置到线程局部存储。 // 如果我们通过 dvmAttachCurrentThread 调用,self值已经正确的成为"thread"。 /* * If we were called by dvmAttachCurrentThread, the self value is * already correctly established as "thread". */ setThreadSelf(thread); ALOGV("threadid=%d: interp stack at %p", thread->threadId, thread->interpStackStart - thread->interpStackSize); ...... }
assignThreadId函数为Thread结构分配了一个线程Id,这个线程Id与gettid和pthread_self函数返回的线程Id不同,我认为这个线程Id代表这个线程在dalvik虚拟机内的线程Id,这个函数在dalvik/vm/Thread.cpp
文件中:
/* * 分配一个线程ID。这需要... * Assign the threadId. This needs to be a small integer so that our * "thin" locks fit in a small number of bits. * * 我们保留零用作无效的ID。 * We reserve zero for use as an invalid ID. * * This must be called with threadListLock held. */ static void assignThreadId(Thread* thread) { // 在threadIdMap中为线程Id分配一位。返回的(num+1)代表线程Id。 /* * Find a small unique integer. threadIdMap is a vector of * kMaxThreadId bits; dvmAllocBit() returns the index of a * bit, meaning that it will always be < kMaxThreadId. */ int num = dvmAllocBit(gDvm.threadIdMap); if (num < 0) { ALOGE("Ran out of thread IDs"); dvmAbort(); // TODO: make this a non-fatal error result } thread->threadId = num + 1; assert(thread->threadId != 0); }
dvmAllocBit函数是实际分配线程Id的函数,这个函数在dalvik/vm/BitVector.cpp
文件中:
/* * 分配bitmap中第一个可用的位。 * "Allocate" the first-available bit in the bitmap. * * 这是不同步的。调用者被期望持有某种锁,以防止多个线程在dvmAllocBit/ dvmFreeBit同时执行。 * This is not synchronized. The caller is expected to hold some sort of * lock that prevents multiple threads from executing simultaneously in * dvmAllocBit/dvmFreeBit. */ int dvmAllocBit(BitVector* pBits) { unsigned int word, bit; retry: for (word = 0; word < pBits->storageSize; word++) { // 0xffffffff代表32位均置位为1。 if (pBits->storage[word] != 0xffffffff) { /* * 在word中有一个位还未分配。返回找到的第一个未分配的位。 * There are unallocated bits in this word. Return the first. */ bit = ffs(~(pBits->storage[word])) -1; assert(bit < 32); pBits->storage[word] |= 1 << bit; // 对未分配的位置1。 // (word << 5) => word * 2^5 => word * 32。 return (word << 5) | bit; // 返回第几位被置位。 } } // 如果位都用完了,那么进行下面的判断来决定是否扩展。 /* * Ran out of space, allocate more if we're allowed to. */ if (!pBits->expandable) return -1; pBits->storage = (u4*)realloc(pBits->storage, (pBits->storageSize + kBitVectorGrowth) * sizeof(u4)); memset(&pBits->storage[pBits->storageSize], 0x00, kBitVectorGrowth * sizeof(u4)); pBits->storageSize += kBitVectorGrowth; goto retry; }
上面函数中参数pBits
其实是gDvm.threadIdMap
,关于gDvm.threadIdMap可以参考上面dvmThreadStartup
函数中相关的介绍。
时间: 2024-10-05 12:49:29