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