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