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