blob: 66c1ad1c09d9687dbd21df64a8ca04871080abfd [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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#include "Dalvik.h"
21#include "test/Test.h"
22#include "mterp/Mterp.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070023#include "Hash.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080024
25#include <stdlib.h>
26#include <stdio.h>
27#include <signal.h>
28#include <limits.h>
29#include <ctype.h>
30#include <sys/wait.h>
31#include <unistd.h>
32
33#define kMinHeapStartSize (1*1024*1024)
34#define kMinHeapSize (2*1024*1024)
35#define kMaxHeapSize (1*1024*1024*1024)
36
37/*
38 * Register VM-agnostic native methods for system classes.
39 *
40 * Currently defined in ../include/nativehelper/AndroidSystemNatives.h
41 */
42extern int jniRegisterSystemMethods(JNIEnv* env);
43
44/* fwd */
45static bool registerSystemNatives(JNIEnv* pEnv);
46static bool dvmInitJDWP(void);
47static bool dvmInitZygote(void);
48
49
50/* global state */
51struct DvmGlobals gDvm;
52
Ben Chengba4fc8b2009-06-01 13:00:29 -070053/* JIT-specific global state */
54#if defined(WITH_JIT)
55struct DvmJitGlobals gDvmJit;
56#endif
57
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080058/*
59 * Show usage.
60 *
61 * We follow the tradition of unhyphenated compound words.
62 */
63static void dvmUsage(const char* progName)
64{
65 dvmFprintf(stderr, "%s: [options] class [argument ...]\n", progName);
66 dvmFprintf(stderr, "%s: [options] -jar file.jar [argument ...]\n",progName);
67 dvmFprintf(stderr, "\n");
68 dvmFprintf(stderr, "The following standard options are recognized:\n");
69 dvmFprintf(stderr, " -classpath classpath\n");
70 dvmFprintf(stderr, " -Dproperty=value\n");
71 dvmFprintf(stderr, " -verbose:tag ('gc', 'jni', or 'class')\n");
72 dvmFprintf(stderr, " -ea[:<package name>... |:<class name>]\n");
73 dvmFprintf(stderr, " -da[:<package name>... |:<class name>]\n");
74 dvmFprintf(stderr, " (-enableassertions, -disableassertions)\n");
75 dvmFprintf(stderr, " -esa\n");
76 dvmFprintf(stderr, " -dsa\n");
77 dvmFprintf(stderr,
78 " (-enablesystemassertions, -disablesystemassertions)\n");
79 dvmFprintf(stderr, " -showversion\n");
80 dvmFprintf(stderr, " -help\n");
81 dvmFprintf(stderr, "\n");
82 dvmFprintf(stderr, "The following extended options are recognized:\n");
83 dvmFprintf(stderr, " -Xrunjdwp:<options>\n");
84 dvmFprintf(stderr, " -Xbootclasspath:bootclasspath\n");
85 dvmFprintf(stderr, " -Xcheck:tag (e.g. 'jni')\n");
86 dvmFprintf(stderr, " -XmsN (min heap, must be multiple of 1K, >= 1MB)\n");
87 dvmFprintf(stderr, " -XmxN (max heap, must be multiple of 1K, >= 2MB)\n");
88 dvmFprintf(stderr, " -XssN (stack size, >= %dKB, <= %dKB)\n",
89 kMinStackSize / 1024, kMaxStackSize / 1024);
90 dvmFprintf(stderr, " -Xverify:{none,remote,all}\n");
91 dvmFprintf(stderr, " -Xrs\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -070092#if defined(WITH_JIT)
93 dvmFprintf(stderr,
94 " -Xint (extended to accept ':portable', ':fast' and ':jit')\n");
95#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080096 dvmFprintf(stderr,
97 " -Xint (extended to accept ':portable' and ':fast')\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -070098#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080099 dvmFprintf(stderr, "\n");
100 dvmFprintf(stderr, "These are unique to Dalvik:\n");
101 dvmFprintf(stderr, " -Xzygote\n");
102 dvmFprintf(stderr, " -Xdexopt:{none,verified,all}\n");
103 dvmFprintf(stderr, " -Xnoquithandler\n");
104 dvmFprintf(stderr,
105 " -Xjnigreflimit:N (must be multiple of 100, >= 200)\n");
106 dvmFprintf(stderr, " -Xjniopts:{warnonly,forcecopy}\n");
107 dvmFprintf(stderr, " -Xdeadlockpredict:{off,warn,err,abort}\n");
108 dvmFprintf(stderr, " -Xstacktracefile:<filename>\n");
The Android Open Source Project99409882009-03-18 22:20:24 -0700109 dvmFprintf(stderr, " -Xgc:[no]precise\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110 dvmFprintf(stderr, " -Xgenregmap\n");
111 dvmFprintf(stderr, " -Xcheckdexsum\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700112#if defined(WITH_JIT)
113 dvmFprintf(stderr, " -Xincludeselectedop\n");
114 dvmFprintf(stderr, " -Xjitop:hexopvalue[-endvalue]"
115 "[,hexopvalue[-endvalue]]*\n");
116 dvmFprintf(stderr, " -Xincludeselectedmethod\n");
Bill Buzbeed7269912009-11-10 14:31:32 -0800117 dvmFprintf(stderr, " -Xjitthreshold:decimalvalue\n");
118 dvmFprintf(stderr, " -Xjitblocking\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700119 dvmFprintf(stderr, " -Xjitmethod:signture[,signature]* "
120 "(eg Ljava/lang/String\\;replace)\n");
121 dvmFprintf(stderr, " -Xjitverbose\n");
Bill Buzbee6e963e12009-06-17 16:56:19 -0700122 dvmFprintf(stderr, " -Xjitprofile\n");
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700123 dvmFprintf(stderr, " -Xjitdisableopt\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700124#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125 dvmFprintf(stderr, "\n");
126 dvmFprintf(stderr, "Configured with:"
127#ifdef WITH_DEBUGGER
128 " debugger"
129#endif
130#ifdef WITH_PROFILER
131 " profiler"
132#endif
133#ifdef WITH_MONITOR_TRACKING
134 " monitor_tracking"
135#endif
136#ifdef WITH_DEADLOCK_PREDICTION
137 " deadlock_prediction"
138#endif
139#ifdef WITH_HPROF
140 " hprof"
141#endif
142#ifdef WITH_HPROF_STACK
143 " hprof_stack"
144#endif
145#ifdef WITH_HPROF_STACK_UNREACHABLE
146 " hprof_stack_unreachable"
147#endif
148#ifdef WITH_ALLOC_LIMITS
149 " alloc_limits"
150#endif
151#ifdef WITH_TRACKREF_CHECKS
152 " trackref_checks"
153#endif
154#ifdef WITH_INSTR_CHECKS
155 " instr_checks"
156#endif
157#ifdef WITH_EXTRA_OBJECT_VALIDATION
158 " extra_object_validation"
159#endif
The Android Open Source Project99409882009-03-18 22:20:24 -0700160#ifdef WITH_EXTRA_GC_CHECKS
161 " extra_gc_checks"
162#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800163#ifdef WITH_DALVIK_ASSERT
164 " dalvik_assert"
165#endif
166#ifdef WITH_JNI_STACK_CHECK
167 " jni_stack_check"
168#endif
169#ifdef EASY_GDB
170 " easy_gdb"
171#endif
172#ifdef CHECK_MUTEX
173 " check_mutex"
174#endif
175#ifdef PROFILE_FIELD_ACCESS
176 " profile_field_access"
177#endif
178#ifdef DVM_TRACK_HEAP_MARKING
179 " track_heap_marking"
180#endif
181#if DVM_RESOLVER_CACHE == DVM_RC_REDUCING
182 " resolver_cache_reducing"
183#elif DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
184 " resolver_cache_expanding"
185#elif DVM_RESOLVER_CACHE == DVM_RC_NO_CACHE
186 " resolver_cache_disabled"
187#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700188#if defined(WITH_JIT)
Jeff Hao97319a82009-08-12 16:57:15 -0700189 " jit"
190#endif
191#if defined(WITH_SELF_VERIFICATION)
192 " self_verification"
Ben Chengba4fc8b2009-06-01 13:00:29 -0700193#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800194 );
195#ifdef DVM_SHOW_EXCEPTION
196 dvmFprintf(stderr, " show_exception=%d", DVM_SHOW_EXCEPTION);
197#endif
198 dvmFprintf(stderr, "\n\n");
199}
200
201/*
202 * Show helpful information on JDWP options.
203 */
204static void showJdwpHelp(void)
205{
206 dvmFprintf(stderr,
207 "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n");
208 dvmFprintf(stderr,
209 "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
210}
211
212/*
213 * Show version and copyright info.
214 */
215static void showVersion(void)
216{
217 dvmFprintf(stdout, "DalvikVM version %d.%d.%d\n",
218 DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
219 dvmFprintf(stdout,
220 "Copyright (C) 2007 The Android Open Source Project\n\n"
221 "This software is built from source code licensed under the "
222 "Apache License,\n"
223 "Version 2.0 (the \"License\"). You may obtain a copy of the "
224 "License at\n\n"
225 " http://www.apache.org/licenses/LICENSE-2.0\n\n"
226 "See the associated NOTICE file for this software for further "
227 "details.\n");
228}
229
230/*
231 * Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
232 * memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
233 * [gG] gigabytes.
234 *
235 * "s" should point just past the "-Xm?" part of the string.
236 * "min" specifies the lowest acceptable value described by "s".
237 * "div" specifies a divisor, e.g. 1024 if the value must be a multiple
238 * of 1024.
239 *
240 * The spec says the -Xmx and -Xms options must be multiples of 1024. It
241 * doesn't say anything about -Xss.
242 *
243 * Returns 0 (a useless size) if "s" is malformed or specifies a low or
244 * non-evenly-divisible value.
245 */
246static unsigned int dvmParseMemOption(const char *s, unsigned int div)
247{
248 /* strtoul accepts a leading [+-], which we don't want,
249 * so make sure our string starts with a decimal digit.
250 */
251 if (isdigit(*s)) {
252 const char *s2;
253 unsigned int val;
254
255 val = (unsigned int)strtoul(s, (char **)&s2, 10);
256 if (s2 != s) {
257 /* s2 should be pointing just after the number.
258 * If this is the end of the string, the user
259 * has specified a number of bytes. Otherwise,
260 * there should be exactly one more character
261 * that specifies a multiplier.
262 */
263 if (*s2 != '\0') {
264 char c;
265
266 /* The remainder of the string is either a single multiplier
267 * character, or nothing to indicate that the value is in
268 * bytes.
269 */
270 c = *s2++;
271 if (*s2 == '\0') {
272 unsigned int mul;
273
274 if (c == '\0') {
275 mul = 1;
276 } else if (c == 'k' || c == 'K') {
277 mul = 1024;
278 } else if (c == 'm' || c == 'M') {
279 mul = 1024 * 1024;
280 } else if (c == 'g' || c == 'G') {
281 mul = 1024 * 1024 * 1024;
282 } else {
283 /* Unknown multiplier character.
284 */
285 return 0;
286 }
287
288 if (val <= UINT_MAX / mul) {
289 val *= mul;
290 } else {
291 /* Clamp to a multiple of 1024.
292 */
293 val = UINT_MAX & ~(1024-1);
294 }
295 } else {
296 /* There's more than one character after the
297 * numeric part.
298 */
299 return 0;
300 }
301 }
302
303 /* The man page says that a -Xm value must be
304 * a multiple of 1024.
305 */
306 if (val % div == 0) {
307 return val;
308 }
309 }
310 }
311
312 return 0;
313}
314
315/*
316 * Handle one of the JDWP name/value pairs.
317 *
318 * JDWP options are:
319 * help: if specified, show help message and bail
320 * transport: may be dt_socket or dt_shmem
321 * address: for dt_socket, "host:port", or just "port" when listening
322 * server: if "y", wait for debugger to attach; if "n", attach to debugger
323 * timeout: how long to wait for debugger to connect / listen
324 *
325 * Useful with server=n (these aren't supported yet):
326 * onthrow=<exception-name>: connect to debugger when exception thrown
327 * onuncaught=y|n: connect to debugger when uncaught exception thrown
328 * launch=<command-line>: launch the debugger itself
329 *
330 * The "transport" option is required, as is "address" if server=n.
331 */
332static bool handleJdwpOption(const char* name, const char* value)
333{
334 if (strcmp(name, "transport") == 0) {
335 if (strcmp(value, "dt_socket") == 0) {
336 gDvm.jdwpTransport = kJdwpTransportSocket;
337 } else if (strcmp(value, "dt_android_adb") == 0) {
338 gDvm.jdwpTransport = kJdwpTransportAndroidAdb;
339 } else {
340 LOGE("JDWP transport '%s' not supported\n", value);
341 return false;
342 }
343 } else if (strcmp(name, "server") == 0) {
344 if (*value == 'n')
345 gDvm.jdwpServer = false;
346 else if (*value == 'y')
347 gDvm.jdwpServer = true;
348 else {
349 LOGE("JDWP option 'server' must be 'y' or 'n'\n");
350 return false;
351 }
352 } else if (strcmp(name, "suspend") == 0) {
353 if (*value == 'n')
354 gDvm.jdwpSuspend = false;
355 else if (*value == 'y')
356 gDvm.jdwpSuspend = true;
357 else {
358 LOGE("JDWP option 'suspend' must be 'y' or 'n'\n");
359 return false;
360 }
361 } else if (strcmp(name, "address") == 0) {
362 /* this is either <port> or <host>:<port> */
363 const char* colon = strchr(value, ':');
364 char* end;
365 long port;
366
367 if (colon != NULL) {
368 free(gDvm.jdwpHost);
369 gDvm.jdwpHost = (char*) malloc(colon - value +1);
370 strncpy(gDvm.jdwpHost, value, colon - value +1);
371 gDvm.jdwpHost[colon-value] = '\0';
372 value = colon + 1;
373 }
374 if (*value == '\0') {
375 LOGE("JDWP address missing port\n");
376 return false;
377 }
378 port = strtol(value, &end, 10);
379 if (*end != '\0') {
380 LOGE("JDWP address has junk in port field '%s'\n", value);
381 return false;
382 }
383 gDvm.jdwpPort = port;
384 } else if (strcmp(name, "launch") == 0 ||
385 strcmp(name, "onthrow") == 0 ||
386 strcmp(name, "oncaught") == 0 ||
387 strcmp(name, "timeout") == 0)
388 {
389 /* valid but unsupported */
390 LOGI("Ignoring JDWP option '%s'='%s'\n", name, value);
391 } else {
392 LOGI("Ignoring unrecognized JDWP option '%s'='%s'\n", name, value);
393 }
394
395 return true;
396}
397
398/*
399 * Parse the latter half of a -Xrunjdwp/-agentlib:jdwp= string, e.g.:
400 * "transport=dt_socket,address=8000,server=y,suspend=n"
401 */
402static bool parseJdwpOptions(const char* str)
403{
404 char* mangle = strdup(str);
405 char* name = mangle;
406 bool result = false;
407
408 /*
409 * Process all of the name=value pairs.
410 */
411 while (true) {
412 char* value;
413 char* comma;
414
415 value = strchr(name, '=');
416 if (value == NULL) {
417 LOGE("JDWP opts: garbage at '%s'\n", name);
418 goto bail;
419 }
420
421 comma = strchr(name, ','); // use name, not value, for safety
422 if (comma != NULL) {
423 if (comma < value) {
424 LOGE("JDWP opts: found comma before '=' in '%s'\n", mangle);
425 goto bail;
426 }
427 *comma = '\0';
428 }
429
430 *value++ = '\0'; // stomp the '='
431
432 if (!handleJdwpOption(name, value))
433 goto bail;
434
435 if (comma == NULL) {
436 /* out of options */
437 break;
438 }
439 name = comma+1;
440 }
441
442 /*
443 * Make sure the combination of arguments makes sense.
444 */
445 if (gDvm.jdwpTransport == kJdwpTransportUnknown) {
446 LOGE("JDWP opts: must specify transport\n");
447 goto bail;
448 }
449 if (!gDvm.jdwpServer && (gDvm.jdwpHost == NULL || gDvm.jdwpPort == 0)) {
450 LOGE("JDWP opts: when server=n, must specify host and port\n");
451 goto bail;
452 }
453 // transport mandatory
454 // outbound server address
455
456 gDvm.jdwpConfigured = true;
457 result = true;
458
459bail:
460 free(mangle);
461 return result;
462}
463
464/*
465 * Handle one of the four kinds of assertion arguments.
466 *
467 * "pkgOrClass" is the last part of an enable/disable line. For a package
468 * the arg looks like "-ea:com.google.fubar...", for a class it looks
469 * like "-ea:com.google.fubar.Wahoo". The string we get starts at the ':'.
470 *
471 * For system assertions (-esa/-dsa), "pkgOrClass" is NULL.
472 *
473 * Multiple instances of these arguments can be specified, e.g. you can
474 * enable assertions for a package and then disable them for one class in
475 * the package.
476 */
477static bool enableAssertions(const char* pkgOrClass, bool enable)
478{
479 AssertionControl* pCtrl = &gDvm.assertionCtrl[gDvm.assertionCtrlCount++];
480 pCtrl->enable = enable;
481
482 if (pkgOrClass == NULL) {
483 /* enable or disable for all system classes */
484 pCtrl->isPackage = false;
485 pCtrl->pkgOrClass = NULL;
486 pCtrl->pkgOrClassLen = 0;
487 } else {
488 if (*pkgOrClass == '\0') {
489 /* global enable/disable for all but system */
490 pCtrl->isPackage = false;
491 pCtrl->pkgOrClass = strdup("");
492 pCtrl->pkgOrClassLen = 0;
493 } else {
494 pCtrl->pkgOrClass = dvmDotToSlash(pkgOrClass+1); // skip ':'
495 if (pCtrl->pkgOrClass == NULL) {
496 /* can happen if class name includes an illegal '/' */
497 LOGW("Unable to process assertion arg '%s'\n", pkgOrClass);
498 return false;
499 }
500
501 int len = strlen(pCtrl->pkgOrClass);
502 if (len >= 3 && strcmp(pCtrl->pkgOrClass + len-3, "///") == 0) {
503 /* mark as package, truncate two of the three slashes */
504 pCtrl->isPackage = true;
505 *(pCtrl->pkgOrClass + len-2) = '\0';
506 pCtrl->pkgOrClassLen = len - 2;
507 } else {
508 /* just a class */
509 pCtrl->isPackage = false;
510 pCtrl->pkgOrClassLen = len;
511 }
512 }
513 }
514
515 return true;
516}
517
518/*
519 * Turn assertions on when requested to do so by the Zygote.
520 *
521 * This is a bit sketchy. We can't (easily) go back and fiddle with all
522 * of the classes that have already been initialized, so this only
523 * affects classes that have yet to be loaded. If some or all assertions
524 * have been enabled through some other means, we don't want to mess with
525 * it here, so we do nothing. Finally, we assume that there's room in
526 * "assertionCtrl" to hold at least one entry; this is guaranteed by the
527 * allocator.
528 *
529 * This must only be called from the main thread during zygote init.
530 */
531void dvmLateEnableAssertions(void)
532{
533 if (gDvm.assertionCtrl == NULL) {
534 LOGD("Not late-enabling assertions: no assertionCtrl array\n");
535 return;
536 } else if (gDvm.assertionCtrlCount != 0) {
537 LOGD("Not late-enabling assertions: some asserts already configured\n");
538 return;
539 }
540 LOGD("Late-enabling assertions\n");
541
542 /* global enable for all but system */
543 AssertionControl* pCtrl = gDvm.assertionCtrl;
544 pCtrl->pkgOrClass = strdup("");
545 pCtrl->pkgOrClassLen = 0;
546 pCtrl->isPackage = false;
547 pCtrl->enable = true;
548 gDvm.assertionCtrlCount = 1;
549}
550
551
552/*
553 * Release memory associated with the AssertionCtrl array.
554 */
555static void freeAssertionCtrl(void)
556{
557 int i;
558
559 for (i = 0; i < gDvm.assertionCtrlCount; i++)
560 free(gDvm.assertionCtrl[i].pkgOrClass);
561 free(gDvm.assertionCtrl);
562}
563
Ben Chengba4fc8b2009-06-01 13:00:29 -0700564#if defined(WITH_JIT)
565/* Parse -Xjitop to selectively turn on/off certain opcodes for JIT */
566static void processXjitop(const char *opt)
567{
568 if (opt[7] == ':') {
569 const char *startPtr = &opt[8];
570 char *endPtr = NULL;
571
572 do {
573 long startValue, endValue;
574
575 startValue = strtol(startPtr, &endPtr, 16);
576 if (startPtr != endPtr) {
577 /* Just in case value is out of range */
578 startValue &= 0xff;
579
580 if (*endPtr == '-') {
581 endValue = strtol(endPtr+1, &endPtr, 16);
582 endValue &= 0xff;
583 } else {
584 endValue = startValue;
585 }
586
587 for (; startValue <= endValue; startValue++) {
588 LOGW("Dalvik opcode %x is selected for debugging",
589 (unsigned int) startValue);
590 /* Mark the corresponding bit to 1 */
591 gDvmJit.opList[startValue >> 3] |=
592 1 << (startValue & 0x7);
593 }
594
595 if (*endPtr == 0) {
596 break;
597 }
598
599 startPtr = endPtr + 1;
600
601 continue;
602 } else {
603 if (*endPtr != 0) {
604 dvmFprintf(stderr,
605 "Warning: Unrecognized opcode value substring "
606 "%s\n", endPtr);
607 }
608 break;
609 }
610 } while (1);
611 } else {
612 int i;
613 for (i = 0; i < 32; i++) {
614 gDvmJit.opList[i] = 0xff;
615 }
616 dvmFprintf(stderr, "Warning: select all opcodes\n");
617 }
618}
619
620/* Parse -Xjitmethod to selectively turn on/off certain methods for JIT */
621static void processXjitmethod(const char *opt)
622{
623 char *buf = strdup(&opt[12]);
624 char *start, *end;
625
626 gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
627
628 start = buf;
629 /*
630 * Break comma-separated method signatures and enter them into the hash
631 * table individually.
632 */
633 do {
634 int hashValue;
635
636 end = strchr(start, ',');
637 if (end) {
638 *end = 0;
639 }
640
641 hashValue = dvmComputeUtf8Hash(start);
642
643 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
644 strdup(start),
645 (HashCompareFunc) strcmp, true);
646 if (end) {
647 start = end + 1;
648 } else {
649 break;
650 }
651 } while (1);
652 free(buf);
653}
654#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800655
656/*
657 * Process an argument vector full of options. Unlike standard C programs,
658 * argv[0] does not contain the name of the program.
659 *
660 * If "ignoreUnrecognized" is set, we ignore options starting with "-X" or "_"
661 * that we don't recognize. Otherwise, we return with an error as soon as
662 * we see anything we can't identify.
663 *
664 * Returns 0 on success, -1 on failure, and 1 for the special case of
665 * "-version" where we want to stop without showing an error message.
666 */
667static int dvmProcessOptions(int argc, const char* const argv[],
668 bool ignoreUnrecognized)
669{
670 int i;
671
672 LOGV("VM options (%d):\n", argc);
673 for (i = 0; i < argc; i++)
674 LOGV(" %d: '%s'\n", i, argv[i]);
675
676 /*
677 * Over-allocate AssertionControl array for convenience. If allocated,
678 * the array must be able to hold at least one entry, so that the
679 * zygote-time activation can do its business.
680 */
681 assert(gDvm.assertionCtrl == NULL);
682 if (argc > 0) {
683 gDvm.assertionCtrl =
684 (AssertionControl*) malloc(sizeof(AssertionControl) * argc);
685 if (gDvm.assertionCtrl == NULL)
686 return -1;
687 assert(gDvm.assertionCtrlCount == 0);
688 }
689
690 for (i = 0; i < argc; i++) {
691 if (strcmp(argv[i], "-help") == 0) {
692 /* show usage and stop */
693 return -1;
694
695 } else if (strcmp(argv[i], "-version") == 0) {
696 /* show version and stop */
697 showVersion();
698 return 1;
699 } else if (strcmp(argv[i], "-showversion") == 0) {
700 /* show version and continue */
701 showVersion();
702
703 } else if (strcmp(argv[i], "-classpath") == 0 ||
704 strcmp(argv[i], "-cp") == 0)
705 {
706 /* set classpath */
707 if (i == argc-1) {
708 dvmFprintf(stderr, "Missing classpath path list\n");
709 return -1;
710 }
711 free(gDvm.classPathStr); /* in case we have compiled-in default */
712 gDvm.classPathStr = strdup(argv[++i]);
713
714 } else if (strncmp(argv[i], "-Xbootclasspath:",
715 sizeof("-Xbootclasspath:")-1) == 0)
716 {
717 /* set bootclasspath */
718 const char* path = argv[i] + sizeof("-Xbootclasspath:")-1;
719
720 if (*path == '\0') {
721 dvmFprintf(stderr, "Missing bootclasspath path list\n");
722 return -1;
723 }
724 free(gDvm.bootClassPathStr);
725 gDvm.bootClassPathStr = strdup(path);
726
727 /*
728 * TODO: support -Xbootclasspath/a and /p, which append or
729 * prepend to the default bootclasspath. We set the default
730 * path earlier.
731 */
732
733 } else if (strncmp(argv[i], "-D", 2) == 0) {
734 /* set property */
735 dvmAddCommandLineProperty(argv[i] + 2);
736
737 } else if (strcmp(argv[i], "-jar") == 0) {
738 // TODO: handle this; name of jar should be in argv[i+1]
739 dvmFprintf(stderr, "-jar not yet handled\n");
740 assert(false);
741
742 } else if (strncmp(argv[i], "-Xms", 4) == 0) {
743 unsigned int val = dvmParseMemOption(argv[i]+4, 1024);
744 if (val != 0) {
745 if (val >= kMinHeapStartSize && val <= kMaxHeapSize) {
746 gDvm.heapSizeStart = val;
747 } else {
748 dvmFprintf(stderr,
749 "Invalid -Xms '%s', range is %dKB to %dKB\n",
750 argv[i], kMinHeapStartSize/1024, kMaxHeapSize/1024);
751 return -1;
752 }
753 } else {
754 dvmFprintf(stderr, "Invalid -Xms option '%s'\n", argv[i]);
755 return -1;
756 }
757 } else if (strncmp(argv[i], "-Xmx", 4) == 0) {
758 unsigned int val = dvmParseMemOption(argv[i]+4, 1024);
759 if (val != 0) {
760 if (val >= kMinHeapSize && val <= kMaxHeapSize) {
761 gDvm.heapSizeMax = val;
762 } else {
763 dvmFprintf(stderr,
764 "Invalid -Xmx '%s', range is %dKB to %dKB\n",
765 argv[i], kMinHeapSize/1024, kMaxHeapSize/1024);
766 return -1;
767 }
768 } else {
769 dvmFprintf(stderr, "Invalid -Xmx option '%s'\n", argv[i]);
770 return -1;
771 }
772 } else if (strncmp(argv[i], "-Xss", 4) == 0) {
773 unsigned int val = dvmParseMemOption(argv[i]+4, 1);
774 if (val != 0) {
775 if (val >= kMinStackSize && val <= kMaxStackSize) {
776 gDvm.stackSize = val;
777 } else {
778 dvmFprintf(stderr, "Invalid -Xss '%s', range is %d to %d\n",
779 argv[i], kMinStackSize, kMaxStackSize);
780 return -1;
781 }
782 } else {
783 dvmFprintf(stderr, "Invalid -Xss option '%s'\n", argv[i]);
784 return -1;
785 }
786
787 } else if (strcmp(argv[i], "-verbose") == 0 ||
788 strcmp(argv[i], "-verbose:class") == 0)
789 {
790 // JNI spec says "-verbose:gc,class" is valid, but cmd line
791 // doesn't work that way; may want to support.
792 gDvm.verboseClass = true;
793 } else if (strcmp(argv[i], "-verbose:jni") == 0) {
794 gDvm.verboseJni = true;
795 } else if (strcmp(argv[i], "-verbose:gc") == 0) {
796 gDvm.verboseGc = true;
797
798 } else if (strncmp(argv[i], "-enableassertions", 17) == 0) {
799 enableAssertions(argv[i] + 17, true);
800 } else if (strncmp(argv[i], "-ea", 3) == 0) {
801 enableAssertions(argv[i] + 3, true);
802 } else if (strncmp(argv[i], "-disableassertions", 18) == 0) {
803 enableAssertions(argv[i] + 18, false);
804 } else if (strncmp(argv[i], "-da", 3) == 0) {
805 enableAssertions(argv[i] + 3, false);
806 } else if (strcmp(argv[i], "-enablesystemassertions") == 0 ||
807 strcmp(argv[i], "-esa") == 0)
808 {
809 enableAssertions(NULL, true);
810 } else if (strcmp(argv[i], "-disablesystemassertions") == 0 ||
811 strcmp(argv[i], "-dsa") == 0)
812 {
813 enableAssertions(NULL, false);
814
815 } else if (strncmp(argv[i], "-Xcheck:jni", 11) == 0) {
816 /* nothing to do now -- was handled during JNI init */
817
818 } else if (strcmp(argv[i], "-Xdebug") == 0) {
819 /* accept but ignore */
820
821 } else if (strncmp(argv[i], "-Xrunjdwp:", 10) == 0 ||
822 strncmp(argv[i], "-agentlib:jdwp=", 15) == 0)
823 {
824 const char* tail;
825 bool result = false;
826
827 if (argv[i][1] == 'X')
828 tail = argv[i] + 10;
829 else
830 tail = argv[i] + 15;
831
832 if (strncmp(tail, "help", 4) == 0 || !parseJdwpOptions(tail)) {
833 showJdwpHelp();
834 return 1;
835 }
836 } else if (strcmp(argv[i], "-Xrs") == 0) {
837 gDvm.reduceSignals = true;
838 } else if (strcmp(argv[i], "-Xnoquithandler") == 0) {
839 /* disables SIGQUIT handler thread while still blocking SIGQUIT */
840 /* (useful if we don't want thread but system still signals us) */
841 gDvm.noQuitHandler = true;
842 } else if (strcmp(argv[i], "-Xzygote") == 0) {
843 gDvm.zygote = true;
844 } else if (strncmp(argv[i], "-Xdexopt:", 9) == 0) {
845 if (strcmp(argv[i] + 9, "none") == 0)
846 gDvm.dexOptMode = OPTIMIZE_MODE_NONE;
847 else if (strcmp(argv[i] + 9, "verified") == 0)
848 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
849 else if (strcmp(argv[i] + 9, "all") == 0)
850 gDvm.dexOptMode = OPTIMIZE_MODE_ALL;
851 else {
852 dvmFprintf(stderr, "Unrecognized dexopt option '%s'\n",argv[i]);
853 return -1;
854 }
855 } else if (strncmp(argv[i], "-Xverify:", 9) == 0) {
856 if (strcmp(argv[i] + 9, "none") == 0)
857 gDvm.classVerifyMode = VERIFY_MODE_NONE;
858 else if (strcmp(argv[i] + 9, "remote") == 0)
859 gDvm.classVerifyMode = VERIFY_MODE_REMOTE;
860 else if (strcmp(argv[i] + 9, "all") == 0)
861 gDvm.classVerifyMode = VERIFY_MODE_ALL;
862 else {
863 dvmFprintf(stderr, "Unrecognized verify option '%s'\n",argv[i]);
864 return -1;
865 }
866 } else if (strncmp(argv[i], "-Xjnigreflimit:", 15) == 0) {
867 int lim = atoi(argv[i] + 15);
868 if (lim < 200 || (lim % 100) != 0) {
869 dvmFprintf(stderr, "Bad value for -Xjnigreflimit: '%s'\n",
870 argv[i]+15);
871 return -1;
872 }
873 gDvm.jniGrefLimit = lim;
874
875 } else if (strcmp(argv[i], "-Xlog-stdio") == 0) {
876 gDvm.logStdio = true;
877
878 } else if (strncmp(argv[i], "-Xint", 5) == 0) {
879 if (argv[i][5] == ':') {
880 if (strcmp(argv[i] + 6, "portable") == 0)
881 gDvm.executionMode = kExecutionModeInterpPortable;
882 else if (strcmp(argv[i] + 6, "fast") == 0)
883 gDvm.executionMode = kExecutionModeInterpFast;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700884#ifdef WITH_JIT
885 else if (strcmp(argv[i] + 6, "jit") == 0)
886 gDvm.executionMode = kExecutionModeJit;
887#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888 else {
889 dvmFprintf(stderr,
890 "Warning: Unrecognized interpreter mode %s\n",argv[i]);
891 /* keep going */
892 }
893 } else {
894 /* disable JIT -- nothing to do here for now */
895 }
896
Ben Chengba4fc8b2009-06-01 13:00:29 -0700897#ifdef WITH_JIT
898 } else if (strncmp(argv[i], "-Xjitop", 7) == 0) {
899 processXjitop(argv[i]);
900 } else if (strncmp(argv[i], "-Xjitmethod", 11) == 0) {
901 processXjitmethod(argv[i]);
Bill Buzbeed7269912009-11-10 14:31:32 -0800902 } else if (strncmp(argv[i], "-Xjitblocking", 13) == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700903 gDvmJit.blockingMode = true;
Bill Buzbeed7269912009-11-10 14:31:32 -0800904 } else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
905 gDvmJit.threshold = atoi(argv[i] + 15);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700906 } else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) {
907 gDvmJit.includeSelectedOp = true;
908 } else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
909 gDvmJit.includeSelectedMethod = true;
910 } else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
911 gDvmJit.printMe = true;
Bill Buzbee6e963e12009-06-17 16:56:19 -0700912 } else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
913 gDvmJit.profile = true;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700914 } else if (strncmp(argv[i], "-Xjitdisableopt:", 16) == 0) {
915 sscanf(argv[i] + 16, "%x", &gDvmJit.disableOpt);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700916#endif
917
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800918 } else if (strncmp(argv[i], "-Xdeadlockpredict:", 18) == 0) {
919#ifdef WITH_DEADLOCK_PREDICTION
920 if (strcmp(argv[i] + 18, "off") == 0)
921 gDvm.deadlockPredictMode = kDPOff;
922 else if (strcmp(argv[i] + 18, "warn") == 0)
923 gDvm.deadlockPredictMode = kDPWarn;
924 else if (strcmp(argv[i] + 18, "err") == 0)
925 gDvm.deadlockPredictMode = kDPErr;
926 else if (strcmp(argv[i] + 18, "abort") == 0)
927 gDvm.deadlockPredictMode = kDPAbort;
928 else {
929 dvmFprintf(stderr, "Bad value for -Xdeadlockpredict");
930 return -1;
931 }
932 if (gDvm.deadlockPredictMode != kDPOff)
933 LOGD("Deadlock prediction enabled (%s)\n", argv[i]+18);
934#endif
935
936 } else if (strncmp(argv[i], "-Xstacktracefile:", 17) == 0) {
937 gDvm.stackTraceFile = strdup(argv[i]+17);
938
939 } else if (strcmp(argv[i], "-Xgenregmap") == 0) {
940 gDvm.generateRegisterMaps = true;
Andy McFaddena66a01a2009-08-18 15:11:35 -0700941 LOGV("Register maps will be generated during verification\n");
The Android Open Source Project99409882009-03-18 22:20:24 -0700942
943 } else if (strncmp(argv[i], "-Xgc:", 5) == 0) {
944 if (strcmp(argv[i] + 5, "precise") == 0)
945 gDvm.preciseGc = true;
946 else if (strcmp(argv[i] + 5, "noprecise") == 0)
947 gDvm.preciseGc = false;
948 else {
949 dvmFprintf(stderr, "Bad value for -Xgc");
950 return -1;
951 }
952 LOGD("Precise GC configured %s\n", gDvm.preciseGc ? "ON" : "OFF");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800953
954 } else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
955 gDvm.verifyDexChecksum = true;
956
957 } else {
958 if (!ignoreUnrecognized) {
959 dvmFprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
960 return -1;
961 }
962 }
963 }
964
965 if (gDvm.heapSizeStart > gDvm.heapSizeMax) {
966 dvmFprintf(stderr, "Heap start size must be <= heap max size\n");
967 return -1;
968 }
969
970 return 0;
971}
972
973/*
974 * Set defaults for fields altered or modified by arguments.
The Android Open Source Project99409882009-03-18 22:20:24 -0700975 *
976 * Globals are initialized to 0 (a/k/a NULL or false).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800977 */
978static void setCommandLineDefaults()
979{
980 const char* envStr;
981
982 envStr = getenv("CLASSPATH");
983 if (envStr != NULL)
984 gDvm.classPathStr = strdup(envStr);
985 else
986 gDvm.classPathStr = strdup(".");
987 envStr = getenv("BOOTCLASSPATH");
988 if (envStr != NULL)
989 gDvm.bootClassPathStr = strdup(envStr);
990 else
991 gDvm.bootClassPathStr = strdup(".");
992
993 /* Defaults overridden by -Xms and -Xmx.
994 * TODO: base these on a system or application-specific default
995 */
996 gDvm.heapSizeStart = 2 * 1024 * 1024; // Spec says 16MB; too big for us.
997 gDvm.heapSizeMax = 16 * 1024 * 1024; // Spec says 75% physical mem
998 gDvm.stackSize = kDefaultStackSize;
999
1000 /* gDvm.jdwpSuspend = true; */
1001
1002 /* allowed unless zygote config doesn't allow it */
1003 gDvm.jdwpAllowed = true;
1004
1005 /* default verification and optimization modes */
1006 gDvm.classVerifyMode = VERIFY_MODE_ALL;
1007 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
1008
1009 /*
1010 * Default execution mode.
1011 *
1012 * This should probably interact with the mterp code somehow, e.g. if
1013 * we know we're using the "desktop" build we should probably be
1014 * using "portable" rather than "fast".
1015 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001016#if defined(WITH_JIT)
1017 gDvm.executionMode = kExecutionModeJit;
1018 /*
1019 * TODO - check system property and insert command-line options in
1020 * frameworks/base/core/jni/AndroidRuntime.cpp
1021 */
1022 gDvmJit.blockingMode = false;
Bill Buzbee27176222009-06-09 09:20:16 -07001023 gDvmJit.jitTableSize = 512;
1024 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001025 gDvmJit.threshold = 200;
1026#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001027 gDvm.executionMode = kExecutionModeInterpFast;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001028#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001029}
1030
1031
1032/*
1033 * Handle a SIGBUS, which frequently occurs because somebody replaced an
1034 * optimized DEX file out from under us.
1035 */
1036static void busCatcher(int signum, siginfo_t* info, void* context)
1037{
1038 void* addr = info->si_addr;
1039
1040 LOGE("Caught a SIGBUS (%d), addr=%p\n", signum, addr);
1041
1042 /*
1043 * If we return at this point the SIGBUS just keeps happening, so we
1044 * remove the signal handler and allow it to kill us. TODO: restore
1045 * the original, which points to a debuggerd stub; if we don't then
1046 * debuggerd won't be notified.
1047 */
1048 signal(SIGBUS, SIG_DFL);
1049}
1050
1051/*
1052 * Configure signals. We need to block SIGQUIT so that the signal only
1053 * reaches the dump-stack-trace thread.
1054 *
1055 * This can be disabled with the "-Xrs" flag.
1056 */
1057static void blockSignals()
1058{
1059 sigset_t mask;
1060 int cc;
1061
1062 sigemptyset(&mask);
1063 sigaddset(&mask, SIGQUIT);
1064 sigaddset(&mask, SIGUSR1); // used to initiate heap dump
Ben Chengba4fc8b2009-06-01 13:00:29 -07001065#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
1066 sigaddset(&mask, SIGUSR2); // used to investigate JIT internals
1067#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001068 //sigaddset(&mask, SIGPIPE);
1069 cc = sigprocmask(SIG_BLOCK, &mask, NULL);
1070 assert(cc == 0);
1071
1072 if (false) {
1073 /* TODO: save the old sigaction in a global */
1074 struct sigaction sa;
1075 memset(&sa, 0, sizeof(sa));
1076 sa.sa_sigaction = busCatcher;
1077 sa.sa_flags = SA_SIGINFO;
1078 cc = sigaction(SIGBUS, &sa, NULL);
1079 assert(cc == 0);
1080 }
1081}
1082
1083/*
1084 * VM initialization. Pass in any options provided on the command line.
1085 * Do not pass in the class name or the options for the class.
1086 *
1087 * Returns 0 on success.
1088 */
1089int dvmStartup(int argc, const char* const argv[], bool ignoreUnrecognized,
1090 JNIEnv* pEnv)
1091{
1092 int i, cc;
1093
1094 assert(gDvm.initializing);
1095
1096 LOGV("VM init args (%d):\n", argc);
1097 for (i = 0; i < argc; i++)
1098 LOGV(" %d: '%s'\n", i, argv[i]);
1099
1100 setCommandLineDefaults();
1101
1102 /* prep properties storage */
1103 if (!dvmPropertiesStartup(argc))
1104 goto fail;
1105
1106 /*
1107 * Process the option flags (if any).
1108 */
1109 cc = dvmProcessOptions(argc, argv, ignoreUnrecognized);
1110 if (cc != 0) {
1111 if (cc < 0) {
1112 dvmFprintf(stderr, "\n");
1113 dvmUsage("dalvikvm");
1114 }
1115 goto fail;
1116 }
1117
The Android Open Source Project99409882009-03-18 22:20:24 -07001118#if WITH_EXTRA_GC_CHECKS > 1
1119 /* only "portable" interp has the extra goodies */
1120 if (gDvm.executionMode != kExecutionModeInterpPortable) {
1121 LOGI("Switching to 'portable' interpreter for GC checks\n");
1122 gDvm.executionMode = kExecutionModeInterpPortable;
1123 }
1124#endif
1125
San Mehat894dd462009-09-08 20:29:15 -07001126 /* Configure group scheduling capabilities */
1127 if (!access("/dev/cpuctl/tasks", F_OK)) {
1128 LOGV("Using kernel group scheduling");
1129 gDvm.kernelGroupScheduling = 1;
1130 } else {
1131 LOGV("Using kernel scheduler policies");
1132 }
1133
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001134 /* configure signal handling */
1135 if (!gDvm.reduceSignals)
1136 blockSignals();
1137
Andy McFadden96516932009-10-28 17:39:02 -07001138 /* verify system page size */
1139 if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {
1140 LOGE("ERROR: expected page size %d, got %d\n",
1141 SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));
1142 goto fail;
1143 }
1144
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001145 /* mterp setup */
1146 LOGV("Using executionMode %d\n", gDvm.executionMode);
1147 dvmCheckAsmConstants();
1148
1149 /*
1150 * Initialize components.
1151 */
1152 if (!dvmAllocTrackerStartup())
1153 goto fail;
1154 if (!dvmGcStartup())
1155 goto fail;
1156 if (!dvmThreadStartup())
1157 goto fail;
1158 if (!dvmInlineNativeStartup())
1159 goto fail;
1160 if (!dvmVerificationStartup())
1161 goto fail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001162 if (!dvmRegisterMapStartup())
1163 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001164 if (!dvmInstanceofStartup())
1165 goto fail;
1166 if (!dvmClassStartup())
1167 goto fail;
1168 if (!dvmThreadObjStartup())
1169 goto fail;
1170 if (!dvmExceptionStartup())
1171 goto fail;
1172 if (!dvmStringInternStartup())
1173 goto fail;
1174 if (!dvmNativeStartup())
1175 goto fail;
1176 if (!dvmInternalNativeStartup())
1177 goto fail;
1178 if (!dvmJniStartup())
1179 goto fail;
1180 if (!dvmReflectStartup())
1181 goto fail;
1182#ifdef WITH_PROFILER
1183 if (!dvmProfilingStartup())
1184 goto fail;
1185#endif
1186
1187 /* make sure we got these [can this go away?] */
1188 assert(gDvm.classJavaLangClass != NULL);
1189 assert(gDvm.classJavaLangObject != NULL);
1190 //assert(gDvm.classJavaLangString != NULL);
1191 assert(gDvm.classJavaLangThread != NULL);
1192 assert(gDvm.classJavaLangVMThread != NULL);
1193 assert(gDvm.classJavaLangThreadGroup != NULL);
1194
1195 /*
1196 * Make sure these exist. If they don't, we can return a failure out
1197 * of main and nip the whole thing in the bud.
1198 */
1199 static const char* earlyClasses[] = {
1200 "Ljava/lang/InternalError;",
1201 "Ljava/lang/StackOverflowError;",
1202 "Ljava/lang/UnsatisfiedLinkError;",
1203 "Ljava/lang/NoClassDefFoundError;",
1204 NULL
1205 };
1206 const char** pClassName;
1207 for (pClassName = earlyClasses; *pClassName != NULL; pClassName++) {
1208 if (dvmFindSystemClassNoInit(*pClassName) == NULL)
1209 goto fail;
1210 }
1211
1212 /*
1213 * Miscellaneous class library validation.
1214 */
1215 if (!dvmValidateBoxClasses())
1216 goto fail;
1217
1218 /*
1219 * Do the last bits of Thread struct initialization we need to allow
1220 * JNI calls to work.
1221 */
1222 if (!dvmPrepMainForJni(pEnv))
1223 goto fail;
1224
1225 /*
1226 * Register the system native methods, which are registered through JNI.
1227 */
1228 if (!registerSystemNatives(pEnv))
1229 goto fail;
1230
1231 /*
1232 * Do some "late" initialization for the memory allocator. This may
1233 * allocate storage and initialize classes.
1234 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -07001235 if (!dvmCreateStockExceptions())
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001236 goto fail;
1237
1238 /*
1239 * At this point, the VM is in a pretty good state. Finish prep on
1240 * the main thread (specifically, create a java.lang.Thread object to go
1241 * along with our Thread struct). Note we will probably be executing
1242 * some interpreted class initializer code in here.
1243 */
1244 if (!dvmPrepMainThread())
1245 goto fail;
1246
1247 /* general debugging setup */
1248 if (!dvmDebuggerStartup())
1249 goto fail;
1250
1251 /*
1252 * Init for either zygote mode or non-zygote mode. The key difference
1253 * is that we don't start any additional threads in Zygote mode.
1254 */
1255 if (gDvm.zygote) {
1256 if (!dvmInitZygote())
1257 goto fail;
1258 } else {
1259 if (!dvmInitAfterZygote())
1260 goto fail;
1261 }
1262
1263
1264#ifndef NDEBUG
Andy McFadden734155e2009-07-16 18:11:22 -07001265 if (!dvmTestHash())
1266 LOGE("dmvTestHash FAILED\n");
1267 if (false /*noisy!*/ && !dvmTestIndirectRefTable())
1268 LOGE("dvmTestIndirectRefTable FAILED\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001269#endif
1270
1271 assert(!dvmCheckException(dvmThreadSelf()));
1272 gDvm.initExceptionCount = 0;
1273
1274 return 0;
1275
1276fail:
1277 dvmShutdown();
1278 return 1;
1279}
1280
1281/*
1282 * Register java.* natives from our class libraries. We need to do
1283 * this after we're ready for JNI registration calls, but before we
1284 * do any class initialization.
1285 *
1286 * If we get this wrong, we will blow up in the ThreadGroup class init if
1287 * interpreted code makes any reference to System. It will likely do this
1288 * since it wants to do some java.io.File setup (e.g. for static in/out/err).
1289 *
1290 * We need to have gDvm.initializing raised here so that JNI FindClass
1291 * won't try to use the system/application class loader.
1292 */
1293static bool registerSystemNatives(JNIEnv* pEnv)
1294{
1295 Thread* self;
1296
1297 /* main thread is always first in list */
1298 self = gDvm.threadList;
1299
1300 /* must set this before allowing JNI-based method registration */
1301 self->status = THREAD_NATIVE;
1302
1303 if (jniRegisterSystemMethods(pEnv) < 0) {
1304 LOGW("jniRegisterSystemMethods failed\n");
1305 return false;
1306 }
1307
1308 /* back to run mode */
1309 self->status = THREAD_RUNNING;
1310
1311 return true;
1312}
1313
1314
1315/*
1316 * Do zygote-mode-only initialization.
1317 */
1318static bool dvmInitZygote(void)
1319{
1320 /* zygote goes into its own process group */
1321 setpgid(0,0);
1322
1323 return true;
1324}
1325
1326/*
1327 * Do non-zygote-mode initialization. This is done during VM init for
1328 * standard startup, or after a "zygote fork" when creating a new process.
1329 */
1330bool dvmInitAfterZygote(void)
1331{
1332 u8 startHeap, startQuit, startJdwp;
1333 u8 endHeap, endQuit, endJdwp;
1334
1335 startHeap = dvmGetRelativeTimeUsec();
1336
1337 /*
1338 * Post-zygote heap initialization, including starting
1339 * the HeapWorker thread.
1340 */
1341 if (!dvmGcStartupAfterZygote())
1342 return false;
1343
1344 endHeap = dvmGetRelativeTimeUsec();
1345 startQuit = dvmGetRelativeTimeUsec();
1346
1347 /* start signal catcher thread that dumps stacks on SIGQUIT */
1348 if (!gDvm.reduceSignals && !gDvm.noQuitHandler) {
1349 if (!dvmSignalCatcherStartup())
1350 return false;
1351 }
1352
1353 /* start stdout/stderr copier, if requested */
1354 if (gDvm.logStdio) {
1355 if (!dvmStdioConverterStartup())
1356 return false;
1357 }
1358
1359 endQuit = dvmGetRelativeTimeUsec();
1360 startJdwp = dvmGetRelativeTimeUsec();
1361
1362 /*
1363 * Start JDWP thread. If the command-line debugger flags specified
1364 * "suspend=y", this will pause the VM. We probably want this to
1365 * come last.
1366 */
1367 if (!dvmInitJDWP()) {
1368 LOGD("JDWP init failed; continuing anyway\n");
1369 }
1370
1371 endJdwp = dvmGetRelativeTimeUsec();
1372
1373 LOGV("thread-start heap=%d quit=%d jdwp=%d total=%d usec\n",
1374 (int)(endHeap-startHeap), (int)(endQuit-startQuit),
1375 (int)(endJdwp-startJdwp), (int)(endJdwp-startHeap));
1376
Ben Chengba4fc8b2009-06-01 13:00:29 -07001377#ifdef WITH_JIT
Ben Cheng580e09e2009-10-09 11:55:30 -07001378 if (gDvm.executionMode == kExecutionModeJit) {
1379 if (!dvmJitStartup())
1380 return false;
1381 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001382#endif
1383
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001384 return true;
1385}
1386
1387/*
1388 * Prepare for a connection to a JDWP-compliant debugger.
1389 *
1390 * Note this needs to happen fairly late in the startup process, because
1391 * we need to have all of the java.* native methods registered (which in
1392 * turn requires JNI to be fully prepped).
1393 *
1394 * There are several ways to initialize:
1395 * server=n
1396 * We immediately try to connect to host:port. Bail on failure. On
1397 * success, send VM_START (suspending the VM if "suspend=y").
1398 * server=y suspend=n
1399 * Passively listen for a debugger to connect. Return immediately.
1400 * server=y suspend=y
1401 * Wait until debugger connects. Send VM_START ASAP, suspending the
1402 * VM after the message is sent.
1403 *
1404 * This gets more complicated with a nonzero value for "timeout".
1405 */
1406static bool dvmInitJDWP(void)
1407{
1408 assert(!gDvm.zygote);
1409
1410#ifndef WITH_DEBUGGER
1411 LOGI("Debugger support not compiled into VM\n");
1412 return false;
1413#endif
1414
1415 /*
1416 * Init JDWP if the debugger is enabled. This may connect out to a
1417 * debugger, passively listen for a debugger, or block waiting for a
1418 * debugger.
1419 */
1420 if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {
1421 JdwpStartupParams params;
1422
1423 if (gDvm.jdwpHost != NULL) {
1424 if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {
1425 LOGE("ERROR: hostname too long: '%s'\n", gDvm.jdwpHost);
1426 return false;
1427 }
1428 strcpy(params.host, gDvm.jdwpHost);
1429 } else {
1430 params.host[0] = '\0';
1431 }
1432 params.transport = gDvm.jdwpTransport;
1433 params.server = gDvm.jdwpServer;
1434 params.suspend = gDvm.jdwpSuspend;
1435 params.port = gDvm.jdwpPort;
1436
1437 gDvm.jdwpState = dvmJdwpStartup(&params);
1438 if (gDvm.jdwpState == NULL) {
1439 LOGW("WARNING: debugger thread failed to initialize\n");
1440 /* TODO: ignore? fail? need to mimic "expected" behavior */
1441 }
1442 }
1443
1444 /*
1445 * If a debugger has already attached, send the "welcome" message. This
1446 * may cause us to suspend all threads.
1447 */
1448 if (dvmJdwpIsActive(gDvm.jdwpState)) {
1449 //dvmChangeStatus(NULL, THREAD_RUNNING);
1450 if (!dvmJdwpPostVMStart(gDvm.jdwpState, gDvm.jdwpSuspend)) {
1451 LOGW("WARNING: failed to post 'start' message to debugger\n");
1452 /* keep going */
1453 }
1454 //dvmChangeStatus(NULL, THREAD_NATIVE);
1455 }
1456
1457 return true;
1458}
1459
1460/*
1461 * An alternative to JNI_CreateJavaVM/dvmStartup that does the first bit
1462 * of initialization and then returns with "initializing" still set. (Used
1463 * by DexOpt command-line utility.)
1464 *
1465 * Attempting to use JNI or internal natives will fail. It's best if
1466 * no bytecode gets executed, which means no <clinit>, which means no
1467 * exception-throwing. We check the "initializing" flag anyway when
1468 * throwing an exception, so we can insert some code that avoids chucking
1469 * an exception when we're optimizing stuff.
1470 *
1471 * Returns 0 on success.
1472 */
1473int dvmPrepForDexOpt(const char* bootClassPath, DexOptimizerMode dexOptMode,
1474 DexClassVerifyMode verifyMode, int dexoptFlags)
1475{
1476 gDvm.initializing = true;
1477 gDvm.optimizing = true;
1478
1479 /* configure signal handling */
1480 blockSignals();
1481
1482 /* set some defaults */
1483 setCommandLineDefaults();
1484 free(gDvm.bootClassPathStr);
1485 gDvm.bootClassPathStr = strdup(bootClassPath);
1486
1487 /* set opt/verify modes */
1488 gDvm.dexOptMode = dexOptMode;
1489 gDvm.classVerifyMode = verifyMode;
1490 gDvm.generateRegisterMaps = (dexoptFlags & DEXOPT_GEN_REGISTER_MAPS) != 0;
1491
1492 /*
1493 * Initialize the heap, some basic thread control mutexes, and
1494 * get the bootclasspath prepped.
1495 *
1496 * We can't load any classes yet because we may not yet have a source
1497 * for things like java.lang.Object and java.lang.Class.
1498 */
1499 if (!dvmGcStartup())
1500 goto fail;
1501 if (!dvmThreadStartup())
1502 goto fail;
1503 if (!dvmInlineNativeStartup())
1504 goto fail;
1505 if (!dvmVerificationStartup())
1506 goto fail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001507 if (!dvmRegisterMapStartup())
1508 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001509 if (!dvmInstanceofStartup())
1510 goto fail;
1511 if (!dvmClassStartup())
1512 goto fail;
1513
1514 /*
1515 * We leave gDvm.initializing set to "true" so that, if we're not
1516 * able to process the "core" classes, we don't go into a death-spin
1517 * trying to throw a "class not found" exception.
1518 */
1519
1520 return 0;
1521
1522fail:
1523 dvmShutdown();
1524 return 1;
1525}
1526
1527
1528/*
1529 * All threads have stopped. Finish the shutdown procedure.
1530 *
1531 * We can also be called if startup fails partway through, so be prepared
1532 * to deal with partially initialized data.
1533 *
1534 * Free any storage allocated in gGlobals.
1535 *
1536 * We can't dlclose() shared libs we've loaded, because it's possible a
1537 * thread not associated with the VM is running code in one.
1538 *
1539 * This is called from the JNI DestroyJavaVM function, which can be
1540 * called from any thread. (In practice, this will usually run in the
1541 * same thread that started the VM, a/k/a the main thread, but we don't
1542 * want to assume that.)
1543 */
1544void dvmShutdown(void)
1545{
1546 LOGV("VM shutting down\n");
1547
1548 if (CALC_CACHE_STATS)
1549 dvmDumpAtomicCacheStats(gDvm.instanceofCache);
1550
1551 /*
1552 * Stop our internal threads.
1553 */
1554 dvmHeapWorkerShutdown();
1555
1556 if (gDvm.jdwpState != NULL)
1557 dvmJdwpShutdown(gDvm.jdwpState);
1558 free(gDvm.jdwpHost);
1559 gDvm.jdwpHost = NULL;
1560 free(gDvm.stackTraceFile);
1561 gDvm.stackTraceFile = NULL;
1562
1563 /* tell signal catcher to shut down if it was started */
1564 dvmSignalCatcherShutdown();
1565
1566 /* shut down stdout/stderr conversion */
1567 dvmStdioConverterShutdown();
1568
Ben Chengef00a852009-06-22 22:53:35 -07001569#ifdef WITH_JIT
Ben Cheng580e09e2009-10-09 11:55:30 -07001570 if (gDvm.executionMode == kExecutionModeJit) {
1571 /* shut down the compiler thread */
1572 dvmJitShutdown();
1573 }
Ben Chengef00a852009-06-22 22:53:35 -07001574#endif
1575
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001576 /*
1577 * Kill any daemon threads that still exist. Actively-running threads
1578 * are likely to crash the process if they continue to execute while
1579 * the VM shuts down.
1580 */
1581 dvmSlayDaemons();
1582
1583 LOGD("VM cleaning up\n");
1584
1585 dvmDebuggerShutdown();
1586 dvmReflectShutdown();
1587#ifdef WITH_PROFILER
1588 dvmProfilingShutdown();
1589#endif
1590 dvmJniShutdown();
1591 dvmStringInternShutdown();
1592 dvmExceptionShutdown();
1593 dvmThreadShutdown();
1594 dvmClassShutdown();
1595 dvmVerificationShutdown();
The Android Open Source Project99409882009-03-18 22:20:24 -07001596 dvmRegisterMapShutdown();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001597 dvmInstanceofShutdown();
1598 dvmInlineNativeShutdown();
1599 dvmGcShutdown();
1600 dvmAllocTrackerShutdown();
1601 dvmPropertiesShutdown();
1602
1603 /* these must happen AFTER dvmClassShutdown has walked through class data */
1604 dvmNativeShutdown();
1605 dvmInternalNativeShutdown();
1606
1607 free(gDvm.bootClassPathStr);
1608 free(gDvm.classPathStr);
1609
1610 freeAssertionCtrl();
1611
1612 /*
1613 * We want valgrind to report anything we forget to free as "definitely
1614 * lost". If there's a pointer in the global chunk, it would be reported
1615 * as "still reachable". Erasing the memory fixes this.
1616 *
1617 * This must be erased to zero if we want to restart the VM within this
1618 * process.
1619 */
1620 memset(&gDvm, 0xcd, sizeof(gDvm));
1621}
1622
1623
1624/*
1625 * fprintf() wrapper that calls through the JNI-specified vfprintf hook if
1626 * one was specified.
1627 */
1628int dvmFprintf(FILE* fp, const char* format, ...)
1629{
1630 va_list args;
1631 int result;
1632
1633 va_start(args, format);
1634 if (gDvm.vfprintfHook != NULL)
1635 result = (*gDvm.vfprintfHook)(fp, format, args);
1636 else
1637 result = vfprintf(fp, format, args);
1638 va_end(args);
1639
1640 return result;
1641}
1642
1643/*
1644 * Abort the VM. We get here on fatal errors. Try very hard not to use
1645 * this; whenever possible, return an error to somebody responsible.
1646 */
1647void dvmAbort(void)
1648{
1649 LOGE("VM aborting\n");
1650
1651 fflush(NULL); // flush all open file buffers
1652
1653 /* JNI-supplied abort hook gets right of first refusal */
1654 if (gDvm.abortHook != NULL)
1655 (*gDvm.abortHook)();
1656
1657 /*
1658 * If we call abort(), all threads in the process receives a SIBABRT.
1659 * debuggerd dumps the stack trace of the main thread, whether or not
1660 * that was the thread that failed.
1661 *
1662 * By stuffing a value into a bogus address, we cause a segmentation
1663 * fault in the current thread, and get a useful log from debuggerd.
1664 * We can also trivially tell the difference between a VM crash and
1665 * a deliberate abort by looking at the fault address.
1666 */
1667 *((char*)0xdeadd00d) = 38;
1668 abort();
1669
1670 /* notreached */
1671}