Home | History | Annotate | Download | only in native
      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