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