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