OSDN Git Service

Merge "More consistent JNI error reporting."
[android-x86/dalvik.git] / vm / Init.cpp
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Dalvik initialization, shutdown, and command-line argument processing.
19  */
20 #define __STDC_LIMIT_MACROS
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <signal.h>
24 #include <limits.h>
25 #include <ctype.h>
26 #include <sys/mount.h>
27 #include <sys/wait.h>
28 #include <linux/fs.h>
29 #include <cutils/fs.h>
30 #include <unistd.h>
31 #ifdef HAVE_ANDROID_OS
32 #include <sys/prctl.h>
33 #endif
34
35 #include "Dalvik.h"
36 #include "test/Test.h"
37 #include "mterp/Mterp.h"
38 #include "Hash.h"
39 #include "JniConstants.h"
40
41 #if defined(WITH_JIT)
42 #include "compiler/codegen/Optimizer.h"
43 #endif
44
45 #define kMinHeapStartSize   (1*1024*1024)
46 #define kMinHeapSize        (2*1024*1024)
47 #define kMaxHeapSize        (1*1024*1024*1024)
48
49 /*
50  * Register VM-agnostic native methods for system classes.
51  */
52 extern int jniRegisterSystemMethods(JNIEnv* env);
53
54 /* fwd */
55 static bool registerSystemNatives(JNIEnv* pEnv);
56 static bool initJdwp();
57 static bool initZygote();
58
59
60 /* global state */
61 struct DvmGlobals gDvm;
62 struct DvmJniGlobals gDvmJni;
63
64 /* JIT-specific global state */
65 #if defined(WITH_JIT)
66 struct DvmJitGlobals gDvmJit;
67
68 #if defined(WITH_JIT_TUNING)
69 /*
70  * Track the number of hits in the inline cache for predicted chaining.
71  * Use an ugly global variable here since it is accessed in assembly code.
72  */
73 int gDvmICHitCount;
74 #endif
75
76 #endif
77
78 /*
79  * Show usage.
80  *
81  * We follow the tradition of unhyphenated compound words.
82  */
83 static void usage(const char* progName)
84 {
85     dvmFprintf(stderr, "%s: [options] class [argument ...]\n", progName);
86     dvmFprintf(stderr, "%s: [options] -jar file.jar [argument ...]\n",progName);
87     dvmFprintf(stderr, "\n");
88     dvmFprintf(stderr, "The following standard options are recognized:\n");
89     dvmFprintf(stderr, "  -classpath classpath\n");
90     dvmFprintf(stderr, "  -Dproperty=value\n");
91     dvmFprintf(stderr, "  -verbose:tag  ('gc', 'jni', or 'class')\n");
92     dvmFprintf(stderr, "  -ea[:<package name>... |:<class name>]\n");
93     dvmFprintf(stderr, "  -da[:<package name>... |:<class name>]\n");
94     dvmFprintf(stderr, "   (-enableassertions, -disableassertions)\n");
95     dvmFprintf(stderr, "  -esa\n");
96     dvmFprintf(stderr, "  -dsa\n");
97     dvmFprintf(stderr,
98                 "   (-enablesystemassertions, -disablesystemassertions)\n");
99     dvmFprintf(stderr, "  -showversion\n");
100     dvmFprintf(stderr, "  -help\n");
101     dvmFprintf(stderr, "\n");
102     dvmFprintf(stderr, "The following extended options are recognized:\n");
103     dvmFprintf(stderr, "  -Xrunjdwp:<options>\n");
104     dvmFprintf(stderr, "  -Xbootclasspath:bootclasspath\n");
105     dvmFprintf(stderr, "  -Xcheck:tag  (e.g. 'jni')\n");
106     dvmFprintf(stderr, "  -XmsN  (min heap, must be multiple of 1K, >= 1MB)\n");
107     dvmFprintf(stderr, "  -XmxN  (max heap, must be multiple of 1K, >= 2MB)\n");
108     dvmFprintf(stderr, "  -XssN  (stack size, >= %dKB, <= %dKB)\n",
109         kMinStackSize / 1024, kMaxStackSize / 1024);
110     dvmFprintf(stderr, "  -Xverify:{none,remote,all}\n");
111     dvmFprintf(stderr, "  -Xrs\n");
112 #if defined(WITH_JIT)
113     dvmFprintf(stderr,
114                 "  -Xint  (extended to accept ':portable', ':fast' and ':jit')\n");
115 #else
116     dvmFprintf(stderr,
117                 "  -Xint  (extended to accept ':portable' and ':fast')\n");
118 #endif
119     dvmFprintf(stderr, "\n");
120     dvmFprintf(stderr, "These are unique to Dalvik:\n");
121     dvmFprintf(stderr, "  -Xzygote\n");
122     dvmFprintf(stderr, "  -Xdexopt:{none,verified,all,full}\n");
123     dvmFprintf(stderr, "  -Xnoquithandler\n");
124     dvmFprintf(stderr, "  -Xjniopts:{warnonly,forcecopy}\n");
125     dvmFprintf(stderr, "  -Xjnitrace:substring (eg NativeClass or nativeMethod)\n");
126     dvmFprintf(stderr, "  -Xstacktracefile:<filename>\n");
127     dvmFprintf(stderr, "  -Xgc:[no]precise\n");
128     dvmFprintf(stderr, "  -Xgc:[no]preverify\n");
129     dvmFprintf(stderr, "  -Xgc:[no]postverify\n");
130     dvmFprintf(stderr, "  -Xgc:[no]concurrent\n");
131     dvmFprintf(stderr, "  -Xgc:[no]verifycardtable\n");
132     dvmFprintf(stderr, "  -XX:+DisableExplicitGC\n");
133     dvmFprintf(stderr, "  -X[no]genregmap\n");
134     dvmFprintf(stderr, "  -Xverifyopt:[no]checkmon\n");
135     dvmFprintf(stderr, "  -Xcheckdexsum\n");
136 #if defined(WITH_JIT)
137     dvmFprintf(stderr, "  -Xincludeselectedop\n");
138     dvmFprintf(stderr, "  -Xjitop:hexopvalue[-endvalue]"
139                        "[,hexopvalue[-endvalue]]*\n");
140     dvmFprintf(stderr, "  -Xincludeselectedmethod\n");
141     dvmFprintf(stderr, "  -Xjitthreshold:decimalvalue\n");
142     dvmFprintf(stderr, "  -Xjitblocking\n");
143     dvmFprintf(stderr, "  -Xjitmethod:signature[,signature]* "
144                        "(eg Ljava/lang/String\\;replace)\n");
145     dvmFprintf(stderr, "  -Xjitclass:classname[,classname]*\n");
146     dvmFprintf(stderr, "  -Xjitoffset:offset[,offset]\n");
147     dvmFprintf(stderr, "  -Xjitconfig:filename\n");
148     dvmFprintf(stderr, "  -Xjitcheckcg\n");
149     dvmFprintf(stderr, "  -Xjitverbose\n");
150     dvmFprintf(stderr, "  -Xjitprofile\n");
151     dvmFprintf(stderr, "  -Xjitdisableopt\n");
152     dvmFprintf(stderr, "  -Xjitsuspendpoll\n");
153 #endif
154     dvmFprintf(stderr, "\n");
155     dvmFprintf(stderr, "Configured with:"
156         " debugger"
157         " profiler"
158         " hprof"
159 #ifdef WITH_TRACKREF_CHECKS
160         " trackref_checks"
161 #endif
162 #ifdef WITH_INSTR_CHECKS
163         " instr_checks"
164 #endif
165 #ifdef WITH_EXTRA_OBJECT_VALIDATION
166         " extra_object_validation"
167 #endif
168 #ifdef WITH_EXTRA_GC_CHECKS
169         " extra_gc_checks"
170 #endif
171 #if !defined(NDEBUG) && defined(WITH_DALVIK_ASSERT)
172         " dalvik_assert"
173 #endif
174 #ifdef WITH_JNI_STACK_CHECK
175         " jni_stack_check"
176 #endif
177 #ifdef EASY_GDB
178         " easy_gdb"
179 #endif
180 #ifdef CHECK_MUTEX
181         " check_mutex"
182 #endif
183 #if defined(WITH_JIT)
184         " jit(" ARCH_VARIANT ")"
185 #endif
186 #if defined(WITH_SELF_VERIFICATION)
187         " self_verification"
188 #endif
189 #if ANDROID_SMP != 0
190         " smp"
191 #endif
192     );
193 #ifdef DVM_SHOW_EXCEPTION
194     dvmFprintf(stderr, " show_exception=%d", DVM_SHOW_EXCEPTION);
195 #endif
196     dvmFprintf(stderr, "\n\n");
197 }
198
199 /*
200  * Show helpful information on JDWP options.
201  */
202 static void showJdwpHelp()
203 {
204     dvmFprintf(stderr,
205         "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n");
206     dvmFprintf(stderr,
207         "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
208 }
209
210 /*
211  * Show version and copyright info.
212  */
213 static void showVersion()
214 {
215     dvmFprintf(stdout, "DalvikVM version %d.%d.%d\n",
216         DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
217     dvmFprintf(stdout,
218         "Copyright (C) 2007 The Android Open Source Project\n\n"
219         "This software is built from source code licensed under the "
220         "Apache License,\n"
221         "Version 2.0 (the \"License\"). You may obtain a copy of the "
222         "License at\n\n"
223         "     http://www.apache.org/licenses/LICENSE-2.0\n\n"
224         "See the associated NOTICE file for this software for further "
225         "details.\n");
226 }
227
228 /*
229  * Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
230  * memory sizes.  [kK] indicates kilobytes, [mM] megabytes, and
231  * [gG] gigabytes.
232  *
233  * "s" should point just past the "-Xm?" part of the string.
234  * "min" specifies the lowest acceptable value described by "s".
235  * "div" specifies a divisor, e.g. 1024 if the value must be a multiple
236  * of 1024.
237  *
238  * The spec says the -Xmx and -Xms options must be multiples of 1024.  It
239  * doesn't say anything about -Xss.
240  *
241  * Returns 0 (a useless size) if "s" is malformed or specifies a low or
242  * non-evenly-divisible value.
243  */
244 static size_t parseMemOption(const char* s, size_t div)
245 {
246     /* strtoul accepts a leading [+-], which we don't want,
247      * so make sure our string starts with a decimal digit.
248      */
249     if (isdigit(*s)) {
250         const char* s2;
251         size_t val;
252
253         val = strtoul(s, (char* *)&s2, 10);
254         if (s2 != s) {
255             /* s2 should be pointing just after the number.
256              * If this is the end of the string, the user
257              * has specified a number of bytes.  Otherwise,
258              * there should be exactly one more character
259              * that specifies a multiplier.
260              */
261             if (*s2 != '\0') {
262                 char c;
263
264                 /* The remainder of the string is either a single multiplier
265                  * character, or nothing to indicate that the value is in
266                  * bytes.
267                  */
268                 c = *s2++;
269                 if (*s2 == '\0') {
270                     size_t mul;
271
272                     if (c == '\0') {
273                         mul = 1;
274                     } else if (c == 'k' || c == 'K') {
275                         mul = 1024;
276                     } else if (c == 'm' || c == 'M') {
277                         mul = 1024 * 1024;
278                     } else if (c == 'g' || c == 'G') {
279                         mul = 1024 * 1024 * 1024;
280                     } else {
281                         /* Unknown multiplier character.
282                          */
283                         return 0;
284                     }
285
286                     if (val <= SIZE_MAX / mul) {
287                         val *= mul;
288                     } else {
289                         /* Clamp to a multiple of 1024.
290                          */
291                         val = SIZE_MAX & ~(1024-1);
292                     }
293                 } else {
294                     /* There's more than one character after the
295                      * numeric part.
296                      */
297                     return 0;
298                 }
299             }
300
301             /* The man page says that a -Xm value must be
302              * a multiple of 1024.
303              */
304             if (val % div == 0) {
305                 return val;
306             }
307         }
308     }
309
310     return 0;
311 }
312
313 /*
314  * Handle one of the JDWP name/value pairs.
315  *
316  * JDWP options are:
317  *  help: if specified, show help message and bail
318  *  transport: may be dt_socket or dt_shmem
319  *  address: for dt_socket, "host:port", or just "port" when listening
320  *  server: if "y", wait for debugger to attach; if "n", attach to debugger
321  *  timeout: how long to wait for debugger to connect / listen
322  *
323  * Useful with server=n (these aren't supported yet):
324  *  onthrow=<exception-name>: connect to debugger when exception thrown
325  *  onuncaught=y|n: connect to debugger when uncaught exception thrown
326  *  launch=<command-line>: launch the debugger itself
327  *
328  * The "transport" option is required, as is "address" if server=n.
329  */
330 static bool handleJdwpOption(const char* name, const char* value)
331 {
332     if (strcmp(name, "transport") == 0) {
333         if (strcmp(value, "dt_socket") == 0) {
334             gDvm.jdwpTransport = kJdwpTransportSocket;
335         } else if (strcmp(value, "dt_android_adb") == 0) {
336             gDvm.jdwpTransport = kJdwpTransportAndroidAdb;
337         } else {
338             ALOGE("JDWP transport '%s' not supported", value);
339             return false;
340         }
341     } else if (strcmp(name, "server") == 0) {
342         if (*value == 'n')
343             gDvm.jdwpServer = false;
344         else if (*value == 'y')
345             gDvm.jdwpServer = true;
346         else {
347             ALOGE("JDWP option 'server' must be 'y' or 'n'");
348             return false;
349         }
350     } else if (strcmp(name, "suspend") == 0) {
351         if (*value == 'n')
352             gDvm.jdwpSuspend = false;
353         else if (*value == 'y')
354             gDvm.jdwpSuspend = true;
355         else {
356             ALOGE("JDWP option 'suspend' must be 'y' or 'n'");
357             return false;
358         }
359     } else if (strcmp(name, "address") == 0) {
360         /* this is either <port> or <host>:<port> */
361         const char* colon = strchr(value, ':');
362         char* end;
363         long port;
364
365         if (colon != NULL) {
366             free(gDvm.jdwpHost);
367             gDvm.jdwpHost = (char*) malloc(colon - value +1);
368             strncpy(gDvm.jdwpHost, value, colon - value +1);
369             gDvm.jdwpHost[colon-value] = '\0';
370             value = colon + 1;
371         }
372         if (*value == '\0') {
373             ALOGE("JDWP address missing port");
374             return false;
375         }
376         port = strtol(value, &end, 10);
377         if (*end != '\0') {
378             ALOGE("JDWP address has junk in port field '%s'", value);
379             return false;
380         }
381         gDvm.jdwpPort = port;
382     } else if (strcmp(name, "launch") == 0 ||
383                strcmp(name, "onthrow") == 0 ||
384                strcmp(name, "oncaught") == 0 ||
385                strcmp(name, "timeout") == 0)
386     {
387         /* valid but unsupported */
388         ALOGI("Ignoring JDWP option '%s'='%s'", name, value);
389     } else {
390         ALOGI("Ignoring unrecognized JDWP option '%s'='%s'", name, value);
391     }
392
393     return true;
394 }
395
396 /*
397  * Parse the latter half of a -Xrunjdwp/-agentlib:jdwp= string, e.g.:
398  * "transport=dt_socket,address=8000,server=y,suspend=n"
399  */
400 static bool parseJdwpOptions(const char* str)
401 {
402     char* mangle = strdup(str);
403     char* name = mangle;
404     bool result = false;
405
406     /*
407      * Process all of the name=value pairs.
408      */
409     while (true) {
410         char* value;
411         char* comma;
412
413         value = strchr(name, '=');
414         if (value == NULL) {
415             ALOGE("JDWP opts: garbage at '%s'", name);
416             goto bail;
417         }
418
419         comma = strchr(name, ',');      // use name, not value, for safety
420         if (comma != NULL) {
421             if (comma < value) {
422                 ALOGE("JDWP opts: found comma before '=' in '%s'", mangle);
423                 goto bail;
424             }
425             *comma = '\0';
426         }
427
428         *value++ = '\0';        // stomp the '='
429
430         if (!handleJdwpOption(name, value))
431             goto bail;
432
433         if (comma == NULL) {
434             /* out of options */
435             break;
436         }
437         name = comma+1;
438     }
439
440     /*
441      * Make sure the combination of arguments makes sense.
442      */
443     if (gDvm.jdwpTransport == kJdwpTransportUnknown) {
444         ALOGE("JDWP opts: must specify transport");
445         goto bail;
446     }
447     if (!gDvm.jdwpServer && (gDvm.jdwpHost == NULL || gDvm.jdwpPort == 0)) {
448         ALOGE("JDWP opts: when server=n, must specify host and port");
449         goto bail;
450     }
451     // transport mandatory
452     // outbound server address
453
454     gDvm.jdwpConfigured = true;
455     result = true;
456
457 bail:
458     free(mangle);
459     return result;
460 }
461
462 /*
463  * Handle one of the four kinds of assertion arguments.
464  *
465  * "pkgOrClass" is the last part of an enable/disable line.  For a package
466  * the arg looks like "-ea:com.google.fubar...", for a class it looks
467  * like "-ea:com.google.fubar.Wahoo".  The string we get starts at the ':'.
468  *
469  * For system assertions (-esa/-dsa), "pkgOrClass" is NULL.
470  *
471  * Multiple instances of these arguments can be specified, e.g. you can
472  * enable assertions for a package and then disable them for one class in
473  * the package.
474  */
475 static bool enableAssertions(const char* pkgOrClass, bool enable)
476 {
477     AssertionControl* pCtrl = &gDvm.assertionCtrl[gDvm.assertionCtrlCount++];
478     pCtrl->enable = enable;
479
480     if (pkgOrClass == NULL) {
481         /* enable or disable for all system classes */
482         pCtrl->isPackage = false;
483         pCtrl->pkgOrClass = NULL;
484         pCtrl->pkgOrClassLen = 0;
485     } else {
486         if (*pkgOrClass == '\0') {
487             /* global enable/disable for all but system */
488             pCtrl->isPackage = false;
489             pCtrl->pkgOrClass = strdup("");
490             pCtrl->pkgOrClassLen = 0;
491         } else {
492             pCtrl->pkgOrClass = dvmDotToSlash(pkgOrClass+1);    // skip ':'
493             if (pCtrl->pkgOrClass == NULL) {
494                 /* can happen if class name includes an illegal '/' */
495                 ALOGW("Unable to process assertion arg '%s'", pkgOrClass);
496                 return false;
497             }
498
499             int len = strlen(pCtrl->pkgOrClass);
500             if (len >= 3 && strcmp(pCtrl->pkgOrClass + len-3, "///") == 0) {
501                 /* mark as package, truncate two of the three slashes */
502                 pCtrl->isPackage = true;
503                 *(pCtrl->pkgOrClass + len-2) = '\0';
504                 pCtrl->pkgOrClassLen = len - 2;
505             } else {
506                 /* just a class */
507                 pCtrl->isPackage = false;
508                 pCtrl->pkgOrClassLen = len;
509             }
510         }
511     }
512
513     return true;
514 }
515
516 /*
517  * Turn assertions on when requested to do so by the Zygote.
518  *
519  * This is a bit sketchy.  We can't (easily) go back and fiddle with all
520  * of the classes that have already been initialized, so this only
521  * affects classes that have yet to be loaded.  If some or all assertions
522  * have been enabled through some other means, we don't want to mess with
523  * it here, so we do nothing.  Finally, we assume that there's room in
524  * "assertionCtrl" to hold at least one entry; this is guaranteed by the
525  * allocator.
526  *
527  * This must only be called from the main thread during zygote init.
528  */
529 void dvmLateEnableAssertions()
530 {
531     if (gDvm.assertionCtrl == NULL) {
532         ALOGD("Not late-enabling assertions: no assertionCtrl array");
533         return;
534     } else if (gDvm.assertionCtrlCount != 0) {
535         ALOGD("Not late-enabling assertions: some asserts already configured");
536         return;
537     }
538     ALOGD("Late-enabling assertions");
539
540     /* global enable for all but system */
541     AssertionControl* pCtrl = gDvm.assertionCtrl;
542     pCtrl->pkgOrClass = strdup("");
543     pCtrl->pkgOrClassLen = 0;
544     pCtrl->isPackage = false;
545     pCtrl->enable = true;
546     gDvm.assertionCtrlCount = 1;
547 }
548
549
550 /*
551  * Release memory associated with the AssertionCtrl array.
552  */
553 static void freeAssertionCtrl()
554 {
555     int i;
556
557     for (i = 0; i < gDvm.assertionCtrlCount; i++)
558         free(gDvm.assertionCtrl[i].pkgOrClass);
559     free(gDvm.assertionCtrl);
560 }
561
562 #if defined(WITH_JIT)
563 /* Parse -Xjitop to selectively turn on/off certain opcodes for JIT */
564 static void processXjitop(const char* opt)
565 {
566     if (opt[7] == ':') {
567         const char* startPtr = &opt[8];
568         char* endPtr = NULL;
569
570         do {
571             long startValue, endValue;
572
573             startValue = strtol(startPtr, &endPtr, 16);
574             if (startPtr != endPtr) {
575                 /* Just in case value is out of range */
576                 startValue %= kNumPackedOpcodes;
577
578                 if (*endPtr == '-') {
579                     endValue = strtol(endPtr+1, &endPtr, 16);
580                     endValue %= kNumPackedOpcodes;
581                 } else {
582                     endValue = startValue;
583                 }
584
585                 for (; startValue <= endValue; startValue++) {
586                     ALOGW("Dalvik opcode %x is selected for debugging",
587                          (unsigned int) startValue);
588                     /* Mark the corresponding bit to 1 */
589                     gDvmJit.opList[startValue >> 3] |= 1 << (startValue & 0x7);
590                 }
591
592                 if (*endPtr == 0) {
593                     break;
594                 }
595
596                 startPtr = endPtr + 1;
597
598                 continue;
599             } else {
600                 if (*endPtr != 0) {
601                     dvmFprintf(stderr,
602                         "Warning: Unrecognized opcode value substring "
603                         "%s\n", endPtr);
604                 }
605                 break;
606             }
607         } while (1);
608     } else {
609         int i;
610         for (i = 0; i < (kNumPackedOpcodes+7)/8; i++) {
611             gDvmJit.opList[i] = 0xff;
612         }
613         dvmFprintf(stderr, "Warning: select all opcodes\n");
614     }
615 }
616
617 /* Parse -Xjitoffset to selectively turn on/off traces with certain offsets for JIT */
618 static void processXjitoffset(const char* opt) {
619     gDvmJit.num_entries_pcTable = 0;
620     char* buf = strdup(opt);
621     char* start, *end;
622     start = buf;
623     int idx = 0;
624     do {
625         end = strchr(start, ',');
626         if (end) {
627             *end = 0;
628         }
629
630         dvmFprintf(stderr, "processXjitoffset start = %s\n", start);
631         char* tmp = strdup(start);
632         gDvmJit.pcTable[idx++] = atoi(tmp);
633         free(tmp);
634         if (idx >= COMPILER_PC_OFFSET_SIZE) {
635             dvmFprintf(stderr, "processXjitoffset: ignore entries beyond %d\n", COMPILER_PC_OFFSET_SIZE);
636             break;
637         }
638         if (end) {
639             start = end + 1;
640         } else {
641             break;
642         }
643     } while (1);
644     gDvmJit.num_entries_pcTable = idx;
645     free(buf);
646 }
647
648 /* Parse -Xjitmethod to selectively turn on/off certain methods for JIT */
649 static void processXjitmethod(const char* opt, bool isMethod) {
650     char* buf = strdup(opt);
651
652     if (isMethod && gDvmJit.methodTable == NULL) {
653         gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
654     }
655     if (!isMethod && gDvmJit.classTable == NULL) {
656         gDvmJit.classTable = dvmHashTableCreate(8, NULL);
657     }
658
659     char* start = buf;
660     char* end;
661     /*
662      * Break comma-separated method signatures and enter them into the hash
663      * table individually.
664      */
665     do {
666         int hashValue;
667
668         end = strchr(start, ',');
669         if (end) {
670             *end = 0;
671         }
672
673         hashValue = dvmComputeUtf8Hash(start);
674         dvmHashTableLookup(isMethod ? gDvmJit.methodTable : gDvmJit.classTable,
675                            hashValue, strdup(start), (HashCompareFunc) strcmp, true);
676
677         if (end) {
678             start = end + 1;
679         } else {
680             break;
681         }
682     } while (1);
683     free(buf);
684 }
685
686 /* The format of jit_config.list:
687    EXCLUDE or INCLUDE
688    CLASS
689    prefix1 ...
690    METHOD
691    prefix 1 ...
692    OFFSET
693    index ... //each pair is a range, if pcOff falls into a range, JIT
694 */
695 static int processXjitconfig(const char* opt) {
696    FILE* fp = fopen(opt, "r");
697    if (fp == NULL) {
698        return -1;
699    }
700
701    char fLine[500];
702    bool startClass = false, startMethod = false, startOffset = false;
703    gDvmJit.num_entries_pcTable = 0;
704    int idx = 0;
705
706    while (fgets(fLine, 500, fp) != NULL) {
707        char* curLine = strtok(fLine, " \t\r\n");
708        /* handles keyword CLASS, METHOD, INCLUDE, EXCLUDE */
709        if (!strncmp(curLine, "CLASS", 5)) {
710            startClass = true;
711            startMethod = false;
712            startOffset = false;
713            continue;
714        }
715        if (!strncmp(curLine, "METHOD", 6)) {
716            startMethod = true;
717            startClass = false;
718            startOffset = false;
719            continue;
720        }
721        if (!strncmp(curLine, "OFFSET", 6)) {
722            startOffset = true;
723            startMethod = false;
724            startClass = false;
725            continue;
726        }
727        if (!strncmp(curLine, "EXCLUDE", 7)) {
728           gDvmJit.includeSelectedMethod = false;
729           continue;
730        }
731        if (!strncmp(curLine, "INCLUDE", 7)) {
732           gDvmJit.includeSelectedMethod = true;
733           continue;
734        }
735        if (!startMethod && !startClass && !startOffset) {
736          continue;
737        }
738
739         int hashValue = dvmComputeUtf8Hash(curLine);
740         if (startMethod) {
741             if (gDvmJit.methodTable == NULL) {
742                 gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
743             }
744             dvmHashTableLookup(gDvmJit.methodTable, hashValue,
745                                strdup(curLine),
746                                (HashCompareFunc) strcmp, true);
747         } else if (startClass) {
748             if (gDvmJit.classTable == NULL) {
749                 gDvmJit.classTable = dvmHashTableCreate(8, NULL);
750             }
751             dvmHashTableLookup(gDvmJit.classTable, hashValue,
752                                strdup(curLine),
753                                (HashCompareFunc) strcmp, true);
754         } else if (startOffset) {
755            int tmpInt = atoi(curLine);
756            gDvmJit.pcTable[idx++] = tmpInt;
757            if (idx >= COMPILER_PC_OFFSET_SIZE) {
758                printf("processXjitoffset: ignore entries beyond %d\n", COMPILER_PC_OFFSET_SIZE);
759                break;
760            }
761         }
762    }
763    gDvmJit.num_entries_pcTable = idx;
764    fclose(fp);
765    return 0;
766 }
767 #endif
768
769 /*
770  * Process an argument vector full of options.  Unlike standard C programs,
771  * argv[0] does not contain the name of the program.
772  *
773  * If "ignoreUnrecognized" is set, we ignore options starting with "-X" or "_"
774  * that we don't recognize.  Otherwise, we return with an error as soon as
775  * we see anything we can't identify.
776  *
777  * Returns 0 on success, -1 on failure, and 1 for the special case of
778  * "-version" where we want to stop without showing an error message.
779  */
780 static int processOptions(int argc, const char* const argv[],
781     bool ignoreUnrecognized)
782 {
783     int i;
784
785     ALOGV("VM options (%d):", argc);
786     for (i = 0; i < argc; i++)
787         ALOGV("  %d: '%s'", i, argv[i]);
788
789     /*
790      * Over-allocate AssertionControl array for convenience.  If allocated,
791      * the array must be able to hold at least one entry, so that the
792      * zygote-time activation can do its business.
793      */
794     assert(gDvm.assertionCtrl == NULL);
795     if (argc > 0) {
796         gDvm.assertionCtrl =
797             (AssertionControl*) malloc(sizeof(AssertionControl) * argc);
798         if (gDvm.assertionCtrl == NULL)
799             return -1;
800         assert(gDvm.assertionCtrlCount == 0);
801     }
802
803     for (i = 0; i < argc; i++) {
804         if (strcmp(argv[i], "-help") == 0) {
805             /* show usage and stop */
806             return -1;
807
808         } else if (strcmp(argv[i], "-version") == 0) {
809             /* show version and stop */
810             showVersion();
811             return 1;
812         } else if (strcmp(argv[i], "-showversion") == 0) {
813             /* show version and continue */
814             showVersion();
815
816         } else if (strcmp(argv[i], "-classpath") == 0 ||
817                    strcmp(argv[i], "-cp") == 0)
818         {
819             /* set classpath */
820             if (i == argc-1) {
821                 dvmFprintf(stderr, "Missing classpath path list\n");
822                 return -1;
823             }
824             free(gDvm.classPathStr); /* in case we have compiled-in default */
825             gDvm.classPathStr = strdup(argv[++i]);
826
827         } else if (strncmp(argv[i], "-Xbootclasspath:",
828                 sizeof("-Xbootclasspath:")-1) == 0)
829         {
830             /* set bootclasspath */
831             const char* path = argv[i] + sizeof("-Xbootclasspath:")-1;
832
833             if (*path == '\0') {
834                 dvmFprintf(stderr, "Missing bootclasspath path list\n");
835                 return -1;
836             }
837             free(gDvm.bootClassPathStr);
838             gDvm.bootClassPathStr = strdup(path);
839
840         } else if (strncmp(argv[i], "-Xbootclasspath/a:",
841                 sizeof("-Xbootclasspath/a:")-1) == 0) {
842             const char* appPath = argv[i] + sizeof("-Xbootclasspath/a:")-1;
843
844             if (*(appPath) == '\0') {
845                 dvmFprintf(stderr, "Missing appending bootclasspath path list\n");
846                 return -1;
847             }
848             char* allPath;
849
850             if (asprintf(&allPath, "%s:%s", gDvm.bootClassPathStr, appPath) < 0) {
851                 dvmFprintf(stderr, "Can't append to bootclasspath path list\n");
852                 return -1;
853             }
854             free(gDvm.bootClassPathStr);
855             gDvm.bootClassPathStr = allPath;
856
857         } else if (strncmp(argv[i], "-Xbootclasspath/p:",
858                 sizeof("-Xbootclasspath/p:")-1) == 0) {
859             const char* prePath = argv[i] + sizeof("-Xbootclasspath/p:")-1;
860
861             if (*(prePath) == '\0') {
862                 dvmFprintf(stderr, "Missing prepending bootclasspath path list\n");
863                 return -1;
864             }
865             char* allPath;
866
867             if (asprintf(&allPath, "%s:%s", prePath, gDvm.bootClassPathStr) < 0) {
868                 dvmFprintf(stderr, "Can't prepend to bootclasspath path list\n");
869                 return -1;
870             }
871             free(gDvm.bootClassPathStr);
872             gDvm.bootClassPathStr = allPath;
873
874         } else if (strncmp(argv[i], "-D", 2) == 0) {
875             /* Properties are handled in managed code. We just check syntax. */
876             if (strchr(argv[i], '=') == NULL) {
877                 dvmFprintf(stderr, "Bad system property setting: \"%s\"\n",
878                     argv[i]);
879                 return -1;
880             }
881             gDvm.properties->push_back(argv[i] + 2);
882
883         } else if (strcmp(argv[i], "-jar") == 0) {
884             // TODO: handle this; name of jar should be in argv[i+1]
885             dvmFprintf(stderr, "-jar not yet handled\n");
886             assert(false);
887
888         } else if (strncmp(argv[i], "-Xms", 4) == 0) {
889             size_t val = parseMemOption(argv[i]+4, 1024);
890             if (val != 0) {
891                 if (val >= kMinHeapStartSize && val <= kMaxHeapSize) {
892                     gDvm.heapStartingSize = val;
893                 } else {
894                     dvmFprintf(stderr,
895                         "Invalid -Xms '%s', range is %dKB to %dKB\n",
896                         argv[i], kMinHeapStartSize/1024, kMaxHeapSize/1024);
897                     return -1;
898                 }
899             } else {
900                 dvmFprintf(stderr, "Invalid -Xms option '%s'\n", argv[i]);
901                 return -1;
902             }
903         } else if (strncmp(argv[i], "-Xmx", 4) == 0) {
904             size_t val = parseMemOption(argv[i]+4, 1024);
905             if (val != 0) {
906                 if (val >= kMinHeapSize && val <= kMaxHeapSize) {
907                     gDvm.heapMaximumSize = val;
908                 } else {
909                     dvmFprintf(stderr,
910                         "Invalid -Xmx '%s', range is %dKB to %dKB\n",
911                         argv[i], kMinHeapSize/1024, kMaxHeapSize/1024);
912                     return -1;
913                 }
914             } else {
915                 dvmFprintf(stderr, "Invalid -Xmx option '%s'\n", argv[i]);
916                 return -1;
917             }
918         } else if (strncmp(argv[i], "-XX:HeapGrowthLimit=", 20) == 0) {
919             size_t val = parseMemOption(argv[i] + 20, 1024);
920             if (val != 0) {
921                 gDvm.heapGrowthLimit = val;
922             } else {
923                 dvmFprintf(stderr, "Invalid -XX:HeapGrowthLimit option '%s'\n", argv[i]);
924                 return -1;
925             }
926         } else if (strncmp(argv[i], "-XX:HeapMinFree=", 16) == 0) {
927             size_t val = parseMemOption(argv[i] + 16, 1024);
928             if (val != 0) {
929                 gDvm.heapMinFree = val;
930             } else {
931                 dvmFprintf(stderr, "Invalid -XX:HeapMinFree option '%s'\n", argv[i]);
932                 return -1;
933             }
934         } else if (strncmp(argv[i], "-XX:HeapMaxFree=", 16) == 0) {
935             size_t val = parseMemOption(argv[i] + 16, 1024);
936             if (val != 0) {
937                 gDvm.heapMaxFree = val;
938             } else {
939                 dvmFprintf(stderr, "Invalid -XX:HeapMaxFree option '%s'\n", argv[i]);
940                 return -1;
941             }
942         } else if (strncmp(argv[i], "-XX:HeapTargetUtilization=", 26) == 0) {
943             const char* start = argv[i] + 26;
944             const char* end = start;
945             double val = strtod(start, const_cast<char**>(&end));
946             // Ensure that we have a value, there was no cruft after it and it
947             // satisfies a sensible range.
948             bool sane_val = (start != end) && (end[0] == '\0') &&
949                 (val >= 0.1) && (val <= 0.9);
950             if (sane_val) {
951                 gDvm.heapTargetUtilization = val;
952             } else {
953                 dvmFprintf(stderr, "Invalid -XX:HeapTargetUtilization option '%s'\n", argv[i]);
954                 return -1;
955             }
956         } else if (strncmp(argv[i], "-Xss", 4) == 0) {
957             size_t val = parseMemOption(argv[i]+4, 1);
958             if (val != 0) {
959                 if (val >= kMinStackSize && val <= kMaxStackSize) {
960                     gDvm.stackSize = val;
961                     if (val > gDvm.mainThreadStackSize) {
962                         gDvm.mainThreadStackSize = val;
963                     }
964                 } else {
965                     dvmFprintf(stderr, "Invalid -Xss '%s', range is %d to %d\n",
966                         argv[i], kMinStackSize, kMaxStackSize);
967                     return -1;
968                 }
969             } else {
970                 dvmFprintf(stderr, "Invalid -Xss option '%s'\n", argv[i]);
971                 return -1;
972             }
973
974         } else if (strncmp(argv[i], "-XX:mainThreadStackSize=", strlen("-XX:mainThreadStackSize=")) == 0) {
975             size_t val = parseMemOption(argv[i] + strlen("-XX:mainThreadStackSize="), 1);
976             if (val != 0) {
977                 if (val >= kMinStackSize && val <= kMaxStackSize) {
978                     gDvm.mainThreadStackSize = val;
979                 } else {
980                     dvmFprintf(stderr, "Invalid -XX:mainThreadStackSize '%s', range is %d to %d\n",
981                                argv[i], kMinStackSize, kMaxStackSize);
982                     return -1;
983                 }
984             } else {
985                 dvmFprintf(stderr, "Invalid -XX:mainThreadStackSize option '%s'\n", argv[i]);
986                 return -1;
987             }
988
989         } else if (strncmp(argv[i], "-XX:+DisableExplicitGC", 22) == 0) {
990             gDvm.disableExplicitGc = true;
991         } else if (strcmp(argv[i], "-verbose") == 0 ||
992             strcmp(argv[i], "-verbose:class") == 0)
993         {
994             // JNI spec says "-verbose:gc,class" is valid, but cmd line
995             // doesn't work that way; may want to support.
996             gDvm.verboseClass = true;
997         } else if (strcmp(argv[i], "-verbose:jni") == 0) {
998             gDvm.verboseJni = true;
999         } else if (strcmp(argv[i], "-verbose:gc") == 0) {
1000             gDvm.verboseGc = true;
1001         } else if (strcmp(argv[i], "-verbose:shutdown") == 0) {
1002             gDvm.verboseShutdown = true;
1003
1004         } else if (strncmp(argv[i], "-enableassertions", 17) == 0) {
1005             enableAssertions(argv[i] + 17, true);
1006         } else if (strncmp(argv[i], "-ea", 3) == 0) {
1007             enableAssertions(argv[i] + 3, true);
1008         } else if (strncmp(argv[i], "-disableassertions", 18) == 0) {
1009             enableAssertions(argv[i] + 18, false);
1010         } else if (strncmp(argv[i], "-da", 3) == 0) {
1011             enableAssertions(argv[i] + 3, false);
1012         } else if (strcmp(argv[i], "-enablesystemassertions") == 0 ||
1013                    strcmp(argv[i], "-esa") == 0)
1014         {
1015             enableAssertions(NULL, true);
1016         } else if (strcmp(argv[i], "-disablesystemassertions") == 0 ||
1017                    strcmp(argv[i], "-dsa") == 0)
1018         {
1019             enableAssertions(NULL, false);
1020
1021         } else if (strncmp(argv[i], "-Xcheck:jni", 11) == 0) {
1022             /* nothing to do now -- was handled during JNI init */
1023
1024         } else if (strcmp(argv[i], "-Xdebug") == 0) {
1025             /* accept but ignore */
1026
1027         } else if (strncmp(argv[i], "-Xrunjdwp:", 10) == 0 ||
1028             strncmp(argv[i], "-agentlib:jdwp=", 15) == 0)
1029         {
1030             const char* tail;
1031
1032             if (argv[i][1] == 'X')
1033                 tail = argv[i] + 10;
1034             else
1035                 tail = argv[i] + 15;
1036
1037             if (strncmp(tail, "help", 4) == 0 || !parseJdwpOptions(tail)) {
1038                 showJdwpHelp();
1039                 return 1;
1040             }
1041         } else if (strcmp(argv[i], "-Xrs") == 0) {
1042             gDvm.reduceSignals = true;
1043         } else if (strcmp(argv[i], "-Xnoquithandler") == 0) {
1044             /* disables SIGQUIT handler thread while still blocking SIGQUIT */
1045             /* (useful if we don't want thread but system still signals us) */
1046             gDvm.noQuitHandler = true;
1047         } else if (strcmp(argv[i], "-Xzygote") == 0) {
1048             gDvm.zygote = true;
1049 #if defined(WITH_JIT)
1050             gDvmJit.runningInAndroidFramework = true;
1051 #endif
1052         } else if (strncmp(argv[i], "-Xdexopt:", 9) == 0) {
1053             if (strcmp(argv[i] + 9, "none") == 0)
1054                 gDvm.dexOptMode = OPTIMIZE_MODE_NONE;
1055             else if (strcmp(argv[i] + 9, "verified") == 0)
1056                 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
1057             else if (strcmp(argv[i] + 9, "all") == 0)
1058                 gDvm.dexOptMode = OPTIMIZE_MODE_ALL;
1059             else if (strcmp(argv[i] + 9, "full") == 0)
1060                 gDvm.dexOptMode = OPTIMIZE_MODE_FULL;
1061             else {
1062                 dvmFprintf(stderr, "Unrecognized dexopt option '%s'\n",argv[i]);
1063                 return -1;
1064             }
1065         } else if (strncmp(argv[i], "-Xverify:", 9) == 0) {
1066             if (strcmp(argv[i] + 9, "none") == 0)
1067                 gDvm.classVerifyMode = VERIFY_MODE_NONE;
1068             else if (strcmp(argv[i] + 9, "remote") == 0)
1069                 gDvm.classVerifyMode = VERIFY_MODE_REMOTE;
1070             else if (strcmp(argv[i] + 9, "all") == 0)
1071                 gDvm.classVerifyMode = VERIFY_MODE_ALL;
1072             else {
1073                 dvmFprintf(stderr, "Unrecognized verify option '%s'\n",argv[i]);
1074                 return -1;
1075             }
1076         } else if (strncmp(argv[i], "-Xjnigreflimit:", 15) == 0) {
1077             // Ignored for backwards compatibility.
1078         } else if (strncmp(argv[i], "-Xjnitrace:", 11) == 0) {
1079             gDvm.jniTrace = strdup(argv[i] + 11);
1080         } else if (strcmp(argv[i], "-Xlog-stdio") == 0) {
1081             gDvm.logStdio = true;
1082
1083         } else if (strncmp(argv[i], "-Xint", 5) == 0) {
1084             if (argv[i][5] == ':') {
1085                 if (strcmp(argv[i] + 6, "portable") == 0)
1086                     gDvm.executionMode = kExecutionModeInterpPortable;
1087                 else if (strcmp(argv[i] + 6, "fast") == 0)
1088                     gDvm.executionMode = kExecutionModeInterpFast;
1089 #ifdef WITH_JIT
1090                 else if (strcmp(argv[i] + 6, "jit") == 0)
1091                     gDvm.executionMode = kExecutionModeJit;
1092 #endif
1093                 else {
1094                     dvmFprintf(stderr,
1095                         "Warning: Unrecognized interpreter mode %s\n",argv[i]);
1096                     /* keep going */
1097                 }
1098             } else {
1099                 /* disable JIT if it was enabled by default */
1100                 gDvm.executionMode = kExecutionModeInterpFast;
1101             }
1102
1103         } else if (strncmp(argv[i], "-Xlockprofthreshold:", 20) == 0) {
1104             gDvm.lockProfThreshold = atoi(argv[i] + 20);
1105
1106 #ifdef WITH_JIT
1107         } else if (strncmp(argv[i], "-Xjitop", 7) == 0) {
1108             processXjitop(argv[i]);
1109         } else if (strncmp(argv[i], "-Xjitmethod:", 12) == 0) {
1110             processXjitmethod(argv[i] + strlen("-Xjitmethod:"), true);
1111         } else if (strncmp(argv[i], "-Xjitclass:", 11) == 0) {
1112             processXjitmethod(argv[i] + strlen("-Xjitclass:"), false);
1113         } else if (strncmp(argv[i], "-Xjitoffset:", 12) == 0) {
1114             processXjitoffset(argv[i] + strlen("-Xjitoffset:"));
1115         } else if (strncmp(argv[i], "-Xjitconfig:", 12) == 0) {
1116             processXjitconfig(argv[i] + strlen("-Xjitconfig:"));
1117         } else if (strncmp(argv[i], "-Xjitblocking", 13) == 0) {
1118           gDvmJit.blockingMode = true;
1119         } else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
1120           gDvmJit.threshold = atoi(argv[i] + 15);
1121         } else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) {
1122           gDvmJit.includeSelectedOp = true;
1123         } else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
1124           gDvmJit.includeSelectedMethod = true;
1125         } else if (strncmp(argv[i], "-Xjitcheckcg", 12) == 0) {
1126           gDvmJit.checkCallGraph = true;
1127           /* Need to enable blocking mode due to stack crawling */
1128           gDvmJit.blockingMode = true;
1129         } else if (strncmp(argv[i], "-Xjitdumpbin", 12) == 0) {
1130           gDvmJit.printBinary = true;
1131         } else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
1132           gDvmJit.printMe = true;
1133         } else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
1134           gDvmJit.profileMode = kTraceProfilingContinuous;
1135         } else if (strncmp(argv[i], "-Xjitdisableopt", 15) == 0) {
1136           /* Disable selected optimizations */
1137           if (argv[i][15] == ':') {
1138               sscanf(argv[i] + 16, "%x", &gDvmJit.disableOpt);
1139           /* Disable all optimizations */
1140           } else {
1141               gDvmJit.disableOpt = -1;
1142           }
1143         } else if (strncmp(argv[i], "-Xjitsuspendpoll", 16) == 0) {
1144           gDvmJit.genSuspendPoll = true;
1145 #endif
1146
1147         } else if (strncmp(argv[i], "-Xstacktracefile:", 17) == 0) {
1148             gDvm.stackTraceFile = strdup(argv[i]+17);
1149
1150         } else if (strcmp(argv[i], "-Xgenregmap") == 0) {
1151             gDvm.generateRegisterMaps = true;
1152         } else if (strcmp(argv[i], "-Xnogenregmap") == 0) {
1153             gDvm.generateRegisterMaps = false;
1154
1155         } else if (strcmp(argv[i], "Xverifyopt:checkmon") == 0) {
1156             gDvm.monitorVerification = true;
1157         } else if (strcmp(argv[i], "Xverifyopt:nocheckmon") == 0) {
1158             gDvm.monitorVerification = false;
1159
1160         } else if (strncmp(argv[i], "-Xgc:", 5) == 0) {
1161             if (strcmp(argv[i] + 5, "precise") == 0)
1162                 gDvm.preciseGc = true;
1163             else if (strcmp(argv[i] + 5, "noprecise") == 0)
1164                 gDvm.preciseGc = false;
1165             else if (strcmp(argv[i] + 5, "preverify") == 0)
1166                 gDvm.preVerify = true;
1167             else if (strcmp(argv[i] + 5, "nopreverify") == 0)
1168                 gDvm.preVerify = false;
1169             else if (strcmp(argv[i] + 5, "postverify") == 0)
1170                 gDvm.postVerify = true;
1171             else if (strcmp(argv[i] + 5, "nopostverify") == 0)
1172                 gDvm.postVerify = false;
1173             else if (strcmp(argv[i] + 5, "concurrent") == 0)
1174                 gDvm.concurrentMarkSweep = true;
1175             else if (strcmp(argv[i] + 5, "noconcurrent") == 0)
1176                 gDvm.concurrentMarkSweep = false;
1177             else if (strcmp(argv[i] + 5, "verifycardtable") == 0)
1178                 gDvm.verifyCardTable = true;
1179             else if (strcmp(argv[i] + 5, "noverifycardtable") == 0)
1180                 gDvm.verifyCardTable = false;
1181             else {
1182                 dvmFprintf(stderr, "Bad value for -Xgc");
1183                 return -1;
1184             }
1185             ALOGV("Precise GC configured %s", gDvm.preciseGc ? "ON" : "OFF");
1186
1187         } else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
1188             gDvm.verifyDexChecksum = true;
1189
1190         } else if (strcmp(argv[i], "-Xprofile:threadcpuclock") == 0) {
1191             gDvm.profilerClockSource = kProfilerClockSourceThreadCpu;
1192         } else if (strcmp(argv[i], "-Xprofile:wallclock") == 0) {
1193             gDvm.profilerClockSource = kProfilerClockSourceWall;
1194         } else if (strcmp(argv[i], "-Xprofile:dualclock") == 0) {
1195             gDvm.profilerClockSource = kProfilerClockSourceDual;
1196
1197         } else {
1198             if (!ignoreUnrecognized) {
1199                 dvmFprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
1200                 return -1;
1201             }
1202         }
1203     }
1204
1205     return 0;
1206 }
1207
1208 /*
1209  * Set defaults for fields altered or modified by arguments.
1210  *
1211  * Globals are initialized to 0 (a/k/a NULL or false).
1212  */
1213 static void setCommandLineDefaults()
1214 {
1215     const char* envStr = getenv("CLASSPATH");
1216     if (envStr != NULL) {
1217         gDvm.classPathStr = strdup(envStr);
1218     } else {
1219         gDvm.classPathStr = strdup(".");
1220     }
1221     envStr = getenv("BOOTCLASSPATH");
1222     if (envStr != NULL) {
1223         gDvm.bootClassPathStr = strdup(envStr);
1224     } else {
1225         gDvm.bootClassPathStr = strdup(".");
1226     }
1227
1228     gDvm.properties = new std::vector<std::string>();
1229
1230     /* Defaults overridden by -Xms and -Xmx.
1231      * TODO: base these on a system or application-specific default
1232      */
1233     gDvm.heapStartingSize = 2 * 1024 * 1024;  // Spec says 16MB; too big for us.
1234     gDvm.heapMaximumSize = 16 * 1024 * 1024;  // Spec says 75% physical mem
1235     gDvm.heapGrowthLimit = 0;  // 0 means no growth limit
1236     gDvm.stackSize = kDefaultStackSize;
1237     gDvm.mainThreadStackSize = kDefaultStackSize;
1238     // When the heap is less than the maximum or growth limited size,
1239     // fix the free portion of the heap. The utilization is the ratio
1240     // of live to free memory, 0.5 implies half the heap is available
1241     // to allocate into before a GC occurs. Min free and max free
1242     // force the free memory to never be smaller than min free or
1243     // larger than max free.
1244     gDvm.heapTargetUtilization = 0.5;
1245     gDvm.heapMaxFree = 2 * 1024 * 1024;
1246     gDvm.heapMinFree = gDvm.heapMaxFree / 4;
1247
1248     gDvm.concurrentMarkSweep = true;
1249
1250     /* gDvm.jdwpSuspend = true; */
1251
1252     /* allowed unless zygote config doesn't allow it */
1253     gDvm.jdwpAllowed = true;
1254
1255     /* default verification and optimization modes */
1256     gDvm.classVerifyMode = VERIFY_MODE_ALL;
1257     gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
1258     gDvm.monitorVerification = false;
1259     gDvm.generateRegisterMaps = true;
1260     gDvm.registerMapMode = kRegisterMapModeTypePrecise;
1261
1262     /*
1263      * Default execution mode.
1264      *
1265      * This should probably interact with the mterp code somehow, e.g. if
1266      * we know we're using the "desktop" build we should probably be
1267      * using "portable" rather than "fast".
1268      */
1269 #if defined(WITH_JIT)
1270     gDvm.executionMode = kExecutionModeJit;
1271     gDvmJit.num_entries_pcTable = 0;
1272     gDvmJit.includeSelectedMethod = false;
1273     gDvmJit.includeSelectedOffset = false;
1274     gDvmJit.methodTable = NULL;
1275     gDvmJit.classTable = NULL;
1276
1277     gDvm.constInit = false;
1278     gDvm.commonInit = false;
1279 #else
1280     gDvm.executionMode = kExecutionModeInterpFast;
1281 #endif
1282
1283     /*
1284      * SMP support is a compile-time define, but we may want to have
1285      * dexopt target a differently-configured device.
1286      */
1287     gDvm.dexOptForSmp = (ANDROID_SMP != 0);
1288
1289     /*
1290      * Default profiler configuration.
1291      */
1292     gDvm.profilerClockSource = kProfilerClockSourceDual;
1293 }
1294
1295
1296 /*
1297  * Handle a SIGBUS, which frequently occurs because somebody replaced an
1298  * optimized DEX file out from under us.
1299  */
1300 static void busCatcher(int signum, siginfo_t* info, void* context)
1301 {
1302     void* addr = info->si_addr;
1303
1304     ALOGE("Caught a SIGBUS (%d), addr=%p", signum, addr);
1305
1306     /*
1307      * If we return at this point the SIGBUS just keeps happening, so we
1308      * remove the signal handler and allow it to kill us.  TODO: restore
1309      * the original, which points to a debuggerd stub; if we don't then
1310      * debuggerd won't be notified.
1311      */
1312     signal(SIGBUS, SIG_DFL);
1313 }
1314
1315 /*
1316  * Configure signals.  We need to block SIGQUIT so that the signal only
1317  * reaches the dump-stack-trace thread.
1318  *
1319  * This can be disabled with the "-Xrs" flag.
1320  */
1321 static void blockSignals()
1322 {
1323     sigset_t mask;
1324     int cc;
1325
1326     sigemptyset(&mask);
1327     sigaddset(&mask, SIGQUIT);
1328     sigaddset(&mask, SIGUSR1);      // used to initiate heap dump
1329 #if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
1330     sigaddset(&mask, SIGUSR2);      // used to investigate JIT internals
1331 #endif
1332     //sigaddset(&mask, SIGPIPE);
1333     cc = sigprocmask(SIG_BLOCK, &mask, NULL);
1334     assert(cc == 0);
1335
1336     if (false) {
1337         /* TODO: save the old sigaction in a global */
1338         struct sigaction sa;
1339         memset(&sa, 0, sizeof(sa));
1340         sa.sa_sigaction = busCatcher;
1341         sa.sa_flags = SA_SIGINFO;
1342         cc = sigaction(SIGBUS, &sa, NULL);
1343         assert(cc == 0);
1344     }
1345 }
1346
1347 class ScopedShutdown {
1348 public:
1349     ScopedShutdown() : armed_(true) {
1350     }
1351
1352     ~ScopedShutdown() {
1353         if (armed_) {
1354             dvmShutdown();
1355         }
1356     }
1357
1358     void disarm() {
1359         armed_ = false;
1360     }
1361
1362 private:
1363     bool armed_;
1364 };
1365
1366 /*
1367  * VM initialization.  Pass in any options provided on the command line.
1368  * Do not pass in the class name or the options for the class.
1369  *
1370  * Returns 0 on success.
1371  */
1372 std::string dvmStartup(int argc, const char* const argv[],
1373         bool ignoreUnrecognized, JNIEnv* pEnv)
1374 {
1375     ScopedShutdown scopedShutdown;
1376
1377     assert(gDvm.initializing);
1378
1379     ALOGV("VM init args (%d):", argc);
1380     for (int i = 0; i < argc; i++) {
1381         ALOGV("  %d: '%s'", i, argv[i]);
1382     }
1383     setCommandLineDefaults();
1384
1385     /*
1386      * Process the option flags (if any).
1387      */
1388     int cc = processOptions(argc, argv, ignoreUnrecognized);
1389     if (cc != 0) {
1390         if (cc < 0) {
1391             dvmFprintf(stderr, "\n");
1392             usage("dalvikvm");
1393         }
1394         return "syntax error";
1395     }
1396
1397 #if WITH_EXTRA_GC_CHECKS > 1
1398     /* only "portable" interp has the extra goodies */
1399     if (gDvm.executionMode != kExecutionModeInterpPortable) {
1400         ALOGI("Switching to 'portable' interpreter for GC checks");
1401         gDvm.executionMode = kExecutionModeInterpPortable;
1402     }
1403 #endif
1404
1405     /* Configure group scheduling capabilities */
1406     if (!access("/dev/cpuctl/tasks", F_OK)) {
1407         ALOGV("Using kernel group scheduling");
1408         gDvm.kernelGroupScheduling = 1;
1409     } else {
1410         ALOGV("Using kernel scheduler policies");
1411     }
1412
1413     /* configure signal handling */
1414     if (!gDvm.reduceSignals)
1415         blockSignals();
1416
1417     /* verify system page size */
1418     if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {
1419         return StringPrintf("expected page size %d, got %d",
1420                 SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));
1421     }
1422
1423     /* mterp setup */
1424     ALOGV("Using executionMode %d", gDvm.executionMode);
1425     dvmCheckAsmConstants();
1426
1427     /*
1428      * Initialize components.
1429      */
1430     dvmQuasiAtomicsStartup();
1431     if (!dvmAllocTrackerStartup()) {
1432         return "dvmAllocTrackerStartup failed";
1433     }
1434     if (!dvmGcStartup()) {
1435         return "dvmGcStartup failed";
1436     }
1437     if (!dvmThreadStartup()) {
1438         return "dvmThreadStartup failed";
1439     }
1440     if (!dvmInlineNativeStartup()) {
1441         return "dvmInlineNativeStartup";
1442     }
1443     if (!dvmRegisterMapStartup()) {
1444         return "dvmRegisterMapStartup failed";
1445     }
1446     if (!dvmInstanceofStartup()) {
1447         return "dvmInstanceofStartup failed";
1448     }
1449     if (!dvmClassStartup()) {
1450         return "dvmClassStartup failed";
1451     }
1452
1453     /*
1454      * At this point, the system is guaranteed to be sufficiently
1455      * initialized that we can look up classes and class members. This
1456      * call populates the gDvm instance with all the class and member
1457      * references that the VM wants to use directly.
1458      */
1459     if (!dvmFindRequiredClassesAndMembers()) {
1460         return "dvmFindRequiredClassesAndMembers failed";
1461     }
1462
1463     if (!dvmStringInternStartup()) {
1464         return "dvmStringInternStartup failed";
1465     }
1466     if (!dvmNativeStartup()) {
1467         return "dvmNativeStartup failed";
1468     }
1469     if (!dvmInternalNativeStartup()) {
1470         return "dvmInternalNativeStartup failed";
1471     }
1472     if (!dvmJniStartup()) {
1473         return "dvmJniStartup failed";
1474     }
1475     if (!dvmProfilingStartup()) {
1476         return "dvmProfilingStartup failed";
1477     }
1478
1479     /*
1480      * Create a table of methods for which we will substitute an "inline"
1481      * version for performance.
1482      */
1483     if (!dvmCreateInlineSubsTable()) {
1484         return "dvmCreateInlineSubsTable failed";
1485     }
1486
1487     /*
1488      * Miscellaneous class library validation.
1489      */
1490     if (!dvmValidateBoxClasses()) {
1491         return "dvmValidateBoxClasses failed";
1492     }
1493
1494     /*
1495      * Do the last bits of Thread struct initialization we need to allow
1496      * JNI calls to work.
1497      */
1498     if (!dvmPrepMainForJni(pEnv)) {
1499         return "dvmPrepMainForJni failed";
1500     }
1501
1502     /*
1503      * Explicitly initialize java.lang.Class.  This doesn't happen
1504      * automatically because it's allocated specially (it's an instance
1505      * of itself).  Must happen before registration of system natives,
1506      * which make some calls that throw assertions if the classes they
1507      * operate on aren't initialized.
1508      */
1509     if (!dvmInitClass(gDvm.classJavaLangClass)) {
1510         return "couldn't initialized java.lang.Class";
1511     }
1512
1513     /*
1514      * Register the system native methods, which are registered through JNI.
1515      */
1516     if (!registerSystemNatives(pEnv)) {
1517         return "couldn't register system natives";
1518     }
1519
1520     /*
1521      * Do some "late" initialization for the memory allocator.  This may
1522      * allocate storage and initialize classes.
1523      */
1524     if (!dvmCreateStockExceptions()) {
1525         return "dvmCreateStockExceptions failed";
1526     }
1527
1528     /*
1529      * At this point, the VM is in a pretty good state.  Finish prep on
1530      * the main thread (specifically, create a java.lang.Thread object to go
1531      * along with our Thread struct).  Note we will probably be executing
1532      * some interpreted class initializer code in here.
1533      */
1534     if (!dvmPrepMainThread()) {
1535         return "dvmPrepMainThread failed";
1536     }
1537
1538     /*
1539      * Make sure we haven't accumulated any tracked references.  The main
1540      * thread should be starting with a clean slate.
1541      */
1542     if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0)
1543     {
1544         ALOGW("Warning: tracked references remain post-initialization");
1545         dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN");
1546     }
1547
1548     /* general debugging setup */
1549     if (!dvmDebuggerStartup()) {
1550         return "dvmDebuggerStartup failed";
1551     }
1552
1553     if (!dvmGcStartupClasses()) {
1554         return "dvmGcStartupClasses failed";
1555     }
1556
1557     /*
1558      * Init for either zygote mode or non-zygote mode.  The key difference
1559      * is that we don't start any additional threads in Zygote mode.
1560      */
1561     if (gDvm.zygote) {
1562         if (!initZygote()) {
1563             return "initZygote failed";
1564         }
1565     } else {
1566         if (!dvmInitAfterZygote()) {
1567             return "dvmInitAfterZygote failed";
1568         }
1569     }
1570
1571
1572 #ifndef NDEBUG
1573     if (!dvmTestHash())
1574         ALOGE("dvmTestHash FAILED");
1575     if (false /*noisy!*/ && !dvmTestIndirectRefTable())
1576         ALOGE("dvmTestIndirectRefTable FAILED");
1577 #endif
1578
1579     if (dvmCheckException(dvmThreadSelf())) {
1580         dvmLogExceptionStackTrace();
1581         return "Exception pending at end of VM initialization";
1582     }
1583
1584     scopedShutdown.disarm();
1585     return "";
1586 }
1587
1588 static void loadJniLibrary(const char* name) {
1589     std::string mappedName(StringPrintf(OS_SHARED_LIB_FORMAT_STR, name));
1590     char* reason = NULL;
1591     if (!dvmLoadNativeCode(mappedName.c_str(), NULL, &reason)) {
1592         ALOGE("dvmLoadNativeCode failed for \"%s\": %s", name, reason);
1593         dvmAbort();
1594     }
1595 }
1596
1597 /*
1598  * Register java.* natives from our class libraries.  We need to do
1599  * this after we're ready for JNI registration calls, but before we
1600  * do any class initialization.
1601  *
1602  * If we get this wrong, we will blow up in the ThreadGroup class init if
1603  * interpreted code makes any reference to System.  It will likely do this
1604  * since it wants to do some java.io.File setup (e.g. for static in/out/err).
1605  *
1606  * We need to have gDvm.initializing raised here so that JNI FindClass
1607  * won't try to use the system/application class loader.
1608  */
1609 static bool registerSystemNatives(JNIEnv* pEnv)
1610 {
1611     // Main thread is always first in list.
1612     Thread* self = gDvm.threadList;
1613
1614     // Must set this before allowing JNI-based method registration.
1615     self->status = THREAD_NATIVE;
1616
1617     // First set up JniConstants, which is used by libcore.
1618     JniConstants::init(pEnv);
1619
1620     // Set up our single JNI method.
1621     // TODO: factor this out if we add more.
1622     jclass c = pEnv->FindClass("java/lang/Class");
1623     if (c == NULL) {
1624         dvmAbort();
1625     }
1626     JNIEXPORT jobject JNICALL Java_java_lang_Class_getDex(JNIEnv* env, jclass javaClass);
1627     const JNINativeMethod Java_java_lang_Class[] = {
1628         { "getDex", "()Lcom/android/dex/Dex;", (void*) Java_java_lang_Class_getDex },
1629     };
1630     if (pEnv->RegisterNatives(c, Java_java_lang_Class, 1) != JNI_OK) {
1631         dvmAbort();
1632     }
1633
1634     // Most JNI libraries can just use System.loadLibrary, but you can't
1635     // if you're the library that implements System.loadLibrary!
1636     loadJniLibrary("javacore");
1637     loadJniLibrary("nativehelper");
1638
1639     // Back to run mode.
1640     self->status = THREAD_RUNNING;
1641
1642     return true;
1643 }
1644
1645 /*
1646  * Copied and modified slightly from system/core/toolbox/mount.c
1647  */
1648 static std::string getMountsDevDir(const char *arg)
1649 {
1650     char mount_dev[256];
1651     char mount_dir[256];
1652     int match;
1653
1654     FILE *fp = fopen("/proc/self/mounts", "r");
1655     if (fp == NULL) {
1656         ALOGE("Could not open /proc/self/mounts: %s", strerror(errno));
1657         return "";
1658     }
1659
1660     while ((match = fscanf(fp, "%255s %255s %*s %*s %*d %*d\n", mount_dev, mount_dir)) != EOF) {
1661         mount_dev[255] = 0;
1662         mount_dir[255] = 0;
1663         if (match == 2 && (strcmp(arg, mount_dir) == 0)) {
1664             fclose(fp);
1665             return mount_dev;
1666         }
1667     }
1668
1669     fclose(fp);
1670     return "";
1671 }
1672
1673 /*
1674  * Do zygote-mode-only initialization.
1675  */
1676 static bool initZygote()
1677 {
1678     /* zygote goes into its own process group */
1679     setpgid(0,0);
1680
1681     // See storage config details at http://source.android.com/tech/storage/
1682     // Create private mount namespace shared by all children
1683     if (unshare(CLONE_NEWNS) == -1) {
1684         SLOGE("Failed to unshare(): %s", strerror(errno));
1685         return -1;
1686     }
1687
1688     // Mark rootfs as being a slave so that changes from default
1689     // namespace only flow into our children.
1690     if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) {
1691         SLOGE("Failed to mount() rootfs as MS_SLAVE: %s", strerror(errno));
1692         return -1;
1693     }
1694
1695     // Create a staging tmpfs that is shared by our children; they will
1696     // bind mount storage into their respective private namespaces, which
1697     // are isolated from each other.
1698     const char* target_base = getenv("EMULATED_STORAGE_TARGET");
1699     if (target_base != NULL) {
1700         if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
1701                 "uid=0,gid=1028,mode=0050") == -1) {
1702             SLOGE("Failed to mount tmpfs to %s: %s", target_base, strerror(errno));
1703             return -1;
1704         }
1705     }
1706
1707     // Mark /system as NOSUID | NODEV
1708     const char* android_root = getenv("ANDROID_ROOT");
1709
1710     if (android_root == NULL) {
1711         SLOGE("environment variable ANDROID_ROOT does not exist?!?!");
1712         return -1;
1713     }
1714
1715     std::string mountDev(getMountsDevDir(android_root));
1716     if (mountDev.empty()) {
1717         SLOGE("Unable to find mount point for %s", android_root);
1718         return -1;
1719     }
1720
1721     if (mount(mountDev.c_str(), android_root, "none",
1722             MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_RDONLY | MS_BIND, NULL) == -1) {
1723         SLOGE("Remount of %s failed: %s", android_root, strerror(errno));
1724         return -1;
1725     }
1726
1727 #ifdef HAVE_ANDROID_OS
1728     if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
1729         if (errno == EINVAL) {
1730             SLOGW("PR_SET_NO_NEW_PRIVS failed. "
1731                   "Is your kernel compiled correctly?: %s", strerror(errno));
1732             // Don't return -1 here, since it's expected that not all
1733             // kernels will support this option.
1734         } else {
1735             SLOGW("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
1736             return -1;
1737         }
1738     }
1739 #endif
1740
1741     return true;
1742 }
1743
1744 /*
1745  * Do non-zygote-mode initialization.  This is done during VM init for
1746  * standard startup, or after a "zygote fork" when creating a new process.
1747  */
1748 bool dvmInitAfterZygote()
1749 {
1750     u8 startHeap, startQuit, startJdwp;
1751     u8 endHeap, endQuit, endJdwp;
1752
1753     startHeap = dvmGetRelativeTimeUsec();
1754
1755     /*
1756      * Post-zygote heap initialization, including starting
1757      * the HeapWorker thread.
1758      */
1759     if (!dvmGcStartupAfterZygote())
1760         return false;
1761
1762     endHeap = dvmGetRelativeTimeUsec();
1763     startQuit = dvmGetRelativeTimeUsec();
1764
1765     /* start signal catcher thread that dumps stacks on SIGQUIT */
1766     if (!gDvm.reduceSignals && !gDvm.noQuitHandler) {
1767         if (!dvmSignalCatcherStartup())
1768             return false;
1769     }
1770
1771     /* start stdout/stderr copier, if requested */
1772     if (gDvm.logStdio) {
1773         if (!dvmStdioConverterStartup())
1774             return false;
1775     }
1776
1777     endQuit = dvmGetRelativeTimeUsec();
1778     startJdwp = dvmGetRelativeTimeUsec();
1779
1780     /*
1781      * Start JDWP thread.  If the command-line debugger flags specified
1782      * "suspend=y", this will pause the VM.  We probably want this to
1783      * come last.
1784      */
1785     if (!initJdwp()) {
1786         ALOGD("JDWP init failed; continuing anyway");
1787     }
1788
1789     endJdwp = dvmGetRelativeTimeUsec();
1790
1791     ALOGV("thread-start heap=%d quit=%d jdwp=%d total=%d usec",
1792         (int)(endHeap-startHeap), (int)(endQuit-startQuit),
1793         (int)(endJdwp-startJdwp), (int)(endJdwp-startHeap));
1794
1795 #ifdef WITH_JIT
1796     if (gDvm.executionMode == kExecutionModeJit) {
1797         if (!dvmCompilerStartup())
1798             return false;
1799     }
1800 #endif
1801
1802     return true;
1803 }
1804
1805 /*
1806  * Prepare for a connection to a JDWP-compliant debugger.
1807  *
1808  * Note this needs to happen fairly late in the startup process, because
1809  * we need to have all of the java.* native methods registered (which in
1810  * turn requires JNI to be fully prepped).
1811  *
1812  * There are several ways to initialize:
1813  *   server=n
1814  *     We immediately try to connect to host:port.  Bail on failure.  On
1815  *     success, send VM_START (suspending the VM if "suspend=y").
1816  *   server=y suspend=n
1817  *     Passively listen for a debugger to connect.  Return immediately.
1818  *   server=y suspend=y
1819  *     Wait until debugger connects.  Send VM_START ASAP, suspending the
1820  *     VM after the message is sent.
1821  *
1822  * This gets more complicated with a nonzero value for "timeout".
1823  */
1824 static bool initJdwp()
1825 {
1826     assert(!gDvm.zygote);
1827
1828     /*
1829      * Init JDWP if the debugger is enabled.  This may connect out to a
1830      * debugger, passively listen for a debugger, or block waiting for a
1831      * debugger.
1832      */
1833     if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {
1834         JdwpStartupParams params;
1835
1836         if (gDvm.jdwpHost != NULL) {
1837             if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {
1838                 ALOGE("ERROR: hostname too long: '%s'", gDvm.jdwpHost);
1839                 return false;
1840             }
1841             strcpy(params.host, gDvm.jdwpHost);
1842         } else {
1843             params.host[0] = '\0';
1844         }
1845         params.transport = gDvm.jdwpTransport;
1846         params.server = gDvm.jdwpServer;
1847         params.suspend = gDvm.jdwpSuspend;
1848         params.port = gDvm.jdwpPort;
1849
1850         gDvm.jdwpState = dvmJdwpStartup(&params);
1851         if (gDvm.jdwpState == NULL) {
1852             ALOGW("WARNING: debugger thread failed to initialize");
1853             /* TODO: ignore? fail? need to mimic "expected" behavior */
1854         }
1855     }
1856
1857     /*
1858      * If a debugger has already attached, send the "welcome" message.  This
1859      * may cause us to suspend all threads.
1860      */
1861     if (dvmJdwpIsActive(gDvm.jdwpState)) {
1862         //dvmChangeStatus(NULL, THREAD_RUNNING);
1863         if (!dvmJdwpPostVMStart(gDvm.jdwpState, gDvm.jdwpSuspend)) {
1864             ALOGW("WARNING: failed to post 'start' message to debugger");
1865             /* keep going */
1866         }
1867         //dvmChangeStatus(NULL, THREAD_NATIVE);
1868     }
1869
1870     return true;
1871 }
1872
1873 /*
1874  * An alternative to JNI_CreateJavaVM/dvmStartup that does the first bit
1875  * of initialization and then returns with "initializing" still set.  (Used
1876  * by DexOpt command-line utility.)
1877  *
1878  * Attempting to use JNI or internal natives will fail.  It's best
1879  * if no bytecode gets executed, which means no <clinit>, which means
1880  * no exception-throwing.  (In practice we need to initialize Class and
1881  * Object, and probably some exception classes.)
1882  *
1883  * Returns 0 on success.
1884  */
1885 int dvmPrepForDexOpt(const char* bootClassPath, DexOptimizerMode dexOptMode,
1886     DexClassVerifyMode verifyMode, int dexoptFlags)
1887 {
1888     gDvm.initializing = true;
1889     gDvm.optimizing = true;
1890
1891     /* configure signal handling */
1892     blockSignals();
1893
1894     /* set some defaults */
1895     setCommandLineDefaults();
1896     free(gDvm.bootClassPathStr);
1897     gDvm.bootClassPathStr = strdup(bootClassPath);
1898
1899     /* set opt/verify modes */
1900     gDvm.dexOptMode = dexOptMode;
1901     gDvm.classVerifyMode = verifyMode;
1902     gDvm.generateRegisterMaps = (dexoptFlags & DEXOPT_GEN_REGISTER_MAPS) != 0;
1903     if (dexoptFlags & DEXOPT_SMP) {
1904         assert((dexoptFlags & DEXOPT_UNIPROCESSOR) == 0);
1905         gDvm.dexOptForSmp = true;
1906     } else if (dexoptFlags & DEXOPT_UNIPROCESSOR) {
1907         gDvm.dexOptForSmp = false;
1908     } else {
1909         gDvm.dexOptForSmp = (ANDROID_SMP != 0);
1910     }
1911
1912     /*
1913      * Initialize the heap, some basic thread control mutexes, and
1914      * get the bootclasspath prepped.
1915      *
1916      * We can't load any classes yet because we may not yet have a source
1917      * for things like java.lang.Object and java.lang.Class.
1918      */
1919     if (!dvmGcStartup())
1920         goto fail;
1921     if (!dvmThreadStartup())
1922         goto fail;
1923     if (!dvmInlineNativeStartup())
1924         goto fail;
1925     if (!dvmRegisterMapStartup())
1926         goto fail;
1927     if (!dvmInstanceofStartup())
1928         goto fail;
1929     if (!dvmClassStartup())
1930         goto fail;
1931
1932     /*
1933      * We leave gDvm.initializing set to "true" so that, if we're not
1934      * able to process the "core" classes, we don't go into a death-spin
1935      * trying to throw a "class not found" exception.
1936      */
1937
1938     return 0;
1939
1940 fail:
1941     dvmShutdown();
1942     return 1;
1943 }
1944
1945
1946 /*
1947  * All threads have stopped.  Finish the shutdown procedure.
1948  *
1949  * We can also be called if startup fails partway through, so be prepared
1950  * to deal with partially initialized data.
1951  *
1952  * Free any storage allocated in gGlobals.
1953  *
1954  * We can't dlclose() shared libs we've loaded, because it's possible a
1955  * thread not associated with the VM is running code in one.
1956  *
1957  * This is called from the JNI DestroyJavaVM function, which can be
1958  * called from any thread.  (In practice, this will usually run in the
1959  * same thread that started the VM, a/k/a the main thread, but we don't
1960  * want to assume that.)
1961  */
1962 void dvmShutdown()
1963 {
1964     ALOGV("VM shutting down");
1965
1966     if (CALC_CACHE_STATS)
1967         dvmDumpAtomicCacheStats(gDvm.instanceofCache);
1968
1969     /*
1970      * Stop our internal threads.
1971      */
1972     dvmGcThreadShutdown();
1973
1974     if (gDvm.jdwpState != NULL)
1975         dvmJdwpShutdown(gDvm.jdwpState);
1976     free(gDvm.jdwpHost);
1977     gDvm.jdwpHost = NULL;
1978     free(gDvm.jniTrace);
1979     gDvm.jniTrace = NULL;
1980     free(gDvm.stackTraceFile);
1981     gDvm.stackTraceFile = NULL;
1982
1983     /* tell signal catcher to shut down if it was started */
1984     dvmSignalCatcherShutdown();
1985
1986     /* shut down stdout/stderr conversion */
1987     dvmStdioConverterShutdown();
1988
1989 #ifdef WITH_JIT
1990     if (gDvm.executionMode == kExecutionModeJit) {
1991         /* shut down the compiler thread */
1992         dvmCompilerShutdown();
1993     }
1994 #endif
1995
1996     /*
1997      * Kill any daemon threads that still exist.  Actively-running threads
1998      * are likely to crash the process if they continue to execute while
1999      * the VM shuts down.
2000      */
2001     dvmSlayDaemons();
2002
2003     if (gDvm.verboseShutdown)
2004         ALOGD("VM cleaning up");
2005
2006     dvmDebuggerShutdown();
2007     dvmProfilingShutdown();
2008     dvmJniShutdown();
2009     dvmStringInternShutdown();
2010     dvmThreadShutdown();
2011     dvmClassShutdown();
2012     dvmRegisterMapShutdown();
2013     dvmInstanceofShutdown();
2014     dvmInlineNativeShutdown();
2015     dvmGcShutdown();
2016     dvmAllocTrackerShutdown();
2017
2018     /* these must happen AFTER dvmClassShutdown has walked through class data */
2019     dvmNativeShutdown();
2020     dvmInternalNativeShutdown();
2021
2022     dvmFreeInlineSubsTable();
2023
2024     free(gDvm.bootClassPathStr);
2025     free(gDvm.classPathStr);
2026     delete gDvm.properties;
2027
2028     freeAssertionCtrl();
2029
2030     dvmQuasiAtomicsShutdown();
2031
2032     /*
2033      * We want valgrind to report anything we forget to free as "definitely
2034      * lost".  If there's a pointer in the global chunk, it would be reported
2035      * as "still reachable".  Erasing the memory fixes this.
2036      *
2037      * This must be erased to zero if we want to restart the VM within this
2038      * process.
2039      */
2040     memset(&gDvm, 0xcd, sizeof(gDvm));
2041 }
2042
2043
2044 /*
2045  * fprintf() wrapper that calls through the JNI-specified vfprintf hook if
2046  * one was specified.
2047  */
2048 int dvmFprintf(FILE* fp, const char* format, ...)
2049 {
2050     va_list args;
2051     int result;
2052
2053     va_start(args, format);
2054     if (gDvm.vfprintfHook != NULL)
2055         result = (*gDvm.vfprintfHook)(fp, format, args);
2056     else
2057         result = vfprintf(fp, format, args);
2058     va_end(args);
2059
2060     return result;
2061 }
2062
2063 #ifdef __GLIBC__
2064 #include <execinfo.h>
2065 /*
2066  * glibc-only stack dump function.  Requires link with "--export-dynamic".
2067  *
2068  * TODO: move this into libs/cutils and make it work for all platforms.
2069  */
2070 void dvmPrintNativeBackTrace()
2071 {
2072     size_t MAX_STACK_FRAMES = 64;
2073     void* stackFrames[MAX_STACK_FRAMES];
2074     size_t frameCount = backtrace(stackFrames, MAX_STACK_FRAMES);
2075
2076     /*
2077      * TODO: in practice, we may find that we should use backtrace_symbols_fd
2078      * to avoid allocation, rather than use our own custom formatting.
2079      */
2080     char** strings = backtrace_symbols(stackFrames, frameCount);
2081     if (strings == NULL) {
2082         ALOGE("backtrace_symbols failed: %s", strerror(errno));
2083         return;
2084     }
2085
2086     size_t i;
2087     for (i = 0; i < frameCount; ++i) {
2088         ALOGW("#%-2d %s", i, strings[i]);
2089     }
2090     free(strings);
2091 }
2092 #else
2093 void dvmPrintNativeBackTrace() {
2094     /* Hopefully, you're on an Android device and debuggerd will do this. */
2095 }
2096 #endif
2097
2098 /*
2099  * Abort the VM.  We get here on fatal errors.  Try very hard not to use
2100  * this; whenever possible, return an error to somebody responsible.
2101  */
2102 void dvmAbort()
2103 {
2104     /*
2105      * Leave gDvm.lastMessage on the stack frame which can be decoded in the
2106      * tombstone file. This is for situations where we only have tombstone files
2107      * but no logs (ie b/5372634).
2108      *
2109      * For example, in the tombstone file you usually see this:
2110      *
2111      *   #00  pc 00050ef2  /system/lib/libdvm.so (dvmAbort)
2112      *   #01  pc 00077670  /system/lib/libdvm.so (_Z15dvmClassStartupv)
2113      *     :
2114      *
2115      * stack:
2116      *     :
2117      * #00 beed2658  00000000
2118      *     beed265c  7379732f
2119      *     beed2660  2f6d6574
2120      *     beed2664  6d617266
2121      *     beed2668  726f7765
2122      *     beed266c  6f632f6b
2123      *     beed2670  6a2e6572
2124      *     beed2674  00007261
2125      *     beed2678  00000000
2126      *
2127      * The ascii values between beed265c and beed2674 belongs to messageBuffer
2128      * and it can be decoded as "/system/framework/core.jar".
2129      */
2130     const int messageLength = 512;
2131     char messageBuffer[messageLength] = {0};
2132     int result = 0;
2133
2134     snprintf(messageBuffer, messageLength, "%s", gDvm.lastMessage);
2135
2136     /* So that messageBuffer[] looks like useful stuff to the compiler */
2137     for (int i = 0; i < messageLength && messageBuffer[i]; i++) {
2138         result += messageBuffer[i];
2139     }
2140
2141     ALOGE("VM aborting");
2142
2143     fflush(NULL);       // flush all open file buffers
2144
2145     /* JNI-supplied abort hook gets right of first refusal */
2146     if (gDvm.abortHook != NULL)
2147         (*gDvm.abortHook)();
2148
2149     /*
2150      * On the device, debuggerd will give us a stack trace.
2151      * On the host, we have to help ourselves.
2152      */
2153     dvmPrintNativeBackTrace();
2154
2155     abort();
2156
2157     /* notreached */
2158 }