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