Debug.java revision fe067a4cc586631881f51d0fd48100dd0f7cadf2
1/* 2 * Copyright (C) 2007 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 17package android.os; 18 19import com.android.internal.util.TypedProperties; 20 21import android.util.Log; 22 23import java.io.FileDescriptor; 24import java.io.FileNotFoundException; 25import java.io.FileOutputStream; 26import java.io.FileReader; 27import java.io.IOException; 28import java.io.OutputStreamWriter; 29import java.io.PrintWriter; 30import java.io.Reader; 31import java.lang.reflect.Field; 32import java.lang.reflect.Modifier; 33import java.lang.annotation.Target; 34import java.lang.annotation.ElementType; 35import java.lang.annotation.Retention; 36import java.lang.annotation.RetentionPolicy; 37 38import org.apache.harmony.dalvik.ddmc.Chunk; 39import org.apache.harmony.dalvik.ddmc.ChunkHandler; 40import org.apache.harmony.dalvik.ddmc.DdmServer; 41 42import dalvik.bytecode.OpcodeInfo; 43import dalvik.bytecode.Opcodes; 44import dalvik.system.VMDebug; 45 46 47/** 48 * Provides various debugging methods for Android applications, including 49 * tracing and allocation counts. 50 * <p><strong>Logging Trace Files</strong></p> 51 * <p>Debug can create log files that give details about an application, such as 52 * a call stack and start/stop times for any running methods. See <a 53href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for 54 * information about reading trace files. To start logging trace files, call one 55 * of the startMethodTracing() methods. To stop tracing, call 56 * {@link #stopMethodTracing()}. 57 */ 58public final class Debug 59{ 60 private static final String TAG = "Debug"; 61 62 /** 63 * Flags for startMethodTracing(). These can be ORed together. 64 * 65 * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the 66 * trace key file. 67 */ 68 public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS; 69 70 /** 71 * Flags for printLoadedClasses(). Default behavior is to only show 72 * the class name. 73 */ 74 public static final int SHOW_FULL_DETAIL = 1; 75 public static final int SHOW_CLASSLOADER = (1 << 1); 76 public static final int SHOW_INITIALIZED = (1 << 2); 77 78 // set/cleared by waitForDebugger() 79 private static volatile boolean mWaiting = false; 80 81 private Debug() {} 82 83 /* 84 * How long to wait for the debugger to finish sending requests. I've 85 * seen this hit 800msec on the device while waiting for a response 86 * to travel over USB and get processed, so we take that and add 87 * half a second. 88 */ 89 private static final int MIN_DEBUGGER_IDLE = 1300; // msec 90 91 /* how long to sleep when polling for activity */ 92 private static final int SPIN_DELAY = 200; // msec 93 94 /** 95 * Default trace file path and file 96 */ 97 private static final String DEFAULT_TRACE_PATH_PREFIX = 98 Environment.getLegacyExternalStorageDirectory().getPath() + "/"; 99 private static final String DEFAULT_TRACE_BODY = "dmtrace"; 100 private static final String DEFAULT_TRACE_EXTENSION = ".trace"; 101 private static final String DEFAULT_TRACE_FILE_PATH = 102 DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY 103 + DEFAULT_TRACE_EXTENSION; 104 105 106 /** 107 * This class is used to retrieved various statistics about the memory mappings for this 108 * process. The returns info broken down by dalvik, native, and other. All results are in kB. 109 */ 110 public static class MemoryInfo implements Parcelable { 111 /** The proportional set size for dalvik. */ 112 public int dalvikPss; 113 /** The private dirty pages used by dalvik. */ 114 public int dalvikPrivateDirty; 115 /** The shared dirty pages used by dalvik. */ 116 public int dalvikSharedDirty; 117 118 /** The proportional set size for the native heap. */ 119 public int nativePss; 120 /** The private dirty pages used by the native heap. */ 121 public int nativePrivateDirty; 122 /** The shared dirty pages used by the native heap. */ 123 public int nativeSharedDirty; 124 125 /** The proportional set size for everything else. */ 126 public int otherPss; 127 /** The private dirty pages used by everything else. */ 128 public int otherPrivateDirty; 129 /** The shared dirty pages used by everything else. */ 130 public int otherSharedDirty; 131 132 /** @hide */ 133 public static final int NUM_OTHER_STATS = 9; 134 135 private int[] otherStats = new int[NUM_OTHER_STATS*3]; 136 137 public MemoryInfo() { 138 } 139 140 /** 141 * Return total PSS memory usage in kB. 142 */ 143 public int getTotalPss() { 144 return dalvikPss + nativePss + otherPss; 145 } 146 147 /** 148 * Return total private dirty memory usage in kB. 149 */ 150 public int getTotalPrivateDirty() { 151 return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty; 152 } 153 154 /** 155 * Return total shared dirty memory usage in kB. 156 */ 157 public int getTotalSharedDirty() { 158 return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty; 159 } 160 161 /* @hide */ 162 public int getOtherPss(int which) { 163 return otherStats[which*3]; 164 } 165 166 /* @hide */ 167 public int getOtherPrivateDirty(int which) { 168 return otherStats[which*3 + 1]; 169 } 170 171 /* @hide */ 172 public int getOtherSharedDirty(int which) { 173 return otherStats[which*3 + 2]; 174 } 175 176 177 /* @hide */ 178 public static String getOtherLabel(int which) { 179 switch (which) { 180 case 0: return "Cursor"; 181 case 1: return "Ashmem"; 182 case 2: return "Other dev"; 183 case 3: return ".so mmap"; 184 case 4: return ".jar mmap"; 185 case 5: return ".apk mmap"; 186 case 6: return ".ttf mmap"; 187 case 7: return ".dex mmap"; 188 case 8: return "Other mmap"; 189 default: return "????"; 190 } 191 } 192 193 public int describeContents() { 194 return 0; 195 } 196 197 public void writeToParcel(Parcel dest, int flags) { 198 dest.writeInt(dalvikPss); 199 dest.writeInt(dalvikPrivateDirty); 200 dest.writeInt(dalvikSharedDirty); 201 dest.writeInt(nativePss); 202 dest.writeInt(nativePrivateDirty); 203 dest.writeInt(nativeSharedDirty); 204 dest.writeInt(otherPss); 205 dest.writeInt(otherPrivateDirty); 206 dest.writeInt(otherSharedDirty); 207 dest.writeIntArray(otherStats); 208 } 209 210 public void readFromParcel(Parcel source) { 211 dalvikPss = source.readInt(); 212 dalvikPrivateDirty = source.readInt(); 213 dalvikSharedDirty = source.readInt(); 214 nativePss = source.readInt(); 215 nativePrivateDirty = source.readInt(); 216 nativeSharedDirty = source.readInt(); 217 otherPss = source.readInt(); 218 otherPrivateDirty = source.readInt(); 219 otherSharedDirty = source.readInt(); 220 otherStats = source.createIntArray(); 221 } 222 223 public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() { 224 public MemoryInfo createFromParcel(Parcel source) { 225 return new MemoryInfo(source); 226 } 227 public MemoryInfo[] newArray(int size) { 228 return new MemoryInfo[size]; 229 } 230 }; 231 232 private MemoryInfo(Parcel source) { 233 readFromParcel(source); 234 } 235 } 236 237 238 /** 239 * Wait until a debugger attaches. As soon as the debugger attaches, 240 * this returns, so you will need to place a breakpoint after the 241 * waitForDebugger() call if you want to start tracing immediately. 242 */ 243 public static void waitForDebugger() { 244 if (!VMDebug.isDebuggingEnabled()) { 245 //System.out.println("debugging not enabled, not waiting"); 246 return; 247 } 248 if (isDebuggerConnected()) 249 return; 250 251 // if DDMS is listening, inform them of our plight 252 System.out.println("Sending WAIT chunk"); 253 byte[] data = new byte[] { 0 }; // 0 == "waiting for debugger" 254 Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1); 255 DdmServer.sendChunk(waitChunk); 256 257 mWaiting = true; 258 while (!isDebuggerConnected()) { 259 try { Thread.sleep(SPIN_DELAY); } 260 catch (InterruptedException ie) {} 261 } 262 mWaiting = false; 263 264 System.out.println("Debugger has connected"); 265 266 /* 267 * There is no "ready to go" signal from the debugger, and we're 268 * not allowed to suspend ourselves -- the debugger expects us to 269 * be running happily, and gets confused if we aren't. We need to 270 * allow the debugger a chance to set breakpoints before we start 271 * running again. 272 * 273 * Sit and spin until the debugger has been idle for a short while. 274 */ 275 while (true) { 276 long delta = VMDebug.lastDebuggerActivity(); 277 if (delta < 0) { 278 System.out.println("debugger detached?"); 279 break; 280 } 281 282 if (delta < MIN_DEBUGGER_IDLE) { 283 System.out.println("waiting for debugger to settle..."); 284 try { Thread.sleep(SPIN_DELAY); } 285 catch (InterruptedException ie) {} 286 } else { 287 System.out.println("debugger has settled (" + delta + ")"); 288 break; 289 } 290 } 291 } 292 293 /** 294 * Returns "true" if one or more threads is waiting for a debugger 295 * to attach. 296 */ 297 public static boolean waitingForDebugger() { 298 return mWaiting; 299 } 300 301 /** 302 * Determine if a debugger is currently attached. 303 */ 304 public static boolean isDebuggerConnected() { 305 return VMDebug.isDebuggerConnected(); 306 } 307 308 /** 309 * Returns an array of strings that identify VM features. This is 310 * used by DDMS to determine what sorts of operations the VM can 311 * perform. 312 * 313 * @hide 314 */ 315 public static String[] getVmFeatureList() { 316 return VMDebug.getVmFeatureList(); 317 } 318 319 /** 320 * Change the JDWP port. 321 * 322 * @deprecated no longer needed or useful 323 */ 324 @Deprecated 325 public static void changeDebugPort(int port) {} 326 327 /** 328 * This is the pathname to the sysfs file that enables and disables 329 * tracing on the qemu emulator. 330 */ 331 private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state"; 332 333 /** 334 * Enable qemu tracing. For this to work requires running everything inside 335 * the qemu emulator; otherwise, this method will have no effect. The trace 336 * file is specified on the command line when the emulator is started. For 337 * example, the following command line <br /> 338 * <code>emulator -trace foo</code><br /> 339 * will start running the emulator and create a trace file named "foo". This 340 * method simply enables writing the trace records to the trace file. 341 * 342 * <p> 343 * The main differences between this and {@link #startMethodTracing()} are 344 * that tracing in the qemu emulator traces every cpu instruction of every 345 * process, including kernel code, so we have more complete information, 346 * including all context switches. We can also get more detailed information 347 * such as cache misses. The sequence of calls is determined by 348 * post-processing the instruction trace. The qemu tracing is also done 349 * without modifying the application or perturbing the timing of calls 350 * because no instrumentation is added to the application being traced. 351 * </p> 352 * 353 * <p> 354 * One limitation of using this method compared to using 355 * {@link #startMethodTracing()} on the real device is that the emulator 356 * does not model all of the real hardware effects such as memory and 357 * bus contention. The emulator also has a simple cache model and cannot 358 * capture all the complexities of a real cache. 359 * </p> 360 */ 361 public static void startNativeTracing() { 362 // Open the sysfs file for writing and write "1" to it. 363 PrintWriter outStream = null; 364 try { 365 FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE); 366 outStream = new PrintWriter(new OutputStreamWriter(fos)); 367 outStream.println("1"); 368 } catch (Exception e) { 369 } finally { 370 if (outStream != null) 371 outStream.close(); 372 } 373 374 VMDebug.startEmulatorTracing(); 375 } 376 377 /** 378 * Stop qemu tracing. See {@link #startNativeTracing()} to start tracing. 379 * 380 * <p>Tracing can be started and stopped as many times as desired. When 381 * the qemu emulator itself is stopped then the buffered trace records 382 * are flushed and written to the trace file. In fact, it is not necessary 383 * to call this method at all; simply killing qemu is sufficient. But 384 * starting and stopping a trace is useful for examining a specific 385 * region of code.</p> 386 */ 387 public static void stopNativeTracing() { 388 VMDebug.stopEmulatorTracing(); 389 390 // Open the sysfs file for writing and write "0" to it. 391 PrintWriter outStream = null; 392 try { 393 FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE); 394 outStream = new PrintWriter(new OutputStreamWriter(fos)); 395 outStream.println("0"); 396 } catch (Exception e) { 397 // We could print an error message here but we probably want 398 // to quietly ignore errors if we are not running in the emulator. 399 } finally { 400 if (outStream != null) 401 outStream.close(); 402 } 403 } 404 405 /** 406 * Enable "emulator traces", in which information about the current 407 * method is made available to the "emulator -trace" feature. There 408 * is no corresponding "disable" call -- this is intended for use by 409 * the framework when tracing should be turned on and left that way, so 410 * that traces captured with F9/F10 will include the necessary data. 411 * 412 * This puts the VM into "profile" mode, which has performance 413 * consequences. 414 * 415 * To temporarily enable tracing, use {@link #startNativeTracing()}. 416 */ 417 public static void enableEmulatorTraceOutput() { 418 VMDebug.startEmulatorTracing(); 419 } 420 421 /** 422 * Start method tracing with default log name and buffer size. See <a 423href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for 424 * information about reading these files. Call stopMethodTracing() to stop 425 * tracing. 426 */ 427 public static void startMethodTracing() { 428 VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0); 429 } 430 431 /** 432 * Start method tracing, specifying the trace log file name. The trace 433 * file will be put under "/sdcard" unless an absolute path is given. 434 * See <a 435 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for 436 * information about reading trace files. 437 * 438 * @param traceName Name for the trace log file to create. 439 * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". 440 * If the files already exist, they will be truncated. 441 * If the trace file given does not end in ".trace", it will be appended for you. 442 */ 443 public static void startMethodTracing(String traceName) { 444 startMethodTracing(traceName, 0, 0); 445 } 446 447 /** 448 * Start method tracing, specifying the trace log file name and the 449 * buffer size. The trace files will be put under "/sdcard" unless an 450 * absolute path is given. See <a 451 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for 452 * information about reading trace files. 453 * @param traceName Name for the trace log file to create. 454 * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". 455 * If the files already exist, they will be truncated. 456 * If the trace file given does not end in ".trace", it will be appended for you. 457 * 458 * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. 459 */ 460 public static void startMethodTracing(String traceName, int bufferSize) { 461 startMethodTracing(traceName, bufferSize, 0); 462 } 463 464 /** 465 * Start method tracing, specifying the trace log file name and the 466 * buffer size. The trace files will be put under "/sdcard" unless an 467 * absolute path is given. See <a 468 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for 469 * information about reading trace files. 470 * 471 * <p> 472 * When method tracing is enabled, the VM will run more slowly than 473 * usual, so the timings from the trace files should only be considered 474 * in relative terms (e.g. was run #1 faster than run #2). The times 475 * for native methods will not change, so don't try to use this to 476 * compare the performance of interpreted and native implementations of the 477 * same method. As an alternative, consider using "native" tracing 478 * in the emulator via {@link #startNativeTracing()}. 479 * </p> 480 * 481 * @param traceName Name for the trace log file to create. 482 * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". 483 * If the files already exist, they will be truncated. 484 * If the trace file given does not end in ".trace", it will be appended for you. 485 * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. 486 */ 487 public static void startMethodTracing(String traceName, int bufferSize, 488 int flags) { 489 490 String pathName = traceName; 491 if (pathName.charAt(0) != '/') 492 pathName = DEFAULT_TRACE_PATH_PREFIX + pathName; 493 if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION)) 494 pathName = pathName + DEFAULT_TRACE_EXTENSION; 495 496 VMDebug.startMethodTracing(pathName, bufferSize, flags); 497 } 498 499 /** 500 * Like startMethodTracing(String, int, int), but taking an already-opened 501 * FileDescriptor in which the trace is written. The file name is also 502 * supplied simply for logging. Makes a dup of the file descriptor. 503 * 504 * Not exposed in the SDK unless we are really comfortable with supporting 505 * this and find it would be useful. 506 * @hide 507 */ 508 public static void startMethodTracing(String traceName, FileDescriptor fd, 509 int bufferSize, int flags) { 510 VMDebug.startMethodTracing(traceName, fd, bufferSize, flags); 511 } 512 513 /** 514 * Starts method tracing without a backing file. When stopMethodTracing 515 * is called, the result is sent directly to DDMS. (If DDMS is not 516 * attached when tracing ends, the profiling data will be discarded.) 517 * 518 * @hide 519 */ 520 public static void startMethodTracingDdms(int bufferSize, int flags) { 521 VMDebug.startMethodTracingDdms(bufferSize, flags); 522 } 523 524 /** 525 * Determine whether method tracing is currently active. 526 * @hide 527 */ 528 public static boolean isMethodTracingActive() { 529 return VMDebug.isMethodTracingActive(); 530 } 531 532 /** 533 * Stop method tracing. 534 */ 535 public static void stopMethodTracing() { 536 VMDebug.stopMethodTracing(); 537 } 538 539 /** 540 * Get an indication of thread CPU usage. The value returned 541 * indicates the amount of time that the current thread has spent 542 * executing code or waiting for certain types of I/O. 543 * 544 * The time is expressed in nanoseconds, and is only meaningful 545 * when compared to the result from an earlier call. Note that 546 * nanosecond resolution does not imply nanosecond accuracy. 547 * 548 * On system which don't support this operation, the call returns -1. 549 */ 550 public static long threadCpuTimeNanos() { 551 return VMDebug.threadCpuTimeNanos(); 552 } 553 554 /** 555 * Start counting the number and aggregate size of memory allocations. 556 * 557 * <p>The {@link #startAllocCounting() start} method resets the counts and enables counting. 558 * The {@link #stopAllocCounting() stop} method disables the counting so that the analysis 559 * code doesn't cause additional allocations. The various <code>get</code> methods return 560 * the specified value. And the various <code>reset</code> methods reset the specified 561 * count.</p> 562 * 563 * <p>Counts are kept for the system as a whole (global) and for each thread. 564 * The per-thread counts for threads other than the current thread 565 * are not cleared by the "reset" or "start" calls.</p> 566 * 567 * @deprecated Accurate counting is a burden on the runtime and may be removed. 568 */ 569 @Deprecated 570 public static void startAllocCounting() { 571 VMDebug.startAllocCounting(); 572 } 573 574 /** 575 * Stop counting the number and aggregate size of memory allocations. 576 * 577 * @see #startAllocCounting() 578 */ 579 public static void stopAllocCounting() { 580 VMDebug.stopAllocCounting(); 581 } 582 583 /** 584 * Returns the global count of objects allocated by the runtime between a 585 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 586 */ 587 public static int getGlobalAllocCount() { 588 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); 589 } 590 591 /** 592 * Clears the global count of objects allocated. 593 * @see #getGlobalAllocCount() 594 */ 595 public static void resetGlobalAllocCount() { 596 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); 597 } 598 599 /** 600 * Returns the global size, in bytes, of objects allocated by the runtime between a 601 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 602 */ 603 public static int getGlobalAllocSize() { 604 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); 605 } 606 607 /** 608 * Clears the global size of objects allocated. 609 * @see #getGlobalAllocCountSize() 610 */ 611 public static void resetGlobalAllocSize() { 612 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); 613 } 614 615 /** 616 * Returns the global count of objects freed by the runtime between a 617 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 618 */ 619 public static int getGlobalFreedCount() { 620 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); 621 } 622 623 /** 624 * Clears the global count of objects freed. 625 * @see #getGlobalFreedCount() 626 */ 627 public static void resetGlobalFreedCount() { 628 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); 629 } 630 631 /** 632 * Returns the global size, in bytes, of objects freed by the runtime between a 633 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 634 */ 635 public static int getGlobalFreedSize() { 636 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); 637 } 638 639 /** 640 * Clears the global size of objects freed. 641 * @see #getGlobalFreedSize() 642 */ 643 public static void resetGlobalFreedSize() { 644 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); 645 } 646 647 /** 648 * Returns the number of non-concurrent GC invocations between a 649 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 650 */ 651 public static int getGlobalGcInvocationCount() { 652 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); 653 } 654 655 /** 656 * Clears the count of non-concurrent GC invocations. 657 * @see #getGlobalGcInvocationCount() 658 */ 659 public static void resetGlobalGcInvocationCount() { 660 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); 661 } 662 663 /** 664 * Returns the number of classes successfully initialized (ie those that executed without 665 * throwing an exception) between a {@link #startAllocCounting() start} and 666 * {@link #stopAllocCounting() stop}. 667 */ 668 public static int getGlobalClassInitCount() { 669 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); 670 } 671 672 /** 673 * Clears the count of classes initialized. 674 * @see #getGlobalClassInitCount() 675 */ 676 public static void resetGlobalClassInitCount() { 677 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); 678 } 679 680 /** 681 * Returns the time spent successfully initializing classes between a 682 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 683 */ 684 public static int getGlobalClassInitTime() { 685 /* cumulative elapsed time for class initialization, in usec */ 686 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); 687 } 688 689 /** 690 * Clears the count of time spent initializing classes. 691 * @see #getGlobalClassInitTime() 692 */ 693 public static void resetGlobalClassInitTime() { 694 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); 695 } 696 697 /** 698 * This method exists for compatibility and always returns 0. 699 * @deprecated This method is now obsolete. 700 */ 701 @Deprecated 702 public static int getGlobalExternalAllocCount() { 703 return 0; 704 } 705 706 /** 707 * This method exists for compatibility and has no effect. 708 * @deprecated This method is now obsolete. 709 */ 710 @Deprecated 711 public static void resetGlobalExternalAllocSize() {} 712 713 /** 714 * This method exists for compatibility and has no effect. 715 * @deprecated This method is now obsolete. 716 */ 717 @Deprecated 718 public static void resetGlobalExternalAllocCount() {} 719 720 /** 721 * This method exists for compatibility and always returns 0. 722 * @deprecated This method is now obsolete. 723 */ 724 @Deprecated 725 public static int getGlobalExternalAllocSize() { 726 return 0; 727 } 728 729 /** 730 * This method exists for compatibility and always returns 0. 731 * @deprecated This method is now obsolete. 732 */ 733 @Deprecated 734 public static int getGlobalExternalFreedCount() { 735 return 0; 736 } 737 738 /** 739 * This method exists for compatibility and has no effect. 740 * @deprecated This method is now obsolete. 741 */ 742 @Deprecated 743 public static void resetGlobalExternalFreedCount() {} 744 745 /** 746 * This method exists for compatibility and has no effect. 747 * @deprecated This method is now obsolete. 748 */ 749 @Deprecated 750 public static int getGlobalExternalFreedSize() { 751 return 0; 752 } 753 754 /** 755 * This method exists for compatibility and has no effect. 756 * @deprecated This method is now obsolete. 757 */ 758 @Deprecated 759 public static void resetGlobalExternalFreedSize() {} 760 761 /** 762 * Returns the thread-local count of objects allocated by the runtime between a 763 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 764 */ 765 public static int getThreadAllocCount() { 766 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); 767 } 768 769 /** 770 * Clears the thread-local count of objects allocated. 771 * @see #getThreadAllocCount() 772 */ 773 public static void resetThreadAllocCount() { 774 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); 775 } 776 777 /** 778 * Returns the thread-local size of objects allocated by the runtime between a 779 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 780 * @return The allocated size in bytes. 781 */ 782 public static int getThreadAllocSize() { 783 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); 784 } 785 786 /** 787 * Clears the thread-local count of objects allocated. 788 * @see #getThreadAllocSize() 789 */ 790 public static void resetThreadAllocSize() { 791 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); 792 } 793 794 /** 795 * This method exists for compatibility and has no effect. 796 * @deprecated This method is now obsolete. 797 */ 798 @Deprecated 799 public static int getThreadExternalAllocCount() { 800 return 0; 801 } 802 803 /** 804 * This method exists for compatibility and has no effect. 805 * @deprecated This method is now obsolete. 806 */ 807 @Deprecated 808 public static void resetThreadExternalAllocCount() {} 809 810 /** 811 * This method exists for compatibility and has no effect. 812 * @deprecated This method is now obsolete. 813 */ 814 @Deprecated 815 public static int getThreadExternalAllocSize() { 816 return 0; 817 } 818 819 /** 820 * This method exists for compatibility and has no effect. 821 * @deprecated This method is now obsolete. 822 */ 823 @Deprecated 824 public static void resetThreadExternalAllocSize() {} 825 826 /** 827 * Returns the number of thread-local non-concurrent GC invocations between a 828 * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. 829 */ 830 public static int getThreadGcInvocationCount() { 831 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); 832 } 833 834 /** 835 * Clears the thread-local count of non-concurrent GC invocations. 836 * @see #getThreadGcInvocationCount() 837 */ 838 public static void resetThreadGcInvocationCount() { 839 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); 840 } 841 842 /** 843 * Clears all the global and thread-local memory allocation counters. 844 * @see #startAllocCounting() 845 */ 846 public static void resetAllCounts() { 847 VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS); 848 } 849 850 /** 851 * Returns the size of the native heap. 852 * @return The size of the native heap in bytes. 853 */ 854 public static native long getNativeHeapSize(); 855 856 /** 857 * Returns the amount of allocated memory in the native heap. 858 * @return The allocated size in bytes. 859 */ 860 public static native long getNativeHeapAllocatedSize(); 861 862 /** 863 * Returns the amount of free memory in the native heap. 864 * @return The freed size in bytes. 865 */ 866 public static native long getNativeHeapFreeSize(); 867 868 /** 869 * Retrieves information about this processes memory usages. This information is broken down by 870 * how much is in use by dalivk, the native heap, and everything else. 871 */ 872 public static native void getMemoryInfo(MemoryInfo memoryInfo); 873 874 /** 875 * Note: currently only works when the requested pid has the same UID 876 * as the caller. 877 * @hide 878 */ 879 public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo); 880 881 /** 882 * Retrieves the PSS memory used by the process as given by the 883 * smaps. 884 */ 885 public static native long getPss(); 886 887 /** 888 * Retrieves the PSS memory used by the process as given by the 889 * smaps. @hide 890 */ 891 public static native long getPss(int pid); 892 893 /** 894 * Establish an object allocation limit in the current thread. 895 * This feature was never enabled in release builds. The 896 * allocation limits feature was removed in Honeycomb. This 897 * method exists for compatibility and always returns -1 and has 898 * no effect. 899 * 900 * @deprecated This method is now obsolete. 901 */ 902 @Deprecated 903 public static int setAllocationLimit(int limit) { 904 return -1; 905 } 906 907 /** 908 * Establish a global object allocation limit. This feature was 909 * never enabled in release builds. The allocation limits feature 910 * was removed in Honeycomb. This method exists for compatibility 911 * and always returns -1 and has no effect. 912 * 913 * @deprecated This method is now obsolete. 914 */ 915 @Deprecated 916 public static int setGlobalAllocationLimit(int limit) { 917 return -1; 918 } 919 920 /** 921 * Dump a list of all currently loaded class to the log file. 922 * 923 * @param flags See constants above. 924 */ 925 public static void printLoadedClasses(int flags) { 926 VMDebug.printLoadedClasses(flags); 927 } 928 929 /** 930 * Get the number of loaded classes. 931 * @return the number of loaded classes. 932 */ 933 public static int getLoadedClassCount() { 934 return VMDebug.getLoadedClassCount(); 935 } 936 937 /** 938 * Dump "hprof" data to the specified file. This may cause a GC. 939 * 940 * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof"). 941 * @throws UnsupportedOperationException if the VM was built without 942 * HPROF support. 943 * @throws IOException if an error occurs while opening or writing files. 944 */ 945 public static void dumpHprofData(String fileName) throws IOException { 946 VMDebug.dumpHprofData(fileName); 947 } 948 949 /** 950 * Like dumpHprofData(String), but takes an already-opened 951 * FileDescriptor to which the trace is written. The file name is also 952 * supplied simply for logging. Makes a dup of the file descriptor. 953 * 954 * Primarily for use by the "am" shell command. 955 * 956 * @hide 957 */ 958 public static void dumpHprofData(String fileName, FileDescriptor fd) 959 throws IOException { 960 VMDebug.dumpHprofData(fileName, fd); 961 } 962 963 /** 964 * Collect "hprof" and send it to DDMS. This may cause a GC. 965 * 966 * @throws UnsupportedOperationException if the VM was built without 967 * HPROF support. 968 * @hide 969 */ 970 public static void dumpHprofDataDdms() { 971 VMDebug.dumpHprofDataDdms(); 972 } 973 974 /** 975 * Writes native heap data to the specified file descriptor. 976 * 977 * @hide 978 */ 979 public static native void dumpNativeHeap(FileDescriptor fd); 980 981 /** 982 * Returns a count of the extant instances of a class. 983 * 984 * @hide 985 */ 986 public static long countInstancesOfClass(Class cls) { 987 return VMDebug.countInstancesOfClass(cls, true); 988 } 989 990 /** 991 * Returns the number of sent transactions from this process. 992 * @return The number of sent transactions or -1 if it could not read t. 993 */ 994 public static native int getBinderSentTransactions(); 995 996 /** 997 * Returns the number of received transactions from the binder driver. 998 * @return The number of received transactions or -1 if it could not read the stats. 999 */ 1000 public static native int getBinderReceivedTransactions(); 1001 1002 /** 1003 * Returns the number of active local Binder objects that exist in the 1004 * current process. 1005 */ 1006 public static final native int getBinderLocalObjectCount(); 1007 1008 /** 1009 * Returns the number of references to remote proxy Binder objects that 1010 * exist in the current process. 1011 */ 1012 public static final native int getBinderProxyObjectCount(); 1013 1014 /** 1015 * Returns the number of death notification links to Binder objects that 1016 * exist in the current process. 1017 */ 1018 public static final native int getBinderDeathObjectCount(); 1019 1020 /** 1021 * Primes the register map cache. 1022 * 1023 * Only works for classes in the bootstrap class loader. Does not 1024 * cause classes to be loaded if they're not already present. 1025 * 1026 * The classAndMethodDesc argument is a concatentation of the VM-internal 1027 * class descriptor, method name, and method descriptor. Examples: 1028 * Landroid/os/Looper;.loop:()V 1029 * Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V 1030 * 1031 * @param classAndMethodDesc the method to prepare 1032 * 1033 * @hide 1034 */ 1035 public static final boolean cacheRegisterMap(String classAndMethodDesc) { 1036 return VMDebug.cacheRegisterMap(classAndMethodDesc); 1037 } 1038 1039 /** 1040 * Dumps the contents of VM reference tables (e.g. JNI locals and 1041 * globals) to the log file. 1042 * 1043 * @hide 1044 */ 1045 public static final void dumpReferenceTables() { 1046 VMDebug.dumpReferenceTables(); 1047 } 1048 1049 /** 1050 * API for gathering and querying instruction counts. 1051 * 1052 * Example usage: 1053 * <pre> 1054 * Debug.InstructionCount icount = new Debug.InstructionCount(); 1055 * icount.resetAndStart(); 1056 * [... do lots of stuff ...] 1057 * if (icount.collect()) { 1058 * System.out.println("Total instructions executed: " 1059 * + icount.globalTotal()); 1060 * System.out.println("Method invocations: " 1061 * + icount.globalMethodInvocations()); 1062 * } 1063 * </pre> 1064 */ 1065 public static class InstructionCount { 1066 private static final int NUM_INSTR = 1067 OpcodeInfo.MAXIMUM_PACKED_VALUE + 1; 1068 1069 private int[] mCounts; 1070 1071 public InstructionCount() { 1072 mCounts = new int[NUM_INSTR]; 1073 } 1074 1075 /** 1076 * Reset counters and ensure counts are running. Counts may 1077 * have already been running. 1078 * 1079 * @return true if counting was started 1080 */ 1081 public boolean resetAndStart() { 1082 try { 1083 VMDebug.startInstructionCounting(); 1084 VMDebug.resetInstructionCount(); 1085 } catch (UnsupportedOperationException uoe) { 1086 return false; 1087 } 1088 return true; 1089 } 1090 1091 /** 1092 * Collect instruction counts. May or may not stop the 1093 * counting process. 1094 */ 1095 public boolean collect() { 1096 try { 1097 VMDebug.stopInstructionCounting(); 1098 VMDebug.getInstructionCount(mCounts); 1099 } catch (UnsupportedOperationException uoe) { 1100 return false; 1101 } 1102 return true; 1103 } 1104 1105 /** 1106 * Return the total number of instructions executed globally (i.e. in 1107 * all threads). 1108 */ 1109 public int globalTotal() { 1110 int count = 0; 1111 1112 for (int i = 0; i < NUM_INSTR; i++) { 1113 count += mCounts[i]; 1114 } 1115 1116 return count; 1117 } 1118 1119 /** 1120 * Return the total number of method-invocation instructions 1121 * executed globally. 1122 */ 1123 public int globalMethodInvocations() { 1124 int count = 0; 1125 1126 for (int i = 0; i < NUM_INSTR; i++) { 1127 if (OpcodeInfo.isInvoke(i)) { 1128 count += mCounts[i]; 1129 } 1130 } 1131 1132 return count; 1133 } 1134 } 1135 1136 /** 1137 * A Map of typed debug properties. 1138 */ 1139 private static final TypedProperties debugProperties; 1140 1141 /* 1142 * Load the debug properties from the standard files into debugProperties. 1143 */ 1144 static { 1145 if (false) { 1146 final String TAG = "DebugProperties"; 1147 final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" }; 1148 final TypedProperties tp = new TypedProperties(); 1149 1150 // Read the properties from each of the files, if present. 1151 for (String file : files) { 1152 Reader r; 1153 try { 1154 r = new FileReader(file); 1155 } catch (FileNotFoundException ex) { 1156 // It's ok if a file is missing. 1157 continue; 1158 } 1159 1160 try { 1161 tp.load(r); 1162 } catch (Exception ex) { 1163 throw new RuntimeException("Problem loading " + file, ex); 1164 } finally { 1165 try { 1166 r.close(); 1167 } catch (IOException ex) { 1168 // Ignore this error. 1169 } 1170 } 1171 } 1172 1173 debugProperties = tp.isEmpty() ? null : tp; 1174 } else { 1175 debugProperties = null; 1176 } 1177 } 1178 1179 1180 /** 1181 * Returns true if the type of the field matches the specified class. 1182 * Handles the case where the class is, e.g., java.lang.Boolean, but 1183 * the field is of the primitive "boolean" type. Also handles all of 1184 * the java.lang.Number subclasses. 1185 */ 1186 private static boolean fieldTypeMatches(Field field, Class<?> cl) { 1187 Class<?> fieldClass = field.getType(); 1188 if (fieldClass == cl) { 1189 return true; 1190 } 1191 Field primitiveTypeField; 1192 try { 1193 /* All of the classes we care about (Boolean, Integer, etc.) 1194 * have a Class field called "TYPE" that points to the corresponding 1195 * primitive class. 1196 */ 1197 primitiveTypeField = cl.getField("TYPE"); 1198 } catch (NoSuchFieldException ex) { 1199 return false; 1200 } 1201 try { 1202 return fieldClass == (Class<?>) primitiveTypeField.get(null); 1203 } catch (IllegalAccessException ex) { 1204 return false; 1205 } 1206 } 1207 1208 1209 /** 1210 * Looks up the property that corresponds to the field, and sets the field's value 1211 * if the types match. 1212 */ 1213 private static void modifyFieldIfSet(final Field field, final TypedProperties properties, 1214 final String propertyName) { 1215 if (field.getType() == java.lang.String.class) { 1216 int stringInfo = properties.getStringInfo(propertyName); 1217 switch (stringInfo) { 1218 case TypedProperties.STRING_SET: 1219 // Handle as usual below. 1220 break; 1221 case TypedProperties.STRING_NULL: 1222 try { 1223 field.set(null, null); // null object for static fields; null string 1224 } catch (IllegalAccessException ex) { 1225 throw new IllegalArgumentException( 1226 "Cannot set field for " + propertyName, ex); 1227 } 1228 return; 1229 case TypedProperties.STRING_NOT_SET: 1230 return; 1231 case TypedProperties.STRING_TYPE_MISMATCH: 1232 throw new IllegalArgumentException( 1233 "Type of " + propertyName + " " + 1234 " does not match field type (" + field.getType() + ")"); 1235 default: 1236 throw new IllegalStateException( 1237 "Unexpected getStringInfo(" + propertyName + ") return value " + 1238 stringInfo); 1239 } 1240 } 1241 Object value = properties.get(propertyName); 1242 if (value != null) { 1243 if (!fieldTypeMatches(field, value.getClass())) { 1244 throw new IllegalArgumentException( 1245 "Type of " + propertyName + " (" + value.getClass() + ") " + 1246 " does not match field type (" + field.getType() + ")"); 1247 } 1248 try { 1249 field.set(null, value); // null object for static fields 1250 } catch (IllegalAccessException ex) { 1251 throw new IllegalArgumentException( 1252 "Cannot set field for " + propertyName, ex); 1253 } 1254 } 1255 } 1256 1257 1258 /** 1259 * Equivalent to <code>setFieldsOn(cl, false)</code>. 1260 * 1261 * @see #setFieldsOn(Class, boolean) 1262 * 1263 * @hide 1264 */ 1265 public static void setFieldsOn(Class<?> cl) { 1266 setFieldsOn(cl, false); 1267 } 1268 1269 /** 1270 * Reflectively sets static fields of a class based on internal debugging 1271 * properties. This method is a no-op if false is 1272 * false. 1273 * <p> 1274 * <strong>NOTE TO APPLICATION DEVELOPERS</strong>: false will 1275 * always be false in release builds. This API is typically only useful 1276 * for platform developers. 1277 * </p> 1278 * Class setup: define a class whose only fields are non-final, static 1279 * primitive types (except for "char") or Strings. In a static block 1280 * after the field definitions/initializations, pass the class to 1281 * this method, Debug.setFieldsOn(). Example: 1282 * <pre> 1283 * package com.example; 1284 * 1285 * import android.os.Debug; 1286 * 1287 * public class MyDebugVars { 1288 * public static String s = "a string"; 1289 * public static String s2 = "second string"; 1290 * public static String ns = null; 1291 * public static boolean b = false; 1292 * public static int i = 5; 1293 * @Debug.DebugProperty 1294 * public static float f = 0.1f; 1295 * @@Debug.DebugProperty 1296 * public static double d = 0.5d; 1297 * 1298 * // This MUST appear AFTER all fields are defined and initialized! 1299 * static { 1300 * // Sets all the fields 1301 * Debug.setFieldsOn(MyDebugVars.class); 1302 * 1303 * // Sets only the fields annotated with @Debug.DebugProperty 1304 * // Debug.setFieldsOn(MyDebugVars.class, true); 1305 * } 1306 * } 1307 * </pre> 1308 * setFieldsOn() may override the value of any field in the class based 1309 * on internal properties that are fixed at boot time. 1310 * <p> 1311 * These properties are only set during platform debugging, and are not 1312 * meant to be used as a general-purpose properties store. 1313 * 1314 * {@hide} 1315 * 1316 * @param cl The class to (possibly) modify 1317 * @param partial If false, sets all static fields, otherwise, only set 1318 * fields with the {@link android.os.Debug.DebugProperty} 1319 * annotation 1320 * @throws IllegalArgumentException if any fields are final or non-static, 1321 * or if the type of the field does not match the type of 1322 * the internal debugging property value. 1323 */ 1324 public static void setFieldsOn(Class<?> cl, boolean partial) { 1325 if (false) { 1326 if (debugProperties != null) { 1327 /* Only look for fields declared directly by the class, 1328 * so we don't mysteriously change static fields in superclasses. 1329 */ 1330 for (Field field : cl.getDeclaredFields()) { 1331 if (!partial || field.getAnnotation(DebugProperty.class) != null) { 1332 final String propertyName = cl.getName() + "." + field.getName(); 1333 boolean isStatic = Modifier.isStatic(field.getModifiers()); 1334 boolean isFinal = Modifier.isFinal(field.getModifiers()); 1335 1336 if (!isStatic || isFinal) { 1337 throw new IllegalArgumentException(propertyName + 1338 " must be static and non-final"); 1339 } 1340 modifyFieldIfSet(field, debugProperties, propertyName); 1341 } 1342 } 1343 } 1344 } else { 1345 Log.wtf(TAG, 1346 "setFieldsOn(" + (cl == null ? "null" : cl.getName()) + 1347 ") called in non-DEBUG build"); 1348 } 1349 } 1350 1351 /** 1352 * Annotation to put on fields you want to set with 1353 * {@link Debug#setFieldsOn(Class, boolean)}. 1354 * 1355 * @hide 1356 */ 1357 @Target({ ElementType.FIELD }) 1358 @Retention(RetentionPolicy.RUNTIME) 1359 public @interface DebugProperty { 1360 } 1361 1362 /** 1363 * Get a debugging dump of a system service by name. 1364 * 1365 * <p>Most services require the caller to hold android.permission.DUMP. 1366 * 1367 * @param name of the service to dump 1368 * @param fd to write dump output to (usually an output log file) 1369 * @param args to pass to the service's dump method, may be null 1370 * @return true if the service was dumped successfully, false if 1371 * the service could not be found or had an error while dumping 1372 */ 1373 public static boolean dumpService(String name, FileDescriptor fd, String[] args) { 1374 IBinder service = ServiceManager.getService(name); 1375 if (service == null) { 1376 Log.e(TAG, "Can't find service to dump: " + name); 1377 return false; 1378 } 1379 1380 try { 1381 service.dump(fd, args); 1382 return true; 1383 } catch (RemoteException e) { 1384 Log.e(TAG, "Can't dump service: " + name, e); 1385 return false; 1386 } 1387 } 1388 1389 /** 1390 * Have the stack traces of the given native process dumped to the 1391 * specified file. Will be appended to the file. 1392 * @hide 1393 */ 1394 public static native void dumpNativeBacktraceToFile(int pid, String file); 1395 1396 /** 1397 * Return a String describing the calling method and location at a particular stack depth. 1398 * @param callStack the Thread stack 1399 * @param depth the depth of stack to return information for. 1400 * @return the String describing the caller at that depth. 1401 */ 1402 private static String getCaller(StackTraceElement callStack[], int depth) { 1403 // callStack[4] is the caller of the method that called getCallers() 1404 if (4 + depth >= callStack.length) { 1405 return "<bottom of call stack>"; 1406 } 1407 StackTraceElement caller = callStack[4 + depth]; 1408 return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber(); 1409 } 1410 1411 /** 1412 * Return a string consisting of methods and locations at multiple call stack levels. 1413 * @param depth the number of levels to return, starting with the immediate caller. 1414 * @return a string describing the call stack. 1415 * {@hide} 1416 */ 1417 public static String getCallers(final int depth) { 1418 final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); 1419 StringBuffer sb = new StringBuffer(); 1420 for (int i = 0; i < depth; i++) { 1421 sb.append(getCaller(callStack, i)).append(" "); 1422 } 1423 return sb.toString(); 1424 } 1425 1426 /** 1427 * Like {@link #getCallers(int)}, but each location is append to the string 1428 * as a new line with <var>linePrefix</var> in front of it. 1429 * @param depth the number of levels to return, starting with the immediate caller. 1430 * @param linePrefix prefix to put in front of each location. 1431 * @return a string describing the call stack. 1432 * {@hide} 1433 */ 1434 public static String getCallers(final int depth, String linePrefix) { 1435 final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); 1436 StringBuffer sb = new StringBuffer(); 1437 for (int i = 0; i < depth; i++) { 1438 sb.append(linePrefix).append(getCaller(callStack, i)).append("\n"); 1439 } 1440 return sb.toString(); 1441 } 1442 1443 /** 1444 * @return a String describing the immediate caller of the calling method. 1445 * {@hide} 1446 */ 1447 public static String getCaller() { 1448 return getCaller(Thread.currentThread().getStackTrace(), 0); 1449 } 1450} 1451