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.system.VMDebug 19 */ 20 #include "Dalvik.h" 21 #include "native/InternalNativePriv.h" 22 23 #include <errno.h> 24 25 26 /* 27 * Convert an array of char* into a String[]. 28 * 29 * Returns NULL on failure, with an exception raised. 30 */ 31 static ArrayObject* convertStringArray(char** strings, size_t count) 32 { 33 /* 34 * Allocate an array to hold the String objects. 35 */ 36 ClassObject* stringArrayClass = 37 dvmFindArrayClass("[Ljava/lang/String;", NULL); 38 if (stringArrayClass == NULL) { 39 /* shouldn't happen */ 40 LOGE("Unable to find [Ljava/lang/String;\n"); 41 dvmAbort(); 42 } 43 44 ArrayObject* stringArray = 45 dvmAllocArrayByClass(stringArrayClass, count, ALLOC_DEFAULT); 46 if (stringArray == NULL) { 47 /* probably OOM */ 48 LOGD("Failed allocating array of %d strings\n", count); 49 return NULL; 50 } 51 52 Thread* self = dvmThreadSelf(); 53 54 /* 55 * Create the individual String objects and add them to the array. 56 */ 57 StringObject** contents = (StringObject**) stringArray->contents; 58 size_t i; 59 for (i = 0; i < count; i++) { 60 contents[i] = dvmCreateStringFromCstr(strings[i], ALLOC_DEFAULT); 61 if (contents[i] == NULL) { 62 /* probably OOM; drop out now */ 63 assert(dvmCheckException(dvmThreadSelf())); 64 dvmReleaseTrackedAlloc((Object*)stringArray, self); 65 return NULL; 66 } 67 68 /* stored in tracked array, okay to release */ 69 dvmReleaseTrackedAlloc((Object*)contents[i], self); 70 } 71 72 dvmReleaseTrackedAlloc((Object*)stringArray, self); 73 return stringArray; 74 } 75 76 /* 77 * static String[] getVmFeatureList() 78 * 79 * Return a set of strings describing available VM features (this is chiefly 80 * of interest to DDMS). Some features may be controlled by compile-time 81 * or command-line flags. 82 */ 83 static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args, 84 JValue* pResult) 85 { 86 static const int MAX_FEATURE_COUNT = 10; 87 char* features[MAX_FEATURE_COUNT]; 88 int idx = 0; 89 90 #ifdef WITH_PROFILER 91 /* VM responds to DDMS method profiling requests */ 92 features[idx++] = "method-trace-profiling"; 93 features[idx++] = "method-trace-profiling-streaming"; 94 #endif 95 #ifdef WITH_HPROF 96 /* VM responds to DDMS heap dump requests */ 97 features[idx++] = "hprof-heap-dump"; 98 features[idx++] = "hprof-heap-dump-streaming"; 99 #endif 100 101 assert(idx <= MAX_FEATURE_COUNT); 102 103 LOGV("+++ sending up %d features\n", idx); 104 ArrayObject* arrayObj = convertStringArray(features, idx); 105 RETURN_PTR(arrayObj); /* will be null on OOM */ 106 } 107 108 109 #ifdef WITH_PROFILER 110 /* These must match the values in dalvik.system.VMDebug. 111 */ 112 enum { 113 KIND_ALLOCATED_OBJECTS = 1<<0, 114 KIND_ALLOCATED_BYTES = 1<<1, 115 KIND_FREED_OBJECTS = 1<<2, 116 KIND_FREED_BYTES = 1<<3, 117 KIND_GC_INVOCATIONS = 1<<4, 118 KIND_CLASS_INIT_COUNT = 1<<5, 119 KIND_CLASS_INIT_TIME = 1<<6, 120 #if PROFILE_EXTERNAL_ALLOCATIONS 121 KIND_EXT_ALLOCATED_OBJECTS = 1<<12, 122 KIND_EXT_ALLOCATED_BYTES = 1<<13, 123 KIND_EXT_FREED_OBJECTS = 1<<14, 124 KIND_EXT_FREED_BYTES = 1<<15, 125 #endif // PROFILE_EXTERNAL_ALLOCATIONS 126 127 KIND_GLOBAL_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS, 128 KIND_GLOBAL_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES, 129 KIND_GLOBAL_FREED_OBJECTS = KIND_FREED_OBJECTS, 130 KIND_GLOBAL_FREED_BYTES = KIND_FREED_BYTES, 131 KIND_GLOBAL_GC_INVOCATIONS = KIND_GC_INVOCATIONS, 132 KIND_GLOBAL_CLASS_INIT_COUNT = KIND_CLASS_INIT_COUNT, 133 KIND_GLOBAL_CLASS_INIT_TIME = KIND_CLASS_INIT_TIME, 134 #if PROFILE_EXTERNAL_ALLOCATIONS 135 KIND_GLOBAL_EXT_ALLOCATED_OBJECTS = KIND_EXT_ALLOCATED_OBJECTS, 136 KIND_GLOBAL_EXT_ALLOCATED_BYTES = KIND_EXT_ALLOCATED_BYTES, 137 KIND_GLOBAL_EXT_FREED_OBJECTS = KIND_EXT_FREED_OBJECTS, 138 KIND_GLOBAL_EXT_FREED_BYTES = KIND_EXT_FREED_BYTES, 139 #endif // PROFILE_EXTERNAL_ALLOCATIONS 140 141 KIND_THREAD_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS << 16, 142 KIND_THREAD_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES << 16, 143 KIND_THREAD_FREED_OBJECTS = KIND_FREED_OBJECTS << 16, 144 KIND_THREAD_FREED_BYTES = KIND_FREED_BYTES << 16, 145 #if PROFILE_EXTERNAL_ALLOCATIONS 146 KIND_THREAD_EXT_ALLOCATED_OBJECTS = KIND_EXT_ALLOCATED_OBJECTS << 16, 147 KIND_THREAD_EXT_ALLOCATED_BYTES = KIND_EXT_ALLOCATED_BYTES << 16, 148 KIND_THREAD_EXT_FREED_OBJECTS = KIND_EXT_FREED_OBJECTS << 16, 149 KIND_THREAD_EXT_FREED_BYTES = KIND_EXT_FREED_BYTES << 16, 150 #endif // PROFILE_EXTERNAL_ALLOCATIONS 151 KIND_THREAD_GC_INVOCATIONS = KIND_GC_INVOCATIONS << 16, 152 153 // TODO: failedAllocCount, failedAllocSize 154 }; 155 156 #define KIND_ALL_COUNTS 0xffffffff 157 158 /* 159 * Zero out the specified fields. 160 */ 161 static void clearAllocProfStateFields(AllocProfState *allocProf, 162 unsigned int kinds) 163 { 164 if (kinds & KIND_ALLOCATED_OBJECTS) { 165 allocProf->allocCount = 0; 166 } 167 if (kinds & KIND_ALLOCATED_BYTES) { 168 allocProf->allocSize = 0; 169 } 170 if (kinds & KIND_FREED_OBJECTS) { 171 allocProf->freeCount = 0; 172 } 173 if (kinds & KIND_FREED_BYTES) { 174 allocProf->freeSize = 0; 175 } 176 if (kinds & KIND_GC_INVOCATIONS) { 177 allocProf->gcCount = 0; 178 } 179 if (kinds & KIND_CLASS_INIT_COUNT) { 180 allocProf->classInitCount = 0; 181 } 182 if (kinds & KIND_CLASS_INIT_TIME) { 183 allocProf->classInitTime = 0; 184 } 185 #if PROFILE_EXTERNAL_ALLOCATIONS 186 if (kinds & KIND_EXT_ALLOCATED_OBJECTS) { 187 allocProf->externalAllocCount = 0; 188 } 189 if (kinds & KIND_EXT_ALLOCATED_BYTES) { 190 allocProf->externalAllocSize = 0; 191 } 192 if (kinds & KIND_EXT_FREED_OBJECTS) { 193 allocProf->externalFreeCount = 0; 194 } 195 if (kinds & KIND_EXT_FREED_BYTES) { 196 allocProf->externalFreeSize = 0; 197 } 198 #endif // PROFILE_EXTERNAL_ALLOCATIONS 199 } 200 #endif 201 202 /* 203 * static void startAllocCounting() 204 * 205 * Reset the counters and enable counting. 206 * 207 * TODO: this currently only resets the per-thread counters for the current 208 * thread. If we actually start using the per-thread counters we'll 209 * probably want to fix this. 210 */ 211 static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args, 212 JValue* pResult) 213 { 214 UNUSED_PARAMETER(args); 215 216 #ifdef WITH_PROFILER 217 clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS); 218 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS); 219 dvmStartAllocCounting(); 220 #endif 221 RETURN_VOID(); 222 } 223 224 /* 225 * public static void stopAllocCounting() 226 */ 227 static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args, 228 JValue* pResult) 229 { 230 UNUSED_PARAMETER(args); 231 232 #ifdef WITH_PROFILER 233 dvmStopAllocCounting(); 234 #endif 235 RETURN_VOID(); 236 } 237 238 /* 239 * private static int getAllocCount(int kind) 240 */ 241 static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args, 242 JValue* pResult) 243 { 244 #ifdef WITH_PROFILER 245 AllocProfState *allocProf; 246 unsigned int kind = args[0]; 247 if (kind < (1<<16)) { 248 allocProf = &gDvm.allocProf; 249 } else { 250 allocProf = &dvmThreadSelf()->allocProf; 251 kind >>= 16; 252 } 253 switch (kind) { 254 case KIND_ALLOCATED_OBJECTS: 255 pResult->i = allocProf->allocCount; 256 break; 257 case KIND_ALLOCATED_BYTES: 258 pResult->i = allocProf->allocSize; 259 break; 260 case KIND_FREED_OBJECTS: 261 pResult->i = allocProf->freeCount; 262 break; 263 case KIND_FREED_BYTES: 264 pResult->i = allocProf->freeSize; 265 break; 266 case KIND_GC_INVOCATIONS: 267 pResult->i = allocProf->gcCount; 268 break; 269 case KIND_CLASS_INIT_COUNT: 270 pResult->i = allocProf->classInitCount; 271 break; 272 case KIND_CLASS_INIT_TIME: 273 /* convert nsec to usec, reduce to 32 bits */ 274 pResult->i = (int) (allocProf->classInitTime / 1000); 275 break; 276 #if PROFILE_EXTERNAL_ALLOCATIONS 277 case KIND_EXT_ALLOCATED_OBJECTS: 278 pResult->i = allocProf->externalAllocCount; 279 break; 280 case KIND_EXT_ALLOCATED_BYTES: 281 pResult->i = allocProf->externalAllocSize; 282 break; 283 case KIND_EXT_FREED_OBJECTS: 284 pResult->i = allocProf->externalFreeCount; 285 break; 286 case KIND_EXT_FREED_BYTES: 287 pResult->i = allocProf->externalFreeSize; 288 break; 289 #endif // PROFILE_EXTERNAL_ALLOCATIONS 290 default: 291 assert(false); 292 pResult->i = -1; 293 } 294 #else 295 RETURN_INT(-1); 296 #endif 297 } 298 299 /* 300 * public static void resetAllocCount(int kinds) 301 */ 302 static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args, 303 JValue* pResult) 304 { 305 #ifdef WITH_PROFILER 306 unsigned int kinds = args[0]; 307 clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff); 308 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16); 309 #endif 310 RETURN_VOID(); 311 } 312 313 /* 314 * static void startMethodTracingNative(String traceFileName, 315 * FileDescriptor fd, int bufferSize, int flags) 316 * 317 * Start method trace profiling. 318 * 319 * If both "traceFileName" and "fd" are null, the result will be sent 320 * directly to DDMS. (The non-DDMS versions of the calls are expected 321 * to enforce non-NULL filenames.) 322 */ 323 static void Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4* args, 324 JValue* pResult) 325 { 326 #ifdef WITH_PROFILER 327 StringObject* traceFileStr = (StringObject*) args[0]; 328 DataObject* traceFd = (DataObject*) args[1]; 329 int bufferSize = args[2]; 330 int flags = args[3]; 331 332 if (bufferSize == 0) { 333 // Default to 8MB per the documentation. 334 bufferSize = 8 * 1024 * 1024; 335 } 336 337 if (bufferSize < 1024) { 338 dvmThrowException("Ljava/lang/IllegalArgumentException;", NULL); 339 RETURN_VOID(); 340 } 341 342 char* traceFileName = NULL; 343 if (traceFileStr != NULL) 344 traceFileName = dvmCreateCstrFromString(traceFileStr); 345 346 int fd = -1; 347 if (traceFd != NULL) { 348 InstField* field = 349 dvmFindInstanceField(traceFd->obj.clazz, "descriptor", "I"); 350 if (field == NULL) { 351 dvmThrowException("Ljava/lang/NoSuchFieldException;", 352 "No FileDescriptor.descriptor field"); 353 RETURN_VOID(); 354 } 355 fd = dup(dvmGetFieldInt(&traceFd->obj, field->byteOffset)); 356 if (fd < 0) { 357 dvmThrowExceptionFmt("Ljava/lang/RuntimeException;", 358 "dup() failed: %s", strerror(errno)); 359 RETURN_VOID(); 360 } 361 } 362 363 dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]", 364 fd, bufferSize, flags, (traceFileName == NULL && fd == -1)); 365 free(traceFileName); 366 #else 367 // throw exception? 368 #endif 369 RETURN_VOID(); 370 } 371 372 /* 373 * static boolean isMethodTracingActive() 374 * 375 * Determine whether method tracing is currently active. 376 */ 377 static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args, 378 JValue* pResult) 379 { 380 UNUSED_PARAMETER(args); 381 382 #ifdef WITH_PROFILER 383 RETURN_BOOLEAN(dvmIsMethodTraceActive()); 384 #else 385 RETURN_BOOLEAN(false); 386 #endif 387 } 388 389 /* 390 * static void stopMethodTracing() 391 * 392 * Stop method tracing. 393 */ 394 static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args, 395 JValue* pResult) 396 { 397 UNUSED_PARAMETER(args); 398 399 #ifdef WITH_PROFILER 400 dvmMethodTraceStop(); 401 #else 402 // throw exception? 403 #endif 404 RETURN_VOID(); 405 } 406 407 /* 408 * static void startEmulatorTracing() 409 * 410 * Start sending method trace info to the emulator. 411 */ 412 static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args, 413 JValue* pResult) 414 { 415 UNUSED_PARAMETER(args); 416 417 #ifdef WITH_PROFILER 418 dvmEmulatorTraceStart(); 419 #else 420 // throw exception? 421 #endif 422 RETURN_VOID(); 423 } 424 425 /* 426 * static void stopEmulatorTracing() 427 * 428 * Start sending method trace info to the emulator. 429 */ 430 static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args, 431 JValue* pResult) 432 { 433 UNUSED_PARAMETER(args); 434 435 #ifdef WITH_PROFILER 436 dvmEmulatorTraceStop(); 437 #else 438 // throw exception? 439 #endif 440 RETURN_VOID(); 441 } 442 443 /* 444 * static int setAllocationLimit(int limit) 445 * 446 * Set the current allocation limit in this thread. Return the previous 447 * value. 448 */ 449 static void Dalvik_dalvik_system_VMDebug_setAllocationLimit(const u4* args, 450 JValue* pResult) 451 { 452 #if defined(WITH_ALLOC_LIMITS) 453 gDvm.checkAllocLimits = true; 454 455 Thread* self = dvmThreadSelf(); 456 int newLimit = args[0]; 457 int oldLimit = self->allocLimit; 458 459 if (newLimit < -1) { 460 LOGE("WARNING: bad limit request (%d)\n", newLimit); 461 newLimit = -1; 462 } 463 self->allocLimit = newLimit; 464 RETURN_INT(oldLimit); 465 #else 466 UNUSED_PARAMETER(args); 467 RETURN_INT(-1); 468 #endif 469 } 470 471 /* 472 * static int setGlobalAllocationLimit(int limit) 473 * 474 * Set the allocation limit for this process. Returns the previous value. 475 */ 476 static void Dalvik_dalvik_system_VMDebug_setGlobalAllocationLimit(const u4* args, 477 JValue* pResult) 478 { 479 #if defined(WITH_ALLOC_LIMITS) 480 gDvm.checkAllocLimits = true; 481 482 int newLimit = args[0]; 483 int oldLimit = gDvm.allocationLimit; 484 485 if (newLimit < -1 || newLimit > 0) { 486 LOGE("WARNING: bad limit request (%d)\n", newLimit); 487 newLimit = -1; 488 } 489 // TODO: should use an atomic swap here 490 gDvm.allocationLimit = newLimit; 491 RETURN_INT(oldLimit); 492 #else 493 UNUSED_PARAMETER(args); 494 RETURN_INT(-1); 495 #endif 496 } 497 498 /* 499 * static boolean isDebuggerConnected() 500 * 501 * Returns "true" if a debugger is attached. 502 */ 503 static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args, 504 JValue* pResult) 505 { 506 UNUSED_PARAMETER(args); 507 508 RETURN_BOOLEAN(dvmDbgIsDebuggerConnected()); 509 } 510 511 /* 512 * static boolean isDebuggingEnabled() 513 * 514 * Returns "true" if debugging is enabled. 515 */ 516 static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args, 517 JValue* pResult) 518 { 519 UNUSED_PARAMETER(args); 520 521 RETURN_BOOLEAN(gDvm.jdwpConfigured); 522 } 523 524 /* 525 * static long lastDebuggerActivity() 526 * 527 * Returns the time, in msec, since we last had an interaction with the 528 * debugger (send or receive). 529 */ 530 static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args, 531 JValue* pResult) 532 { 533 UNUSED_PARAMETER(args); 534 535 RETURN_LONG(dvmDbgLastDebuggerActivity()); 536 } 537 538 /* 539 * static void startInstructionCounting() 540 */ 541 static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args, 542 JValue* pResult) 543 { 544 #if defined(WITH_PROFILER) 545 dvmStartInstructionCounting(); 546 #else 547 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL); 548 #endif 549 RETURN_VOID(); 550 } 551 552 /* 553 * static void stopInstructionCounting() 554 */ 555 static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args, 556 JValue* pResult) 557 { 558 #if defined(WITH_PROFILER) 559 dvmStopInstructionCounting(); 560 #else 561 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL); 562 #endif 563 RETURN_VOID(); 564 } 565 566 /* 567 * static boolean getInstructionCount(int[] counts) 568 * 569 * Grab a copy of the global instruction count array. 570 * 571 * Since the instruction counts aren't synchronized, we use sched_yield 572 * to improve our chances of finishing without contention. (Only makes 573 * sense on a uniprocessor.) 574 */ 575 static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args, 576 JValue* pResult) 577 { 578 #if defined(WITH_PROFILER) 579 ArrayObject* countArray = (ArrayObject*) args[0]; 580 int* storage; 581 582 storage = (int*) countArray->contents; 583 sched_yield(); 584 memcpy(storage, gDvm.executedInstrCounts, 585 kNumDalvikInstructions * sizeof(int)); 586 #else 587 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL); 588 #endif 589 RETURN_VOID(); 590 } 591 592 /* 593 * static boolean resetInstructionCount() 594 * 595 * Reset the instruction count array. 596 */ 597 static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args, 598 JValue* pResult) 599 { 600 #if defined(WITH_PROFILER) 601 sched_yield(); 602 memset(gDvm.executedInstrCounts, 0, kNumDalvikInstructions * sizeof(int)); 603 #else 604 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL); 605 #endif 606 RETURN_VOID(); 607 } 608 609 /* 610 * static void printLoadedClasses(int flags) 611 * 612 * Dump the list of loaded classes. 613 */ 614 static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args, 615 JValue* pResult) 616 { 617 int flags = args[0]; 618 619 dvmDumpAllClasses(flags); 620 621 RETURN_VOID(); 622 } 623 624 /* 625 * static int getLoadedClassCount() 626 * 627 * Return the number of loaded classes 628 */ 629 static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args, 630 JValue* pResult) 631 { 632 int count; 633 634 UNUSED_PARAMETER(args); 635 636 count = dvmGetNumLoadedClasses(); 637 638 RETURN_INT(count); 639 } 640 641 /* 642 * Returns the thread-specific CPU-time clock value for the current thread, 643 * or -1 if the feature isn't supported. 644 */ 645 static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args, 646 JValue* pResult) 647 { 648 jlong result; 649 650 #ifdef HAVE_POSIX_CLOCKS 651 struct timespec now; 652 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); 653 result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec); 654 #else 655 result = (jlong) -1; 656 #endif 657 658 RETURN_LONG(result); 659 } 660 661 /* 662 * static void dumpHprofData(String fileName) 663 * 664 * Cause "hprof" data to be dumped. We can throw an IOException if an 665 * error occurs during file handling. 666 */ 667 static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args, 668 JValue* pResult) 669 { 670 #ifdef WITH_HPROF 671 StringObject* fileNameStr = (StringObject*) args[0]; 672 char* fileName; 673 int result; 674 675 if (fileNameStr == NULL) { 676 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 677 RETURN_VOID(); 678 } 679 680 fileName = dvmCreateCstrFromString(fileNameStr); 681 if (fileName == NULL) { 682 /* unexpected -- malloc failure? */ 683 dvmThrowException("Ljava/lang/RuntimeException;", "malloc failure?"); 684 RETURN_VOID(); 685 } 686 687 result = hprofDumpHeap(fileName, false); 688 free(fileName); 689 690 if (result != 0) { 691 /* ideally we'd throw something more specific based on actual failure */ 692 dvmThrowException("Ljava/lang/RuntimeException;", 693 "Failure during heap dump -- check log output for details"); 694 RETURN_VOID(); 695 } 696 #else 697 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL); 698 #endif 699 700 RETURN_VOID(); 701 } 702 703 /* 704 * static void dumpHprofDataDdms() 705 * 706 * Cause "hprof" data to be computed and sent directly to DDMS. 707 */ 708 static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args, 709 JValue* pResult) 710 { 711 #ifdef WITH_HPROF 712 int result; 713 714 result = hprofDumpHeap("[DDMS]", true); 715 716 if (result != 0) { 717 /* ideally we'd throw something more specific based on actual failure */ 718 dvmThrowException("Ljava/lang/RuntimeException;", 719 "Failure during heap dump -- check log output for details"); 720 RETURN_VOID(); 721 } 722 #else 723 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL); 724 #endif 725 726 RETURN_VOID(); 727 } 728 729 /* 730 * static boolean cacheRegisterMap(String classAndMethodDescr) 731 * 732 * If the specified class is loaded, and the named method exists, ensure 733 * that the method's register map is ready for use. If the class/method 734 * cannot be found, nothing happens. 735 * 736 * This can improve the zygote's sharing of compressed register maps. Do 737 * this after class preloading. 738 * 739 * Returns true if the register map is cached and ready, either as a result 740 * of this call or earlier activity. Returns false if the class isn't loaded, 741 * if the method couldn't be found, or if the method has no register map. 742 * 743 * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.) 744 */ 745 static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args, 746 JValue* pResult) 747 { 748 StringObject* classAndMethodDescStr = (StringObject*) args[0]; 749 ClassObject* clazz; 750 bool result = false; 751 752 if (classAndMethodDescStr == NULL) { 753 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 754 RETURN_VOID(); 755 } 756 757 char* classAndMethodDesc = NULL; 758 759 /* 760 * Pick the string apart. We have a local copy, so just modify it 761 * in place. 762 */ 763 classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr); 764 765 char* methodName = strchr(classAndMethodDesc, '.'); 766 if (methodName == NULL) { 767 dvmThrowException("Ljava/lang/RuntimeException;", 768 "method name not found in string"); 769 RETURN_VOID(); 770 } 771 *methodName++ = '\0'; 772 773 char* methodDescr = strchr(methodName, ':'); 774 if (methodDescr == NULL) { 775 dvmThrowException("Ljava/lang/RuntimeException;", 776 "method descriptor not found in string"); 777 RETURN_VOID(); 778 } 779 *methodDescr++ = '\0'; 780 781 //LOGD("GOT: %s %s %s\n", classAndMethodDesc, methodName, methodDescr); 782 783 /* 784 * Find the class, but only if it's already loaded. 785 */ 786 clazz = dvmLookupClass(classAndMethodDesc, NULL, false); 787 if (clazz == NULL) { 788 LOGD("Class %s not found in bootstrap loader\n", classAndMethodDesc); 789 goto bail; 790 } 791 792 Method* method; 793 794 /* 795 * Find the method, which could be virtual or direct, defined directly 796 * or inherited. 797 */ 798 if (methodName[0] == '<') { 799 /* 800 * Constructor or class initializer. Only need to examine the 801 * "direct" list, and don't need to search up the class hierarchy. 802 */ 803 method = dvmFindDirectMethodByDescriptor(clazz, methodName, 804 methodDescr); 805 } else { 806 /* 807 * Try both lists, and scan up the tree. 808 */ 809 method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName, 810 methodDescr); 811 if (method == NULL) { 812 method = dvmFindDirectMethodHierByDescriptor(clazz, methodName, 813 methodDescr); 814 } 815 } 816 817 if (method != NULL) { 818 /* 819 * Got it. See if there's a register map here. 820 */ 821 const RegisterMap* pMap; 822 pMap = dvmGetExpandedRegisterMap(method); 823 if (pMap == NULL) { 824 LOGV("No map for %s.%s %s\n", 825 classAndMethodDesc, methodName, methodDescr); 826 } else { 827 LOGV("Found map %s.%s %s\n", 828 classAndMethodDesc, methodName, methodDescr); 829 result = true; 830 } 831 } else { 832 LOGV("Unable to find %s.%s %s\n", 833 classAndMethodDesc, methodName, methodDescr); 834 } 835 836 bail: 837 free(classAndMethodDesc); 838 RETURN_BOOLEAN(result); 839 } 840 841 /* 842 * static void dumpReferenceTables() 843 */ 844 static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args, 845 JValue* pResult) 846 { 847 UNUSED_PARAMETER(args); 848 UNUSED_PARAMETER(pResult); 849 850 LOGI("--- reference table dump ---\n"); 851 dvmDumpJniReferenceTables(); 852 // could dump thread's internalLocalRefTable, probably not useful 853 // ditto for thread's jniMonitorRefTable 854 LOGI("---\n"); 855 RETURN_VOID(); 856 } 857 858 /* 859 * static void crash() 860 * 861 * Dump the current thread's interpreted stack and abort the VM. Useful 862 * for seeing both interpreted and native stack traces. 863 * 864 * (Might want to restrict this to debuggable processes as a security 865 * measure, or check SecurityManager.checkExit().) 866 */ 867 static void Dalvik_dalvik_system_VMDebug_crash(const u4* args, 868 JValue* pResult) 869 { 870 UNUSED_PARAMETER(args); 871 UNUSED_PARAMETER(pResult); 872 873 LOGW("Crashing VM on request\n"); 874 dvmDumpThread(dvmThreadSelf(), false); 875 dvmAbort(); 876 } 877 878 /* 879 * static void infopoint(int id) 880 * 881 * Provide a hook for gdb to hang to so that the VM can be stopped when 882 * user-tagged source locations are being executed. 883 */ 884 static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args, 885 JValue* pResult) 886 { 887 gDvm.nativeDebuggerActive = true; 888 889 LOGD("VMDebug infopoint %d hit", args[0]); 890 891 gDvm.nativeDebuggerActive = false; 892 RETURN_VOID(); 893 } 894 895 const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = { 896 { "getVmFeatureList", "()[Ljava/lang/String;", 897 Dalvik_dalvik_system_VMDebug_getVmFeatureList }, 898 { "getAllocCount", "(I)I", 899 Dalvik_dalvik_system_VMDebug_getAllocCount }, 900 { "resetAllocCount", "(I)V", 901 Dalvik_dalvik_system_VMDebug_resetAllocCount }, 902 { "startAllocCounting", "()V", 903 Dalvik_dalvik_system_VMDebug_startAllocCounting }, 904 { "stopAllocCounting", "()V", 905 Dalvik_dalvik_system_VMDebug_stopAllocCounting }, 906 { "startMethodTracingNative", "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V", 907 Dalvik_dalvik_system_VMDebug_startMethodTracingNative }, 908 { "isMethodTracingActive", "()Z", 909 Dalvik_dalvik_system_VMDebug_isMethodTracingActive }, 910 { "stopMethodTracing", "()V", 911 Dalvik_dalvik_system_VMDebug_stopMethodTracing }, 912 { "startEmulatorTracing", "()V", 913 Dalvik_dalvik_system_VMDebug_startEmulatorTracing }, 914 { "stopEmulatorTracing", "()V", 915 Dalvik_dalvik_system_VMDebug_stopEmulatorTracing }, 916 { "setAllocationLimit", "(I)I", 917 Dalvik_dalvik_system_VMDebug_setAllocationLimit }, 918 { "setGlobalAllocationLimit", "(I)I", 919 Dalvik_dalvik_system_VMDebug_setGlobalAllocationLimit }, 920 { "startInstructionCounting", "()V", 921 Dalvik_dalvik_system_VMDebug_startInstructionCounting }, 922 { "stopInstructionCounting", "()V", 923 Dalvik_dalvik_system_VMDebug_stopInstructionCounting }, 924 { "resetInstructionCount", "()V", 925 Dalvik_dalvik_system_VMDebug_resetInstructionCount }, 926 { "getInstructionCount", "([I)V", 927 Dalvik_dalvik_system_VMDebug_getInstructionCount }, 928 { "isDebuggerConnected", "()Z", 929 Dalvik_dalvik_system_VMDebug_isDebuggerConnected }, 930 { "isDebuggingEnabled", "()Z", 931 Dalvik_dalvik_system_VMDebug_isDebuggingEnabled }, 932 { "lastDebuggerActivity", "()J", 933 Dalvik_dalvik_system_VMDebug_lastDebuggerActivity }, 934 { "printLoadedClasses", "(I)V", 935 Dalvik_dalvik_system_VMDebug_printLoadedClasses }, 936 { "getLoadedClassCount", "()I", 937 Dalvik_dalvik_system_VMDebug_getLoadedClassCount }, 938 { "threadCpuTimeNanos", "()J", 939 Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos }, 940 { "dumpHprofData", "(Ljava/lang/String;)V", 941 Dalvik_dalvik_system_VMDebug_dumpHprofData }, 942 { "dumpHprofDataDdms", "()V", 943 Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms }, 944 { "cacheRegisterMap", "(Ljava/lang/String;)Z", 945 Dalvik_dalvik_system_VMDebug_cacheRegisterMap }, 946 { "dumpReferenceTables", "()V", 947 Dalvik_dalvik_system_VMDebug_dumpReferenceTables }, 948 { "crash", "()V", 949 Dalvik_dalvik_system_VMDebug_crash }, 950 { "infopoint", "(I)V", 951 Dalvik_dalvik_system_VMDebug_infopoint }, 952 { NULL, NULL, NULL }, 953 }; 954