1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Dalvik initialization, shutdown, and command-line argument processing. 19 */ 20 #include "Dalvik.h" 21 #include "test/Test.h" 22 #include "mterp/Mterp.h" 23 #include "Hash.h" 24 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 */ 42 extern int jniRegisterSystemMethods(JNIEnv* env); 43 44 /* fwd */ 45 static bool registerSystemNatives(JNIEnv* pEnv); 46 static bool dvmInitJDWP(void); 47 static bool dvmInitZygote(void); 48 49 50 /* global state */ 51 struct DvmGlobals gDvm; 52 53 /* JIT-specific global state */ 54 #if defined(WITH_JIT) 55 struct DvmJitGlobals gDvmJit; 56 #endif 57 58 /* 59 * Show usage. 60 * 61 * We follow the tradition of unhyphenated compound words. 62 */ 63 static 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"); 92 #if defined(WITH_JIT) 93 dvmFprintf(stderr, 94 " -Xint (extended to accept ':portable', ':fast' and ':jit')\n"); 95 #else 96 dvmFprintf(stderr, 97 " -Xint (extended to accept ':portable' and ':fast')\n"); 98 #endif 99 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"); 109 dvmFprintf(stderr, " -Xgc:[no]precise\n"); 110 dvmFprintf(stderr, " -Xgenregmap\n"); 111 dvmFprintf(stderr, " -Xcheckdexsum\n"); 112 #if defined(WITH_JIT) 113 dvmFprintf(stderr, " -Xincludeselectedop\n"); 114 dvmFprintf(stderr, " -Xjitop:hexopvalue[-endvalue]" 115 "[,hexopvalue[-endvalue]]*\n"); 116 dvmFprintf(stderr, " -Xincludeselectedmethod\n"); 117 dvmFprintf(stderr, " -Xjitthreshold:decimalvalue\n"); 118 dvmFprintf(stderr, " -Xjitblocking\n"); 119 dvmFprintf(stderr, " -Xjitmethod:signature[,signature]* " 120 "(eg Ljava/lang/String\\;replace)\n"); 121 dvmFprintf(stderr, " -Xjitcheckcg\n"); 122 dvmFprintf(stderr, " -Xjitverbose\n"); 123 dvmFprintf(stderr, " -Xjitprofile\n"); 124 dvmFprintf(stderr, " -Xjitdisableopt\n"); 125 #endif 126 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 161 #ifdef WITH_EXTRA_GC_CHECKS 162 " extra_gc_checks" 163 #endif 164 #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 189 #if defined(WITH_JIT) 190 " jit" 191 #endif 192 #if defined(WITH_SELF_VERIFICATION) 193 " self_verification" 194 #endif 195 ); 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 */ 205 static 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 */ 216 static 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 */ 247 static 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 */ 333 static 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 */ 403 static 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 460 bail: 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 */ 478 static 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 */ 532 void 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 */ 556 static 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 565 #if defined(WITH_JIT) 566 /* Parse -Xjitop to selectively turn on/off certain opcodes for JIT */ 567 static 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 */ 622 static 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 656 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 */ 668 static 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 } else if (strcmp(argv[i], "-verbose:shutdown") == 0) { 799 gDvm.verboseShutdown = true; 800 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; 847 #if defined(WITH_JIT) 848 gDvmJit.runningInAndroidFramework = true; 849 #endif 850 } 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; 890 #ifdef WITH_JIT 891 else if (strcmp(argv[i] + 6, "jit") == 0) 892 gDvm.executionMode = kExecutionModeJit; 893 #endif 894 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 903 } else if (strncmp(argv[i], "-Xlockprofthreshold:", 20) == 0) { 904 gDvm.lockProfThreshold = atoi(argv[i] + 20); 905 906 #ifdef WITH_JIT 907 } else if (strncmp(argv[i], "-Xjitop", 7) == 0) { 908 processXjitop(argv[i]); 909 } else if (strncmp(argv[i], "-Xjitmethod", 11) == 0) { 910 processXjitmethod(argv[i]); 911 } else if (strncmp(argv[i], "-Xjitblocking", 13) == 0) { 912 gDvmJit.blockingMode = true; 913 } else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) { 914 gDvmJit.threshold = atoi(argv[i] + 15); 915 } else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) { 916 gDvmJit.includeSelectedOp = true; 917 } else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) { 918 gDvmJit.includeSelectedMethod = true; 919 } else if (strncmp(argv[i], "-Xjitcheckcg", 12) == 0) { 920 gDvmJit.checkCallGraph = true; 921 /* Need to enable blocking mode due to stack crawling */ 922 gDvmJit.blockingMode = true; 923 } else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) { 924 gDvmJit.printMe = true; 925 } else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) { 926 gDvmJit.profile = true; 927 } else if (strncmp(argv[i], "-Xjitdisableopt", 15) == 0) { 928 /* Disable selected optimizations */ 929 if (argv[i][15] == ':') { 930 sscanf(argv[i] + 16, "%x", &gDvmJit.disableOpt); 931 /* Disable all optimizations */ 932 } else { 933 gDvmJit.disableOpt = -1; 934 } 935 #endif 936 937 } else if (strncmp(argv[i], "-Xdeadlockpredict:", 18) == 0) { 938 #ifdef WITH_DEADLOCK_PREDICTION 939 if (strcmp(argv[i] + 18, "off") == 0) 940 gDvm.deadlockPredictMode = kDPOff; 941 else if (strcmp(argv[i] + 18, "warn") == 0) 942 gDvm.deadlockPredictMode = kDPWarn; 943 else if (strcmp(argv[i] + 18, "err") == 0) 944 gDvm.deadlockPredictMode = kDPErr; 945 else if (strcmp(argv[i] + 18, "abort") == 0) 946 gDvm.deadlockPredictMode = kDPAbort; 947 else { 948 dvmFprintf(stderr, "Bad value for -Xdeadlockpredict"); 949 return -1; 950 } 951 if (gDvm.deadlockPredictMode != kDPOff) 952 LOGD("Deadlock prediction enabled (%s)\n", argv[i]+18); 953 #endif 954 955 } else if (strncmp(argv[i], "-Xstacktracefile:", 17) == 0) { 956 gDvm.stackTraceFile = strdup(argv[i]+17); 957 958 } else if (strcmp(argv[i], "-Xgenregmap") == 0) { 959 gDvm.generateRegisterMaps = true; 960 LOGV("Register maps will be generated during verification\n"); 961 962 } else if (strncmp(argv[i], "-Xgc:", 5) == 0) { 963 if (strcmp(argv[i] + 5, "precise") == 0) 964 gDvm.preciseGc = true; 965 else if (strcmp(argv[i] + 5, "noprecise") == 0) 966 gDvm.preciseGc = false; 967 else { 968 dvmFprintf(stderr, "Bad value for -Xgc"); 969 return -1; 970 } 971 LOGV("Precise GC configured %s\n", gDvm.preciseGc ? "ON" : "OFF"); 972 973 } else if (strcmp(argv[i], "-Xcheckdexsum") == 0) { 974 gDvm.verifyDexChecksum = true; 975 976 } else { 977 if (!ignoreUnrecognized) { 978 dvmFprintf(stderr, "Unrecognized option '%s'\n", argv[i]); 979 return -1; 980 } 981 } 982 } 983 984 if (gDvm.heapSizeStart > gDvm.heapSizeMax) { 985 dvmFprintf(stderr, "Heap start size must be <= heap max size\n"); 986 return -1; 987 } 988 989 return 0; 990 } 991 992 /* 993 * Set defaults for fields altered or modified by arguments. 994 * 995 * Globals are initialized to 0 (a/k/a NULL or false). 996 */ 997 static void setCommandLineDefaults() 998 { 999 const char* envStr; 1000 1001 envStr = getenv("CLASSPATH"); 1002 if (envStr != NULL) 1003 gDvm.classPathStr = strdup(envStr); 1004 else 1005 gDvm.classPathStr = strdup("."); 1006 envStr = getenv("BOOTCLASSPATH"); 1007 if (envStr != NULL) 1008 gDvm.bootClassPathStr = strdup(envStr); 1009 else 1010 gDvm.bootClassPathStr = strdup("."); 1011 1012 /* Defaults overridden by -Xms and -Xmx. 1013 * TODO: base these on a system or application-specific default 1014 */ 1015 gDvm.heapSizeStart = 2 * 1024 * 1024; // Spec says 16MB; too big for us. 1016 gDvm.heapSizeMax = 16 * 1024 * 1024; // Spec says 75% physical mem 1017 gDvm.stackSize = kDefaultStackSize; 1018 1019 /* gDvm.jdwpSuspend = true; */ 1020 1021 /* allowed unless zygote config doesn't allow it */ 1022 gDvm.jdwpAllowed = true; 1023 1024 /* default verification and optimization modes */ 1025 gDvm.classVerifyMode = VERIFY_MODE_ALL; 1026 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED; 1027 1028 /* 1029 * Default execution mode. 1030 * 1031 * This should probably interact with the mterp code somehow, e.g. if 1032 * we know we're using the "desktop" build we should probably be 1033 * using "portable" rather than "fast". 1034 */ 1035 #if defined(WITH_JIT) 1036 gDvm.executionMode = kExecutionModeJit; 1037 #else 1038 gDvm.executionMode = kExecutionModeInterpFast; 1039 #endif 1040 } 1041 1042 1043 /* 1044 * Handle a SIGBUS, which frequently occurs because somebody replaced an 1045 * optimized DEX file out from under us. 1046 */ 1047 static void busCatcher(int signum, siginfo_t* info, void* context) 1048 { 1049 void* addr = info->si_addr; 1050 1051 LOGE("Caught a SIGBUS (%d), addr=%p\n", signum, addr); 1052 1053 /* 1054 * If we return at this point the SIGBUS just keeps happening, so we 1055 * remove the signal handler and allow it to kill us. TODO: restore 1056 * the original, which points to a debuggerd stub; if we don't then 1057 * debuggerd won't be notified. 1058 */ 1059 signal(SIGBUS, SIG_DFL); 1060 } 1061 1062 /* 1063 * Configure signals. We need to block SIGQUIT so that the signal only 1064 * reaches the dump-stack-trace thread. 1065 * 1066 * This can be disabled with the "-Xrs" flag. 1067 */ 1068 static void blockSignals() 1069 { 1070 sigset_t mask; 1071 int cc; 1072 1073 sigemptyset(&mask); 1074 sigaddset(&mask, SIGQUIT); 1075 sigaddset(&mask, SIGUSR1); // used to initiate heap dump 1076 #if defined(WITH_JIT) && defined(WITH_JIT_TUNING) 1077 sigaddset(&mask, SIGUSR2); // used to investigate JIT internals 1078 #endif 1079 //sigaddset(&mask, SIGPIPE); 1080 cc = sigprocmask(SIG_BLOCK, &mask, NULL); 1081 assert(cc == 0); 1082 1083 if (false) { 1084 /* TODO: save the old sigaction in a global */ 1085 struct sigaction sa; 1086 memset(&sa, 0, sizeof(sa)); 1087 sa.sa_sigaction = busCatcher; 1088 sa.sa_flags = SA_SIGINFO; 1089 cc = sigaction(SIGBUS, &sa, NULL); 1090 assert(cc == 0); 1091 } 1092 } 1093 1094 /* 1095 * VM initialization. Pass in any options provided on the command line. 1096 * Do not pass in the class name or the options for the class. 1097 * 1098 * Returns 0 on success. 1099 */ 1100 int dvmStartup(int argc, const char* const argv[], bool ignoreUnrecognized, 1101 JNIEnv* pEnv) 1102 { 1103 int i, cc; 1104 1105 assert(gDvm.initializing); 1106 1107 LOGV("VM init args (%d):\n", argc); 1108 for (i = 0; i < argc; i++) 1109 LOGV(" %d: '%s'\n", i, argv[i]); 1110 1111 setCommandLineDefaults(); 1112 1113 /* prep properties storage */ 1114 if (!dvmPropertiesStartup(argc)) 1115 goto fail; 1116 1117 /* 1118 * Process the option flags (if any). 1119 */ 1120 cc = dvmProcessOptions(argc, argv, ignoreUnrecognized); 1121 if (cc != 0) { 1122 if (cc < 0) { 1123 dvmFprintf(stderr, "\n"); 1124 dvmUsage("dalvikvm"); 1125 } 1126 goto fail; 1127 } 1128 1129 #if WITH_EXTRA_GC_CHECKS > 1 1130 /* only "portable" interp has the extra goodies */ 1131 if (gDvm.executionMode != kExecutionModeInterpPortable) { 1132 LOGI("Switching to 'portable' interpreter for GC checks\n"); 1133 gDvm.executionMode = kExecutionModeInterpPortable; 1134 } 1135 #endif 1136 1137 /* Configure group scheduling capabilities */ 1138 if (!access("/dev/cpuctl/tasks", F_OK)) { 1139 LOGV("Using kernel group scheduling"); 1140 gDvm.kernelGroupScheduling = 1; 1141 } else { 1142 LOGV("Using kernel scheduler policies"); 1143 } 1144 1145 /* configure signal handling */ 1146 if (!gDvm.reduceSignals) 1147 blockSignals(); 1148 1149 /* verify system page size */ 1150 if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) { 1151 LOGE("ERROR: expected page size %d, got %d\n", 1152 SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE)); 1153 goto fail; 1154 } 1155 1156 /* mterp setup */ 1157 LOGV("Using executionMode %d\n", gDvm.executionMode); 1158 dvmCheckAsmConstants(); 1159 1160 /* 1161 * Initialize components. 1162 */ 1163 if (!dvmAllocTrackerStartup()) 1164 goto fail; 1165 if (!dvmGcStartup()) 1166 goto fail; 1167 if (!dvmThreadStartup()) 1168 goto fail; 1169 if (!dvmInlineNativeStartup()) 1170 goto fail; 1171 if (!dvmVerificationStartup()) 1172 goto fail; 1173 if (!dvmRegisterMapStartup()) 1174 goto fail; 1175 if (!dvmInstanceofStartup()) 1176 goto fail; 1177 if (!dvmClassStartup()) 1178 goto fail; 1179 if (!dvmThreadObjStartup()) 1180 goto fail; 1181 if (!dvmExceptionStartup()) 1182 goto fail; 1183 if (!dvmStringInternStartup()) 1184 goto fail; 1185 if (!dvmNativeStartup()) 1186 goto fail; 1187 if (!dvmInternalNativeStartup()) 1188 goto fail; 1189 if (!dvmJniStartup()) 1190 goto fail; 1191 if (!dvmReflectStartup()) 1192 goto fail; 1193 #ifdef WITH_PROFILER 1194 if (!dvmProfilingStartup()) 1195 goto fail; 1196 #endif 1197 1198 /* make sure we got these [can this go away?] */ 1199 assert(gDvm.classJavaLangClass != NULL); 1200 assert(gDvm.classJavaLangObject != NULL); 1201 //assert(gDvm.classJavaLangString != NULL); 1202 assert(gDvm.classJavaLangThread != NULL); 1203 assert(gDvm.classJavaLangVMThread != NULL); 1204 assert(gDvm.classJavaLangThreadGroup != NULL); 1205 1206 /* 1207 * Make sure these exist. If they don't, we can return a failure out 1208 * of main and nip the whole thing in the bud. 1209 */ 1210 static const char* earlyClasses[] = { 1211 "Ljava/lang/InternalError;", 1212 "Ljava/lang/StackOverflowError;", 1213 "Ljava/lang/UnsatisfiedLinkError;", 1214 "Ljava/lang/NoClassDefFoundError;", 1215 NULL 1216 }; 1217 const char** pClassName; 1218 for (pClassName = earlyClasses; *pClassName != NULL; pClassName++) { 1219 if (dvmFindSystemClassNoInit(*pClassName) == NULL) 1220 goto fail; 1221 } 1222 1223 /* 1224 * Miscellaneous class library validation. 1225 */ 1226 if (!dvmValidateBoxClasses()) 1227 goto fail; 1228 1229 /* 1230 * Do the last bits of Thread struct initialization we need to allow 1231 * JNI calls to work. 1232 */ 1233 if (!dvmPrepMainForJni(pEnv)) 1234 goto fail; 1235 1236 /* 1237 * Register the system native methods, which are registered through JNI. 1238 */ 1239 if (!registerSystemNatives(pEnv)) 1240 goto fail; 1241 1242 /* 1243 * Do some "late" initialization for the memory allocator. This may 1244 * allocate storage and initialize classes. 1245 */ 1246 if (!dvmCreateStockExceptions()) 1247 goto fail; 1248 1249 /* 1250 * At this point, the VM is in a pretty good state. Finish prep on 1251 * the main thread (specifically, create a java.lang.Thread object to go 1252 * along with our Thread struct). Note we will probably be executing 1253 * some interpreted class initializer code in here. 1254 */ 1255 if (!dvmPrepMainThread()) 1256 goto fail; 1257 1258 /* 1259 * Make sure we haven't accumulated any tracked references. The main 1260 * thread should be starting with a clean slate. 1261 */ 1262 if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0) 1263 { 1264 LOGW("Warning: tracked references remain post-initialization\n"); 1265 dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN"); 1266 } 1267 1268 /* general debugging setup */ 1269 if (!dvmDebuggerStartup()) 1270 goto fail; 1271 1272 /* 1273 * Init for either zygote mode or non-zygote mode. The key difference 1274 * is that we don't start any additional threads in Zygote mode. 1275 */ 1276 if (gDvm.zygote) { 1277 if (!dvmInitZygote()) 1278 goto fail; 1279 } else { 1280 if (!dvmInitAfterZygote()) 1281 goto fail; 1282 } 1283 1284 1285 #ifndef NDEBUG 1286 if (!dvmTestHash()) 1287 LOGE("dmvTestHash FAILED\n"); 1288 if (false /*noisy!*/ && !dvmTestIndirectRefTable()) 1289 LOGE("dvmTestIndirectRefTable FAILED\n"); 1290 #endif 1291 1292 assert(!dvmCheckException(dvmThreadSelf())); 1293 gDvm.initExceptionCount = 0; 1294 1295 return 0; 1296 1297 fail: 1298 dvmShutdown(); 1299 return 1; 1300 } 1301 1302 /* 1303 * Register java.* natives from our class libraries. We need to do 1304 * this after we're ready for JNI registration calls, but before we 1305 * do any class initialization. 1306 * 1307 * If we get this wrong, we will blow up in the ThreadGroup class init if 1308 * interpreted code makes any reference to System. It will likely do this 1309 * since it wants to do some java.io.File setup (e.g. for static in/out/err). 1310 * 1311 * We need to have gDvm.initializing raised here so that JNI FindClass 1312 * won't try to use the system/application class loader. 1313 */ 1314 static bool registerSystemNatives(JNIEnv* pEnv) 1315 { 1316 Thread* self; 1317 1318 /* main thread is always first in list */ 1319 self = gDvm.threadList; 1320 1321 /* must set this before allowing JNI-based method registration */ 1322 self->status = THREAD_NATIVE; 1323 1324 if (jniRegisterSystemMethods(pEnv) < 0) { 1325 LOGW("jniRegisterSystemMethods failed\n"); 1326 return false; 1327 } 1328 1329 /* back to run mode */ 1330 self->status = THREAD_RUNNING; 1331 1332 return true; 1333 } 1334 1335 1336 /* 1337 * Do zygote-mode-only initialization. 1338 */ 1339 static bool dvmInitZygote(void) 1340 { 1341 /* zygote goes into its own process group */ 1342 setpgid(0,0); 1343 1344 return true; 1345 } 1346 1347 /* 1348 * Do non-zygote-mode initialization. This is done during VM init for 1349 * standard startup, or after a "zygote fork" when creating a new process. 1350 */ 1351 bool dvmInitAfterZygote(void) 1352 { 1353 u8 startHeap, startQuit, startJdwp; 1354 u8 endHeap, endQuit, endJdwp; 1355 1356 startHeap = dvmGetRelativeTimeUsec(); 1357 1358 /* 1359 * Post-zygote heap initialization, including starting 1360 * the HeapWorker thread. 1361 */ 1362 if (!dvmGcStartupAfterZygote()) 1363 return false; 1364 1365 endHeap = dvmGetRelativeTimeUsec(); 1366 startQuit = dvmGetRelativeTimeUsec(); 1367 1368 /* start signal catcher thread that dumps stacks on SIGQUIT */ 1369 if (!gDvm.reduceSignals && !gDvm.noQuitHandler) { 1370 if (!dvmSignalCatcherStartup()) 1371 return false; 1372 } 1373 1374 /* start stdout/stderr copier, if requested */ 1375 if (gDvm.logStdio) { 1376 if (!dvmStdioConverterStartup()) 1377 return false; 1378 } 1379 1380 endQuit = dvmGetRelativeTimeUsec(); 1381 startJdwp = dvmGetRelativeTimeUsec(); 1382 1383 /* 1384 * Start JDWP thread. If the command-line debugger flags specified 1385 * "suspend=y", this will pause the VM. We probably want this to 1386 * come last. 1387 */ 1388 if (!dvmInitJDWP()) { 1389 LOGD("JDWP init failed; continuing anyway\n"); 1390 } 1391 1392 endJdwp = dvmGetRelativeTimeUsec(); 1393 1394 LOGV("thread-start heap=%d quit=%d jdwp=%d total=%d usec\n", 1395 (int)(endHeap-startHeap), (int)(endQuit-startQuit), 1396 (int)(endJdwp-startJdwp), (int)(endJdwp-startHeap)); 1397 1398 #ifdef WITH_JIT 1399 if (gDvm.executionMode == kExecutionModeJit) { 1400 if (!dvmCompilerStartup()) 1401 return false; 1402 } 1403 #endif 1404 1405 return true; 1406 } 1407 1408 /* 1409 * Prepare for a connection to a JDWP-compliant debugger. 1410 * 1411 * Note this needs to happen fairly late in the startup process, because 1412 * we need to have all of the java.* native methods registered (which in 1413 * turn requires JNI to be fully prepped). 1414 * 1415 * There are several ways to initialize: 1416 * server=n 1417 * We immediately try to connect to host:port. Bail on failure. On 1418 * success, send VM_START (suspending the VM if "suspend=y"). 1419 * server=y suspend=n 1420 * Passively listen for a debugger to connect. Return immediately. 1421 * server=y suspend=y 1422 * Wait until debugger connects. Send VM_START ASAP, suspending the 1423 * VM after the message is sent. 1424 * 1425 * This gets more complicated with a nonzero value for "timeout". 1426 */ 1427 static bool dvmInitJDWP(void) 1428 { 1429 assert(!gDvm.zygote); 1430 1431 #ifndef WITH_DEBUGGER 1432 LOGI("Debugger support not compiled into VM\n"); 1433 return false; 1434 #endif 1435 1436 /* 1437 * Init JDWP if the debugger is enabled. This may connect out to a 1438 * debugger, passively listen for a debugger, or block waiting for a 1439 * debugger. 1440 */ 1441 if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) { 1442 JdwpStartupParams params; 1443 1444 if (gDvm.jdwpHost != NULL) { 1445 if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) { 1446 LOGE("ERROR: hostname too long: '%s'\n", gDvm.jdwpHost); 1447 return false; 1448 } 1449 strcpy(params.host, gDvm.jdwpHost); 1450 } else { 1451 params.host[0] = '\0'; 1452 } 1453 params.transport = gDvm.jdwpTransport; 1454 params.server = gDvm.jdwpServer; 1455 params.suspend = gDvm.jdwpSuspend; 1456 params.port = gDvm.jdwpPort; 1457 1458 gDvm.jdwpState = dvmJdwpStartup(¶ms); 1459 if (gDvm.jdwpState == NULL) { 1460 LOGW("WARNING: debugger thread failed to initialize\n"); 1461 /* TODO: ignore? fail? need to mimic "expected" behavior */ 1462 } 1463 } 1464 1465 /* 1466 * If a debugger has already attached, send the "welcome" message. This 1467 * may cause us to suspend all threads. 1468 */ 1469 if (dvmJdwpIsActive(gDvm.jdwpState)) { 1470 //dvmChangeStatus(NULL, THREAD_RUNNING); 1471 if (!dvmJdwpPostVMStart(gDvm.jdwpState, gDvm.jdwpSuspend)) { 1472 LOGW("WARNING: failed to post 'start' message to debugger\n"); 1473 /* keep going */ 1474 } 1475 //dvmChangeStatus(NULL, THREAD_NATIVE); 1476 } 1477 1478 return true; 1479 } 1480 1481 /* 1482 * An alternative to JNI_CreateJavaVM/dvmStartup that does the first bit 1483 * of initialization and then returns with "initializing" still set. (Used 1484 * by DexOpt command-line utility.) 1485 * 1486 * Attempting to use JNI or internal natives will fail. It's best if 1487 * no bytecode gets executed, which means no <clinit>, which means no 1488 * exception-throwing. We check the "initializing" flag anyway when 1489 * throwing an exception, so we can insert some code that avoids chucking 1490 * an exception when we're optimizing stuff. 1491 * 1492 * Returns 0 on success. 1493 */ 1494 int dvmPrepForDexOpt(const char* bootClassPath, DexOptimizerMode dexOptMode, 1495 DexClassVerifyMode verifyMode, int dexoptFlags) 1496 { 1497 gDvm.initializing = true; 1498 gDvm.optimizing = true; 1499 1500 /* configure signal handling */ 1501 blockSignals(); 1502 1503 /* set some defaults */ 1504 setCommandLineDefaults(); 1505 free(gDvm.bootClassPathStr); 1506 gDvm.bootClassPathStr = strdup(bootClassPath); 1507 1508 /* set opt/verify modes */ 1509 gDvm.dexOptMode = dexOptMode; 1510 gDvm.classVerifyMode = verifyMode; 1511 gDvm.generateRegisterMaps = (dexoptFlags & DEXOPT_GEN_REGISTER_MAPS) != 0; 1512 1513 /* 1514 * Initialize the heap, some basic thread control mutexes, and 1515 * get the bootclasspath prepped. 1516 * 1517 * We can't load any classes yet because we may not yet have a source 1518 * for things like java.lang.Object and java.lang.Class. 1519 */ 1520 if (!dvmGcStartup()) 1521 goto fail; 1522 if (!dvmThreadStartup()) 1523 goto fail; 1524 if (!dvmInlineNativeStartup()) 1525 goto fail; 1526 if (!dvmVerificationStartup()) 1527 goto fail; 1528 if (!dvmRegisterMapStartup()) 1529 goto fail; 1530 if (!dvmInstanceofStartup()) 1531 goto fail; 1532 if (!dvmClassStartup()) 1533 goto fail; 1534 1535 /* 1536 * We leave gDvm.initializing set to "true" so that, if we're not 1537 * able to process the "core" classes, we don't go into a death-spin 1538 * trying to throw a "class not found" exception. 1539 */ 1540 1541 return 0; 1542 1543 fail: 1544 dvmShutdown(); 1545 return 1; 1546 } 1547 1548 1549 /* 1550 * All threads have stopped. Finish the shutdown procedure. 1551 * 1552 * We can also be called if startup fails partway through, so be prepared 1553 * to deal with partially initialized data. 1554 * 1555 * Free any storage allocated in gGlobals. 1556 * 1557 * We can't dlclose() shared libs we've loaded, because it's possible a 1558 * thread not associated with the VM is running code in one. 1559 * 1560 * This is called from the JNI DestroyJavaVM function, which can be 1561 * called from any thread. (In practice, this will usually run in the 1562 * same thread that started the VM, a/k/a the main thread, but we don't 1563 * want to assume that.) 1564 */ 1565 void dvmShutdown(void) 1566 { 1567 LOGV("VM shutting down\n"); 1568 1569 if (CALC_CACHE_STATS) 1570 dvmDumpAtomicCacheStats(gDvm.instanceofCache); 1571 1572 /* 1573 * Stop our internal threads. 1574 */ 1575 dvmHeapWorkerShutdown(); 1576 1577 if (gDvm.jdwpState != NULL) 1578 dvmJdwpShutdown(gDvm.jdwpState); 1579 free(gDvm.jdwpHost); 1580 gDvm.jdwpHost = NULL; 1581 free(gDvm.stackTraceFile); 1582 gDvm.stackTraceFile = NULL; 1583 1584 /* tell signal catcher to shut down if it was started */ 1585 dvmSignalCatcherShutdown(); 1586 1587 /* shut down stdout/stderr conversion */ 1588 dvmStdioConverterShutdown(); 1589 1590 #ifdef WITH_JIT 1591 if (gDvm.executionMode == kExecutionModeJit) { 1592 /* shut down the compiler thread */ 1593 dvmCompilerShutdown(); 1594 } 1595 #endif 1596 1597 /* 1598 * Kill any daemon threads that still exist. Actively-running threads 1599 * are likely to crash the process if they continue to execute while 1600 * the VM shuts down. 1601 */ 1602 dvmSlayDaemons(); 1603 1604 if (gDvm.verboseShutdown) 1605 LOGD("VM cleaning up\n"); 1606 1607 dvmDebuggerShutdown(); 1608 dvmReflectShutdown(); 1609 #ifdef WITH_PROFILER 1610 dvmProfilingShutdown(); 1611 #endif 1612 dvmJniShutdown(); 1613 dvmStringInternShutdown(); 1614 dvmExceptionShutdown(); 1615 dvmThreadShutdown(); 1616 dvmClassShutdown(); 1617 dvmVerificationShutdown(); 1618 dvmRegisterMapShutdown(); 1619 dvmInstanceofShutdown(); 1620 dvmInlineNativeShutdown(); 1621 dvmGcShutdown(); 1622 dvmAllocTrackerShutdown(); 1623 dvmPropertiesShutdown(); 1624 1625 /* these must happen AFTER dvmClassShutdown has walked through class data */ 1626 dvmNativeShutdown(); 1627 dvmInternalNativeShutdown(); 1628 1629 free(gDvm.bootClassPathStr); 1630 free(gDvm.classPathStr); 1631 1632 freeAssertionCtrl(); 1633 1634 /* 1635 * We want valgrind to report anything we forget to free as "definitely 1636 * lost". If there's a pointer in the global chunk, it would be reported 1637 * as "still reachable". Erasing the memory fixes this. 1638 * 1639 * This must be erased to zero if we want to restart the VM within this 1640 * process. 1641 */ 1642 memset(&gDvm, 0xcd, sizeof(gDvm)); 1643 } 1644 1645 1646 /* 1647 * fprintf() wrapper that calls through the JNI-specified vfprintf hook if 1648 * one was specified. 1649 */ 1650 int dvmFprintf(FILE* fp, const char* format, ...) 1651 { 1652 va_list args; 1653 int result; 1654 1655 va_start(args, format); 1656 if (gDvm.vfprintfHook != NULL) 1657 result = (*gDvm.vfprintfHook)(fp, format, args); 1658 else 1659 result = vfprintf(fp, format, args); 1660 va_end(args); 1661 1662 return result; 1663 } 1664 1665 /* 1666 * Abort the VM. We get here on fatal errors. Try very hard not to use 1667 * this; whenever possible, return an error to somebody responsible. 1668 */ 1669 void dvmAbort(void) 1670 { 1671 LOGE("VM aborting\n"); 1672 1673 fflush(NULL); // flush all open file buffers 1674 1675 /* JNI-supplied abort hook gets right of first refusal */ 1676 if (gDvm.abortHook != NULL) 1677 (*gDvm.abortHook)(); 1678 1679 /* 1680 * If we call abort(), all threads in the process receives a SIBABRT. 1681 * debuggerd dumps the stack trace of the main thread, whether or not 1682 * that was the thread that failed. 1683 * 1684 * By stuffing a value into a bogus address, we cause a segmentation 1685 * fault in the current thread, and get a useful log from debuggerd. 1686 * We can also trivially tell the difference between a VM crash and 1687 * a deliberate abort by looking at the fault address. 1688 */ 1689 *((char*)0xdeadd00d) = 38; 1690 abort(); 1691 1692 /* notreached */ 1693 } 1694