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