/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dalvik.system; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import java.io.FileDescriptor; import java.io.IOException; import java.util.HashMap; import java.util.Map; import dalvik.annotation.optimization.FastNative; /** * Provides access to some VM-specific debug features. Though this class and * many of its members are public, this class is meant to be wrapped in a more * friendly way for use by application developers. On the Android platform, the * recommended way to access this functionality is through the class * android.os.Debug. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public final class VMDebug { /** * flag for startMethodTracing(), which adds the results from * startAllocCounting to the trace key file. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) // Must match android.os.Debug.TRACE_COUNT_ALLOCS. public static final int TRACE_COUNT_ALLOCS = 1; /* constants for getAllocCount */ private static final int KIND_ALLOCATED_OBJECTS = 1<<0; private static final int KIND_ALLOCATED_BYTES = 1<<1; private static final int KIND_FREED_OBJECTS = 1<<2; private static final int KIND_FREED_BYTES = 1<<3; private static final int KIND_GC_INVOCATIONS = 1<<4; private static final int KIND_CLASS_INIT_COUNT = 1<<5; private static final int KIND_CLASS_INIT_TIME = 1<<6; private static final int KIND_EXT_ALLOCATED_OBJECTS = 1<<12; private static final int KIND_EXT_ALLOCATED_BYTES = 1<<13; private static final int KIND_EXT_FREED_OBJECTS = 1<<14; private static final int KIND_EXT_FREED_BYTES = 1<<15; /** * Constant for {@link #getAllocCount(int)} * to get the number of all allocated objects. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS; /** * Constant for {@link #getAllocCount(int)} * to get the cumulative size of all objects allocated. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES; /** * Constant for {@link #getAllocCount(int)} * to get the number of freed objects. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_FREED_OBJECTS = KIND_FREED_OBJECTS; /** * Constant for {@link #getAllocCount(int)} * to get the cumulative size of all freed objects. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_FREED_BYTES = KIND_FREED_BYTES; /** * Constant for {@link #getAllocCount(int)} * to get the number of times an allocation triggered a blocking GC. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_GC_INVOCATIONS = KIND_GC_INVOCATIONS; /** * Constant for {@link #getAllocCount(int)} * to get the number of initialized classes. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_CLASS_INIT_COUNT = KIND_CLASS_INIT_COUNT; /** * Constant for {@link #getAllocCount(int)} * to get the cumulative time spent in class initialization. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_GLOBAL_CLASS_INIT_TIME = KIND_CLASS_INIT_TIME; /** * Constant for {@link #getAllocCount(int)} * to get the number of all allocated objects for current thread. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_THREAD_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS << 16; /** * Constant for {@link #getAllocCount(int)} * to get the cumulative size of all objects allocated for current thread. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_THREAD_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES << 16; /** * Constant for {@link #getAllocCount(int)} * to get the number of times an allocation triggered a blocking GC for current thread. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_THREAD_GC_INVOCATIONS = KIND_GC_INVOCATIONS << 16; /** * Constant for {@link #getAllocCount(int)} to get all possible stats. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int KIND_ALL_COUNTS = 0xffffffff; /* all methods are static */ private VMDebug() {} /** * Request JDWP agent to suspend all Java Thread and send VM_START. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void suspendAllAndSendVmStart(); /** * Returns the time since the last known debugger activity. * * @return the time in milliseconds, or -1 if the debugger is not connected * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @FastNative public static native long lastDebuggerActivity(); /** * Determines if debugging is enabled in this VM. If debugging is not * enabled, a debugger cannot be attached. * * @return true if debugging is enabled * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @FastNative public static native boolean isDebuggingEnabled(); /** * Determines if a debugger is currently attached. * * @return true if (and only if) a debugger is connected * * @hide */ @UnsupportedAppUsage @SystemApi(client = MODULE_LIBRARIES) @FastNative public static native boolean isDebuggerConnected(); /** * Returns an array of strings that identify VM features. This is * used by DDMS to determine what sorts of operations the VM can * perform. * * @return array of strings identifying VM features * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native String[] getVmFeatureList(); /** * Start method tracing, specifying a file name as well as a default * buffer size. See Running the * Traceview Debugging Program for information about reading * trace files. * *

You can use either a fully qualified path and * name, or just a name. If only a name is specified, the file will * be created under the /sdcard/ directory. If a name is not given, * the default is /sdcard/dmtrace.trace.

* * @param traceFileName name to give the trace file * @param bufferSize the maximum size of both files combined. If passed * as {@code 0}, it defaults to 8MB. * @param flags flags to control method tracing. The only one that * is currently defined is {@link #TRACE_COUNT_ALLOCS}. * @param samplingEnabled if true, sample profiling is enabled. Otherwise, * method instrumentation is used. * @param intervalUs the time between samples in microseconds when * sampling is enabled. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void startMethodTracing(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { startMethodTracingFilename(traceFileName, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); } /** * Like {@link #startMethodTracing(String, int, int)}, but taking an already-opened * {@code FileDescriptor} in which the trace is written. The file name is also * supplied simply for logging. Makes a dup of the file descriptor. * Streams tracing data to the file if streamingOutput is true. * * @param traceFileName name to give the trace file * @param fd already opened {@code FileDescriptor} in which trace is written * @param bufferSize the maximum size of both files combined. If passed * as {@code 0}, it defaults to 8MB. * @param flags flags to control method tracing. The only one that * is currently defined is {@link #TRACE_COUNT_ALLOCS}. * @param samplingEnabled if true, sample profiling is enabled. Otherwise, * method instrumentation is used. * @param intervalUs the time between samples in microseconds when * sampling is enabled. * @param streamingOutput streams tracing data to the duped {@code fd} file descriptor * if {@code streamingOutput} is {@code true}. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs, boolean streamingOutput) { if (fd == null) { throw new NullPointerException("fd == null"); } startMethodTracingFd(traceFileName, fd.getInt$(), checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs, streamingOutput); } /** * Starts method tracing without a backing file. When {@link #stopMethodTracing()} * is called, the result is sent directly to DDMS. (If DDMS is not * attached when tracing ends, the profiling data will be discarded.) * * @param bufferSize the maximum size of both files combined. If passed * as {@code 0}, it defaults to 8MB. * @param flags flags to control method tracing. The only one that * is currently defined is {@link #TRACE_COUNT_ALLOCS}. * @param samplingEnabled if true, sample profiling is enabled. Otherwise, * method instrumentation is used. * @param intervalUs the time between samples in microseconds when * sampling is enabled. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void startMethodTracingDdms(int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { startMethodTracingDdmsImpl(checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); } private static int checkBufferSize(int bufferSize) { if (bufferSize == 0) { // Default to 8MB per the documentation. bufferSize = 8 * 1024 * 1024; } if (bufferSize < 1024) { throw new IllegalArgumentException("buffer size < 1024: " + bufferSize); } return bufferSize; } private static native void startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs); private static native void startMethodTracingFd(String traceFileName, int fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs, boolean streamingOutput); private static native void startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs); /** * Determine whether method tracing is currently active and what type is * active. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native int getMethodTracingMode(); /** * Stops method tracing. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void stopMethodTracing(); /** * Get an indication of thread CPU usage. The value returned indicates the * amount of time that the current thread has spent executing code or * waiting for certain types of I/O. *

* The time is expressed in nanoseconds, and is only meaningful when * compared to the result from an earlier call. Note that nanosecond * resolution does not imply nanosecond accuracy. * * @return the CPU usage. A value of -1 means the system does not support * this feature. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @FastNative public static native long threadCpuTimeNanos(); /** * Starts counting the number and aggregate size of memory allocations. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void startAllocCounting(); /** * Stops counting the number and aggregate size of memory allocations. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void stopAllocCounting(); /** * Returns information on the number of objects allocated by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. * * @param kind either {@code KIND_GLOBAL_*} or {@code KIND_THREAD_*}. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native int getAllocCount(int kind); /** * Resets counting the number and aggregate size of memory allocations for the given kinds. * * @param kinds a union of {@code KIND_GLOBAL_*} and {@code KIND_THREAD_*}. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void resetAllocCount(int kinds); /** * This method exists for binary compatibility. It was part of * the allocation limits API which was removed in Android 3.0 (Honeycomb). * * @hide */ @Deprecated public static int setAllocationLimit(int limit) { return -1; } /** * This method exists for binary compatibility. It was part of * the allocation limits API which was removed in Android 3.0 (Honeycomb). * * @hide */ @Deprecated public static int setGlobalAllocationLimit(int limit) { return -1; } /** * Count the number of instructions executed between two points. * * @hide */ @Deprecated public static void startInstructionCounting() {} /** * * @hide */ @Deprecated public static void stopInstructionCounting() {} /** * * @hide */ @Deprecated public static void getInstructionCount(int[] counts) {} /** * * @hide */ @Deprecated public static void resetInstructionCount() {} /** * Dumps a list of loaded class to the log file. * * @param flags a union of {@link android.os.Debug.SHOW_FULL_DETAIL}, * {@link android.os.Debug.SHOW_CLASSLOADER}, and {@link android.os.Debug.SHOW_INITIALIZED}. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @FastNative public static native void printLoadedClasses(int flags); /** * Gets the number of loaded classes. * * @return the number of loaded classes * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @FastNative public static native int getLoadedClassCount(); /** * Dumps "hprof" data to the specified file. This may cause a GC. * * The VM may create a temporary file in the same directory. * * @param filename Full pathname of output file (e.g. "/sdcard/dump.hprof"). * @throws UnsupportedOperationException if the VM was built without * HPROF support. * @throws IOException if an error occurs while opening or writing files. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void dumpHprofData(String filename) throws IOException { if (filename == null) { throw new NullPointerException("filename == null"); } dumpHprofData(filename, null); } /** * Collects "hprof" heap data and sends it to DDMS. This may cause a GC. * * @throws UnsupportedOperationException if the VM was built without * HPROF support. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void dumpHprofDataDdms(); /** * Dumps "hprof" heap data to a file, by name or descriptor. * * @param fileName Name of output file. If fd is non-null, the * file name is only used in log messages (and may be null). * @param fd Descriptor of open file that will receive the output. * If this is null, the fileName is used instead. * @throws {@link IOException} if an error occurs while opening or writing files. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void dumpHprofData(String fileName, FileDescriptor fd) throws IOException { dumpHprofData(fileName, fd != null ? fd.getInt$() : -1); } private static native void dumpHprofData(String fileName, int fd) throws IOException; /** * Dumps the contents of the VM reference tables (e.g. JNI locals and * globals) to the log file. * * @hide */ @UnsupportedAppUsage @SystemApi(client = MODULE_LIBRARIES) public static native void dumpReferenceTables(); /** * Counts the instances of a class. * It is the caller's responsibility to do GC if they don't want unreachable * objects to get counted. * * @param klass the class to be counted. * @param assignable if true, any instance whose class is assignable to * {@code klass}, as defined by {@link Class#isAssignableFrom}, * is counted. If false, only instances whose class is * equal to {@code klass} are counted. * @return the number of matching instances. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native long countInstancesOfClass(Class klass, boolean assignable); /** * Counts the instances of classes. * It is the caller's responsibility to do GC if they don't want unreachable * objects to get counted. * * @param classes the classes to be counted. * @param assignable if true, any instance whose class is assignable to * {@code classes[i]}, as defined by {@link Class#isAssignableFrom}, * is counted. If false, only instances whose class is * equal to {@code classes[i]} are counted. * @return an array containing the number of matching instances. The value * for index {@code i} is the number of instances of * the class {@code classes[i]} * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native long[] countInstancesOfClasses(Class[] classes, boolean assignable); /* Map from the names of the runtime stats supported by getRuntimeStat() to their IDs */ private static final HashMap runtimeStatsMap = new HashMap<>(); static { runtimeStatsMap.put("art.gc.gc-count", 0); runtimeStatsMap.put("art.gc.gc-time", 1); runtimeStatsMap.put("art.gc.bytes-allocated", 2); runtimeStatsMap.put("art.gc.bytes-freed", 3); runtimeStatsMap.put("art.gc.blocking-gc-count", 4); runtimeStatsMap.put("art.gc.blocking-gc-time", 5); runtimeStatsMap.put("art.gc.gc-count-rate-histogram", 6); runtimeStatsMap.put("art.gc.blocking-gc-count-rate-histogram", 7); runtimeStatsMap.put("art.gc.objects-allocated", 8); runtimeStatsMap.put("art.gc.total-time-waiting-for-gc", 9); runtimeStatsMap.put("art.gc.pre-oome-gc-count", 10); } /** * Returns the value of a particular runtime statistic or {@code null} if no * such runtime statistic exists. * * @param statName the name of the runtime statistic to look up. * * @return the value of the runtime statistic. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static String getRuntimeStat(String statName) { if (statName == null) { throw new NullPointerException("statName == null"); } Integer statId = runtimeStatsMap.get(statName); if (statId != null) { return getRuntimeStatInternal(statId); } return null; } /** * Returns a map of the names/values of the runtime statistics * that {@link #getRuntimeStat()} supports. * * @return a map of the names/values of the supported runtime statistics. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static Map getRuntimeStats() { HashMap map = new HashMap<>(); String[] values = getRuntimeStatsInternal(); for (String name : runtimeStatsMap.keySet()) { int id = runtimeStatsMap.get(name); String value = values[id]; map.put(name, value); } return map; } private static native String getRuntimeStatInternal(int statId); private static native String[] getRuntimeStatsInternal(); /** * Attaches an agent to the VM. * * @param agent The path to the agent .so file plus optional agent arguments. * @param classLoader The classloader to use as a loading context. * * @throws IOException if an error occurs while opening {@code agent} file. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void attachAgent(String agent, ClassLoader classLoader) throws IOException { nativeAttachAgent(agent, classLoader); } private static native void nativeAttachAgent(String agent, ClassLoader classLoader) throws IOException; /** * Exempts a class from any future non-SDK API access checks. * Methods declared in the class will be allowed to perform * reflection/JNI against the framework completely unrestricted. * Note that this does not affect uses of non-SDK APIs that the class links against. * Note that this does not affect methods declared outside this class, e.g. * inherited from a superclass or an implemented interface. * * @param klass The class whose methods should be exempted. * * @hide */ @UnsupportedAppUsage public static native void allowHiddenApiReflectionFrom(Class klass); /** * Sets the number of frames recorded for allocation tracking. * * @param stackDepth The number of frames captured for each stack trace. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void setAllocTrackerStackDepth(int stackDepth); }