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/scoped_local_ref.h"
     44 #include "nativehelper/scoped_utf_chars.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                                          jint javaFd, jint bufferSize, jint flags,
     99                                          jboolean samplingEnabled, jint intervalUs,
    100                                          jboolean streamingOutput) {
    101   int originalFd = 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* env, jclass) {
    161   ScopedObjectAccess soa(env);
    162   return Runtime::Current()->GetRuntimeCallbacks()->IsDebuggerConfigured();
    163 }
    164 
    165 static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
    166   return Dbg::LastDebuggerActivity();
    167 }
    168 
    169 static void ThrowUnsupportedOperationException(JNIEnv* env) {
    170   ScopedObjectAccess soa(env);
    171   soa.Self()->ThrowNewException("Ljava/lang/UnsupportedOperationException;", nullptr);
    172 }
    173 
    174 static void VMDebug_startInstructionCounting(JNIEnv* env, jclass) {
    175   ThrowUnsupportedOperationException(env);
    176 }
    177 
    178 static void VMDebug_stopInstructionCounting(JNIEnv* env, jclass) {
    179   ThrowUnsupportedOperationException(env);
    180 }
    181 
    182 static void VMDebug_getInstructionCount(JNIEnv* env, jclass, jintArray /*javaCounts*/) {
    183   ThrowUnsupportedOperationException(env);
    184 }
    185 
    186 static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) {
    187   ThrowUnsupportedOperationException(env);
    188 }
    189 
    190 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
    191   class DumpClassVisitor : public ClassVisitor {
    192    public:
    193     explicit DumpClassVisitor(int dump_flags) : flags_(dump_flags) {}
    194 
    195     bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
    196       klass->DumpClass(LOG_STREAM(ERROR), flags_);
    197       return true;
    198     }
    199 
    200    private:
    201     const int flags_;
    202   };
    203   DumpClassVisitor visitor(flags);
    204 
    205   ScopedFastNativeObjectAccess soa(env);
    206   return Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
    207 }
    208 
    209 static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
    210   ScopedFastNativeObjectAccess soa(env);
    211   return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
    212 }
    213 
    214 /*
    215  * Returns the thread-specific CPU-time clock value for the current thread,
    216  * or -1 if the feature isn't supported.
    217  */
    218 static jlong VMDebug_threadCpuTimeNanos(JNIEnv*, jclass) {
    219   return ThreadCpuNanoTime();
    220 }
    221 
    222 /*
    223  * static void dumpHprofData(String fileName, FileDescriptor fd)
    224  *
    225  * Cause "hprof" data to be dumped.  We can throw an IOException if an
    226  * error occurs during file handling.
    227  */
    228 static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jint javaFd) {
    229   // Only one of these may be null.
    230   if (javaFilename == nullptr && javaFd < 0) {
    231     ScopedObjectAccess soa(env);
    232     ThrowNullPointerException("fileName == null && fd == null");
    233     return;
    234   }
    235 
    236   std::string filename;
    237   if (javaFilename != nullptr) {
    238     ScopedUtfChars chars(env, javaFilename);
    239     if (env->ExceptionCheck()) {
    240       return;
    241     }
    242     filename = chars.c_str();
    243   } else {
    244     filename = "[fd]";
    245   }
    246 
    247   int fd = javaFd;
    248 
    249   hprof::DumpHeap(filename.c_str(), fd, false);
    250 }
    251 
    252 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
    253   hprof::DumpHeap("[DDMS]", -1, true);
    254 }
    255 
    256 static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {
    257   ScopedObjectAccess soa(env);
    258   LOG(INFO) << "--- reference table dump ---";
    259 
    260   soa.Env()->DumpReferenceTables(LOG_STREAM(INFO));
    261   soa.Vm()->DumpReferenceTables(LOG_STREAM(INFO));
    262 
    263   LOG(INFO) << "---";
    264 }
    265 
    266 static void VMDebug_crash(JNIEnv*, jclass) {
    267   LOG(FATAL) << "Crashing runtime on request";
    268 }
    269 
    270 static void VMDebug_infopoint(JNIEnv*, jclass, jint id) {
    271   LOG(INFO) << "VMDebug infopoint " << id << " hit";
    272 }
    273 
    274 static jlong VMDebug_countInstancesOfClass(JNIEnv* env,
    275                                            jclass,
    276                                            jclass javaClass,
    277                                            jboolean countAssignable) {
    278   ScopedObjectAccess soa(env);
    279   gc::Heap* const heap = Runtime::Current()->GetHeap();
    280   // Caller's responsibility to do GC if desired.
    281   ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
    282   if (c == nullptr) {
    283     return 0;
    284   }
    285   VariableSizedHandleScope hs(soa.Self());
    286   std::vector<Handle<mirror::Class>> classes {hs.NewHandle(c)};
    287   uint64_t count = 0;
    288   heap->CountInstances(classes, countAssignable, &count);
    289   return count;
    290 }
    291 
    292 static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env,
    293                                                   jclass,
    294                                                   jobjectArray javaClasses,
    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::ObjectArray<mirror::Class>> decoded_classes =
    300       soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
    301   if (decoded_classes == nullptr) {
    302     return nullptr;
    303   }
    304   VariableSizedHandleScope hs(soa.Self());
    305   std::vector<Handle<mirror::Class>> classes;
    306   for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) {
    307     classes.push_back(hs.NewHandle(decoded_classes->Get(i)));
    308   }
    309   std::vector<uint64_t> counts(classes.size(), 0u);
    310   // Heap::CountInstances can handle null and will put 0 for these classes.
    311   heap->CountInstances(classes, countAssignable, &counts[0]);
    312   ObjPtr<mirror::LongArray> long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size());
    313   if (long_counts == nullptr) {
    314     soa.Self()->AssertPendingOOMException();
    315     return nullptr;
    316   }
    317   for (size_t i = 0; i < counts.size(); ++i) {
    318     long_counts->Set(i, counts[i]);
    319   }
    320   return soa.AddLocalReference<jlongArray>(long_counts);
    321 }
    322 
    323 static jobjectArray VMDebug_getInstancesOfClasses(JNIEnv* env,
    324                                                   jclass,
    325                                                   jobjectArray javaClasses,
    326                                                   jboolean includeAssignable) {
    327   ScopedObjectAccess soa(env);
    328   StackHandleScope<2> hs(soa.Self());
    329   Handle<mirror::ObjectArray<mirror::Class>> classes = hs.NewHandle(
    330       soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses));
    331   if (classes == nullptr) {
    332     return nullptr;
    333   }
    334 
    335   jclass object_array_class = env->FindClass("[Ljava/lang/Object;");
    336   if (env->ExceptionCheck() == JNI_TRUE) {
    337     return nullptr;
    338   }
    339   CHECK(object_array_class != nullptr);
    340 
    341   size_t num_classes = classes->GetLength();
    342   jobjectArray result = env->NewObjectArray(num_classes, object_array_class, nullptr);
    343   if (env->ExceptionCheck() == JNI_TRUE) {
    344     return nullptr;
    345   }
    346 
    347   gc::Heap* const heap = Runtime::Current()->GetHeap();
    348   MutableHandle<mirror::Class> h_class(hs.NewHandle<mirror::Class>(nullptr));
    349   for (size_t i = 0; i < num_classes; ++i) {
    350     h_class.Assign(classes->Get(i));
    351 
    352     VariableSizedHandleScope hs2(soa.Self());
    353     std::vector<Handle<mirror::Object>> raw_instances;
    354     heap->GetInstances(hs2, h_class, includeAssignable, /* max_count */ 0, raw_instances);
    355     jobjectArray array = env->NewObjectArray(raw_instances.size(),
    356                                              WellKnownClasses::java_lang_Object,
    357                                              nullptr);
    358     if (env->ExceptionCheck() == JNI_TRUE) {
    359       return nullptr;
    360     }
    361 
    362     for (size_t j = 0; j < raw_instances.size(); ++j) {
    363       env->SetObjectArrayElement(array, j, raw_instances[j].ToJObject());
    364     }
    365     env->SetObjectArrayElement(result, i, array);
    366   }
    367   return result;
    368 }
    369 
    370 // We export the VM internal per-heap-space size/alloc/free metrics
    371 // for the zygote space, alloc space (application heap), and the large
    372 // object space for dumpsys meminfo. The other memory region data such
    373 // as PSS, private/shared dirty/shared data are available via
    374 // /proc/<pid>/smaps.
    375 static void VMDebug_getHeapSpaceStats(JNIEnv* env, jclass, jlongArray data) {
    376   jlong* arr = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(data, 0));
    377   if (arr == nullptr || env->GetArrayLength(data) < 9) {
    378     return;
    379   }
    380 
    381   size_t allocSize = 0;
    382   size_t allocUsed = 0;
    383   size_t zygoteSize = 0;
    384   size_t zygoteUsed = 0;
    385   size_t largeObjectsSize = 0;
    386   size_t largeObjectsUsed = 0;
    387   gc::Heap* heap = Runtime::Current()->GetHeap();
    388   {
    389     ScopedObjectAccess soa(env);
    390     for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
    391       if (space->IsImageSpace()) {
    392         // Currently don't include the image space.
    393       } else if (space->IsZygoteSpace()) {
    394         gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace();
    395         zygoteSize += zygote_space->Size();
    396         zygoteUsed += zygote_space->GetBytesAllocated();
    397       } else if (space->IsMallocSpace()) {
    398         // This is a malloc space.
    399         gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
    400         allocSize += malloc_space->GetFootprint();
    401         allocUsed += malloc_space->GetBytesAllocated();
    402       } else if (space->IsBumpPointerSpace()) {
    403         gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace();
    404         allocSize += bump_pointer_space->Size();
    405         allocUsed += bump_pointer_space->GetBytesAllocated();
    406       }
    407     }
    408     for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) {
    409       if (space->IsLargeObjectSpace()) {
    410         largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated();
    411         largeObjectsUsed += largeObjectsSize;
    412       }
    413     }
    414   }
    415   size_t allocFree = allocSize - allocUsed;
    416   size_t zygoteFree = zygoteSize - zygoteUsed;
    417   size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed;
    418 
    419   int j = 0;
    420   arr[j++] = allocSize;
    421   arr[j++] = allocUsed;
    422   arr[j++] = allocFree;
    423   arr[j++] = zygoteSize;
    424   arr[j++] = zygoteUsed;
    425   arr[j++] = zygoteFree;
    426   arr[j++] = largeObjectsSize;
    427   arr[j++] = largeObjectsUsed;
    428   arr[j++] = largeObjectsFree;
    429   env->ReleasePrimitiveArrayCritical(data, arr, 0);
    430 }
    431 
    432 // The runtime stat names for VMDebug.getRuntimeStat().
    433 enum class VMDebugRuntimeStatId {
    434   kArtGcGcCount = 0,
    435   kArtGcGcTime,
    436   kArtGcBytesAllocated,
    437   kArtGcBytesFreed,
    438   kArtGcBlockingGcCount,
    439   kArtGcBlockingGcTime,
    440   kArtGcGcCountRateHistogram,
    441   kArtGcBlockingGcCountRateHistogram,
    442   kNumRuntimeStats,
    443 };
    444 
    445 static jstring VMDebug_getRuntimeStatInternal(JNIEnv* env, jclass, jint statId) {
    446   gc::Heap* heap = Runtime::Current()->GetHeap();
    447   switch (static_cast<VMDebugRuntimeStatId>(statId)) {
    448     case VMDebugRuntimeStatId::kArtGcGcCount: {
    449       std::string output = std::to_string(heap->GetGcCount());
    450       return env->NewStringUTF(output.c_str());
    451     }
    452     case VMDebugRuntimeStatId::kArtGcGcTime: {
    453       std::string output = std::to_string(NsToMs(heap->GetGcTime()));
    454       return env->NewStringUTF(output.c_str());
    455     }
    456     case VMDebugRuntimeStatId::kArtGcBytesAllocated: {
    457       std::string output = std::to_string(heap->GetBytesAllocatedEver());
    458       return env->NewStringUTF(output.c_str());
    459     }
    460     case VMDebugRuntimeStatId::kArtGcBytesFreed: {
    461       std::string output = std::to_string(heap->GetBytesFreedEver());
    462       return env->NewStringUTF(output.c_str());
    463     }
    464     case VMDebugRuntimeStatId::kArtGcBlockingGcCount: {
    465       std::string output = std::to_string(heap->GetBlockingGcCount());
    466       return env->NewStringUTF(output.c_str());
    467     }
    468     case VMDebugRuntimeStatId::kArtGcBlockingGcTime: {
    469       std::string output = std::to_string(NsToMs(heap->GetBlockingGcTime()));
    470       return env->NewStringUTF(output.c_str());
    471     }
    472     case VMDebugRuntimeStatId::kArtGcGcCountRateHistogram: {
    473       std::ostringstream output;
    474       heap->DumpGcCountRateHistogram(output);
    475       return env->NewStringUTF(output.str().c_str());
    476     }
    477     case VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram: {
    478       std::ostringstream output;
    479       heap->DumpBlockingGcCountRateHistogram(output);
    480       return env->NewStringUTF(output.str().c_str());
    481     }
    482     default:
    483       return nullptr;
    484   }
    485 }
    486 
    487 static bool SetRuntimeStatValue(JNIEnv* env,
    488                                 jobjectArray result,
    489                                 VMDebugRuntimeStatId id,
    490                                 const std::string& value) {
    491   ScopedLocalRef<jstring> jvalue(env, env->NewStringUTF(value.c_str()));
    492   if (jvalue.get() == nullptr) {
    493     return false;
    494   }
    495   env->SetObjectArrayElement(result, static_cast<jint>(id), jvalue.get());
    496   return true;
    497 }
    498 
    499 static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) {
    500   jobjectArray result = env->NewObjectArray(
    501       static_cast<jint>(VMDebugRuntimeStatId::kNumRuntimeStats),
    502       WellKnownClasses::java_lang_String,
    503       nullptr);
    504   if (result == nullptr) {
    505     return nullptr;
    506   }
    507   gc::Heap* heap = Runtime::Current()->GetHeap();
    508   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCount,
    509                            std::to_string(heap->GetGcCount()))) {
    510     return nullptr;
    511   }
    512   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcTime,
    513                            std::to_string(NsToMs(heap->GetGcTime())))) {
    514     return nullptr;
    515   }
    516   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesAllocated,
    517                            std::to_string(heap->GetBytesAllocatedEver()))) {
    518     return nullptr;
    519   }
    520   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesFreed,
    521                            std::to_string(heap->GetBytesFreedEver()))) {
    522     return nullptr;
    523   }
    524   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCount,
    525                            std::to_string(heap->GetBlockingGcCount()))) {
    526     return nullptr;
    527   }
    528   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcTime,
    529                            std::to_string(NsToMs(heap->GetBlockingGcTime())))) {
    530     return nullptr;
    531   }
    532   {
    533     std::ostringstream output;
    534     heap->DumpGcCountRateHistogram(output);
    535     if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCountRateHistogram,
    536                              output.str())) {
    537       return nullptr;
    538     }
    539   }
    540   {
    541     std::ostringstream output;
    542     heap->DumpBlockingGcCountRateHistogram(output);
    543     if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram,
    544                              output.str())) {
    545       return nullptr;
    546     }
    547   }
    548   return result;
    549 }
    550 
    551 static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) {
    552   if (agent == nullptr) {
    553     ScopedObjectAccess soa(env);
    554     ThrowNullPointerException("agent is null");
    555     return;
    556   }
    557 
    558   if (!Dbg::IsJdwpAllowed()) {
    559     ScopedObjectAccess soa(env);
    560     ThrowSecurityException("Can't attach agent, process is not debuggable.");
    561     return;
    562   }
    563 
    564   std::string filename;
    565   {
    566     ScopedUtfChars chars(env, agent);
    567     if (env->ExceptionCheck()) {
    568       return;
    569     }
    570     filename = chars.c_str();
    571   }
    572 
    573   Runtime::Current()->AttachAgent(env, filename, classloader);
    574 }
    575 
    576 static void VMDebug_allowHiddenApiReflectionFrom(JNIEnv* env, jclass, jclass j_caller) {
    577   Runtime* runtime = Runtime::Current();
    578   ScopedObjectAccess soa(env);
    579 
    580   if (!runtime->IsJavaDebuggable()) {
    581     ThrowSecurityException("Can't exempt class, process is not debuggable.");
    582     return;
    583   }
    584 
    585   StackHandleScope<1> hs(soa.Self());
    586   Handle<mirror::Class> h_caller(hs.NewHandle(soa.Decode<mirror::Class>(j_caller)));
    587   if (h_caller.IsNull()) {
    588     ThrowNullPointerException("argument is null");
    589     return;
    590   }
    591 
    592   h_caller->SetSkipHiddenApiChecks();
    593 }
    594 
    595 static JNINativeMethod gMethods[] = {
    596   NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
    597   NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
    598   NATIVE_METHOD(VMDebug, crash, "()V"),
    599   NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;I)V"),
    600   NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
    601   NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
    602   NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
    603   NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
    604   NATIVE_METHOD(VMDebug, getInstancesOfClasses, "([Ljava/lang/Class;Z)[[Ljava/lang/Object;"),
    605   NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
    606   FAST_NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
    607   NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
    608   NATIVE_METHOD(VMDebug, infopoint, "(I)V"),
    609   FAST_NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
    610   FAST_NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
    611   NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
    612   FAST_NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
    613   FAST_NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
    614   NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
    615   NATIVE_METHOD(VMDebug, resetInstructionCount, "()V"),
    616   NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
    617   NATIVE_METHOD(VMDebug, startEmulatorTracing, "()V"),
    618   NATIVE_METHOD(VMDebug, startInstructionCounting, "()V"),
    619   NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(IIZI)V"),
    620   NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;IIIZIZ)V"),
    621   NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;IIZI)V"),
    622   NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
    623   NATIVE_METHOD(VMDebug, stopEmulatorTracing, "()V"),
    624   NATIVE_METHOD(VMDebug, stopInstructionCounting, "()V"),
    625   NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
    626   FAST_NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
    627   NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
    628   NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
    629   NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"),
    630   NATIVE_METHOD(VMDebug, allowHiddenApiReflectionFrom, "(Ljava/lang/Class;)V"),
    631 };
    632 
    633 void register_dalvik_system_VMDebug(JNIEnv* env) {
    634   REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
    635 }
    636 
    637 }  // namespace art
    638