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 /*
     18  * dalvik.system.VMStack
     19  */
     20 #include "Dalvik.h"
     21 #include "UniquePtr.h"
     22 #include "native/InternalNativePriv.h"
     23 
     24 /*
     25  * public static ClassLoader getCallingClassLoader()
     26  *
     27  * Return the defining class loader of the caller's caller.
     28  */
     29 static void Dalvik_dalvik_system_VMStack_getCallingClassLoader(const u4* args,
     30     JValue* pResult)
     31 {
     32     ClassObject* clazz =
     33         dvmGetCaller2Class(dvmThreadSelf()->interpSave.curFrame);
     34 
     35     UNUSED_PARAMETER(args);
     36 
     37     if (clazz == NULL)
     38         RETURN_PTR(NULL);
     39     RETURN_PTR(clazz->classLoader);
     40 }
     41 
     42 /*
     43  * public static Class<?> getStackClass2()
     44  *
     45  * Returns the class of the caller's caller's caller.
     46  */
     47 static void Dalvik_dalvik_system_VMStack_getStackClass2(const u4* args,
     48     JValue* pResult)
     49 {
     50     ClassObject* clazz =
     51         dvmGetCaller3Class(dvmThreadSelf()->interpSave.curFrame);
     52 
     53     UNUSED_PARAMETER(args);
     54 
     55     RETURN_PTR(clazz);
     56 }
     57 
     58 /*
     59  * public static Class<?>[] getClasses(int maxDepth)
     60  *
     61  * Create an array of classes for the methods on the stack, skipping the
     62  * first two and all reflection methods.  If "stopAtPrivileged" is set,
     63  * stop shortly after we encounter a privileged class.
     64  */
     65 static void Dalvik_dalvik_system_VMStack_getClasses(const u4* args,
     66     JValue* pResult)
     67 {
     68     /* note "maxSize" is unsigned, so -1 turns into a very large value */
     69     size_t maxSize = args[0];
     70     size_t size = 0;
     71     const size_t kSkip = 2;
     72 
     73     /*
     74      * Get an array with the stack trace in it.
     75      */
     76     void *fp = dvmThreadSelf()->interpSave.curFrame;
     77     size_t depth = dvmComputeExactFrameDepth(fp);
     78     UniquePtr<const Method*[]> methods(new const Method*[depth]);
     79     dvmFillStackTraceArray(fp, methods.get(), depth);
     80 
     81     /*
     82      * Run through the array and count up how many elements there are.
     83      */
     84     for (size_t i = kSkip; i < depth && size < maxSize; ++i) {
     85         const Method* meth = methods[i];
     86 
     87         if (dvmIsReflectionMethod(meth))
     88             continue;
     89 
     90         size++;
     91     }
     92 
     93     /*
     94      * Create an array object to hold the classes.
     95      * TODO: can use gDvm.classJavaLangClassArray here?
     96      */
     97     ClassObject* classArrayClass = dvmFindArrayClass("[Ljava/lang/Class;",
     98                                                      NULL);
     99     if (classArrayClass == NULL) {
    100         ALOGW("Unable to find java.lang.Class array class");
    101         return;
    102     }
    103     ArrayObject* classes = dvmAllocArrayByClass(classArrayClass,
    104                                                 size,
    105                                                 ALLOC_DEFAULT);
    106     if (classes == NULL) {
    107         ALOGW("Unable to allocate class array of %zd elements", size);
    108         return;
    109     }
    110 
    111     /*
    112      * Fill in the array.
    113      */
    114     size_t objCount = 0;
    115     for (size_t i = kSkip; i < depth; ++i) {
    116         if (dvmIsReflectionMethod(methods[i])) {
    117             continue;
    118         }
    119         Object* klass = (Object *)methods[i]->clazz;
    120         dvmSetObjectArrayElement(classes, objCount, klass);
    121         objCount++;
    122     }
    123     assert(objCount == classes->length);
    124 
    125     dvmReleaseTrackedAlloc((Object*)classes, NULL);
    126     RETURN_PTR(classes);
    127 }
    128 
    129 /*
    130  * Return a trace buffer for the specified thread or NULL if the
    131  * thread is not still alive. *depth is set to the length of a
    132  * non-NULL trace buffer. Caller is responsible for freeing the trace
    133  * buffer.
    134  */
    135 static int* getTraceBuf(Object* targetThreadObj, size_t* pStackDepth)
    136 {
    137     Thread* self = dvmThreadSelf();
    138     Thread* thread;
    139     int* traceBuf;
    140 
    141     assert(targetThreadObj != NULL);
    142 
    143     dvmLockThreadList(self);
    144 
    145     /*
    146      * Make sure the thread is still alive and in the list.
    147      */
    148     for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
    149         if (thread->threadObj == targetThreadObj)
    150             break;
    151     }
    152     if (thread == NULL) {
    153         ALOGI("VMStack.getTraceBuf: threadObj %p not active",
    154             targetThreadObj);
    155         dvmUnlockThreadList();
    156         return NULL;
    157     }
    158 
    159     /*
    160      * Suspend the thread, pull out the stack trace, then resume the thread
    161      * and release the thread list lock.  If we're being asked to examine
    162      * our own stack trace, skip the suspend/resume.
    163      */
    164     if (thread != self)
    165         dvmSuspendThread(thread);
    166     traceBuf = dvmFillInStackTraceRaw(thread, pStackDepth);
    167     if (thread != self)
    168         dvmResumeThread(thread);
    169     dvmUnlockThreadList();
    170 
    171     return traceBuf;
    172 }
    173 
    174 /*
    175  * public static StackTraceElement[] getThreadStackTrace(Thread t)
    176  *
    177  * Retrieve the stack trace of the specified thread and return it as an
    178  * array of StackTraceElement.  Returns NULL on failure.
    179  */
    180 static void Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4* args,
    181     JValue* pResult)
    182 {
    183     Object* targetThreadObj = (Object*) args[0];
    184     size_t stackDepth;
    185     int* traceBuf = getTraceBuf(targetThreadObj, &stackDepth);
    186 
    187     if (traceBuf == NULL)
    188         RETURN_PTR(NULL);
    189 
    190     /*
    191      * Convert the raw buffer into an array of StackTraceElement.
    192      */
    193     ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth);
    194     free(traceBuf);
    195     RETURN_PTR(trace);
    196 }
    197 
    198 /*
    199  * public static int fillStackTraceElements(Thread t, StackTraceElement[] stackTraceElements)
    200  *
    201  * Retrieve a partial stack trace of the specified thread and return
    202  * the number of frames filled.  Returns 0 on failure.
    203  */
    204 static void Dalvik_dalvik_system_VMStack_fillStackTraceElements(const u4* args,
    205     JValue* pResult)
    206 {
    207     Object* targetThreadObj = (Object*) args[0];
    208     ArrayObject* steArray = (ArrayObject*) args[1];
    209     size_t stackDepth;
    210     int* traceBuf = getTraceBuf(targetThreadObj, &stackDepth);
    211 
    212     if (traceBuf == NULL)
    213         RETURN_PTR(NULL);
    214 
    215     /*
    216      * Set the raw buffer into an array of StackTraceElement.
    217      */
    218     if (stackDepth > steArray->length) {
    219         stackDepth = steArray->length;
    220     }
    221     dvmFillStackTraceElements(traceBuf, stackDepth, steArray);
    222     free(traceBuf);
    223     RETURN_INT(stackDepth);
    224 }
    225 
    226 const DalvikNativeMethod dvm_dalvik_system_VMStack[] = {
    227     { "getCallingClassLoader",  "()Ljava/lang/ClassLoader;",
    228         Dalvik_dalvik_system_VMStack_getCallingClassLoader },
    229     { "getStackClass2",         "()Ljava/lang/Class;",
    230         Dalvik_dalvik_system_VMStack_getStackClass2 },
    231     { "getClasses",             "(I)[Ljava/lang/Class;",
    232         Dalvik_dalvik_system_VMStack_getClasses },
    233     { "getThreadStackTrace",    "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;",
    234         Dalvik_dalvik_system_VMStack_getThreadStackTrace },
    235     { "fillStackTraceElements", "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I",
    236         Dalvik_dalvik_system_VMStack_fillStackTraceElements },
    237     { NULL, NULL, NULL },
    238 };
    239