Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "dalvik_system_VMDebug.h"
     18 
     19 #include <string.h>
     20 #include <unistd.h>
     21 
     22 #include <sstream>
     23 
     24 #include "nativehelper/jni_macros.h"
     25 
     26 #include "base/histogram-inl.h"
     27 #include "base/time_utils.h"
     28 #include "class_linker.h"
     29 #include "common_throws.h"
     30 #include "debugger.h"
     31 #include "gc/space/bump_pointer_space.h"
     32 #include "gc/space/dlmalloc_space.h"
     33 #include "gc/space/large_object_space.h"
     34 #include "gc/space/space-inl.h"
     35 #include "gc/space/zygote_space.h"
     36 #include "handle_scope-inl.h"
     37 #include "hprof/hprof.h"
     38 #include "java_vm_ext.h"
     39 #include "jni_internal.h"
     40 #include "mirror/class.h"
     41 #include "mirror/object_array-inl.h"
     42 #include "native_util.h"
     43 #include "nativehelper/ScopedLocalRef.h"
     44 #include "nativehelper/ScopedUtfChars.h"
     45 #include "scoped_fast_native_object_access-inl.h"
     46 #include "trace.h"
     47 #include "well_known_classes.h"
     48 
     49 namespace art {
     50 
     51 static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) {
     52   static const char* features[] = {
     53     "method-trace-profiling",
     54     "method-trace-profiling-streaming",
     55     "method-sample-profiling",
     56     "hprof-heap-dump",
     57     "hprof-heap-dump-streaming",
     58   };
     59   jobjectArray result = env->NewObjectArray(arraysize(features),
     60                                             WellKnownClasses::java_lang_String,
     61                                             nullptr);
     62   if (result != nullptr) {
     63     for (size_t i = 0; i < arraysize(features); ++i) {
     64       ScopedLocalRef<jstring> jfeature(env, env->NewStringUTF(features[i]));
     65       if (jfeature.get() == nullptr) {
     66         return nullptr;
     67       }
     68       env->SetObjectArrayElement(result, i, jfeature.get());
     69     }
     70   }
     71   return result;
     72 }
     73 
     74 static void VMDebug_startAllocCounting(JNIEnv*, jclass) {
     75   Runtime::Current()->SetStatsEnabled(true);
     76 }
     77 
     78 static void VMDebug_stopAllocCounting(JNIEnv*, jclass) {
     79   Runtime::Current()->SetStatsEnabled(false);
     80 }
     81 
     82 static jint VMDebug_getAllocCount(JNIEnv*, jclass, jint kind) {
     83   return Runtime::Current()->GetStat(kind);
     84 }
     85 
     86 static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) {
     87   Runtime::Current()->ResetStats(kinds);
     88 }
     89 
     90 static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
     91                                                jboolean samplingEnabled, jint intervalUs) {
     92   Trace::Start("[DDMS]", -1, bufferSize, flags, Trace::TraceOutputMode::kDDMS,
     93                samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
     94                intervalUs);
     95 }
     96 
     97 static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
     98                                          jobject javaFd, jint bufferSize, jint flags,
     99                                          jboolean samplingEnabled, jint intervalUs,
    100                                          jboolean streamingOutput) {
    101   int originalFd = jniGetFDFromFileDescriptor(env, javaFd);
    102   if (originalFd < 0) {
    103     return;
    104   }
    105 
    106   int fd = dup(originalFd);
    107   if (fd < 0) {
    108     ScopedObjectAccess soa(env);
    109     soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
    110                                    "dup(%d) failed: %s", originalFd, strerror(errno));
    111     return;
    112   }
    113 
    114   ScopedUtfChars traceFilename(env, javaTraceFilename);
    115   if (traceFilename.c_str() == nullptr) {
    116     return;
    117   }
    118   Trace::TraceOutputMode outputMode = streamingOutput
    119                                           ? Trace::TraceOutputMode::kStreaming
    120                                           : Trace::TraceOutputMode::kFile;
    121   Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, outputMode,
    122                samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
    123                intervalUs);
    124 }
    125 
    126 static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring javaTraceFilename,
    127                                                jint bufferSize, jint flags,
    128                                                jboolean samplingEnabled, jint intervalUs) {
    129   ScopedUtfChars traceFilename(env, javaTraceFilename);
    130   if (traceFilename.c_str() == nullptr) {
    131     return;
    132   }
    133   Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, Trace::TraceOutputMode::kFile,
    134                samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
    135                intervalUs);
    136 }
    137 
    138 static jint VMDebug_getMethodTracingMode(JNIEnv*, jclass) {
    139   return Trace::GetMethodTracingMode();
    140 }
    141 
    142 static void VMDebug_stopMethodTracing(JNIEnv*, jclass) {
    143   Trace::Stop();
    144 }
    145 
    146 static void VMDebug_startEmulatorTracing(JNIEnv*, jclass) {
    147   UNIMPLEMENTED(WARNING);
    148   // dvmEmulatorTraceStart();
    149 }
    150 
    151 static void VMDebug_stopEmulatorTracing(JNIEnv*, jclass) {
    152   UNIMPLEMENTED(WARNING);
    153   // dvmEmulatorTraceStop();
    154 }
    155 
    156 static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) {
    157   return Dbg::IsDebuggerActive();
    158 }
    159 
    160 static jboolean VMDebug_isDebuggingEnabled(JNIEnv*, jclass) {
    161   return Dbg::IsJdwpConfigured();
    162 }
    163 
    164 static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
    165   return Dbg::LastDebuggerActivity();
    166 }
    167 
    168 static void ThrowUnsupportedOperationException(JNIEnv* env) {
    169   ScopedObjectAccess soa(env);
    170   soa.Self()->ThrowNewException("Ljava/lang/UnsupportedOperationException;", nullptr);
    171 }
    172 
    173 static void VMDebug_startInstructionCounting(JNIEnv* env, jclass) {
    174   ThrowUnsupportedOperationException(env);
    175 }
    176 
    177 static void VMDebug_stopInstructionCounting(JNIEnv* env, jclass) {
    178   ThrowUnsupportedOperationException(env);
    179 }
    180 
    181 static void VMDebug_getInstructionCount(JNIEnv* env, jclass, jintArray /*javaCounts*/) {
    182   ThrowUnsupportedOperationException(env);
    183 }
    184 
    185 static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) {
    186   ThrowUnsupportedOperationException(env);
    187 }
    188 
    189 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
    190   class DumpClassVisitor : public ClassVisitor {
    191    public:
    192     explicit DumpClassVisitor(int dump_flags) : flags_(dump_flags) {}
    193 
    194     bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
    195       klass->DumpClass(LOG_STREAM(ERROR), flags_);
    196       return true;
    197     }
    198 
    199    private:
    200     const int flags_;
    201   };
    202   DumpClassVisitor visitor(flags);
    203 
    204   ScopedFastNativeObjectAccess soa(env);
    205   return Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
    206 }
    207 
    208 static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
    209   ScopedFastNativeObjectAccess soa(env);
    210   return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
    211 }
    212 
    213 /*
    214  * Returns the thread-specific CPU-time clock value for the current thread,
    215  * or -1 if the feature isn't supported.
    216  */
    217 static jlong VMDebug_threadCpuTimeNanos(JNIEnv*, jclass) {
    218   return ThreadCpuNanoTime();
    219 }
    220 
    221 /*
    222  * static void dumpHprofData(String fileName, FileDescriptor fd)
    223  *
    224  * Cause "hprof" data to be dumped.  We can throw an IOException if an
    225  * error occurs during file handling.
    226  */
    227 static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jobject javaFd) {
    228   // Only one of these may be null.
    229   if (javaFilename == nullptr && javaFd == nullptr) {
    230     ScopedObjectAccess soa(env);
    231     ThrowNullPointerException("fileName == null && fd == null");
    232     return;
    233   }
    234 
    235   std::string filename;
    236   if (javaFilename != nullptr) {
    237     ScopedUtfChars chars(env, javaFilename);
    238     if (env->ExceptionCheck()) {
    239       return;
    240     }
    241     filename = chars.c_str();
    242   } else {
    243     filename = "[fd]";
    244   }
    245 
    246   int fd = -1;
    247   if (javaFd != nullptr) {
    248     fd = jniGetFDFromFileDescriptor(env, javaFd);
    249     if (fd < 0) {
    250       ScopedObjectAccess soa(env);
    251       ThrowRuntimeException("Invalid file descriptor");
    252       return;
    253     }
    254   }
    255 
    256   hprof::DumpHeap(filename.c_str(), fd, false);
    257 }
    258 
    259 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
    260   hprof::DumpHeap("[DDMS]", -1, true);
    261 }
    262 
    263 static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {
    264   ScopedObjectAccess soa(env);
    265   LOG(INFO) << "--- reference table dump ---";
    266 
    267   soa.Env()->DumpReferenceTables(LOG_STREAM(INFO));
    268   soa.Vm()->DumpReferenceTables(LOG_STREAM(INFO));
    269 
    270   LOG(INFO) << "---";
    271 }
    272 
    273 static void VMDebug_crash(JNIEnv*, jclass) {
    274   LOG(FATAL) << "Crashing runtime on request";
    275 }
    276 
    277 static void VMDebug_infopoint(JNIEnv*, jclass, jint id) {
    278   LOG(INFO) << "VMDebug infopoint " << id << " hit";
    279 }
    280 
    281 static jlong VMDebug_countInstancesOfClass(JNIEnv* env,
    282                                            jclass,
    283                                            jclass javaClass,
    284                                            jboolean countAssignable) {
    285   ScopedObjectAccess soa(env);
    286   gc::Heap* const heap = Runtime::Current()->GetHeap();
    287   // Caller's responsibility to do GC if desired.
    288   ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
    289   if (c == nullptr) {
    290     return 0;
    291   }
    292   VariableSizedHandleScope hs(soa.Self());
    293   std::vector<Handle<mirror::Class>> classes {hs.NewHandle(c)};
    294   uint64_t count = 0;
    295   heap->CountInstances(classes, countAssignable, &count);
    296   return count;
    297 }
    298 
    299 static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env,
    300                                                   jclass,
    301                                                   jobjectArray javaClasses,
    302                                                   jboolean countAssignable) {
    303   ScopedObjectAccess soa(env);
    304   gc::Heap* const heap = Runtime::Current()->GetHeap();
    305   // Caller's responsibility to do GC if desired.
    306   ObjPtr<mirror::ObjectArray<mirror::Class>> decoded_classes =
    307       soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
    308   if (decoded_classes == nullptr) {
    309     return nullptr;
    310   }
    311   VariableSizedHandleScope hs(soa.Self());
    312   std::vector<Handle<mirror::Class>> classes;
    313   for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) {
    314     classes.push_back(hs.NewHandle(decoded_classes->Get(i)));
    315   }
    316   std::vector<uint64_t> counts(classes.size(), 0u);
    317   // Heap::CountInstances can handle null and will put 0 for these classes.
    318   heap->CountInstances(classes, countAssignable, &counts[0]);
    319   ObjPtr<mirror::LongArray> long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size());
    320   if (long_counts == nullptr) {
    321     soa.Self()->AssertPendingOOMException();
    322     return nullptr;
    323   }
    324   for (size_t i = 0; i < counts.size(); ++i) {
    325     long_counts->Set(i, counts[i]);
    326   }
    327   return soa.AddLocalReference<jlongArray>(long_counts);
    328 }
    329 
    330 // We export the VM internal per-heap-space size/alloc/free metrics
    331 // for the zygote space, alloc space (application heap), and the large
    332 // object space for dumpsys meminfo. The other memory region data such
    333 // as PSS, private/shared dirty/shared data are available via
    334 // /proc/<pid>/smaps.
    335 static void VMDebug_getHeapSpaceStats(JNIEnv* env, jclass, jlongArray data) {
    336   jlong* arr = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(data, 0));
    337   if (arr == nullptr || env->GetArrayLength(data) < 9) {
    338     return;
    339   }
    340 
    341   size_t allocSize = 0;
    342   size_t allocUsed = 0;
    343   size_t zygoteSize = 0;
    344   size_t zygoteUsed = 0;
    345   size_t largeObjectsSize = 0;
    346   size_t largeObjectsUsed = 0;
    347   gc::Heap* heap = Runtime::Current()->GetHeap();
    348   {
    349     ScopedObjectAccess soa(env);
    350     for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
    351       if (space->IsImageSpace()) {
    352         // Currently don't include the image space.
    353       } else if (space->IsZygoteSpace()) {
    354         gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace();
    355         zygoteSize += zygote_space->Size();
    356         zygoteUsed += zygote_space->GetBytesAllocated();
    357       } else if (space->IsMallocSpace()) {
    358         // This is a malloc space.
    359         gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
    360         allocSize += malloc_space->GetFootprint();
    361         allocUsed += malloc_space->GetBytesAllocated();
    362       } else if (space->IsBumpPointerSpace()) {
    363         gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace();
    364         allocSize += bump_pointer_space->Size();
    365         allocUsed += bump_pointer_space->GetBytesAllocated();
    366       }
    367     }
    368     for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) {
    369       if (space->IsLargeObjectSpace()) {
    370         largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated();
    371         largeObjectsUsed += largeObjectsSize;
    372       }
    373     }
    374   }
    375   size_t allocFree = allocSize - allocUsed;
    376   size_t zygoteFree = zygoteSize - zygoteUsed;
    377   size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed;
    378 
    379   int j = 0;
    380   arr[j++] = allocSize;
    381   arr[j++] = allocUsed;
    382   arr[j++] = allocFree;
    383   arr[j++] = zygoteSize;
    384   arr[j++] = zygoteUsed;
    385   arr[j++] = zygoteFree;
    386   arr[j++] = largeObjectsSize;
    387   arr[j++] = largeObjectsUsed;
    388   arr[j++] = largeObjectsFree;
    389   env->ReleasePrimitiveArrayCritical(data, arr, 0);
    390 }
    391 
    392 // The runtime stat names for VMDebug.getRuntimeStat().
    393 enum class VMDebugRuntimeStatId {
    394   kArtGcGcCount = 0,
    395   kArtGcGcTime,
    396   kArtGcBytesAllocated,
    397   kArtGcBytesFreed,
    398   kArtGcBlockingGcCount,
    399   kArtGcBlockingGcTime,
    400   kArtGcGcCountRateHistogram,
    401   kArtGcBlockingGcCountRateHistogram,
    402   kNumRuntimeStats,
    403 };
    404 
    405 static jobject VMDebug_getRuntimeStatInternal(JNIEnv* env, jclass, jint statId) {
    406   gc::Heap* heap = Runtime::Current()->GetHeap();
    407   switch (static_cast<VMDebugRuntimeStatId>(statId)) {
    408     case VMDebugRuntimeStatId::kArtGcGcCount: {
    409       std::string output = std::to_string(heap->GetGcCount());
    410       return env->NewStringUTF(output.c_str());
    411     }
    412     case VMDebugRuntimeStatId::kArtGcGcTime: {
    413       std::string output = std::to_string(NsToMs(heap->GetGcTime()));
    414       return env->NewStringUTF(output.c_str());
    415     }
    416     case VMDebugRuntimeStatId::kArtGcBytesAllocated: {
    417       std::string output = std::to_string(heap->GetBytesAllocatedEver());
    418       return env->NewStringUTF(output.c_str());
    419     }
    420     case VMDebugRuntimeStatId::kArtGcBytesFreed: {
    421       std::string output = std::to_string(heap->GetBytesFreedEver());
    422       return env->NewStringUTF(output.c_str());
    423     }
    424     case VMDebugRuntimeStatId::kArtGcBlockingGcCount: {
    425       std::string output = std::to_string(heap->GetBlockingGcCount());
    426       return env->NewStringUTF(output.c_str());
    427     }
    428     case VMDebugRuntimeStatId::kArtGcBlockingGcTime: {
    429       std::string output = std::to_string(NsToMs(heap->GetBlockingGcTime()));
    430       return env->NewStringUTF(output.c_str());
    431     }
    432     case VMDebugRuntimeStatId::kArtGcGcCountRateHistogram: {
    433       std::ostringstream output;
    434       heap->DumpGcCountRateHistogram(output);
    435       return env->NewStringUTF(output.str().c_str());
    436     }
    437     case VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram: {
    438       std::ostringstream output;
    439       heap->DumpBlockingGcCountRateHistogram(output);
    440       return env->NewStringUTF(output.str().c_str());
    441     }
    442     default:
    443       return nullptr;
    444   }
    445 }
    446 
    447 static bool SetRuntimeStatValue(JNIEnv* env,
    448                                 jobjectArray result,
    449                                 VMDebugRuntimeStatId id,
    450                                 const std::string& value) {
    451   ScopedLocalRef<jstring> jvalue(env, env->NewStringUTF(value.c_str()));
    452   if (jvalue.get() == nullptr) {
    453     return false;
    454   }
    455   env->SetObjectArrayElement(result, static_cast<jint>(id), jvalue.get());
    456   return true;
    457 }
    458 
    459 static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) {
    460   jobjectArray result = env->NewObjectArray(
    461       static_cast<jint>(VMDebugRuntimeStatId::kNumRuntimeStats),
    462       WellKnownClasses::java_lang_String,
    463       nullptr);
    464   if (result == nullptr) {
    465     return nullptr;
    466   }
    467   gc::Heap* heap = Runtime::Current()->GetHeap();
    468   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCount,
    469                            std::to_string(heap->GetGcCount()))) {
    470     return nullptr;
    471   }
    472   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcTime,
    473                            std::to_string(NsToMs(heap->GetGcTime())))) {
    474     return nullptr;
    475   }
    476   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesAllocated,
    477                            std::to_string(heap->GetBytesAllocatedEver()))) {
    478     return nullptr;
    479   }
    480   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesFreed,
    481                            std::to_string(heap->GetBytesFreedEver()))) {
    482     return nullptr;
    483   }
    484   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCount,
    485                            std::to_string(heap->GetBlockingGcCount()))) {
    486     return nullptr;
    487   }
    488   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcTime,
    489                            std::to_string(NsToMs(heap->GetBlockingGcTime())))) {
    490     return nullptr;
    491   }
    492   {
    493     std::ostringstream output;
    494     heap->DumpGcCountRateHistogram(output);
    495     if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCountRateHistogram,
    496                              output.str())) {
    497       return nullptr;
    498     }
    499   }
    500   {
    501     std::ostringstream output;
    502     heap->DumpBlockingGcCountRateHistogram(output);
    503     if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram,
    504                              output.str())) {
    505       return nullptr;
    506     }
    507   }
    508   return result;
    509 }
    510 
    511 static void VMDebug_attachAgent(JNIEnv* env, jclass, jstring agent) {
    512   if (agent == nullptr) {
    513     ScopedObjectAccess soa(env);
    514     ThrowNullPointerException("agent is null");
    515     return;
    516   }
    517 
    518   if (!Dbg::IsJdwpAllowed()) {
    519     ScopedObjectAccess soa(env);
    520     ThrowSecurityException("Can't attach agent, process is not debuggable.");
    521     return;
    522   }
    523 
    524   std::string filename;
    525   {
    526     ScopedUtfChars chars(env, agent);
    527     if (env->ExceptionCheck()) {
    528       return;
    529     }
    530     filename = chars.c_str();
    531   }
    532 
    533   Runtime::Current()->AttachAgent(filename);
    534 }
    535 
    536 static JNINativeMethod gMethods[] = {
    537   NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
    538   NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
    539   NATIVE_METHOD(VMDebug, crash, "()V"),
    540   NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;Ljava/io/FileDescriptor;)V"),
    541   NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
    542   NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
    543   NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
    544   NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
    545   NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
    546   FAST_NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
    547   NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
    548   NATIVE_METHOD(VMDebug, infopoint, "(I)V"),
    549   FAST_NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
    550   FAST_NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
    551   NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
    552   FAST_NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
    553   FAST_NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
    554   NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
    555   NATIVE_METHOD(VMDebug, resetInstructionCount, "()V"),
    556   NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
    557   NATIVE_METHOD(VMDebug, startEmulatorTracing, "()V"),
    558   NATIVE_METHOD(VMDebug, startInstructionCounting, "()V"),
    559   NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(IIZI)V"),
    560   NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V"),
    561   NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;IIZI)V"),
    562   NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
    563   NATIVE_METHOD(VMDebug, stopEmulatorTracing, "()V"),
    564   NATIVE_METHOD(VMDebug, stopInstructionCounting, "()V"),
    565   NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
    566   FAST_NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
    567   NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
    568   NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
    569   NATIVE_METHOD(VMDebug, attachAgent, "(Ljava/lang/String;)V"),
    570 };
    571 
    572 void register_dalvik_system_VMDebug(JNIEnv* env) {
    573   REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
    574 }
    575 
    576 }  // namespace art
    577