/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * dalvik.system.VMStack */ #include "Dalvik.h" #include "native/InternalNativePriv.h" /* * public static ClassLoader getCallingClassLoader() * * Return the defining class loader of the caller's caller. */ static void Dalvik_dalvik_system_VMStack_getCallingClassLoader(const u4* args, JValue* pResult) { ClassObject* clazz = dvmGetCaller2Class(dvmThreadSelf()->curFrame); UNUSED_PARAMETER(args); if (clazz == NULL) RETURN_PTR(NULL); RETURN_PTR(clazz->classLoader); } /* * public static ClassLoader getCallingClassLoader2() * * Return the defining class loader of the caller's caller's caller. */ static void Dalvik_dalvik_system_VMStack_getCallingClassLoader2(const u4* args, JValue* pResult) { ClassObject* clazz = dvmGetCaller3Class(dvmThreadSelf()->curFrame); UNUSED_PARAMETER(args); if (clazz == NULL) RETURN_PTR(NULL); RETURN_PTR(clazz->classLoader); } /* * public static Class[] getClasses(int maxDepth, boolean stopAtPrivileged) * * Create an array of classes for the methods on the stack, skipping the * first two and all reflection methods. If "stopAtPrivileged" is set, * stop shortly after we encounter a privileged class. */ static void Dalvik_dalvik_system_VMStack_getClasses(const u4* args, JValue* pResult) { /* note "maxSize" is unsigned, so -1 turns into a very large value */ unsigned int maxSize = args[0]; bool stopAtPrivileged = args[1]; unsigned int size = 0; const unsigned int kSkip = 2; const Method** methods = NULL; int methodCount; /* * Get an array with the stack trace in it. */ if (!dvmCreateStackTraceArray(dvmThreadSelf()->curFrame, &methods, &methodCount)) { LOGE("Failed to create stack trace array\n"); dvmThrowException("Ljava/lang/InternalError;", NULL); RETURN_VOID(); } //int i; //LOGI("dvmCreateStackTraceArray results:\n"); //for (i = 0; i < methodCount; i++) { // LOGI(" %2d: %s.%s\n", // i, methods[i]->clazz->descriptor, methods[i]->name); //} /* * Run through the array and count up how many elements there are. */ unsigned int idx; for (idx = kSkip; (int) idx < methodCount && size < maxSize; idx++) { const Method* meth = methods[idx]; if (dvmIsReflectionMethod(meth)) continue; if (stopAtPrivileged && dvmIsPrivilegedMethod(meth)) { /* * We want the last element of the array to be the caller of * the privileged method, so we want to include the privileged * method and the next one. */ if (maxSize > size + 2) maxSize = size + 2; } size++; } /* * Create an array object to hold the classes. * TODO: can use gDvm.classJavaLangClassArray here? */ ClassObject* classArrayClass = NULL; ArrayObject* classes = NULL; classArrayClass = dvmFindArrayClass("[Ljava/lang/Class;", NULL); if (classArrayClass == NULL) { LOGW("Unable to find java.lang.Class array class\n"); goto bail; } classes = dvmAllocArray(classArrayClass, size, kObjectArrayRefWidth, ALLOC_DEFAULT); if (classes == NULL) { LOGW("Unable to allocate class array (%d elems)\n", size); goto bail; } /* * Fill in the array. */ ClassObject** objects = (ClassObject**) classes->contents; unsigned int sidx = 0; for (idx = kSkip; (int) idx < methodCount && sidx < size; idx++) { const Method* meth = methods[idx]; if (dvmIsReflectionMethod(meth)) continue; *objects++ = meth->clazz; sidx++; } bail: free(methods); dvmReleaseTrackedAlloc((Object*) classes, NULL); RETURN_PTR(classes); } /* * public static StackTraceElement[] getThreadStackTrace(Thread t) * * Retrieve the stack trace of the specified thread and return it as an * array of StackTraceElement. Returns NULL on failure. */ static void Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4* args, JValue* pResult) { Object* targetThreadObj = (Object*) args[0]; Thread* self = dvmThreadSelf(); Thread* thread; int* traceBuf; assert(targetThreadObj != NULL); dvmLockThreadList(self); /* * Make sure the thread is still alive and in the list. */ for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { if (thread->threadObj == targetThreadObj) break; } if (thread == NULL) { LOGI("VMStack.getThreadStackTrace: threadObj %p not active\n", targetThreadObj); dvmUnlockThreadList(); RETURN_PTR(NULL); } /* * Suspend the thread, pull out the stack trace, then resume the thread * and release the thread list lock. If we're being asked to examine * our own stack trace, skip the suspend/resume. */ int stackDepth = -1; if (thread != self) dvmSuspendThread(thread); traceBuf = dvmFillInStackTraceRaw(thread, &stackDepth); if (thread != self) dvmResumeThread(thread); dvmUnlockThreadList(); /* * Convert the raw buffer into an array of StackTraceElement. */ ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth); free(traceBuf); RETURN_PTR(trace); } const DalvikNativeMethod dvm_dalvik_system_VMStack[] = { { "getCallingClassLoader", "()Ljava/lang/ClassLoader;", Dalvik_dalvik_system_VMStack_getCallingClassLoader }, { "getCallingClassLoader2", "()Ljava/lang/ClassLoader;", Dalvik_dalvik_system_VMStack_getCallingClassLoader2 }, { "getClasses", "(IZ)[Ljava/lang/Class;", Dalvik_dalvik_system_VMStack_getClasses }, { "getThreadStackTrace", "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;", Dalvik_dalvik_system_VMStack_getThreadStackTrace }, { NULL, NULL, NULL }, };