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/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