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