SOURCE version: ANDROID-4.4.4_R2
Tips: Most of the analysis is directly annotated within the code.
Then the previous "analysis" Dalvik virtual machine boot process (i)
JNI_CreateJavaVM
After the function call dvmCreateJNIEnv
creates the jnienv, it then calls the dvmStartup
function to initialize the VM:
/* VM initialization. * VM initialization. Pass in any options provided on the command line. * Do not pass in the class name or the options for the class. * * If successful, an empty string is returned. * Returns 0 on success. * * ARGC: Number of parameters. * argv: Parameter array. */std::string dvmstartup (int argc, const char* const argv[], bool ignoreunrecognized, jnienv* penv) {SCOPEDSHUTD Own Scopedshutdown; ASSERT (gdvm.initializing); ALOGV ("VM init args (%d):", argc); for (int i = 0; i < argc; i++) {ALOGV ("%d: '%s '", I, argv[i]); }//Set default values. Setcommandlinedefaults (); Handles the option flags, if any. /* * 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 the System page size. /* Verify system page Size */if (sysconf (_sc_pagesize)! = system_page_size) {return stringprintf ("expected Pag E size %d, got%d ", system_page_size, (int) sysconf (_sc_pagesize)); }//Verify constants for the MTERP interpreter. /* MTERP Setup */ALOGV ("Using executionmode%d", gdvm.executionmode); Dvmcheckasmconstants (); Initializes the component. /* * Initialize components. */Dvmquasiatomicsstartup (); if (!dvmalloctrackerstartup ()) {return "Dvmalloctrackerstartup failed"; } if (!dvmgcstartup ()) {return "Dvmgcstartup failed"; }//initializes the thread. if (!dvmthreadstartup ()) {return "Dvmthreadstartup failed"; } ......}
the Dvmsartup function calls the
dvmThreadStartup
The function initializes the thread, which is the function of the
dalvik/vm/Thread.cpp
in the file:
/* * Initialize the threads list and the main thread's environment. * We need to set something up and dvmthreadself () will work when we start loading the class. * * Initialize thread list and main thread ' s environment. We need to set * up some basic stuff so dvmthreadself () would work when we start * loading classes (e.g. to check for exceptions). */bool Dvmthreadstartup () {thread* Thread; Allocates a thread-local storage. /* 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-crea Ted Pthread TLS slot is not NULL "); Prepares thread-related locks and conditions. /* 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 (&AMp;gdvm.threadsuspendcountcond, NULL); Dedicated to monitoring Thread.Sleep (). /* * Dedicated monitor for Thread.Sleep (). * Todo:change The object* so we don ' t has to expose this * call, and we interact better with JDWP monitor cal Ls. Requires * Deferring the object creation to much later (e.g. final "main" * thread Prep) or until first use. */Gdvm.threadsleepmon = Dvmcreatemonitor (NULL); /* Create thread ID mappings. * The returned bitvector structure can hold data for (Kmaxthreadid +) >> 5 bits, * see below for dvmallocbitvector function description. * * The thread ID of all threads is saved in Gdvm.threadidmap. * If the thread ID is 1, then 1th position 1, if the thread ID is, then 2nd position 1, and so on. * Bit index starting from 0. 0 is reserved as an invalid thread ID. * The thread ID mentioned here is not the same as the return value of Pthread_self (). * * Gettid () is the ID of the thread in the kernel. (Linux uses the process to simulate threads, the Gettid function returns the actual process ID, so the expansion is long ...) * Pthread_self () gets the POSIX thread ID. * So I think that the thread ID within the GDVM.THREADIDMAP represents the thread ID within the Android virtual machine. * * #define KMAXTHREADID ((1 << 16)-1), i.e. 65535 * Kmaxthreadid, indicates the maximum number of thread IDs. */GDVM.THREADIDMAP = Dvmallocbitvector (Kmaxthreadid, false); Dynamically allocates and initializes a thread structure. Thread = Allocthread (gdvm.mainthreadstacksize); if (thread = = NULL) return false; Thread state: Running. /* Switch mode for when we run initializers */thread->status = thread_running; Completes the initialization of a thread structure. /* * 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 ($), #endif return TR UE;}
Dvmallocbitvector function:
/* * Allocate a bit vector with enough space to hold at least the specified * number of bits. * * Expandable: When the bit in Bitvector is finished, whether to expand it. true: Extended. False: Not extended. */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 represents the number of array elements. count = (startbits +) >> 5; Bv->storagesize = count; bv->expandable = expandable; Bv->storage = (u4*) calloc (count, sizeof (U4)); Return BV;}
The Allocthread function dynamically allocates and initializes a thread that functions in the
dalvik/vm/Thread.cpp
in the file:
/* * Assign and initialize a thread structure. * Alloc and initialize a Thread struct. * * Don't create any objects, ... * Does not created any objects, just stuff on the system (malloc) heap. */static thread* allocthread (int interpstacksize) { thread* Thread; U1* Stackbottom; Allocates memory from the heap to the thread structure. 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;}
The Preparethread function completes the initialization of a thread structure, which is
dalvik/vm/Thread.cpp
in the file:
/* * Complete initialization of a thread structure. * Finish initialization of a Thread struct. * * The call must be executed in the new thread at the same time, but the thread is added before the list of threads. * This must was called while executing in the new thread, but before the * thread was added to the thread list. * * Note: Threadlistlock must be maintained by the caller (requires Assignthreadid ()). * Note:the Threadlistlock must is held by the caller (needed for * ASSIGNTHREADID ()). */static bool Preparethread (thread* thread) {assignthreadid (thread);//assigns a thread ID. In fact, it is for thread->threadid assignment. Thread->handle = Pthread_self (); Thread->systemtid = Dvmgetsysthreadid (); Alogi ("SYSTEM TID is%d (PID is%d)", (int) Thread->systemtid,//(int) getpid ()); Sets the thread to local storage of threads. If we call through Dvmattachcurrentthread, the self value has been correctly "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); ......}
The assignthreadid function assigns a thread ID to the threads structure, which is different from the thread ID returned by the Gettid and pthread_self functions, and I think this thread ID represents the thread ID of the thread in the Dalvik virtual machine. This function is
dalvik/vm/Thread.cpp
in the file:
/* Assign a thread ID. This requires ... * Assign the threadId. This needs to is a small integer so, our * "thin" locks fit in a small number of bits. * We reserve 0 as an invalid ID. * We Reserve zero for use as an invalid ID. * * This must is called with Threadlistlock held. */static void Assignthreadid (thread* thread) { //assigns one to thread ID in Threadidmap. The returned (num+1) represents the thread ID. / * Find a small unique integer. Threadidmap is a vector of * kmaxthreadid bits; Dvmallocbit () returns the index of a * bit, meaning that it'll 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);}
The dvmallocbit function is a function that actually assigns the thread ID, and the function
dalvik/vm/BitVector.cpp
in the file:
/span>
/* * Assign the first available bit in the bitmap. * "Allocate" the first-available bit in the bitmap. * * This is out of sync. The caller is expected to hold some kind of lock to prevent multiple threads from executing concurrently at Dvmallocbit/dvmfreebit. * This was not synchronized. The caller is expected to hold some sort of * lock this prevents multiple threads from executing simultaneously in * dvmal Locbit/dvmfreebit. */int dvmallocbit (bitvector* pbits) {unsigned int word, bit;retry:for (word = 0; Word < pbits->storagesize; W ord++) {//0xFFFFFFFF for 32-bit mean position is 1. if (Pbits->storage[word]! = 0xFFFFFFFF) {/* * There is a bit in word that is not yet assigned. Returns the first unassigned bit found. * There is unallocated bits in this word. Return to the first. */bit = FFS (~ (Pbits->storage[word]))-1; ASSERT (Bit < 32); Pbits->storage[word] |= 1 << bit; For unassigned position 1. (Word << 5) = word * 2^5 = word * 32. Return (Word << 5) | Bit Returns the first digit of the position. }}//If the bits are exhausted, then make the following decision to decide whether to expand. /* * Ran out of space, allocate + 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;}
parameters in the above function
pBits
is actually
gDvm.threadIdMap
, about Gdvm.threadidmap can refer to the above
dvmThreadStartup
the relevant description in the function.
"Analysis" Dalvik virtual machine boot process (ii)