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