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