blob: c65ce65a95cbb7328a4461520148e7f9755e7c62 [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;
798
799 } else if (strncmp(argv[i], "-enableassertions", 17) == 0) {
800 enableAssertions(argv[i] + 17, true);
801 } else if (strncmp(argv[i], "-ea", 3) == 0) {
802 enableAssertions(argv[i] + 3, true);
803 } else if (strncmp(argv[i], "-disableassertions", 18) == 0) {
804 enableAssertions(argv[i] + 18, false);
805 } else if (strncmp(argv[i], "-da", 3) == 0) {
806 enableAssertions(argv[i] + 3, false);
807 } else if (strcmp(argv[i], "-enablesystemassertions") == 0 ||
808 strcmp(argv[i], "-esa") == 0)
809 {
810 enableAssertions(NULL, true);
811 } else if (strcmp(argv[i], "-disablesystemassertions") == 0 ||
812 strcmp(argv[i], "-dsa") == 0)
813 {
814 enableAssertions(NULL, false);
815
816 } else if (strncmp(argv[i], "-Xcheck:jni", 11) == 0) {
817 /* nothing to do now -- was handled during JNI init */
818
819 } else if (strcmp(argv[i], "-Xdebug") == 0) {
820 /* accept but ignore */
821
822 } else if (strncmp(argv[i], "-Xrunjdwp:", 10) == 0 ||
823 strncmp(argv[i], "-agentlib:jdwp=", 15) == 0)
824 {
825 const char* tail;
826 bool result = false;
827
828 if (argv[i][1] == 'X')
829 tail = argv[i] + 10;
830 else
831 tail = argv[i] + 15;
832
833 if (strncmp(tail, "help", 4) == 0 || !parseJdwpOptions(tail)) {
834 showJdwpHelp();
835 return 1;
836 }
837 } else if (strcmp(argv[i], "-Xrs") == 0) {
838 gDvm.reduceSignals = true;
839 } else if (strcmp(argv[i], "-Xnoquithandler") == 0) {
840 /* disables SIGQUIT handler thread while still blocking SIGQUIT */
841 /* (useful if we don't want thread but system still signals us) */
842 gDvm.noQuitHandler = true;
843 } else if (strcmp(argv[i], "-Xzygote") == 0) {
844 gDvm.zygote = true;
845 } else if (strncmp(argv[i], "-Xdexopt:", 9) == 0) {
846 if (strcmp(argv[i] + 9, "none") == 0)
847 gDvm.dexOptMode = OPTIMIZE_MODE_NONE;
848 else if (strcmp(argv[i] + 9, "verified") == 0)
849 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
850 else if (strcmp(argv[i] + 9, "all") == 0)
851 gDvm.dexOptMode = OPTIMIZE_MODE_ALL;
852 else {
853 dvmFprintf(stderr, "Unrecognized dexopt option '%s'\n",argv[i]);
854 return -1;
855 }
856 } else if (strncmp(argv[i], "-Xverify:", 9) == 0) {
857 if (strcmp(argv[i] + 9, "none") == 0)
858 gDvm.classVerifyMode = VERIFY_MODE_NONE;
859 else if (strcmp(argv[i] + 9, "remote") == 0)
860 gDvm.classVerifyMode = VERIFY_MODE_REMOTE;
861 else if (strcmp(argv[i] + 9, "all") == 0)
862 gDvm.classVerifyMode = VERIFY_MODE_ALL;
863 else {
864 dvmFprintf(stderr, "Unrecognized verify option '%s'\n",argv[i]);
865 return -1;
866 }
867 } else if (strncmp(argv[i], "-Xjnigreflimit:", 15) == 0) {
868 int lim = atoi(argv[i] + 15);
869 if (lim < 200 || (lim % 100) != 0) {
870 dvmFprintf(stderr, "Bad value for -Xjnigreflimit: '%s'\n",
871 argv[i]+15);
872 return -1;
873 }
874 gDvm.jniGrefLimit = lim;
875
876 } else if (strcmp(argv[i], "-Xlog-stdio") == 0) {
877 gDvm.logStdio = true;
878
879 } else if (strncmp(argv[i], "-Xint", 5) == 0) {
880 if (argv[i][5] == ':') {
881 if (strcmp(argv[i] + 6, "portable") == 0)
882 gDvm.executionMode = kExecutionModeInterpPortable;
883 else if (strcmp(argv[i] + 6, "fast") == 0)
884 gDvm.executionMode = kExecutionModeInterpFast;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700885#ifdef WITH_JIT
886 else if (strcmp(argv[i] + 6, "jit") == 0)
887 gDvm.executionMode = kExecutionModeJit;
888#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800889 else {
890 dvmFprintf(stderr,
891 "Warning: Unrecognized interpreter mode %s\n",argv[i]);
892 /* keep going */
893 }
894 } else {
895 /* disable JIT -- nothing to do here for now */
896 }
897
Ben Chengba4fc8b2009-06-01 13:00:29 -0700898#ifdef WITH_JIT
899 } else if (strncmp(argv[i], "-Xjitop", 7) == 0) {
900 processXjitop(argv[i]);
901 } else if (strncmp(argv[i], "-Xjitmethod", 11) == 0) {
902 processXjitmethod(argv[i]);
Bill Buzbeed7269912009-11-10 14:31:32 -0800903 } else if (strncmp(argv[i], "-Xjitblocking", 13) == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700904 gDvmJit.blockingMode = true;
Bill Buzbeed7269912009-11-10 14:31:32 -0800905 } else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
906 gDvmJit.threshold = atoi(argv[i] + 15);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700907 } else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) {
908 gDvmJit.includeSelectedOp = true;
909 } else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
910 gDvmJit.includeSelectedMethod = true;
Ben Cheng33672452010-01-12 14:59:30 -0800911 } else if (strncmp(argv[i], "-Xjitcheckcg", 12) == 0) {
912 gDvmJit.checkCallGraph = true;
913 /* Need to enable blocking mode due to stack crawling */
914 gDvmJit.blockingMode = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700915 } else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
916 gDvmJit.printMe = true;
Bill Buzbee6e963e12009-06-17 16:56:19 -0700917 } else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
918 gDvmJit.profile = true;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700919 } else if (strncmp(argv[i], "-Xjitdisableopt:", 16) == 0) {
920 sscanf(argv[i] + 16, "%x", &gDvmJit.disableOpt);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700921#endif
922
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800923 } else if (strncmp(argv[i], "-Xdeadlockpredict:", 18) == 0) {
924#ifdef WITH_DEADLOCK_PREDICTION
925 if (strcmp(argv[i] + 18, "off") == 0)
926 gDvm.deadlockPredictMode = kDPOff;
927 else if (strcmp(argv[i] + 18, "warn") == 0)
928 gDvm.deadlockPredictMode = kDPWarn;
929 else if (strcmp(argv[i] + 18, "err") == 0)
930 gDvm.deadlockPredictMode = kDPErr;
931 else if (strcmp(argv[i] + 18, "abort") == 0)
932 gDvm.deadlockPredictMode = kDPAbort;
933 else {
934 dvmFprintf(stderr, "Bad value for -Xdeadlockpredict");
935 return -1;
936 }
937 if (gDvm.deadlockPredictMode != kDPOff)
938 LOGD("Deadlock prediction enabled (%s)\n", argv[i]+18);
939#endif
940
941 } else if (strncmp(argv[i], "-Xstacktracefile:", 17) == 0) {
942 gDvm.stackTraceFile = strdup(argv[i]+17);
943
944 } else if (strcmp(argv[i], "-Xgenregmap") == 0) {
945 gDvm.generateRegisterMaps = true;
Andy McFaddena66a01a2009-08-18 15:11:35 -0700946 LOGV("Register maps will be generated during verification\n");
The Android Open Source Project99409882009-03-18 22:20:24 -0700947
948 } else if (strncmp(argv[i], "-Xgc:", 5) == 0) {
949 if (strcmp(argv[i] + 5, "precise") == 0)
950 gDvm.preciseGc = true;
951 else if (strcmp(argv[i] + 5, "noprecise") == 0)
952 gDvm.preciseGc = false;
953 else {
954 dvmFprintf(stderr, "Bad value for -Xgc");
955 return -1;
956 }
957 LOGD("Precise GC configured %s\n", gDvm.preciseGc ? "ON" : "OFF");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800958
959 } else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
960 gDvm.verifyDexChecksum = true;
961
962 } else {
963 if (!ignoreUnrecognized) {
964 dvmFprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
965 return -1;
966 }
967 }
968 }
969
970 if (gDvm.heapSizeStart > gDvm.heapSizeMax) {
971 dvmFprintf(stderr, "Heap start size must be <= heap max size\n");
972 return -1;
973 }
974
975 return 0;
976}
977
978/*
979 * Set defaults for fields altered or modified by arguments.
The Android Open Source Project99409882009-03-18 22:20:24 -0700980 *
981 * Globals are initialized to 0 (a/k/a NULL or false).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800982 */
983static void setCommandLineDefaults()
984{
985 const char* envStr;
986
987 envStr = getenv("CLASSPATH");
988 if (envStr != NULL)
989 gDvm.classPathStr = strdup(envStr);
990 else
991 gDvm.classPathStr = strdup(".");
992 envStr = getenv("BOOTCLASSPATH");
993 if (envStr != NULL)
994 gDvm.bootClassPathStr = strdup(envStr);
995 else
996 gDvm.bootClassPathStr = strdup(".");
997
998 /* Defaults overridden by -Xms and -Xmx.
999 * TODO: base these on a system or application-specific default
1000 */
1001 gDvm.heapSizeStart = 2 * 1024 * 1024; // Spec says 16MB; too big for us.
1002 gDvm.heapSizeMax = 16 * 1024 * 1024; // Spec says 75% physical mem
1003 gDvm.stackSize = kDefaultStackSize;
1004
1005 /* gDvm.jdwpSuspend = true; */
1006
1007 /* allowed unless zygote config doesn't allow it */
1008 gDvm.jdwpAllowed = true;
1009
1010 /* default verification and optimization modes */
1011 gDvm.classVerifyMode = VERIFY_MODE_ALL;
1012 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
1013
1014 /*
1015 * Default execution mode.
1016 *
1017 * This should probably interact with the mterp code somehow, e.g. if
1018 * we know we're using the "desktop" build we should probably be
1019 * using "portable" rather than "fast".
1020 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001021#if defined(WITH_JIT)
1022 gDvm.executionMode = kExecutionModeJit;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001023#else
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001024 gDvm.executionMode = kExecutionModeInterpFast;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001025#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001026}
1027
1028
1029/*
1030 * Handle a SIGBUS, which frequently occurs because somebody replaced an
1031 * optimized DEX file out from under us.
1032 */
1033static void busCatcher(int signum, siginfo_t* info, void* context)
1034{
1035 void* addr = info->si_addr;
1036
1037 LOGE("Caught a SIGBUS (%d), addr=%p\n", signum, addr);
1038
1039 /*
1040 * If we return at this point the SIGBUS just keeps happening, so we
1041 * remove the signal handler and allow it to kill us. TODO: restore
1042 * the original, which points to a debuggerd stub; if we don't then
1043 * debuggerd won't be notified.
1044 */
1045 signal(SIGBUS, SIG_DFL);
1046}
1047
1048/*
1049 * Configure signals. We need to block SIGQUIT so that the signal only
1050 * reaches the dump-stack-trace thread.
1051 *
1052 * This can be disabled with the "-Xrs" flag.
1053 */
1054static void blockSignals()
1055{
1056 sigset_t mask;
1057 int cc;
1058
1059 sigemptyset(&mask);
1060 sigaddset(&mask, SIGQUIT);
1061 sigaddset(&mask, SIGUSR1); // used to initiate heap dump
Ben Chengba4fc8b2009-06-01 13:00:29 -07001062#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
1063 sigaddset(&mask, SIGUSR2); // used to investigate JIT internals
1064#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001065 //sigaddset(&mask, SIGPIPE);
1066 cc = sigprocmask(SIG_BLOCK, &mask, NULL);
1067 assert(cc == 0);
1068
1069 if (false) {
1070 /* TODO: save the old sigaction in a global */
1071 struct sigaction sa;
1072 memset(&sa, 0, sizeof(sa));
1073 sa.sa_sigaction = busCatcher;
1074 sa.sa_flags = SA_SIGINFO;
1075 cc = sigaction(SIGBUS, &sa, NULL);
1076 assert(cc == 0);
1077 }
1078}
1079
1080/*
1081 * VM initialization. Pass in any options provided on the command line.
1082 * Do not pass in the class name or the options for the class.
1083 *
1084 * Returns 0 on success.
1085 */
1086int dvmStartup(int argc, const char* const argv[], bool ignoreUnrecognized,
1087 JNIEnv* pEnv)
1088{
1089 int i, cc;
1090
1091 assert(gDvm.initializing);
1092
1093 LOGV("VM init args (%d):\n", argc);
1094 for (i = 0; i < argc; i++)
1095 LOGV(" %d: '%s'\n", i, argv[i]);
1096
1097 setCommandLineDefaults();
1098
1099 /* prep properties storage */
1100 if (!dvmPropertiesStartup(argc))
1101 goto fail;
1102
1103 /*
1104 * Process the option flags (if any).
1105 */
1106 cc = dvmProcessOptions(argc, argv, ignoreUnrecognized);
1107 if (cc != 0) {
1108 if (cc < 0) {
1109 dvmFprintf(stderr, "\n");
1110 dvmUsage("dalvikvm");
1111 }
1112 goto fail;
1113 }
1114
The Android Open Source Project99409882009-03-18 22:20:24 -07001115#if WITH_EXTRA_GC_CHECKS > 1
1116 /* only "portable" interp has the extra goodies */
1117 if (gDvm.executionMode != kExecutionModeInterpPortable) {
1118 LOGI("Switching to 'portable' interpreter for GC checks\n");
1119 gDvm.executionMode = kExecutionModeInterpPortable;
1120 }
1121#endif
1122
San Mehat894dd462009-09-08 20:29:15 -07001123 /* Configure group scheduling capabilities */
1124 if (!access("/dev/cpuctl/tasks", F_OK)) {
1125 LOGV("Using kernel group scheduling");
1126 gDvm.kernelGroupScheduling = 1;
1127 } else {
1128 LOGV("Using kernel scheduler policies");
1129 }
1130
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001131 /* configure signal handling */
1132 if (!gDvm.reduceSignals)
1133 blockSignals();
1134
Andy McFadden96516932009-10-28 17:39:02 -07001135 /* verify system page size */
1136 if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {
1137 LOGE("ERROR: expected page size %d, got %d\n",
1138 SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));
1139 goto fail;
1140 }
1141
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001142 /* mterp setup */
1143 LOGV("Using executionMode %d\n", gDvm.executionMode);
1144 dvmCheckAsmConstants();
1145
1146 /*
1147 * Initialize components.
1148 */
1149 if (!dvmAllocTrackerStartup())
1150 goto fail;
1151 if (!dvmGcStartup())
1152 goto fail;
1153 if (!dvmThreadStartup())
1154 goto fail;
1155 if (!dvmInlineNativeStartup())
1156 goto fail;
1157 if (!dvmVerificationStartup())
1158 goto fail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001159 if (!dvmRegisterMapStartup())
1160 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001161 if (!dvmInstanceofStartup())
1162 goto fail;
1163 if (!dvmClassStartup())
1164 goto fail;
1165 if (!dvmThreadObjStartup())
1166 goto fail;
1167 if (!dvmExceptionStartup())
1168 goto fail;
1169 if (!dvmStringInternStartup())
1170 goto fail;
1171 if (!dvmNativeStartup())
1172 goto fail;
1173 if (!dvmInternalNativeStartup())
1174 goto fail;
1175 if (!dvmJniStartup())
1176 goto fail;
1177 if (!dvmReflectStartup())
1178 goto fail;
1179#ifdef WITH_PROFILER
1180 if (!dvmProfilingStartup())
1181 goto fail;
1182#endif
1183
1184 /* make sure we got these [can this go away?] */
1185 assert(gDvm.classJavaLangClass != NULL);
1186 assert(gDvm.classJavaLangObject != NULL);
1187 //assert(gDvm.classJavaLangString != NULL);
1188 assert(gDvm.classJavaLangThread != NULL);
1189 assert(gDvm.classJavaLangVMThread != NULL);
1190 assert(gDvm.classJavaLangThreadGroup != NULL);
1191
1192 /*
1193 * Make sure these exist. If they don't, we can return a failure out
1194 * of main and nip the whole thing in the bud.
1195 */
1196 static const char* earlyClasses[] = {
1197 "Ljava/lang/InternalError;",
1198 "Ljava/lang/StackOverflowError;",
1199 "Ljava/lang/UnsatisfiedLinkError;",
1200 "Ljava/lang/NoClassDefFoundError;",
1201 NULL
1202 };
1203 const char** pClassName;
1204 for (pClassName = earlyClasses; *pClassName != NULL; pClassName++) {
1205 if (dvmFindSystemClassNoInit(*pClassName) == NULL)
1206 goto fail;
1207 }
1208
1209 /*
1210 * Miscellaneous class library validation.
1211 */
1212 if (!dvmValidateBoxClasses())
1213 goto fail;
1214
1215 /*
1216 * Do the last bits of Thread struct initialization we need to allow
1217 * JNI calls to work.
1218 */
1219 if (!dvmPrepMainForJni(pEnv))
1220 goto fail;
1221
1222 /*
1223 * Register the system native methods, which are registered through JNI.
1224 */
1225 if (!registerSystemNatives(pEnv))
1226 goto fail;
1227
1228 /*
1229 * Do some "late" initialization for the memory allocator. This may
1230 * allocate storage and initialize classes.
1231 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -07001232 if (!dvmCreateStockExceptions())
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001233 goto fail;
1234
1235 /*
1236 * At this point, the VM is in a pretty good state. Finish prep on
1237 * the main thread (specifically, create a java.lang.Thread object to go
1238 * along with our Thread struct). Note we will probably be executing
1239 * some interpreted class initializer code in here.
1240 */
1241 if (!dvmPrepMainThread())
1242 goto fail;
1243
1244 /* general debugging setup */
1245 if (!dvmDebuggerStartup())
1246 goto fail;
1247
1248 /*
1249 * Init for either zygote mode or non-zygote mode. The key difference
1250 * is that we don't start any additional threads in Zygote mode.
1251 */
1252 if (gDvm.zygote) {
1253 if (!dvmInitZygote())
1254 goto fail;
1255 } else {
1256 if (!dvmInitAfterZygote())
1257 goto fail;
1258 }
1259
1260
1261#ifndef NDEBUG
Andy McFadden734155e2009-07-16 18:11:22 -07001262 if (!dvmTestHash())
1263 LOGE("dmvTestHash FAILED\n");
1264 if (false /*noisy!*/ && !dvmTestIndirectRefTable())
1265 LOGE("dvmTestIndirectRefTable FAILED\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001266#endif
1267
1268 assert(!dvmCheckException(dvmThreadSelf()));
1269 gDvm.initExceptionCount = 0;
1270
1271 return 0;
1272
1273fail:
1274 dvmShutdown();
1275 return 1;
1276}
1277
1278/*
1279 * Register java.* natives from our class libraries. We need to do
1280 * this after we're ready for JNI registration calls, but before we
1281 * do any class initialization.
1282 *
1283 * If we get this wrong, we will blow up in the ThreadGroup class init if
1284 * interpreted code makes any reference to System. It will likely do this
1285 * since it wants to do some java.io.File setup (e.g. for static in/out/err).
1286 *
1287 * We need to have gDvm.initializing raised here so that JNI FindClass
1288 * won't try to use the system/application class loader.
1289 */
1290static bool registerSystemNatives(JNIEnv* pEnv)
1291{
1292 Thread* self;
1293
1294 /* main thread is always first in list */
1295 self = gDvm.threadList;
1296
1297 /* must set this before allowing JNI-based method registration */
1298 self->status = THREAD_NATIVE;
1299
1300 if (jniRegisterSystemMethods(pEnv) < 0) {
1301 LOGW("jniRegisterSystemMethods failed\n");
1302 return false;
1303 }
1304
1305 /* back to run mode */
1306 self->status = THREAD_RUNNING;
1307
1308 return true;
1309}
1310
1311
1312/*
1313 * Do zygote-mode-only initialization.
1314 */
1315static bool dvmInitZygote(void)
1316{
1317 /* zygote goes into its own process group */
1318 setpgid(0,0);
1319
1320 return true;
1321}
1322
1323/*
1324 * Do non-zygote-mode initialization. This is done during VM init for
1325 * standard startup, or after a "zygote fork" when creating a new process.
1326 */
1327bool dvmInitAfterZygote(void)
1328{
1329 u8 startHeap, startQuit, startJdwp;
1330 u8 endHeap, endQuit, endJdwp;
1331
1332 startHeap = dvmGetRelativeTimeUsec();
1333
1334 /*
1335 * Post-zygote heap initialization, including starting
1336 * the HeapWorker thread.
1337 */
1338 if (!dvmGcStartupAfterZygote())
1339 return false;
1340
1341 endHeap = dvmGetRelativeTimeUsec();
1342 startQuit = dvmGetRelativeTimeUsec();
1343
1344 /* start signal catcher thread that dumps stacks on SIGQUIT */
1345 if (!gDvm.reduceSignals && !gDvm.noQuitHandler) {
1346 if (!dvmSignalCatcherStartup())
1347 return false;
1348 }
1349
1350 /* start stdout/stderr copier, if requested */
1351 if (gDvm.logStdio) {
1352 if (!dvmStdioConverterStartup())
1353 return false;
1354 }
1355
1356 endQuit = dvmGetRelativeTimeUsec();
1357 startJdwp = dvmGetRelativeTimeUsec();
1358
1359 /*
1360 * Start JDWP thread. If the command-line debugger flags specified
1361 * "suspend=y", this will pause the VM. We probably want this to
1362 * come last.
1363 */
1364 if (!dvmInitJDWP()) {
1365 LOGD("JDWP init failed; continuing anyway\n");
1366 }
1367
1368 endJdwp = dvmGetRelativeTimeUsec();
1369
1370 LOGV("thread-start heap=%d quit=%d jdwp=%d total=%d usec\n",
1371 (int)(endHeap-startHeap), (int)(endQuit-startQuit),
1372 (int)(endJdwp-startJdwp), (int)(endJdwp-startHeap));
1373
Ben Chengba4fc8b2009-06-01 13:00:29 -07001374#ifdef WITH_JIT
Ben Cheng580e09e2009-10-09 11:55:30 -07001375 if (gDvm.executionMode == kExecutionModeJit) {
1376 if (!dvmJitStartup())
1377 return false;
1378 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001379#endif
1380
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001381 return true;
1382}
1383
1384/*
1385 * Prepare for a connection to a JDWP-compliant debugger.
1386 *
1387 * Note this needs to happen fairly late in the startup process, because
1388 * we need to have all of the java.* native methods registered (which in
1389 * turn requires JNI to be fully prepped).
1390 *
1391 * There are several ways to initialize:
1392 * server=n
1393 * We immediately try to connect to host:port. Bail on failure. On
1394 * success, send VM_START (suspending the VM if "suspend=y").
1395 * server=y suspend=n
1396 * Passively listen for a debugger to connect. Return immediately.
1397 * server=y suspend=y
1398 * Wait until debugger connects. Send VM_START ASAP, suspending the
1399 * VM after the message is sent.
1400 *
1401 * This gets more complicated with a nonzero value for "timeout".
1402 */
1403static bool dvmInitJDWP(void)
1404{
1405 assert(!gDvm.zygote);
1406
1407#ifndef WITH_DEBUGGER
1408 LOGI("Debugger support not compiled into VM\n");
1409 return false;
1410#endif
1411
1412 /*
1413 * Init JDWP if the debugger is enabled. This may connect out to a
1414 * debugger, passively listen for a debugger, or block waiting for a
1415 * debugger.
1416 */
1417 if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {
1418 JdwpStartupParams params;
1419
1420 if (gDvm.jdwpHost != NULL) {
1421 if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {
1422 LOGE("ERROR: hostname too long: '%s'\n", gDvm.jdwpHost);
1423 return false;
1424 }
1425 strcpy(params.host, gDvm.jdwpHost);
1426 } else {
1427 params.host[0] = '\0';
1428 }
1429 params.transport = gDvm.jdwpTransport;
1430 params.server = gDvm.jdwpServer;
1431 params.suspend = gDvm.jdwpSuspend;
1432 params.port = gDvm.jdwpPort;
1433
1434 gDvm.jdwpState = dvmJdwpStartup(&params);
1435 if (gDvm.jdwpState == NULL) {
1436 LOGW("WARNING: debugger thread failed to initialize\n");
1437 /* TODO: ignore? fail? need to mimic "expected" behavior */
1438 }
1439 }
1440
1441 /*
1442 * If a debugger has already attached, send the "welcome" message. This
1443 * may cause us to suspend all threads.
1444 */
1445 if (dvmJdwpIsActive(gDvm.jdwpState)) {
1446 //dvmChangeStatus(NULL, THREAD_RUNNING);
1447 if (!dvmJdwpPostVMStart(gDvm.jdwpState, gDvm.jdwpSuspend)) {
1448 LOGW("WARNING: failed to post 'start' message to debugger\n");
1449 /* keep going */
1450 }
1451 //dvmChangeStatus(NULL, THREAD_NATIVE);
1452 }
1453
1454 return true;
1455}
1456
1457/*
1458 * An alternative to JNI_CreateJavaVM/dvmStartup that does the first bit
1459 * of initialization and then returns with "initializing" still set. (Used
1460 * by DexOpt command-line utility.)
1461 *
1462 * Attempting to use JNI or internal natives will fail. It's best if
1463 * no bytecode gets executed, which means no <clinit>, which means no
1464 * exception-throwing. We check the "initializing" flag anyway when
1465 * throwing an exception, so we can insert some code that avoids chucking
1466 * an exception when we're optimizing stuff.
1467 *
1468 * Returns 0 on success.
1469 */
1470int dvmPrepForDexOpt(const char* bootClassPath, DexOptimizerMode dexOptMode,
1471 DexClassVerifyMode verifyMode, int dexoptFlags)
1472{
1473 gDvm.initializing = true;
1474 gDvm.optimizing = true;
1475
1476 /* configure signal handling */
1477 blockSignals();
1478
1479 /* set some defaults */
1480 setCommandLineDefaults();
1481 free(gDvm.bootClassPathStr);
1482 gDvm.bootClassPathStr = strdup(bootClassPath);
1483
1484 /* set opt/verify modes */
1485 gDvm.dexOptMode = dexOptMode;
1486 gDvm.classVerifyMode = verifyMode;
1487 gDvm.generateRegisterMaps = (dexoptFlags & DEXOPT_GEN_REGISTER_MAPS) != 0;
1488
1489 /*
1490 * Initialize the heap, some basic thread control mutexes, and
1491 * get the bootclasspath prepped.
1492 *
1493 * We can't load any classes yet because we may not yet have a source
1494 * for things like java.lang.Object and java.lang.Class.
1495 */
1496 if (!dvmGcStartup())
1497 goto fail;
1498 if (!dvmThreadStartup())
1499 goto fail;
1500 if (!dvmInlineNativeStartup())
1501 goto fail;
1502 if (!dvmVerificationStartup())
1503 goto fail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001504 if (!dvmRegisterMapStartup())
1505 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001506 if (!dvmInstanceofStartup())
1507 goto fail;
1508 if (!dvmClassStartup())
1509 goto fail;
1510
1511 /*
1512 * We leave gDvm.initializing set to "true" so that, if we're not
1513 * able to process the "core" classes, we don't go into a death-spin
1514 * trying to throw a "class not found" exception.
1515 */
1516
1517 return 0;
1518
1519fail:
1520 dvmShutdown();
1521 return 1;
1522}
1523
1524
1525/*
1526 * All threads have stopped. Finish the shutdown procedure.
1527 *
1528 * We can also be called if startup fails partway through, so be prepared
1529 * to deal with partially initialized data.
1530 *
1531 * Free any storage allocated in gGlobals.
1532 *
1533 * We can't dlclose() shared libs we've loaded, because it's possible a
1534 * thread not associated with the VM is running code in one.
1535 *
1536 * This is called from the JNI DestroyJavaVM function, which can be
1537 * called from any thread. (In practice, this will usually run in the
1538 * same thread that started the VM, a/k/a the main thread, but we don't
1539 * want to assume that.)
1540 */
1541void dvmShutdown(void)
1542{
1543 LOGV("VM shutting down\n");
1544
1545 if (CALC_CACHE_STATS)
1546 dvmDumpAtomicCacheStats(gDvm.instanceofCache);
1547
1548 /*
1549 * Stop our internal threads.
1550 */
1551 dvmHeapWorkerShutdown();
1552
1553 if (gDvm.jdwpState != NULL)
1554 dvmJdwpShutdown(gDvm.jdwpState);
1555 free(gDvm.jdwpHost);
1556 gDvm.jdwpHost = NULL;
1557 free(gDvm.stackTraceFile);
1558 gDvm.stackTraceFile = NULL;
1559
1560 /* tell signal catcher to shut down if it was started */
1561 dvmSignalCatcherShutdown();
1562
1563 /* shut down stdout/stderr conversion */
1564 dvmStdioConverterShutdown();
1565
Ben Chengef00a852009-06-22 22:53:35 -07001566#ifdef WITH_JIT
Ben Cheng580e09e2009-10-09 11:55:30 -07001567 if (gDvm.executionMode == kExecutionModeJit) {
1568 /* shut down the compiler thread */
1569 dvmJitShutdown();
1570 }
Ben Chengef00a852009-06-22 22:53:35 -07001571#endif
1572
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001573 /*
1574 * Kill any daemon threads that still exist. Actively-running threads
1575 * are likely to crash the process if they continue to execute while
1576 * the VM shuts down.
1577 */
1578 dvmSlayDaemons();
1579
1580 LOGD("VM cleaning up\n");
1581
1582 dvmDebuggerShutdown();
1583 dvmReflectShutdown();
1584#ifdef WITH_PROFILER
1585 dvmProfilingShutdown();
1586#endif
1587 dvmJniShutdown();
1588 dvmStringInternShutdown();
1589 dvmExceptionShutdown();
1590 dvmThreadShutdown();
1591 dvmClassShutdown();
1592 dvmVerificationShutdown();
The Android Open Source Project99409882009-03-18 22:20:24 -07001593 dvmRegisterMapShutdown();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001594 dvmInstanceofShutdown();
1595 dvmInlineNativeShutdown();
1596 dvmGcShutdown();
1597 dvmAllocTrackerShutdown();
1598 dvmPropertiesShutdown();
1599
1600 /* these must happen AFTER dvmClassShutdown has walked through class data */
1601 dvmNativeShutdown();
1602 dvmInternalNativeShutdown();
1603
1604 free(gDvm.bootClassPathStr);
1605 free(gDvm.classPathStr);
1606
1607 freeAssertionCtrl();
1608
1609 /*
1610 * We want valgrind to report anything we forget to free as "definitely
1611 * lost". If there's a pointer in the global chunk, it would be reported
1612 * as "still reachable". Erasing the memory fixes this.
1613 *
1614 * This must be erased to zero if we want to restart the VM within this
1615 * process.
1616 */
1617 memset(&gDvm, 0xcd, sizeof(gDvm));
1618}
1619
1620
1621/*
1622 * fprintf() wrapper that calls through the JNI-specified vfprintf hook if
1623 * one was specified.
1624 */
1625int dvmFprintf(FILE* fp, const char* format, ...)
1626{
1627 va_list args;
1628 int result;
1629
1630 va_start(args, format);
1631 if (gDvm.vfprintfHook != NULL)
1632 result = (*gDvm.vfprintfHook)(fp, format, args);
1633 else
1634 result = vfprintf(fp, format, args);
1635 va_end(args);
1636
1637 return result;
1638}
1639
1640/*
1641 * Abort the VM. We get here on fatal errors. Try very hard not to use
1642 * this; whenever possible, return an error to somebody responsible.
1643 */
1644void dvmAbort(void)
1645{
1646 LOGE("VM aborting\n");
1647
1648 fflush(NULL); // flush all open file buffers
1649
1650 /* JNI-supplied abort hook gets right of first refusal */
1651 if (gDvm.abortHook != NULL)
1652 (*gDvm.abortHook)();
1653
1654 /*
1655 * If we call abort(), all threads in the process receives a SIBABRT.
1656 * debuggerd dumps the stack trace of the main thread, whether or not
1657 * that was the thread that failed.
1658 *
1659 * By stuffing a value into a bogus address, we cause a segmentation
1660 * fault in the current thread, and get a useful log from debuggerd.
1661 * We can also trivially tell the difference between a VM crash and
1662 * a deliberate abort by looking at the fault address.
1663 */
1664 *((char*)0xdeadd00d) = 38;
1665 abort();
1666
1667 /* notreached */
1668}