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