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