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