• 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 <string.h>
18 #include <unistd.h>
19 
20 #include "class_linker.h"
21 #include "common_throws.h"
22 #include "debugger.h"
23 #include "gc/space/bump_pointer_space.h"
24 #include "gc/space/dlmalloc_space.h"
25 #include "gc/space/large_object_space.h"
26 #include "gc/space/space-inl.h"
27 #include "gc/space/zygote_space.h"
28 #include "hprof/hprof.h"
29 #include "jni_internal.h"
30 #include "mirror/class.h"
31 #include "ScopedLocalRef.h"
32 #include "ScopedUtfChars.h"
33 #include "scoped_fast_native_object_access.h"
34 #include "trace.h"
35 #include "well_known_classes.h"
36 
37 namespace art {
38 
VMDebug_getVmFeatureList(JNIEnv * env,jclass)39 static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) {
40   static const char* features[] = {
41     "method-trace-profiling",
42     "method-trace-profiling-streaming",
43     "method-sample-profiling",
44     "hprof-heap-dump",
45     "hprof-heap-dump-streaming",
46   };
47   jobjectArray result = env->NewObjectArray(arraysize(features),
48                                             WellKnownClasses::java_lang_String,
49                                             nullptr);
50   if (result != nullptr) {
51     for (size_t i = 0; i < arraysize(features); ++i) {
52       ScopedLocalRef<jstring> jfeature(env, env->NewStringUTF(features[i]));
53       if (jfeature.get() == nullptr) {
54         return nullptr;
55       }
56       env->SetObjectArrayElement(result, i, jfeature.get());
57     }
58   }
59   return result;
60 }
61 
VMDebug_startAllocCounting(JNIEnv *,jclass)62 static void VMDebug_startAllocCounting(JNIEnv*, jclass) {
63   Runtime::Current()->SetStatsEnabled(true);
64 }
65 
VMDebug_stopAllocCounting(JNIEnv *,jclass)66 static void VMDebug_stopAllocCounting(JNIEnv*, jclass) {
67   Runtime::Current()->SetStatsEnabled(false);
68 }
69 
VMDebug_getAllocCount(JNIEnv *,jclass,jint kind)70 static jint VMDebug_getAllocCount(JNIEnv*, jclass, jint kind) {
71   return Runtime::Current()->GetStat(kind);
72 }
73 
VMDebug_resetAllocCount(JNIEnv *,jclass,jint kinds)74 static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) {
75   Runtime::Current()->ResetStats(kinds);
76 }
77 
VMDebug_startMethodTracingDdmsImpl(JNIEnv *,jclass,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)78 static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
79                                                jboolean samplingEnabled, jint intervalUs) {
80   Trace::Start("[DDMS]", -1, bufferSize, flags, true, samplingEnabled, intervalUs);
81 }
82 
VMDebug_startMethodTracingFd(JNIEnv * env,jclass,jstring javaTraceFilename,jobject javaFd,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)83 static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
84                                          jobject javaFd, jint bufferSize, jint flags,
85                                          jboolean samplingEnabled, jint intervalUs) {
86   int originalFd = jniGetFDFromFileDescriptor(env, javaFd);
87   if (originalFd < 0) {
88     return;
89   }
90 
91   int fd = dup(originalFd);
92   if (fd < 0) {
93     ScopedObjectAccess soa(env);
94     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
95     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/RuntimeException;",
96                                    "dup(%d) failed: %s", originalFd, strerror(errno));
97     return;
98   }
99 
100   ScopedUtfChars traceFilename(env, javaTraceFilename);
101   if (traceFilename.c_str() == NULL) {
102     return;
103   }
104   Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, false, samplingEnabled, intervalUs);
105 }
106 
VMDebug_startMethodTracingFilename(JNIEnv * env,jclass,jstring javaTraceFilename,jint bufferSize,jint flags,jboolean samplingEnabled,jint intervalUs)107 static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring javaTraceFilename,
108                                                jint bufferSize, jint flags,
109                                                jboolean samplingEnabled, jint intervalUs) {
110   ScopedUtfChars traceFilename(env, javaTraceFilename);
111   if (traceFilename.c_str() == NULL) {
112     return;
113   }
114   Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, false, samplingEnabled, intervalUs);
115 }
116 
VMDebug_getMethodTracingMode(JNIEnv *,jclass)117 static jint VMDebug_getMethodTracingMode(JNIEnv*, jclass) {
118   return Trace::GetMethodTracingMode();
119 }
120 
VMDebug_stopMethodTracing(JNIEnv *,jclass)121 static void VMDebug_stopMethodTracing(JNIEnv*, jclass) {
122   Trace::Stop();
123 }
124 
VMDebug_startEmulatorTracing(JNIEnv *,jclass)125 static void VMDebug_startEmulatorTracing(JNIEnv*, jclass) {
126   UNIMPLEMENTED(WARNING);
127   // dvmEmulatorTraceStart();
128 }
129 
VMDebug_stopEmulatorTracing(JNIEnv *,jclass)130 static void VMDebug_stopEmulatorTracing(JNIEnv*, jclass) {
131   UNIMPLEMENTED(WARNING);
132   // dvmEmulatorTraceStop();
133 }
134 
VMDebug_isDebuggerConnected(JNIEnv *,jclass)135 static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) {
136   return Dbg::IsDebuggerActive();
137 }
138 
VMDebug_isDebuggingEnabled(JNIEnv *,jclass)139 static jboolean VMDebug_isDebuggingEnabled(JNIEnv*, jclass) {
140   return Dbg::IsJdwpConfigured();
141 }
142 
VMDebug_lastDebuggerActivity(JNIEnv *,jclass)143 static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
144   return Dbg::LastDebuggerActivity();
145 }
146 
ThrowUnsupportedOperationException(JNIEnv * env)147 static void ThrowUnsupportedOperationException(JNIEnv* env) {
148   ScopedObjectAccess soa(env);
149   ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
150   soa.Self()->ThrowNewException(throw_location, "Ljava/lang/UnsupportedOperationException;", NULL);
151 }
152 
VMDebug_startInstructionCounting(JNIEnv * env,jclass)153 static void VMDebug_startInstructionCounting(JNIEnv* env, jclass) {
154   ThrowUnsupportedOperationException(env);
155 }
156 
VMDebug_stopInstructionCounting(JNIEnv * env,jclass)157 static void VMDebug_stopInstructionCounting(JNIEnv* env, jclass) {
158   ThrowUnsupportedOperationException(env);
159 }
160 
VMDebug_getInstructionCount(JNIEnv * env,jclass,jintArray)161 static void VMDebug_getInstructionCount(JNIEnv* env, jclass, jintArray /*javaCounts*/) {
162   ThrowUnsupportedOperationException(env);
163 }
164 
VMDebug_resetInstructionCount(JNIEnv * env,jclass)165 static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) {
166   ThrowUnsupportedOperationException(env);
167 }
168 
VMDebug_printLoadedClasses(JNIEnv * env,jclass,jint flags)169 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
170   ScopedFastNativeObjectAccess soa(env);
171   return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags);
172 }
173 
VMDebug_getLoadedClassCount(JNIEnv * env,jclass)174 static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
175   ScopedFastNativeObjectAccess soa(env);
176   return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
177 }
178 
179 /*
180  * Returns the thread-specific CPU-time clock value for the current thread,
181  * or -1 if the feature isn't supported.
182  */
VMDebug_threadCpuTimeNanos(JNIEnv *,jclass)183 static jlong VMDebug_threadCpuTimeNanos(JNIEnv*, jclass) {
184   return ThreadCpuNanoTime();
185 }
186 
187 /*
188  * static void dumpHprofData(String fileName, FileDescriptor fd)
189  *
190  * Cause "hprof" data to be dumped.  We can throw an IOException if an
191  * error occurs during file handling.
192  */
VMDebug_dumpHprofData(JNIEnv * env,jclass,jstring javaFilename,jobject javaFd)193 static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jobject javaFd) {
194   // Only one of these may be NULL.
195   if (javaFilename == NULL && javaFd == NULL) {
196     ScopedObjectAccess soa(env);
197     ThrowNullPointerException(NULL, "fileName == null && fd == null");
198     return;
199   }
200 
201   std::string filename;
202   if (javaFilename != NULL) {
203     ScopedUtfChars chars(env, javaFilename);
204     if (env->ExceptionCheck()) {
205       return;
206     }
207     filename = chars.c_str();
208   } else {
209     filename = "[fd]";
210   }
211 
212   int fd = -1;
213   if (javaFd != NULL) {
214     fd = jniGetFDFromFileDescriptor(env, javaFd);
215     if (fd < 0) {
216       ScopedObjectAccess soa(env);
217       ThrowRuntimeException("Invalid file descriptor");
218       return;
219     }
220   }
221 
222   hprof::DumpHeap(filename.c_str(), fd, false);
223 }
224 
VMDebug_dumpHprofDataDdms(JNIEnv *,jclass)225 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
226   hprof::DumpHeap("[DDMS]", -1, true);
227 }
228 
VMDebug_dumpReferenceTables(JNIEnv * env,jclass)229 static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {
230   ScopedObjectAccess soa(env);
231   LOG(INFO) << "--- reference table dump ---";
232 
233   soa.Env()->DumpReferenceTables(LOG(INFO));
234   soa.Vm()->DumpReferenceTables(LOG(INFO));
235 
236   LOG(INFO) << "---";
237 }
238 
VMDebug_crash(JNIEnv *,jclass)239 static void VMDebug_crash(JNIEnv*, jclass) {
240   LOG(FATAL) << "Crashing runtime on request";
241 }
242 
VMDebug_infopoint(JNIEnv *,jclass,jint id)243 static void VMDebug_infopoint(JNIEnv*, jclass, jint id) {
244   LOG(INFO) << "VMDebug infopoint " << id << " hit";
245 }
246 
VMDebug_countInstancesOfClass(JNIEnv * env,jclass,jclass javaClass,jboolean countAssignable)247 static jlong VMDebug_countInstancesOfClass(JNIEnv* env, jclass, jclass javaClass,
248                                            jboolean countAssignable) {
249   ScopedObjectAccess soa(env);
250   gc::Heap* heap = Runtime::Current()->GetHeap();
251   // We only want reachable instances, so do a GC. Heap::VisitObjects visits all of the heap
252   // objects in the all spaces and the allocation stack.
253   heap->CollectGarbage(false);
254   mirror::Class* c = soa.Decode<mirror::Class*>(javaClass);
255   if (c == nullptr) {
256     return 0;
257   }
258   std::vector<mirror::Class*> classes;
259   classes.push_back(c);
260   uint64_t count = 0;
261   heap->CountInstances(classes, countAssignable, &count);
262   return count;
263 }
264 
265 // We export the VM internal per-heap-space size/alloc/free metrics
266 // for the zygote space, alloc space (application heap), and the large
267 // object space for dumpsys meminfo. The other memory region data such
268 // as PSS, private/shared dirty/shared data are available via
269 // /proc/<pid>/smaps.
VMDebug_getHeapSpaceStats(JNIEnv * env,jclass,jlongArray data)270 static void VMDebug_getHeapSpaceStats(JNIEnv* env, jclass, jlongArray data) {
271   jlong* arr = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(data, 0));
272   if (arr == nullptr || env->GetArrayLength(data) < 9) {
273     return;
274   }
275 
276   size_t allocSize = 0;
277   size_t allocUsed = 0;
278   size_t zygoteSize = 0;
279   size_t zygoteUsed = 0;
280   size_t largeObjectsSize = 0;
281   size_t largeObjectsUsed = 0;
282   gc::Heap* heap = Runtime::Current()->GetHeap();
283   for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
284     if (space->IsImageSpace()) {
285       // Currently don't include the image space.
286     } else if (space->IsZygoteSpace()) {
287       gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace();
288       zygoteSize += zygote_space->Size();
289       zygoteUsed += zygote_space->GetBytesAllocated();
290     } else if (space->IsMallocSpace()) {
291       // This is a malloc space.
292       gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
293       allocSize += malloc_space->GetFootprint();
294       allocUsed += malloc_space->GetBytesAllocated();
295     } else if (space->IsBumpPointerSpace()) {
296       ScopedObjectAccess soa(env);
297       gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace();
298       allocSize += bump_pointer_space->Size();
299       allocUsed += bump_pointer_space->GetBytesAllocated();
300     }
301   }
302   for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) {
303     if (space->IsLargeObjectSpace()) {
304       largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated();
305       largeObjectsUsed += largeObjectsSize;
306     }
307   }
308 
309   size_t allocFree = allocSize - allocUsed;
310   size_t zygoteFree = zygoteSize - zygoteUsed;
311   size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed;
312 
313   int j = 0;
314   arr[j++] = allocSize;
315   arr[j++] = allocUsed;
316   arr[j++] = allocFree;
317   arr[j++] = zygoteSize;
318   arr[j++] = zygoteUsed;
319   arr[j++] = zygoteFree;
320   arr[j++] = largeObjectsSize;
321   arr[j++] = largeObjectsUsed;
322   arr[j++] = largeObjectsFree;
323   env->ReleasePrimitiveArrayCritical(data, arr, 0);
324 }
325 
326 static JNINativeMethod gMethods[] = {
327   NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
328   NATIVE_METHOD(VMDebug, crash, "()V"),
329   NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;Ljava/io/FileDescriptor;)V"),
330   NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
331   NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
332   NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
333   NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
334   NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
335   NATIVE_METHOD(VMDebug, getLoadedClassCount, "!()I"),
336   NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
337   NATIVE_METHOD(VMDebug, infopoint, "(I)V"),
338   NATIVE_METHOD(VMDebug, isDebuggerConnected, "!()Z"),
339   NATIVE_METHOD(VMDebug, isDebuggingEnabled, "!()Z"),
340   NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
341   NATIVE_METHOD(VMDebug, lastDebuggerActivity, "!()J"),
342   NATIVE_METHOD(VMDebug, printLoadedClasses, "!(I)V"),
343   NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
344   NATIVE_METHOD(VMDebug, resetInstructionCount, "()V"),
345   NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
346   NATIVE_METHOD(VMDebug, startEmulatorTracing, "()V"),
347   NATIVE_METHOD(VMDebug, startInstructionCounting, "()V"),
348   NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(IIZI)V"),
349   NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;Ljava/io/FileDescriptor;IIZI)V"),
350   NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;IIZI)V"),
351   NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
352   NATIVE_METHOD(VMDebug, stopEmulatorTracing, "()V"),
353   NATIVE_METHOD(VMDebug, stopInstructionCounting, "()V"),
354   NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
355   NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "!()J"),
356 };
357 
register_dalvik_system_VMDebug(JNIEnv * env)358 void register_dalvik_system_VMDebug(JNIEnv* env) {
359   REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
360 }
361 
362 }  // namespace art
363