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 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 62 static void VMDebug_startAllocCounting(JNIEnv*, jclass) { 63 Runtime::Current()->SetStatsEnabled(true); 64 } 65 66 static void VMDebug_stopAllocCounting(JNIEnv*, jclass) { 67 Runtime::Current()->SetStatsEnabled(false); 68 } 69 70 static jint VMDebug_getAllocCount(JNIEnv*, jclass, jint kind) { 71 return Runtime::Current()->GetStat(kind); 72 } 73 74 static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) { 75 Runtime::Current()->ResetStats(kinds); 76 } 77 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 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 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 117 static jint VMDebug_getMethodTracingMode(JNIEnv*, jclass) { 118 return Trace::GetMethodTracingMode(); 119 } 120 121 static void VMDebug_stopMethodTracing(JNIEnv*, jclass) { 122 Trace::Stop(); 123 } 124 125 static void VMDebug_startEmulatorTracing(JNIEnv*, jclass) { 126 UNIMPLEMENTED(WARNING); 127 // dvmEmulatorTraceStart(); 128 } 129 130 static void VMDebug_stopEmulatorTracing(JNIEnv*, jclass) { 131 UNIMPLEMENTED(WARNING); 132 // dvmEmulatorTraceStop(); 133 } 134 135 static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) { 136 return Dbg::IsDebuggerActive(); 137 } 138 139 static jboolean VMDebug_isDebuggingEnabled(JNIEnv*, jclass) { 140 return Dbg::IsJdwpConfigured(); 141 } 142 143 static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) { 144 return Dbg::LastDebuggerActivity(); 145 } 146 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 153 static void VMDebug_startInstructionCounting(JNIEnv* env, jclass) { 154 ThrowUnsupportedOperationException(env); 155 } 156 157 static void VMDebug_stopInstructionCounting(JNIEnv* env, jclass) { 158 ThrowUnsupportedOperationException(env); 159 } 160 161 static void VMDebug_getInstructionCount(JNIEnv* env, jclass, jintArray /*javaCounts*/) { 162 ThrowUnsupportedOperationException(env); 163 } 164 165 static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) { 166 ThrowUnsupportedOperationException(env); 167 } 168 169 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) { 170 ScopedFastNativeObjectAccess soa(env); 171 return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags); 172 } 173 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 */ 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 */ 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 225 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) { 226 hprof::DumpHeap("[DDMS]", -1, true); 227 } 228 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 239 static void VMDebug_crash(JNIEnv*, jclass) { 240 LOG(FATAL) << "Crashing runtime on request"; 241 } 242 243 static void VMDebug_infopoint(JNIEnv*, jclass, jint id) { 244 LOG(INFO) << "VMDebug infopoint " << id << " hit"; 245 } 246 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. 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 358 void register_dalvik_system_VMDebug(JNIEnv* env) { 359 REGISTER_NATIVE_METHODS("dalvik/system/VMDebug"); 360 } 361 362 } // namespace art 363