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