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 "class_root-inl.h"
31 #include "common_throws.h"
32 #include "debugger.h"
33 #include "gc/space/bump_pointer_space.h"
34 #include "gc/space/dlmalloc_space.h"
35 #include "gc/space/large_object_space.h"
36 #include "gc/space/space-inl.h"
37 #include "gc/space/zygote_space.h"
38 #include "handle_scope-inl.h"
39 #include "hprof/hprof.h"
40 #include "jni/java_vm_ext.h"
41 #include "jni/jni_internal.h"
42 #include "mirror/array-alloc-inl.h"
43 #include "mirror/array-inl.h"
44 #include "mirror/class.h"
45 #include "mirror/object_array-alloc-inl.h"
46 #include "native_util.h"
47 #include "nativehelper/scoped_local_ref.h"
48 #include "nativehelper/scoped_utf_chars.h"
49 #include "scoped_fast_native_object_access-inl.h"
50 #include "string_array_utils.h"
51 #include "thread-inl.h"
52 #include "trace.h"
53
54 namespace art HIDDEN {
55
VMDebug_getVmFeatureList(JNIEnv * env,jclass)56 static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) {
57 ScopedObjectAccess soa(Thread::ForEnv(env));
58 return soa.AddLocalReference<jobjectArray>(
59 CreateStringArray(soa.Self(),
60 {
61 "method-trace-profiling",
62 "method-trace-profiling-streaming",
63 "method-sample-profiling",
64 "hprof-heap-dump",
65 "hprof-heap-dump-streaming",
66 "app_info",
67 }));
68 }
69
VMDebug_startAllocCounting(JNIEnv *,jclass)70 static void VMDebug_startAllocCounting(JNIEnv*, jclass) {
71 Runtime::Current()->SetStatsEnabled(true);
72 }
73
VMDebug_stopAllocCounting(JNIEnv *,jclass)74 static void VMDebug_stopAllocCounting(JNIEnv*, jclass) {
75 Runtime::Current()->SetStatsEnabled(false);
76 }
77
VMDebug_getAllocCount(JNIEnv *,jclass,jint kind)78 static jint VMDebug_getAllocCount(JNIEnv*, jclass, jint kind) {
79 return static_cast<jint>(Runtime::Current()->GetStat(kind));
80 }
81
VMDebug_resetAllocCount(JNIEnv *,jclass,jint kinds)82 static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) {
83 Runtime::Current()->ResetStats(kinds);
84 }
85
VMDebug_startMethodTracingDdmsImpl(JNIEnv *,jclass,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)86 static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
87 jboolean samplingEnabled, jint intervalUs) {
88 Trace::StartDDMS(bufferSize,
89 flags,
90 samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
91 intervalUs);
92 }
93
VMDebug_startMethodTracingFd(JNIEnv * env,jclass,jstring javaTraceFilename,jint javaFd,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs,jboolean streamingOutput)94 static void VMDebug_startMethodTracingFd(JNIEnv* env,
95 jclass,
96 [[maybe_unused]] jstring javaTraceFilename,
97 jint javaFd,
98 jint bufferSize,
99 jint flags,
100 jboolean samplingEnabled,
101 jint intervalUs,
102 jboolean streamingOutput) {
103 int originalFd = javaFd;
104 if (originalFd < 0) {
105 ScopedObjectAccess soa(env);
106 soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
107 "Trace fd is invalid: %d",
108 originalFd);
109 return;
110 }
111
112 int fd = DupCloexec(originalFd);
113 if (fd < 0) {
114 ScopedObjectAccess soa(env);
115 soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
116 "dup(%d) failed: %s",
117 originalFd,
118 strerror(errno));
119 return;
120 }
121
122 // Ignore the traceFilename.
123 TraceOutputMode outputMode =
124 streamingOutput ? TraceOutputMode::kStreaming : TraceOutputMode::kFile;
125 Trace::Start(fd,
126 bufferSize,
127 flags,
128 outputMode,
129 samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
130 intervalUs);
131 }
132
VMDebug_startMethodTracingFilename(JNIEnv * env,jclass,jstring javaTraceFilename,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)133 static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring javaTraceFilename,
134 jint bufferSize, jint flags,
135 jboolean samplingEnabled, jint intervalUs) {
136 ScopedUtfChars traceFilename(env, javaTraceFilename);
137 if (traceFilename.c_str() == nullptr) {
138 return;
139 }
140 Trace::Start(traceFilename.c_str(),
141 bufferSize,
142 flags,
143 TraceOutputMode::kFile,
144 samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
145 intervalUs);
146 }
147
VMDebug_getMethodTracingMode(JNIEnv *,jclass)148 static jint VMDebug_getMethodTracingMode(JNIEnv*, jclass) {
149 return Trace::GetMethodTracingMode();
150 }
151
VMDebug_stopMethodTracing(JNIEnv *,jclass)152 static void VMDebug_stopMethodTracing(JNIEnv*, jclass) {
153 Trace::Stop();
154 }
155
VMDebug_isDebuggerConnected(JNIEnv *,jclass)156 static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) {
157 // This function will be replaced by the debugger when it's connected. See
158 // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected.
159 return false;
160 }
161
VMDebug_isDebuggingEnabled(JNIEnv * env,jclass)162 static jboolean VMDebug_isDebuggingEnabled(JNIEnv* env, jclass) {
163 ScopedObjectAccess soa(env);
164 return Runtime::Current()->GetRuntimeCallbacks()->IsDebuggerConfigured();
165 }
166
VMDebug_lastDebuggerActivity(JNIEnv *,jclass)167 static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
168 // This function will be replaced by the debugger when it's connected. See
169 // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected.
170 return -1;
171 }
172
VMDebug_suspendAllAndSendVmStart(JNIEnv *,jclass)173 static void VMDebug_suspendAllAndSendVmStart(JNIEnv*, jclass)
174 REQUIRES_SHARED(Locks::mutator_lock_) {
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 ThrowRuntimeException("ART's suspendAllAndSendVmStart is not implemented");
178 }
179
VMDebug_printLoadedClasses(JNIEnv * env,jclass,jint flags)180 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
181 class DumpClassVisitor : public ClassVisitor {
182 public:
183 explicit DumpClassVisitor(int dump_flags) : flags_(dump_flags) {}
184
185 bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
186 klass->DumpClass(LOG_STREAM(ERROR), flags_);
187 return true;
188 }
189
190 private:
191 const int flags_;
192 };
193 DumpClassVisitor visitor(flags);
194
195 ScopedFastNativeObjectAccess soa(env);
196 return Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
197 }
198
VMDebug_getLoadedClassCount(JNIEnv * env,jclass)199 static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
200 ScopedFastNativeObjectAccess soa(env);
201 return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
202 }
203
204 /*
205 * Returns the thread-specific CPU-time clock value for the current thread,
206 * or -1 if the feature isn't supported.
207 */
VMDebug_threadCpuTimeNanos(JNIEnv *,jclass)208 static jlong VMDebug_threadCpuTimeNanos(JNIEnv*, jclass) {
209 return ThreadCpuNanoTime();
210 }
211
212 /*
213 * static void dumpHprofData(String fileName, FileDescriptor fd)
214 *
215 * Cause "hprof" data to be dumped. We can throw an IOException if an
216 * error occurs during file handling.
217 */
VMDebug_dumpHprofData(JNIEnv * env,jclass,jstring javaFilename,jint javaFd)218 static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jint javaFd) {
219 // Only one of these may be null.
220 if (javaFilename == nullptr && javaFd < 0) {
221 ScopedObjectAccess soa(env);
222 ThrowNullPointerException("fileName == null && fd == null");
223 return;
224 }
225
226 std::string filename;
227 if (javaFilename != nullptr) {
228 ScopedUtfChars chars(env, javaFilename);
229 if (env->ExceptionCheck()) {
230 return;
231 }
232 filename = chars.c_str();
233 } else {
234 filename = "[fd]";
235 }
236
237 int fd = javaFd;
238
239 hprof::DumpHeap(filename.c_str(), fd, false);
240 }
241
VMDebug_dumpHprofDataDdms(JNIEnv *,jclass)242 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
243 hprof::DumpHeap("[DDMS]", -1, true);
244 }
245
VMDebug_dumpReferenceTables(JNIEnv * env,jclass)246 static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {
247 ScopedObjectAccess soa(env);
248 LOG(INFO) << "--- reference table dump ---";
249
250 soa.Env()->DumpReferenceTables(LOG_STREAM(INFO));
251 soa.Vm()->DumpReferenceTables(LOG_STREAM(INFO));
252
253 LOG(INFO) << "---";
254 }
255
VMDebug_countInstancesOfClass(JNIEnv * env,jclass,jclass javaClass,jboolean countAssignable)256 static jlong VMDebug_countInstancesOfClass(JNIEnv* env,
257 jclass,
258 jclass javaClass,
259 jboolean countAssignable) {
260 ScopedObjectAccess soa(env);
261 gc::Heap* const heap = Runtime::Current()->GetHeap();
262 // Caller's responsibility to do GC if desired.
263 ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
264 if (c == nullptr) {
265 return 0;
266 }
267 VariableSizedHandleScope hs(soa.Self());
268 std::vector<Handle<mirror::Class>> classes {hs.NewHandle(c)};
269 uint64_t count = 0;
270 heap->CountInstances(classes, countAssignable, &count);
271 return count;
272 }
273
VMDebug_countInstancesOfClasses(JNIEnv * env,jclass,jobjectArray javaClasses,jboolean countAssignable)274 static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env,
275 jclass,
276 jobjectArray javaClasses,
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::ObjectArray<mirror::Class>> decoded_classes =
282 soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
283 if (decoded_classes == nullptr) {
284 return nullptr;
285 }
286 VariableSizedHandleScope hs(soa.Self());
287 std::vector<Handle<mirror::Class>> classes;
288 for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) {
289 classes.push_back(hs.NewHandle(decoded_classes->Get(i)));
290 }
291 std::vector<uint64_t> counts(classes.size(), 0u);
292 // Heap::CountInstances can handle null and will put 0 for these classes.
293 heap->CountInstances(classes, countAssignable, &counts[0]);
294 ObjPtr<mirror::LongArray> long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size());
295 if (long_counts == nullptr) {
296 soa.Self()->AssertPendingOOMException();
297 return nullptr;
298 }
299 for (size_t i = 0; i < counts.size(); ++i) {
300 long_counts->Set(i, counts[i]);
301 }
302 return soa.AddLocalReference<jlongArray>(long_counts);
303 }
304
305 // The runtime stat names for VMDebug.getRuntimeStat().
306 enum class VMDebugRuntimeStatId {
307 kArtGcGcCount = 0,
308 kArtGcGcTime,
309 kArtGcBytesAllocated,
310 kArtGcBytesFreed,
311 kArtGcBlockingGcCount,
312 kArtGcBlockingGcTime,
313 kArtGcGcCountRateHistogram,
314 kArtGcBlockingGcCountRateHistogram,
315 kArtGcObjectsAllocated,
316 kArtGcTotalTimeWaitingForGc,
317 kArtGcPreOomeGcCount,
318 kNumRuntimeStats,
319 };
320
VMDebug_getRuntimeStatInternal(JNIEnv * env,jclass,jint statId)321 static jstring VMDebug_getRuntimeStatInternal(JNIEnv* env, jclass, jint statId) {
322 gc::Heap* heap = Runtime::Current()->GetHeap();
323 switch (static_cast<VMDebugRuntimeStatId>(statId)) {
324 case VMDebugRuntimeStatId::kArtGcGcCount: {
325 std::string output = std::to_string(heap->GetGcCount());
326 return env->NewStringUTF(output.c_str());
327 }
328 case VMDebugRuntimeStatId::kArtGcGcTime: {
329 std::string output = std::to_string(NsToMs(heap->GetGcTime()));
330 return env->NewStringUTF(output.c_str());
331 }
332 case VMDebugRuntimeStatId::kArtGcBytesAllocated: {
333 std::string output = std::to_string(heap->GetBytesAllocatedEver());
334 return env->NewStringUTF(output.c_str());
335 }
336 case VMDebugRuntimeStatId::kArtGcBytesFreed: {
337 std::string output = std::to_string(heap->GetBytesFreedEver());
338 return env->NewStringUTF(output.c_str());
339 }
340 case VMDebugRuntimeStatId::kArtGcBlockingGcCount: {
341 std::string output = std::to_string(heap->GetBlockingGcCount());
342 return env->NewStringUTF(output.c_str());
343 }
344 case VMDebugRuntimeStatId::kArtGcBlockingGcTime: {
345 std::string output = std::to_string(NsToMs(heap->GetBlockingGcTime()));
346 return env->NewStringUTF(output.c_str());
347 }
348 case VMDebugRuntimeStatId::kArtGcGcCountRateHistogram: {
349 std::ostringstream output;
350 heap->DumpGcCountRateHistogram(output);
351 return env->NewStringUTF(output.str().c_str());
352 }
353 case VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram: {
354 std::ostringstream output;
355 heap->DumpBlockingGcCountRateHistogram(output);
356 return env->NewStringUTF(output.str().c_str());
357 }
358 case VMDebugRuntimeStatId::kArtGcObjectsAllocated: {
359 std::string output = std::to_string(heap->GetObjectsAllocated());
360 return env->NewStringUTF(output.c_str());
361 }
362 case VMDebugRuntimeStatId::kArtGcTotalTimeWaitingForGc: {
363 std::string output = std::to_string(heap->GetTotalTimeWaitingForGC());
364 return env->NewStringUTF(output.c_str());
365 }
366 case VMDebugRuntimeStatId::kArtGcPreOomeGcCount: {
367 std::string output = std::to_string(heap->GetPreOomeGcCount());
368 return env->NewStringUTF(output.c_str());
369 }
370 default:
371 return nullptr;
372 }
373 }
374
SetRuntimeStatValue(Thread * self,Handle<mirror::ObjectArray<mirror::String>> array,VMDebugRuntimeStatId id,const std::string & value)375 static bool SetRuntimeStatValue(Thread* self,
376 Handle<mirror::ObjectArray<mirror::String>> array,
377 VMDebugRuntimeStatId id,
378 const std::string& value) REQUIRES_SHARED(Locks::mutator_lock_) {
379 ObjPtr<mirror::String> ovalue = mirror::String::AllocFromModifiedUtf8(self, value.c_str());
380 if (ovalue == nullptr) {
381 DCHECK(self->IsExceptionPending());
382 return false;
383 }
384 // We're initializing a newly allocated array object, so we do not need to record that under
385 // a transaction. If the transaction is aborted, the whole object shall be unreachable.
386 array->SetWithoutChecks</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>(
387 static_cast<int32_t>(id), ovalue);
388 return true;
389 }
390
VMDebug_getRuntimeStatsInternal(JNIEnv * env,jclass)391 static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) {
392 Thread* self = Thread::ForEnv(env);
393 ScopedObjectAccess soa(self);
394 StackHandleScope<1u> hs(self);
395 int32_t size = enum_cast<int32_t>(VMDebugRuntimeStatId::kNumRuntimeStats);
396 Handle<mirror::ObjectArray<mirror::String>> array = hs.NewHandle(
397 mirror::ObjectArray<mirror::String>::Alloc(
398 self, GetClassRoot<mirror::ObjectArray<mirror::String>>(), size));
399 if (array == nullptr) {
400 DCHECK(self->IsExceptionPending());
401 return nullptr;
402 }
403 gc::Heap* heap = Runtime::Current()->GetHeap();
404 if (!SetRuntimeStatValue(self,
405 array,
406 VMDebugRuntimeStatId::kArtGcGcCount,
407 std::to_string(heap->GetGcCount()))) {
408 return nullptr;
409 }
410 if (!SetRuntimeStatValue(self,
411 array,
412 VMDebugRuntimeStatId::kArtGcGcTime,
413 std::to_string(NsToMs(heap->GetGcTime())))) {
414 return nullptr;
415 }
416 if (!SetRuntimeStatValue(self,
417 array,
418 VMDebugRuntimeStatId::kArtGcBytesAllocated,
419 std::to_string(heap->GetBytesAllocatedEver()))) {
420 return nullptr;
421 }
422 if (!SetRuntimeStatValue(self,
423 array,
424 VMDebugRuntimeStatId::kArtGcBytesFreed,
425 std::to_string(heap->GetBytesFreedEver()))) {
426 return nullptr;
427 }
428 if (!SetRuntimeStatValue(self,
429 array,
430 VMDebugRuntimeStatId::kArtGcBlockingGcCount,
431 std::to_string(heap->GetBlockingGcCount()))) {
432 return nullptr;
433 }
434 if (!SetRuntimeStatValue(self,
435 array,
436 VMDebugRuntimeStatId::kArtGcBlockingGcTime,
437 std::to_string(NsToMs(heap->GetBlockingGcTime())))) {
438 return nullptr;
439 }
440 {
441 std::ostringstream output;
442 heap->DumpGcCountRateHistogram(output);
443 if (!SetRuntimeStatValue(self,
444 array,
445 VMDebugRuntimeStatId::kArtGcGcCountRateHistogram,
446 output.str())) {
447 return nullptr;
448 }
449 }
450 {
451 std::ostringstream output;
452 heap->DumpBlockingGcCountRateHistogram(output);
453 if (!SetRuntimeStatValue(self,
454 array,
455 VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram,
456 output.str())) {
457 return nullptr;
458 }
459 }
460 return soa.AddLocalReference<jobjectArray>(array.Get());
461 }
462
VMDebug_nativeAttachAgent(JNIEnv * env,jclass,jstring agent,jobject classloader)463 static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) {
464 if (agent == nullptr) {
465 ScopedObjectAccess soa(env);
466 ThrowNullPointerException("agent is null");
467 return;
468 }
469
470 if (!Dbg::IsJdwpAllowed()) {
471 ScopedObjectAccess soa(env);
472 ThrowSecurityException("Can't attach agent, process is not debuggable.");
473 return;
474 }
475
476 std::string filename;
477 {
478 ScopedUtfChars chars(env, agent);
479 if (env->ExceptionCheck()) {
480 return;
481 }
482 filename = chars.c_str();
483 }
484
485 Runtime::Current()->AttachAgent(env, filename, classloader);
486 }
487
VMDebug_allowHiddenApiReflectionFrom(JNIEnv * env,jclass,jclass j_caller)488 static void VMDebug_allowHiddenApiReflectionFrom(JNIEnv* env, jclass, jclass j_caller) {
489 Runtime* runtime = Runtime::Current();
490 ScopedObjectAccess soa(env);
491
492 if (!runtime->IsJavaDebuggableAtInit()) {
493 ThrowSecurityException("Can't exempt class, process is not debuggable.");
494 return;
495 }
496
497 StackHandleScope<1> hs(soa.Self());
498 Handle<mirror::Class> h_caller(hs.NewHandle(soa.Decode<mirror::Class>(j_caller)));
499 if (h_caller.IsNull()) {
500 ThrowNullPointerException("argument is null");
501 return;
502 }
503
504 h_caller->SetSkipHiddenApiChecks();
505 }
506
VMDebug_setAllocTrackerStackDepth(JNIEnv * env,jclass,jint stack_depth)507 static void VMDebug_setAllocTrackerStackDepth(JNIEnv* env, jclass, jint stack_depth) {
508 Runtime* runtime = Runtime::Current();
509 if (stack_depth < 0 ||
510 static_cast<size_t>(stack_depth) > gc::AllocRecordObjectMap::kMaxSupportedStackDepth) {
511 ScopedObjectAccess soa(env);
512 soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
513 "Stack depth is invalid: %d",
514 stack_depth);
515 } else {
516 runtime->GetHeap()->SetAllocTrackerStackDepth(static_cast<size_t>(stack_depth));
517 }
518 }
519
VMDebug_setCurrentProcessName(JNIEnv * env,jclass,jstring process_name)520 static void VMDebug_setCurrentProcessName(JNIEnv* env, jclass, jstring process_name) {
521 ScopedFastNativeObjectAccess soa(env);
522
523 // Android application ID naming convention states:
524 // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')"
525 // This is fine to convert to std::string
526 const char* c_process_name = env->GetStringUTFChars(process_name, NULL);
527 Runtime::Current()->GetRuntimeCallbacks()->SetCurrentProcessName(std::string(c_process_name));
528 env->ReleaseStringUTFChars(process_name, c_process_name);
529 }
530
VMDebug_addApplication(JNIEnv * env,jclass,jstring package_name)531 static void VMDebug_addApplication(JNIEnv* env, jclass, jstring package_name) {
532 ScopedFastNativeObjectAccess soa(env);
533
534 // Android application ID naming convention states:
535 // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')"
536 // This is fine to convert to std::string
537 const char* c_package_name = env->GetStringUTFChars(package_name, NULL);
538 Runtime::Current()->GetRuntimeCallbacks()->AddApplication(std::string(c_package_name));
539 env->ReleaseStringUTFChars(package_name, c_package_name);
540 }
541
VMDebug_removeApplication(JNIEnv * env,jclass,jstring package_name)542 static void VMDebug_removeApplication(JNIEnv* env, jclass, jstring package_name) {
543 ScopedFastNativeObjectAccess soa(env);
544
545 // Android application ID naming convention states:
546 // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')"
547 // This is fine to convert to std::string
548 const char* c_package_name = env->GetStringUTFChars(package_name, NULL);
549 Runtime::Current()->GetRuntimeCallbacks()->RemoveApplication(std::string(c_package_name));
550 env->ReleaseStringUTFChars(package_name, c_package_name);
551 }
552
VMDebug_setWaitingForDebugger(JNIEnv * env,jclass,jboolean waiting)553 static void VMDebug_setWaitingForDebugger(JNIEnv* env, jclass, jboolean waiting) {
554 ScopedFastNativeObjectAccess soa(env);
555 Runtime::Current()->GetRuntimeCallbacks()->SetWaitingForDebugger(waiting);
556 }
557
VMDebug_setUserId(JNIEnv * env,jclass,jint user_id)558 static void VMDebug_setUserId(JNIEnv* env, jclass, jint user_id) {
559 ScopedFastNativeObjectAccess soa(env);
560 Runtime::Current()->GetRuntimeCallbacks()->SetUserId(user_id);
561 }
562
563 static JNINativeMethod gMethods[] = {
564 NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
565 NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
566 NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;I)V"),
567 NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
568 NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
569 NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
570 FAST_NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
571 NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
572 FAST_NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
573 FAST_NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
574 NATIVE_METHOD(VMDebug, suspendAllAndSendVmStart, "()V"),
575 NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
576 FAST_NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
577 FAST_NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
578 NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
579 NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
580 NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(IIZI)V"),
581 NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;IIIZIZ)V"),
582 NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;IIZI)V"),
583 NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
584 NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
585 FAST_NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
586 NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
587 NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
588 NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"),
589 NATIVE_METHOD(VMDebug, allowHiddenApiReflectionFrom, "(Ljava/lang/Class;)V"),
590 NATIVE_METHOD(VMDebug, setAllocTrackerStackDepth, "(I)V"),
591 NATIVE_METHOD(VMDebug, setCurrentProcessName, "(Ljava/lang/String;)V"),
592 NATIVE_METHOD(VMDebug, setWaitingForDebugger, "(Z)V"),
593 NATIVE_METHOD(VMDebug, addApplication, "(Ljava/lang/String;)V"),
594 NATIVE_METHOD(VMDebug, removeApplication, "(Ljava/lang/String;)V"),
595 NATIVE_METHOD(VMDebug, setUserId, "(I)V"),
596 };
597
register_dalvik_system_VMDebug(JNIEnv * env)598 void register_dalvik_system_VMDebug(JNIEnv* env) {
599 REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
600 }
601
602 } // namespace art
603