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 17 package dalvik.system; 18 19 import dalvik.annotation.optimization.FastNative; 20 import java.io.FileDescriptor; 21 import java.io.IOException; 22 import java.util.HashMap; 23 import java.util.Map; 24 25 /** 26 * Provides access to some VM-specific debug features. Though this class and 27 * many of its members are public, this class is meant to be wrapped in a more 28 * friendly way for use by application developers. On the Android platform, the 29 * recommended way to access this functionality is through the class 30 * <code>android.os.Debug</code>. 31 * 32 * @hide 33 */ 34 public final class VMDebug { 35 /** 36 * flag for startMethodTracing(), which adds the results from 37 * startAllocCounting to the trace key file. 38 */ 39 public static final int TRACE_COUNT_ALLOCS = 1; 40 41 /* constants for getAllocCount */ 42 private static final int KIND_ALLOCATED_OBJECTS = 1<<0; 43 private static final int KIND_ALLOCATED_BYTES = 1<<1; 44 private static final int KIND_FREED_OBJECTS = 1<<2; 45 private static final int KIND_FREED_BYTES = 1<<3; 46 private static final int KIND_GC_INVOCATIONS = 1<<4; 47 private static final int KIND_CLASS_INIT_COUNT = 1<<5; 48 private static final int KIND_CLASS_INIT_TIME = 1<<6; 49 private static final int KIND_EXT_ALLOCATED_OBJECTS = 1<<12; 50 private static final int KIND_EXT_ALLOCATED_BYTES = 1<<13; 51 private static final int KIND_EXT_FREED_OBJECTS = 1<<14; 52 private static final int KIND_EXT_FREED_BYTES = 1<<15; 53 54 public static final int KIND_GLOBAL_ALLOCATED_OBJECTS = 55 KIND_ALLOCATED_OBJECTS; 56 public static final int KIND_GLOBAL_ALLOCATED_BYTES = 57 KIND_ALLOCATED_BYTES; 58 public static final int KIND_GLOBAL_FREED_OBJECTS = 59 KIND_FREED_OBJECTS; 60 public static final int KIND_GLOBAL_FREED_BYTES = 61 KIND_FREED_BYTES; 62 public static final int KIND_GLOBAL_GC_INVOCATIONS = 63 KIND_GC_INVOCATIONS; 64 public static final int KIND_GLOBAL_CLASS_INIT_COUNT = 65 KIND_CLASS_INIT_COUNT; 66 public static final int KIND_GLOBAL_CLASS_INIT_TIME = 67 KIND_CLASS_INIT_TIME; 68 public static final int KIND_GLOBAL_EXT_ALLOCATED_OBJECTS = 69 KIND_EXT_ALLOCATED_OBJECTS; 70 public static final int KIND_GLOBAL_EXT_ALLOCATED_BYTES = 71 KIND_EXT_ALLOCATED_BYTES; 72 public static final int KIND_GLOBAL_EXT_FREED_OBJECTS = 73 KIND_EXT_FREED_OBJECTS; 74 public static final int KIND_GLOBAL_EXT_FREED_BYTES = 75 KIND_EXT_FREED_BYTES; 76 77 public static final int KIND_THREAD_ALLOCATED_OBJECTS = 78 KIND_ALLOCATED_OBJECTS << 16; 79 public static final int KIND_THREAD_ALLOCATED_BYTES = 80 KIND_ALLOCATED_BYTES << 16; 81 public static final int KIND_THREAD_FREED_OBJECTS = 82 KIND_FREED_OBJECTS << 16; 83 public static final int KIND_THREAD_FREED_BYTES = 84 KIND_FREED_BYTES << 16; 85 public static final int KIND_THREAD_GC_INVOCATIONS = 86 KIND_GC_INVOCATIONS << 16; 87 public static final int KIND_THREAD_CLASS_INIT_COUNT = 88 KIND_CLASS_INIT_COUNT << 16; 89 public static final int KIND_THREAD_CLASS_INIT_TIME = 90 KIND_CLASS_INIT_TIME << 16; 91 public static final int KIND_THREAD_EXT_ALLOCATED_OBJECTS = 92 KIND_EXT_ALLOCATED_OBJECTS << 16; 93 public static final int KIND_THREAD_EXT_ALLOCATED_BYTES = 94 KIND_EXT_ALLOCATED_BYTES << 16; 95 public static final int KIND_THREAD_EXT_FREED_OBJECTS = 96 KIND_EXT_FREED_OBJECTS << 16; 97 public static final int KIND_THREAD_EXT_FREED_BYTES = 98 KIND_EXT_FREED_BYTES << 16; 99 100 public static final int KIND_ALL_COUNTS = 0xffffffff; 101 102 /* all methods are static */ 103 private VMDebug() {} 104 105 /** 106 * Returns the time since the last known debugger activity. 107 * 108 * @return the time in milliseconds, or -1 if the debugger is not connected 109 */ 110 @FastNative 111 public static native long lastDebuggerActivity(); 112 113 /** 114 * Determines if debugging is enabled in this VM. If debugging is not 115 * enabled, a debugger cannot be attached. 116 * 117 * @return true if debugging is enabled 118 */ 119 @FastNative 120 public static native boolean isDebuggingEnabled(); 121 122 /** 123 * Determines if a debugger is currently attached. 124 * 125 * @return true if (and only if) a debugger is connected 126 */ 127 @FastNative 128 public static native boolean isDebuggerConnected(); 129 130 /** 131 * Returns an array of strings that identify VM features. This is 132 * used by DDMS to determine what sorts of operations the VM can 133 * perform. 134 */ 135 public static native String[] getVmFeatureList(); 136 137 /** 138 * Start method tracing with default name, size, and with <code>0</code> 139 * flags. 140 * 141 * @deprecated Not used, not needed. 142 */ 143 @Deprecated 144 public static void startMethodTracing() { 145 throw new UnsupportedOperationException(); 146 } 147 148 /** 149 * Start method tracing, specifying a file name as well as a default 150 * buffer size. See <a 151 * href="{@docRoot}guide/developing/tools/traceview.html"> Running the 152 * Traceview Debugging Program</a> for information about reading 153 * trace files. 154 * 155 * <p>You can use either a fully qualified path and 156 * name, or just a name. If only a name is specified, the file will 157 * be created under the /sdcard/ directory. If a name is not given, 158 * the default is /sdcard/dmtrace.trace.</p> 159 * 160 * @param traceFileName name to give the trace file 161 * @param bufferSize the maximum size of both files combined. If passed 162 * as <code>0</code>, it defaults to 8MB. 163 * @param flags flags to control method tracing. The only one that 164 * is currently defined is {@link #TRACE_COUNT_ALLOCS}. 165 * @param samplingEnabled if true, sample profiling is enabled. Otherwise, 166 * method instrumentation is used. 167 * @param intervalUs the time between samples in microseconds when 168 * sampling is enabled. 169 */ 170 public static void startMethodTracing(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { 171 startMethodTracingFilename(traceFileName, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); 172 } 173 174 /** 175 * Like startMethodTracing(String, int, int), but taking an already-opened 176 * FileDescriptor in which the trace is written. The file name is also 177 * supplied simply for logging. Makes a dup of the file descriptor. 178 */ 179 public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, 180 int flags, boolean samplingEnabled, int intervalUs) { 181 startMethodTracing(traceFileName, fd, bufferSize, flags, samplingEnabled, intervalUs, 182 false); 183 } 184 185 /** 186 * Like startMethodTracing(String, int, int), but taking an already-opened 187 * FileDescriptor in which the trace is written. The file name is also 188 * supplied simply for logging. Makes a dup of the file descriptor. 189 * Streams tracing data to the file if streamingOutput is true. 190 */ 191 public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, 192 int flags, boolean samplingEnabled, int intervalUs, 193 boolean streamingOutput) { 194 if (fd == null) { 195 throw new NullPointerException("fd == null"); 196 } 197 startMethodTracingFd(traceFileName, fd, checkBufferSize(bufferSize), flags, 198 samplingEnabled, intervalUs, streamingOutput); 199 } 200 201 /** 202 * Starts method tracing without a backing file. When stopMethodTracing 203 * is called, the result is sent directly to DDMS. (If DDMS is not 204 * attached when tracing ends, the profiling data will be discarded.) 205 */ 206 public static void startMethodTracingDdms(int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { 207 startMethodTracingDdmsImpl(checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); 208 } 209 210 private static int checkBufferSize(int bufferSize) { 211 if (bufferSize == 0) { 212 // Default to 8MB per the documentation. 213 bufferSize = 8 * 1024 * 1024; 214 } 215 if (bufferSize < 1024) { 216 throw new IllegalArgumentException("buffer size < 1024: " + bufferSize); 217 } 218 return bufferSize; 219 } 220 221 private static native void startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs); 222 private static native void startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs, boolean streamingOutput); 223 private static native void startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs); 224 225 /** 226 * Determine whether method tracing is currently active and what type is 227 * active. 228 */ 229 public static native int getMethodTracingMode(); 230 231 /** 232 * Stops method tracing. 233 */ 234 public static native void stopMethodTracing(); 235 236 /** 237 * Starts sending Dalvik method trace info to the emulator. 238 */ 239 public static native void startEmulatorTracing(); 240 241 /** 242 * Stops sending Dalvik method trace info to the emulator. 243 */ 244 public static native void stopEmulatorTracing(); 245 246 /** 247 * Get an indication of thread CPU usage. The value returned indicates the 248 * amount of time that the current thread has spent executing code or 249 * waiting for certain types of I/O. 250 * <p> 251 * The time is expressed in nanoseconds, and is only meaningful when 252 * compared to the result from an earlier call. Note that nanosecond 253 * resolution does not imply nanosecond accuracy. 254 * 255 * @return the CPU usage. A value of -1 means the system does not support 256 * this feature. 257 */ 258 @FastNative 259 public static native long threadCpuTimeNanos(); 260 261 /** 262 * Count the number and aggregate size of memory allocations between 263 * two points. 264 */ 265 public static native void startAllocCounting(); 266 public static native void stopAllocCounting(); 267 public static native int getAllocCount(int kind); 268 public static native void resetAllocCount(int kinds); 269 270 /** 271 * This method exists for binary compatibility. It was part of 272 * the allocation limits API which was removed in Android 3.0 (Honeycomb). 273 */ 274 @Deprecated 275 public static int setAllocationLimit(int limit) { 276 return -1; 277 } 278 279 /** 280 * This method exists for binary compatibility. It was part of 281 * the allocation limits API which was removed in Android 3.0 (Honeycomb). 282 */ 283 @Deprecated 284 public static int setGlobalAllocationLimit(int limit) { 285 return -1; 286 } 287 288 /** 289 * Count the number of instructions executed between two points. 290 */ 291 public static native void startInstructionCounting(); 292 public static native void stopInstructionCounting(); 293 public static native void getInstructionCount(int[] counts); 294 public static native void resetInstructionCount(); 295 296 /** 297 * Dumps a list of loaded class to the log file. 298 */ 299 @FastNative 300 public static native void printLoadedClasses(int flags); 301 302 /** 303 * Gets the number of loaded classes. 304 * 305 * @return the number of loaded classes 306 */ 307 @FastNative 308 public static native int getLoadedClassCount(); 309 310 /** 311 * Dumps "hprof" data to the specified file. This may cause a GC. 312 * 313 * The VM may create a temporary file in the same directory. 314 * 315 * @param filename Full pathname of output file (e.g. "/sdcard/dump.hprof"). 316 * @throws UnsupportedOperationException if the VM was built without 317 * HPROF support. 318 * @throws IOException if an error occurs while opening or writing files. 319 */ 320 public static void dumpHprofData(String filename) throws IOException { 321 if (filename == null) { 322 throw new NullPointerException("filename == null"); 323 } 324 dumpHprofData(filename, null); 325 } 326 327 /** 328 * Collects "hprof" heap data and sends it to DDMS. This may cause a GC. 329 * 330 * @throws UnsupportedOperationException if the VM was built without 331 * HPROF support. 332 */ 333 public static native void dumpHprofDataDdms(); 334 335 /** 336 * Dumps "hprof" heap data to a file, by name or descriptor. 337 * 338 * @param fileName Name of output file. If fd is non-null, the 339 * file name is only used in log messages (and may be null). 340 * @param fd Descriptor of open file that will receive the output. 341 * If this is null, the fileName is used instead. 342 */ 343 public static native void dumpHprofData(String fileName, FileDescriptor fd) 344 throws IOException; 345 346 /** 347 * Primes the register map cache. 348 */ 349 public static native boolean cacheRegisterMap(String classAndMethodDesc); 350 351 /** 352 * Dumps the contents of the VM reference tables (e.g. JNI locals and 353 * globals) to the log file. 354 */ 355 public static native void dumpReferenceTables(); 356 357 /** 358 * Crashes the VM. Seriously. Dumps the interpreter stack trace for 359 * the current thread and then aborts the VM so you can see the native 360 * stack trace. Useful for figuring out how you got somewhere when 361 * lots of native code is involved. 362 */ 363 public static native void crash(); 364 365 /** 366 * Together with gdb, provide a handy way to stop the VM at user-tagged 367 * locations. 368 */ 369 public static native void infopoint(int id); 370 371 /* 372 * Fake method, inserted into dmtrace output when the garbage collector 373 * runs. Not actually called. 374 */ 375 private static void startGC() {} 376 377 /* 378 * Fake method, inserted into dmtrace output during class preparation 379 * (loading and linking, but not verification or initialization). Not 380 * actually called. 381 */ 382 private static void startClassPrep() {} 383 384 /** 385 * Counts the instances of a class. 386 * It is the caller's responsibility to do GC if they don't want unreachable 387 * objects to get counted. 388 * 389 * @param klass the class to be counted. 390 * @param assignable if false, direct instances of klass are 391 * counted. If true, instances that are 392 * assignable to klass, as defined by 393 * {@link Class#isAssignableFrom} are counted. 394 * @return the number of matching instances. 395 */ 396 public static native long countInstancesOfClass(Class klass, boolean assignable); 397 398 /** 399 * Counts the instances of classes. 400 * It is the caller's responsibility to do GC if they don't want unreachable 401 * objects to get counted. 402 * 403 * @param classes the classes to be counted. 404 * @param assignable if false, direct instances of klass are 405 * counted. If true, instances that are 406 * assignable to klass, as defined by 407 * {@link Class#isAssignableFrom} are counted. 408 * @return an array containing the number of matching instances. The value for 409 * an index is the number of instances of the class at that index in number classes. 410 */ 411 public static native long[] countInstancesOfClasses(Class[] classes, boolean assignable); 412 413 /** 414 * Export the heap per-space stats for dumpsys meminfo. 415 * 416 * The content of the array is: 417 * 418 * <pre> 419 * data[0] : the application heap space size 420 * data[1] : the application heap space allocated bytes 421 * data[2] : the application heap space free bytes 422 * data[3] : the zygote heap space size 423 * data[4] : the zygote heap space allocated size 424 * data[5] : the zygote heap space free size 425 * data[6] : the large object space size 426 * data[7] : the large object space allocated bytes 427 * data[8] : the large object space free bytes 428 * </pre> 429 * 430 * @param data the array into which the stats are written. 431 */ 432 public static native void getHeapSpaceStats(long[] data); 433 434 /* Map from the names of the runtime stats supported by getRuntimeStat() to their IDs */ 435 private static final HashMap<String, Integer> runtimeStatsMap = new HashMap<>(); 436 437 static { 438 runtimeStatsMap.put("art.gc.gc-count", 0); 439 runtimeStatsMap.put("art.gc.gc-time", 1); 440 runtimeStatsMap.put("art.gc.bytes-allocated", 2); 441 runtimeStatsMap.put("art.gc.bytes-freed", 3); 442 runtimeStatsMap.put("art.gc.blocking-gc-count", 4); 443 runtimeStatsMap.put("art.gc.blocking-gc-time", 5); 444 runtimeStatsMap.put("art.gc.gc-count-rate-histogram", 6); 445 runtimeStatsMap.put("art.gc.blocking-gc-count-rate-histogram", 7); 446 } 447 448 /** 449 * Returns the value of a particular runtime statistic or {@code null} if no 450 * such runtime statistic exists. 451 * 452 * @param statName 453 * the name of the runtime statistic to look up. 454 * @return the value of the runtime statistic. 455 */ 456 public static String getRuntimeStat(String statName) { 457 if (statName == null) { 458 throw new NullPointerException("statName == null"); 459 } 460 Integer statId = runtimeStatsMap.get(statName); 461 if (statId != null) { 462 return getRuntimeStatInternal(statId); 463 } 464 return null; 465 } 466 467 /** 468 * Returns a map of the names/values of the runtime statistics 469 * that {@link #getRuntimeStat()} supports. 470 * 471 * @return a map of the names/values of the supported runtime statistics. 472 */ 473 public static Map<String, String> getRuntimeStats() { 474 HashMap<String, String> map = new HashMap<>(); 475 String[] values = getRuntimeStatsInternal(); 476 for (String name : runtimeStatsMap.keySet()) { 477 int id = runtimeStatsMap.get(name); 478 String value = values[id]; 479 map.put(name, value); 480 } 481 return map; 482 } 483 484 private static native String getRuntimeStatInternal(int statId); 485 private static native String[] getRuntimeStatsInternal(); 486 487 /** 488 * Attaches an agent to the VM. 489 * 490 * @param agent The path to the agent .so file plus optional agent arguments. 491 */ 492 public static native void attachAgent(String agent) throws IOException; 493 } 494