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