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 
VMDebug_getVmFeatureList(JNIEnv * env,jclass)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 
VMDebug_startAllocCounting(JNIEnv *,jclass)77 static void VMDebug_startAllocCounting(JNIEnv*, jclass) {
78   Runtime::Current()->SetStatsEnabled(true);
79 }
80 
VMDebug_stopAllocCounting(JNIEnv *,jclass)81 static void VMDebug_stopAllocCounting(JNIEnv*, jclass) {
82   Runtime::Current()->SetStatsEnabled(false);
83 }
84 
VMDebug_getAllocCount(JNIEnv *,jclass,jint kind)85 static jint VMDebug_getAllocCount(JNIEnv*, jclass, jint kind) {
86   return static_cast<jint>(Runtime::Current()->GetStat(kind));
87 }
88 
VMDebug_resetAllocCount(JNIEnv *,jclass,jint kinds)89 static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) {
90   Runtime::Current()->ResetStats(kinds);
91 }
92 
VMDebug_startMethodTracingDdmsImpl(JNIEnv *,jclass,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)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 
VMDebug_startMethodTracingFd(JNIEnv * env,jclass,jstring javaTraceFilename ATTRIBUTE_UNUSED,jint javaFd,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs,jboolean streamingOutput)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 
VMDebug_startMethodTracingFilename(JNIEnv * env,jclass,jstring javaTraceFilename,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)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 
VMDebug_getMethodTracingMode(JNIEnv *,jclass)156 static jint VMDebug_getMethodTracingMode(JNIEnv*, jclass) {
157   return Trace::GetMethodTracingMode();
158 }
159 
VMDebug_stopMethodTracing(JNIEnv *,jclass)160 static void VMDebug_stopMethodTracing(JNIEnv*, jclass) {
161   Trace::Stop();
162 }
163 
VMDebug_isDebuggerConnected(JNIEnv *,jclass)164 static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) {
165   // This function will be replaced by the debugger when it's connected. See
166   // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected.
167   return false;
168 }
169 
VMDebug_isDebuggingEnabled(JNIEnv * env,jclass)170 static jboolean VMDebug_isDebuggingEnabled(JNIEnv* env, jclass) {
171   ScopedObjectAccess soa(env);
172   return Runtime::Current()->GetRuntimeCallbacks()->IsDebuggerConfigured();
173 }
174 
VMDebug_lastDebuggerActivity(JNIEnv *,jclass)175 static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
176   // This function will be replaced by the debugger when it's connected. See
177   // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected.
178   return -1;
179 }
180 
VMDebug_printLoadedClasses(JNIEnv * env,jclass,jint flags)181 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
182   class DumpClassVisitor : public ClassVisitor {
183    public:
184     explicit DumpClassVisitor(int dump_flags) : flags_(dump_flags) {}
185 
186     bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
187       klass->DumpClass(LOG_STREAM(ERROR), flags_);
188       return true;
189     }
190 
191    private:
192     const int flags_;
193   };
194   DumpClassVisitor visitor(flags);
195 
196   ScopedFastNativeObjectAccess soa(env);
197   return Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
198 }
199 
VMDebug_getLoadedClassCount(JNIEnv * env,jclass)200 static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
201   ScopedFastNativeObjectAccess soa(env);
202   return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
203 }
204 
205 /*
206  * Returns the thread-specific CPU-time clock value for the current thread,
207  * or -1 if the feature isn't supported.
208  */
VMDebug_threadCpuTimeNanos(JNIEnv *,jclass)209 static jlong VMDebug_threadCpuTimeNanos(JNIEnv*, jclass) {
210   return ThreadCpuNanoTime();
211 }
212 
213 /*
214  * static void dumpHprofData(String fileName, FileDescriptor fd)
215  *
216  * Cause "hprof" data to be dumped.  We can throw an IOException if an
217  * error occurs during file handling.
218  */
VMDebug_dumpHprofData(JNIEnv * env,jclass,jstring javaFilename,jint javaFd)219 static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jint javaFd) {
220   // Only one of these may be null.
221   if (javaFilename == nullptr && javaFd < 0) {
222     ScopedObjectAccess soa(env);
223     ThrowNullPointerException("fileName == null && fd == null");
224     return;
225   }
226 
227   std::string filename;
228   if (javaFilename != nullptr) {
229     ScopedUtfChars chars(env, javaFilename);
230     if (env->ExceptionCheck()) {
231       return;
232     }
233     filename = chars.c_str();
234   } else {
235     filename = "[fd]";
236   }
237 
238   int fd = javaFd;
239 
240   hprof::DumpHeap(filename.c_str(), fd, false);
241 }
242 
VMDebug_dumpHprofDataDdms(JNIEnv *,jclass)243 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
244   hprof::DumpHeap("[DDMS]", -1, true);
245 }
246 
VMDebug_dumpReferenceTables(JNIEnv * env,jclass)247 static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {
248   ScopedObjectAccess soa(env);
249   LOG(INFO) << "--- reference table dump ---";
250 
251   soa.Env()->DumpReferenceTables(LOG_STREAM(INFO));
252   soa.Vm()->DumpReferenceTables(LOG_STREAM(INFO));
253 
254   LOG(INFO) << "---";
255 }
256 
VMDebug_countInstancesOfClass(JNIEnv * env,jclass,jclass javaClass,jboolean countAssignable)257 static jlong VMDebug_countInstancesOfClass(JNIEnv* env,
258                                            jclass,
259                                            jclass javaClass,
260                                            jboolean countAssignable) {
261   ScopedObjectAccess soa(env);
262   gc::Heap* const heap = Runtime::Current()->GetHeap();
263   // Caller's responsibility to do GC if desired.
264   ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
265   if (c == nullptr) {
266     return 0;
267   }
268   VariableSizedHandleScope hs(soa.Self());
269   std::vector<Handle<mirror::Class>> classes {hs.NewHandle(c)};
270   uint64_t count = 0;
271   heap->CountInstances(classes, countAssignable, &count);
272   return count;
273 }
274 
VMDebug_countInstancesOfClasses(JNIEnv * env,jclass,jobjectArray javaClasses,jboolean countAssignable)275 static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env,
276                                                   jclass,
277                                                   jobjectArray javaClasses,
278                                                   jboolean countAssignable) {
279   ScopedObjectAccess soa(env);
280   gc::Heap* const heap = Runtime::Current()->GetHeap();
281   // Caller's responsibility to do GC if desired.
282   ObjPtr<mirror::ObjectArray<mirror::Class>> decoded_classes =
283       soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
284   if (decoded_classes == nullptr) {
285     return nullptr;
286   }
287   VariableSizedHandleScope hs(soa.Self());
288   std::vector<Handle<mirror::Class>> classes;
289   for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) {
290     classes.push_back(hs.NewHandle(decoded_classes->Get(i)));
291   }
292   std::vector<uint64_t> counts(classes.size(), 0u);
293   // Heap::CountInstances can handle null and will put 0 for these classes.
294   heap->CountInstances(classes, countAssignable, &counts[0]);
295   ObjPtr<mirror::LongArray> long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size());
296   if (long_counts == nullptr) {
297     soa.Self()->AssertPendingOOMException();
298     return nullptr;
299   }
300   for (size_t i = 0; i < counts.size(); ++i) {
301     long_counts->Set(i, counts[i]);
302   }
303   return soa.AddLocalReference<jlongArray>(long_counts);
304 }
305 
306 // The runtime stat names for VMDebug.getRuntimeStat().
307 enum class VMDebugRuntimeStatId {
308   kArtGcGcCount = 0,
309   kArtGcGcTime,
310   kArtGcBytesAllocated,
311   kArtGcBytesFreed,
312   kArtGcBlockingGcCount,
313   kArtGcBlockingGcTime,
314   kArtGcGcCountRateHistogram,
315   kArtGcBlockingGcCountRateHistogram,
316   kArtGcObjectsAllocated,
317   kArtGcTotalTimeWaitingForGc,
318   kNumRuntimeStats,
319 };
320 
VMDebug_getRuntimeStatInternal(JNIEnv * env,jclass,jint statId)321 static jstring VMDebug_getRuntimeStatInternal(JNIEnv* env, jclass, jint statId) {
322   gc::Heap* heap = Runtime::Current()->GetHeap();
323   switch (static_cast<VMDebugRuntimeStatId>(statId)) {
324     case VMDebugRuntimeStatId::kArtGcGcCount: {
325       std::string output = std::to_string(heap->GetGcCount());
326       return env->NewStringUTF(output.c_str());
327     }
328     case VMDebugRuntimeStatId::kArtGcGcTime: {
329       std::string output = std::to_string(NsToMs(heap->GetGcTime()));
330       return env->NewStringUTF(output.c_str());
331     }
332     case VMDebugRuntimeStatId::kArtGcBytesAllocated: {
333       std::string output = std::to_string(heap->GetBytesAllocatedEver());
334       return env->NewStringUTF(output.c_str());
335     }
336     case VMDebugRuntimeStatId::kArtGcBytesFreed: {
337       std::string output = std::to_string(heap->GetBytesFreedEver());
338       return env->NewStringUTF(output.c_str());
339     }
340     case VMDebugRuntimeStatId::kArtGcBlockingGcCount: {
341       std::string output = std::to_string(heap->GetBlockingGcCount());
342       return env->NewStringUTF(output.c_str());
343     }
344     case VMDebugRuntimeStatId::kArtGcBlockingGcTime: {
345       std::string output = std::to_string(NsToMs(heap->GetBlockingGcTime()));
346       return env->NewStringUTF(output.c_str());
347     }
348     case VMDebugRuntimeStatId::kArtGcGcCountRateHistogram: {
349       std::ostringstream output;
350       heap->DumpGcCountRateHistogram(output);
351       return env->NewStringUTF(output.str().c_str());
352     }
353     case VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram: {
354       std::ostringstream output;
355       heap->DumpBlockingGcCountRateHistogram(output);
356       return env->NewStringUTF(output.str().c_str());
357     }
358     case VMDebugRuntimeStatId::kArtGcObjectsAllocated: {
359       std::string output = std::to_string(heap->GetObjectsAllocated());
360       return env->NewStringUTF(output.c_str());
361     }
362     case VMDebugRuntimeStatId::kArtGcTotalTimeWaitingForGc: {
363       std::string output = std::to_string(heap->GetTotalTimeWaitingForGC());
364       return env->NewStringUTF(output.c_str());
365     }
366     default:
367       return nullptr;
368   }
369 }
370 
SetRuntimeStatValue(JNIEnv * env,jobjectArray result,VMDebugRuntimeStatId id,const std::string & value)371 static bool SetRuntimeStatValue(JNIEnv* env,
372                                 jobjectArray result,
373                                 VMDebugRuntimeStatId id,
374                                 const std::string& value) {
375   ScopedLocalRef<jstring> jvalue(env, env->NewStringUTF(value.c_str()));
376   if (jvalue.get() == nullptr) {
377     return false;
378   }
379   env->SetObjectArrayElement(result, static_cast<jint>(id), jvalue.get());
380   return true;
381 }
382 
VMDebug_getRuntimeStatsInternal(JNIEnv * env,jclass)383 static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) {
384   jobjectArray result = env->NewObjectArray(
385       static_cast<jint>(VMDebugRuntimeStatId::kNumRuntimeStats),
386       WellKnownClasses::java_lang_String,
387       nullptr);
388   if (result == nullptr) {
389     return nullptr;
390   }
391   gc::Heap* heap = Runtime::Current()->GetHeap();
392   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCount,
393                            std::to_string(heap->GetGcCount()))) {
394     return nullptr;
395   }
396   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcTime,
397                            std::to_string(NsToMs(heap->GetGcTime())))) {
398     return nullptr;
399   }
400   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesAllocated,
401                            std::to_string(heap->GetBytesAllocatedEver()))) {
402     return nullptr;
403   }
404   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesFreed,
405                            std::to_string(heap->GetBytesFreedEver()))) {
406     return nullptr;
407   }
408   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCount,
409                            std::to_string(heap->GetBlockingGcCount()))) {
410     return nullptr;
411   }
412   if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcTime,
413                            std::to_string(NsToMs(heap->GetBlockingGcTime())))) {
414     return nullptr;
415   }
416   {
417     std::ostringstream output;
418     heap->DumpGcCountRateHistogram(output);
419     if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCountRateHistogram,
420                              output.str())) {
421       return nullptr;
422     }
423   }
424   {
425     std::ostringstream output;
426     heap->DumpBlockingGcCountRateHistogram(output);
427     if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram,
428                              output.str())) {
429       return nullptr;
430     }
431   }
432   return result;
433 }
434 
VMDebug_nativeAttachAgent(JNIEnv * env,jclass,jstring agent,jobject classloader)435 static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) {
436   if (agent == nullptr) {
437     ScopedObjectAccess soa(env);
438     ThrowNullPointerException("agent is null");
439     return;
440   }
441 
442   if (!Dbg::IsJdwpAllowed()) {
443     ScopedObjectAccess soa(env);
444     ThrowSecurityException("Can't attach agent, process is not debuggable.");
445     return;
446   }
447 
448   std::string filename;
449   {
450     ScopedUtfChars chars(env, agent);
451     if (env->ExceptionCheck()) {
452       return;
453     }
454     filename = chars.c_str();
455   }
456 
457   Runtime::Current()->AttachAgent(env, filename, classloader);
458 }
459 
VMDebug_allowHiddenApiReflectionFrom(JNIEnv * env,jclass,jclass j_caller)460 static void VMDebug_allowHiddenApiReflectionFrom(JNIEnv* env, jclass, jclass j_caller) {
461   Runtime* runtime = Runtime::Current();
462   ScopedObjectAccess soa(env);
463 
464   if (!runtime->IsJavaDebuggable()) {
465     ThrowSecurityException("Can't exempt class, process is not debuggable.");
466     return;
467   }
468 
469   StackHandleScope<1> hs(soa.Self());
470   Handle<mirror::Class> h_caller(hs.NewHandle(soa.Decode<mirror::Class>(j_caller)));
471   if (h_caller.IsNull()) {
472     ThrowNullPointerException("argument is null");
473     return;
474   }
475 
476   h_caller->SetSkipHiddenApiChecks();
477 }
478 
VMDebug_setAllocTrackerStackDepth(JNIEnv * env,jclass,jint stack_depth)479 static void VMDebug_setAllocTrackerStackDepth(JNIEnv* env, jclass, jint stack_depth) {
480   Runtime* runtime = Runtime::Current();
481   if (stack_depth < 0 ||
482       static_cast<size_t>(stack_depth) > gc::AllocRecordObjectMap::kMaxSupportedStackDepth) {
483     ScopedObjectAccess soa(env);
484     soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
485                                    "Stack depth is invalid: %d",
486                                    stack_depth);
487   } else {
488     runtime->GetHeap()->SetAllocTrackerStackDepth(static_cast<size_t>(stack_depth));
489   }
490 }
491 
492 static JNINativeMethod gMethods[] = {
493   NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
494   NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
495   NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;I)V"),
496   NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
497   NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
498   NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
499   FAST_NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
500   NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
501   FAST_NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
502   FAST_NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
503   NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
504   FAST_NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
505   FAST_NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
506   NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
507   NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
508   NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(IIZI)V"),
509   NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;IIIZIZ)V"),
510   NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;IIZI)V"),
511   NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
512   NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
513   FAST_NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
514   NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
515   NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
516   NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"),
517   NATIVE_METHOD(VMDebug, allowHiddenApiReflectionFrom, "(Ljava/lang/Class;)V"),
518   NATIVE_METHOD(VMDebug, setAllocTrackerStackDepth, "(I)V"),
519 };
520 
register_dalvik_system_VMDebug(JNIEnv * env)521 void register_dalvik_system_VMDebug(JNIEnv* env) {
522   REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
523 }
524 
525 }  // namespace art
526