How dvm calls native method
来源:互联网 发布:帝国网站分类目录源码 编辑:程序博客网 时间:2024/05/15 07:33
http://blog.csdn.net/zirconsdu/article/details/8954887
1 ***********************************************************************************************************************************
We dig more about the native method call processing flow of dvm with source code.
When a transmit from java to native occurs, dvm sets up a native stack.
In dvmCallJNIMethod(), dvmPlatformInvoke is used to call the native method(signature in Method.insns).
- 1181 dvmPlatformInvoke(env,
- 1182 (ClassObject*) staticMethodClass,
- 1183 method->jniArgInfo, method->insSize, modArgs, method->shorty,
- 1184 (void*) method->insns, pResult);
(gdb) disass dvmPlatformInvoke
Dump of assembler code for function dvmPlatformInvoke:
0x40c8b2c0 <+0>: push {r6, r7, r8, r9, r11, lr}
0x40c8b2c4 <+4>: add r11, sp, #20
0x40c8b2c8 <+8>: ldr r9, [r11, #4]
0x40c8b2cc <+12>: cmp r1, #0
0x40c8b2d0 <+16>: subeq r3, r3, #1
0x40c8b2d4 <+20>: ldreq r1, [r9], #4
0x40c8b2d8 <+24>: teq r2, #0
0x40c8b2dc <+28>: bmi 0x40c8b348 <dvmPlatformInvoke+136>
0x40c8b2e0 <+32>: and r12, r2, #251658240 ; 0xf000000
0x40c8b2e4 <+36>: lsr r6, r2, #28
0x40c8b2e8 <+40>: sub sp, sp, r12, lsr #21
0x40c8b2ec <+44>: mov r8, sp
0x40c8b2f0 <+48>: mov r7, r9
0x40c8b2f4 <+52>: lsrs r2, r2, #2
0x40c8b2f8 <+56>: addcc r7, r7, #8
0x40c8b2fc <+60>: subcc r3, r3, #2
0x40c8b300 <+64>: addcs r7, r7, #4
0x40c8b304 <+68>: subcs r3, r3, #1
0x40c8b308 <+72>: subs r3, r3, #1
0x40c8b30c <+76>: bmi 0x40c8b328 <dvmPlatformInvoke+104>
0x40c8b310 <+80>: lsrs r2, r2, #1
0x40c8b314 <+84>: ldrcc r12, [r7], #4
0x40c8b318 <+88>: strcc r12, [r8], #4
0x40c8b31c <+92>: bcc 0x40c8b308 <dvmPlatformInvoke+72>
0x40c8b320 <+96>: add r8, r8, #4
0x40c8b324 <+100>: b 0x40c8b310 <dvmPlatformInvoke+80>
0x40c8b328 <+104>: ldm r9, {r2, r3}
0x40c8b32c <+108>: ldr r12, [r11, #12]
0x40c8b330 <+112>: blx r12
=> 0x40c8b334 <+116>: cmp r6, #0
dvmPlatformInvoke() @ CallEABI.S
- 37Function prototype:
- 38
- 39void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
- 40 const u4* argv, const char* signature, void* func, JValue* pReturn)
- 88 * On entry:
- 89 * r0 JNIEnv (can be left alone)
- 90 * r1 clazz (NULL for virtual method calls, non-NULL for static)
- 91 * r2 arg info
- 92 * r3 argc (number of 32-bit values in argv)
- 93 * [sp] argv
- 94 * [sp,#4] short signature
- 95 * [sp,#8] func
- 96 * [sp,#12] pReturn
- 134 * stack looks like:
- 135 *
- 136 * pReturn
- 137 * func
- 138 * shorty
- 139 * argv <-- sp on entry
- 140 * lr <-- fp
- 141 * fp
- 142 * r9...r7
- 143 * r6 <-- sp after reg save
- 236.Lcopy_done:
- 237 /*
- 238 * Currently:
- 239 * r0-r3 args (JNIEnv*, thisOrClass, arg0, arg1)
- 240 * r6 return type (enum DalvikJniReturnType)
- 241 * r9 original argv
- 242 * fp frame pointer
- 243 *
- 244 * The stack copy is complete. Grab the first two words off of argv
- 245 * and tuck them into r2/r3. If the first arg is 32-bit and the second
- 246 * arg is 64-bit, then r3 "holds" a pad word and the load is unnecessary
- 247 * but harmless.
- 248 *
- 249 * If there are 0 or 1 arg words in argv, we will be loading uninitialized
- 250 * data into the registers, but since nothing tries to use it it's also
- 251 * harmless (assuming argv[0] and argv[1] point to valid memory, which
- 252 * is a reasonable assumption for Dalvik's interpreted stacks).
- 253 */
- 254 ldmia r9, {r2-r3} @ r2/r3<- argv[0]/argv[1]
- 255
- 256 ldr ip, [fp, #8+FP_ADJ] @ ip<- func
- 257#ifdef __ARM_HAVE_BLX
- 258 blx ip @ call func ******* call the jni function ********
- 259#else
- 260 mov lr, pc @ call func the old-fashioned way
- 261 bx ip
- 262#endif
The args for jni function are passed in args[1-(argc-1)].
agrs[0] is the java object on which to call the method, it is use to refer object and lock object if the method is synchronized.
dalvik_mterp () at dalvik/vm/mterp/out/InterpAsm-armv7-a-neon.S
(gdb) disass dalvik_mterp
Dump of assembler code for function dalvik_mterp:
0x40c947cc <+0>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x40c947d0 <+4>: sub sp, sp, #4
0x40c947d4 <+8>: cmp lr, #0
0x40c947d8 <+12>: bne 0x40c94808 <dalvik_mterp+60>
0x40c947dc <+16>: mov lr, pc
0x40c947e0 <+20>: ldr pc, [r2, #40] ; 0x28 ** call dvmCallJNIMethod
=> 0x40c947e4 <+24>: ldr r0, [r10, #12]
called in <-----------
dvmInterpret(Thread*, Method const*, JValue*) @ dalvik/vm/interp/Interp.cpp:1964
On initilizing....... meth->nativeFunc and meth->jniArgInfo are assigned with dvmResolveNativeMethod and computeJniArgInfo(&meth->prototype) separately.
After name resolved via dvmResolveNativeMethod, meth->nativeFunc is assigned with new MethodCallBridge dvmCallJNIMethod.
So, only resolve once for one native method.
- 2150 * Pull the interesting pieces out of a DexMethod.
- 2151 *
- 2152 * The DEX file isn't going anywhere, so we don't need to make copies of
- 2153 * the code area.
- 2154 */
- 2155static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod, @ dalvik/vm/oo/Class.cpp
- 2156 Method* meth)
- 2157{
- 2158 DexFile* pDexFile = clazz->pDvmDex->pDexFile;
- 2159 const DexMethodId* pMethodId;
- 2160 const DexCode* pDexCode;
- 2161
- 2162 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- 2163
- 2164 meth->name = dexStringById(pDexFile, pMethodId->nameIdx);
- 2165 dexProtoSetFromMethodId(&meth->prototype, pDexFile, pMethodId);
- 2166 meth->shorty = dexProtoGetShorty(&meth->prototype);
- 2167 meth->accessFlags = pDexMethod->accessFlags;
- 2168 meth->clazz = clazz;
- 2169 meth->jniArgInfo = 0;
- 2170
- 2171 if (dvmCompareNameDescriptorAndMethod("finalize", "()V", meth) == 0) {
- 2172 /*
- 2173 * The Enum class declares a "final" finalize() method to
- 2174 * prevent subclasses from introducing a finalizer. We don't
- 2175 * want to set the finalizable flag for Enum or its subclasses,
- 2176 * so we check for it here.
- 2177 *
- 2178 * We also want to avoid setting it on Object, but it's easier
- 2179 * to just strip that out later.
- 2180 */
- 2181 if (clazz->classLoader != NULL ||
- 2182 strcmp(clazz->descriptor, "Ljava/lang/Enum;") != 0)
- 2183 {
- 2184 SET_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
- 2185 }
- 2186 }
- 2187
- 2188 pDexCode = dexGetCode(pDexFile, pDexMethod);
- 2189 if (pDexCode != NULL) {
- 2190 /* integer constants, copy over for faster access */
- 2191 meth->registersSize = pDexCode->registersSize;
- 2192 meth->insSize = pDexCode->insSize;
- 2193 meth->outsSize = pDexCode->outsSize;
- 2194
- 2195 /* pointer to code area */
- 2196 meth->insns = pDexCode->insns;
- 2197 } else {
- 2198 /*
- 2199 * We don't have a DexCode block, but we still want to know how
- 2200 * much space is needed for the arguments (so we don't have to
- 2201 * compute it later). We also take this opportunity to compute
- 2202 * JNI argument info.
- 2203 *
- 2204 * We do this for abstract methods as well, because we want to
- 2205 * be able to substitute our exception-throwing "stub" in.
- 2206 */
- 2207 int argsSize = dvmComputeMethodArgsSize(meth);
- 2208 if (!dvmIsStaticMethod(meth))
- 2209 argsSize++;
- 2210 meth->registersSize = meth->insSize = argsSize;
- 2211 assert(meth->outsSize == 0);
- 2212 assert(meth->insns == NULL);
- 2213
- 2214 if (dvmIsNativeMethod(meth)) { *****************
- 2215 meth->nativeFunc = dvmResolveNativeMethod; *****************
- 2216 meth->jniArgInfo = computeJniArgInfo(&meth->prototype); *****************
- 2217 }
- 2218 }
- 2219}
On running, dvmCallMethodV is used to transfer execution from java to native.
- /*
- 434 * Issue a method call with a variable number of arguments. We process
- 435 * the contents of "args" by scanning the method signature.
- 436 *
- 437 * Pass in NULL for "obj" on calls to static methods.
- 438 *
- 439 * We don't need to take the class as an argument because, in Dalvik,
- 440 * we don't need to worry about static synchronized methods.
- 441 */
- 442void dvmCallMethodV(Thread* self, const Method* method, Object* obj, @ dalvik/vm/interp/Stack.cpp
- 443 bool fromJni, JValue* pResult, va_list args)
- 444{
- 445 const char* desc = &(method->shorty[1]); // [0] is the return type.
- 446 int verifyCount = 0;
- 447 ClassObject* clazz;
- 448 u4* ins;
- 449
- 450 clazz = callPrep(self, method, obj, false);
- 451 if (clazz == NULL)
- 452 return;
- 453
- 454 /* "ins" for new frame start at frame pointer plus locals */
- 455 ins = ((u4*)self->interpSave.curFrame) +
- 456 (method->registersSize - method->insSize);
- 457
- 458 //ALOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
- 459
- 460 /* put "this" pointer into in0 if appropriate */
- 461 if (!dvmIsStaticMethod(method)) {
- 462#ifdef WITH_EXTRA_OBJECT_VALIDATION
- 463 assert(obj != NULL && dvmIsHeapAddress(obj));
- 464#endif
- 465 *ins++ = (u4) obj;
- 466 verifyCount++;
- 467 }
- 468
- 469 while (*desc != '\0') {
- 470 switch (*(desc++)) {
- 471 case 'D': case 'J': {
- 472 u8 val = va_arg(args, u8);
- 473 memcpy(ins, &val, 8); // EABI prevents direct store
- 474 ins += 2;
- 475 verifyCount += 2;
- 476 break;
- 477 }
- 478 case 'F': {
- 479 /* floats were normalized to doubles; convert back */
- 480 float f = (float) va_arg(args, double);
- 481 *ins++ = dvmFloatToU4(f);
- 482 verifyCount++;
- 483 break;
- 484 }
- 485 case 'L': { /* 'shorty' descr uses L for all refs, incl array */
- 486 void* arg = va_arg(args, void*);
- 487 assert(obj == NULL || dvmIsHeapAddress(obj));
- 488 jobject argObj = reinterpret_cast<jobject>(arg);
- 489 if (fromJni)
- 490 *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
- 491 else
- 492 *ins++ = (u4) argObj;
- 493 verifyCount++;
- 494 break;
- 495 }
- 496 default: {
- 497 /* Z B C S I -- all passed as 32-bit integers */
- 498 *ins++ = va_arg(args, u4);
- 499 verifyCount++;
- 500 break;
- 501 }
- 502 }
- 503 }
- 504
- 505#ifndef NDEBUG
- 506 if (verifyCount != method->insSize) {
- 507 ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
- 508 method->insSize, clazz->descriptor, method->name);
- 509 assert(false);
- 510 goto bail;
- 511 }
- 512#endif
- 513
- 514 //dvmDumpThreadStack(dvmThreadSelf());
- 515
- 516 if (dvmIsNativeMethod(method)) { ***************
- 517 TRACE_METHOD_ENTER(self, method);
- 518 /*
- 519 * Because we leave no space for local variables, "curFrame" points
- 520 * directly at the method arguments.
- 521 */
- 522 (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, ***************
- 523 method, self);
- 524 TRACE_METHOD_EXIT(self, method);
- 525 } else {
- 526 dvmInterpret(self, method, pResult); ***************
- 527 }
- 528
- 529#ifndef NDEBUG
- 530bail:
- 531#endif
- 532 dvmPopFrame(self);
- 533}
Like dynamic symbol resolve, resolver function as native function slot entry.resolve once!!!
- 70void dvmResolveNativeMethod(const u4* args, JValue* pResult,
- 71 const Method* method, Thread* self)
- 72{
- 73 ClassObject* clazz = method->clazz;
- 74
- 75 /*
- 76 * If this is a static method, it could be called before the class
- 77 * has been initialized.
- 78 */
- 79 if (dvmIsStaticMethod(method)) {
- 80 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
- 81 assert(dvmCheckException(dvmThreadSelf()));
- 82 return;
- 83 }
- 84 } else {
- 85 assert(dvmIsClassInitialized(clazz) ||
- 86 dvmIsClassInitializing(clazz));
- 87 }
- 88
- 89 /* start with our internal-native methods */
- 90 DalvikNativeFunc infunc = dvmLookupInternalNativeMethod(method);
- 91 if (infunc != NULL) {
- 92 /* resolution always gets the same answer, so no race here */
- 93 IF_LOGVV() {
- 94 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
- 95 LOGVV("+++ resolved native %s.%s %s, invoking",
- 96 clazz->descriptor, method->name, desc);
- 97 free(desc);
- 98 }
- 99 if (dvmIsSynchronizedMethod(method)) {
- 100 ALOGE("ERROR: internal-native can't be declared 'synchronized'");
- 101 ALOGE("Failing on %s.%s", method->clazz->descriptor, method->name);
- 102 dvmAbort(); // harsh, but this is VM-internal problem
- 103 }
- 104 DalvikBridgeFunc dfunc = (DalvikBridgeFunc) infunc;
- 105 dvmSetNativeFunc((Method*) method, dfunc, NULL); ********************
- 106 dfunc(args, pResult, method, self);
- 107 return;
- 108 }
- 109
- 110 /* now scan any DLLs we have loaded for JNI signatures */
- 111 void* func = lookupSharedLibMethod(method);
- 112 if (func != NULL) {
- 113 /* found it, point it at the JNI bridge and then call it */
- 114 dvmUseJNIBridge((Method*) method, func); ********************
- 115 (*method->nativeFunc)(args, pResult, method, self);
- 116 return;
- 117 }
- 118
- 119 IF_ALOGW() {
- 120 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
- 121 ALOGW("No implementation found for native %s.%s:%s",
- 122 clazz->descriptor, method->name, desc);
- 123 free(desc);
- 124 }
- 125
- 126 dvmThrowUnsatisfiedLinkError("Native method not found", method);
- 127}
- 827/*
- 828 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
- 829 * to point at the actual function.
- 830 */
- 831void dvmUseJNIBridge(Method* method, void* func) {
- 832 method->shouldTrace = shouldTrace(method);
- 833
- 834 // Does the method take any reference arguments?
- 835 method->noRef = true;
- 836 const char* cp = method->shorty;
- 837 while (*++cp != '\0') { // Pre-increment to skip return type.
- 838 if (*cp == 'L') {
- 839 method->noRef = false;
- 840 break;
- 841 }
- 842 }
- 843
- 844 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
- 845 dvmSetNativeFunc(method, bridge, (const u2*) func);
- 846}
- /*
- 4532 * Replace method->nativeFunc and method->insns with new values. This is
- 4533 * commonly performed after successful resolution of a native method.
- 4534 *
- 4535 * There are three basic states:
- 4536 * (1) (initial) nativeFunc = dvmResolveNativeMethod, insns = NULL
- 4537 * (2) (internal native) nativeFunc = <impl>, insns = NULL
- 4538 * (3) (JNI) nativeFunc = JNI call bridge, insns = <impl>
- 4539 *
- 4540 * nativeFunc must never be NULL for a native method.
- 4541 *
- 4542 * The most common transitions are (1)->(2) and (1)->(3). The former is
- 4543 * atomic, since only one field is updated; the latter is not, but since
- 4544 * dvmResolveNativeMethod ignores the "insns" field we just need to make
- 4545 * sure the update happens in the correct order.
- 4546 *
- 4547 * A transition from (2)->(1) would work fine, but (3)->(1) will not,
- 4548 * because both fields change. If we did this while a thread was executing
- 4549 * in the call bridge, we could null out the "insns" field right before
- 4550 * the bridge tried to call through it. So, once "insns" is set, we do
- 4551 * not allow it to be cleared. A NULL value for the "insns" argument is
- 4552 * treated as "do not change existing value".
- 4553 */
- 4554void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func,
- 4555 const u2* insns)
- 4556{
- 4557 ClassObject* clazz = method->clazz;
- 4558
- 4559 assert(func != NULL);
- 4560
- 4561 /* just open up both; easier that way */
- 4562 dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
- 4563 dvmLinearReadWrite(clazz->classLoader, clazz->directMethods);
- 4564
- 4565 if (insns != NULL) {
- 4566 /* update both, ensuring that "insns" is observed first */
- 4567 method->insns = insns;
- 4568 android_atomic_release_store((int32_t) func,
- 4569 (volatile int32_t*)(void*) &method->nativeFunc);
- 4570 } else {
- 4571 /* only update nativeFunc */
- 4572 method->nativeFunc = func;
- 4573 }
- 4574
- 4575 dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
- 4576 dvmLinearReadOnly(clazz->classLoader, clazz->directMethods);
- 4577}
- /*
- 1117 * General form, handles all cases.
- 1118 */
- 1119void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
- 1120 u4* modArgs = (u4*) args;
- 1121 jclass staticMethodClass = NULL;
- 1122
- 1123 u4 accessFlags = method->accessFlags;
- 1124 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
- 1125
- 1126 //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,
- 1127 // method->clazz->descriptor, method->name, method->shorty);
- 1128
- 1129 /*
- 1130 * Walk the argument list, creating local references for appropriate
- 1131 * arguments.
- 1132 */
- 1133 int idx = 0;
- 1134 Object* lockObj;
- 1135 if ((accessFlags & ACC_STATIC) != 0) {
- 1136 lockObj = (Object*) method->clazz;
- 1137 /* add the class object we pass in */
- 1138 staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
- 1139 } else {
- 1140 lockObj = (Object*) args[0];
- 1141 /* add "this" */
- 1142 modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
- 1143 }
- 1144
- 1145 if (!method->noRef) {
- 1146 const char* shorty = &method->shorty[1]; /* skip return type */
- 1147 while (*shorty != '\0') {
- 1148 switch (*shorty++) {
- 1149 case 'L':
- 1150 //ALOGI(" local %d: 0x%08x", idx, modArgs[idx]);
- 1151 if (modArgs[idx] != 0) {
- 1152 modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
- 1153 }
- 1154 break;
- 1155 case 'D':
- 1156 case 'J':
- 1157 idx++;
- 1158 break;
- 1159 default:
- 1160 /* Z B C S I -- do nothing */
- 1161 break;
- 1162 }
- 1163 idx++;
- 1164 }
- 1165 }
- 1166
- 1167 if (UNLIKELY(method->shouldTrace)) {
- 1168 logNativeMethodEntry(method, args);
- 1169 }
- 1170 if (UNLIKELY(isSynchronized)) {
- 1171 dvmLockObject(self, lockObj);
- 1172 }
- 1173
- 1174 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
- 1175
- 1176 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
- 1177 assert(method->insns != NULL);
- 1178
- 1179 JNIEnv* env = self->jniEnv;
- 1180 COMPUTE_STACK_SUM(self);
- 1181 dvmPlatformInvoke(env,
- 1182 (ClassObject*) staticMethodClass,
- 1183 method->jniArgInfo, method->insSize, modArgs, method->shorty,
- 1184 (void*) method->insns, pResult);
- 1185 CHECK_STACK_SUM(self);
- 1186
- 1187 dvmChangeStatus(self, oldStatus);
- 1188
- 1189 convertReferenceResult(env, pResult, method, self);
- 1190
- 1191 if (UNLIKELY(isSynchronized)) {
- 1192 dvmUnlockObject(self, lockObj);
- 1193 }
- 1194 if (UNLIKELY(method->shouldTrace)) {
- 1195 logNativeMethodExit(method, self, *pResult);
- 1196 }
- 1197}
======================================================================================
2 **********************************************************************************************************************
More things about reflect invoke. This is to invoke 'main' in the case.
We dig more to get a view of the start of an activity via logcat.
- 506 public Object invoke(Object receiver, Object... args) @ libcore/luni/src/main/java/java/lang/reflect/Method.java
- 507 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- 508 if (args == null) {
- 509 args = EmptyArray.OBJECT;
- 510 }
- 511 return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);
- 512 }
- 41/*
- 42 * private Object invokeNative(Object obj, Object[] args, Class declaringClass,
- 43 * Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck)
- 44 *
- 45 * Invoke a static or virtual method via reflection.
- 46 */
- 47static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,
- 48 JValue* pResult)
- 49{
- 50 // ignore thisPtr in args[0]
- 51 Object* methObj = (Object*) args[1]; // null for static methods
- 52 ArrayObject* argList = (ArrayObject*) args[2];
- 53 ClassObject* declaringClass = (ClassObject*) args[3];
- 54 ArrayObject* params = (ArrayObject*) args[4];
- 55 ClassObject* returnType = (ClassObject*) args[5];
- 56 int slot = args[6];
- 57 bool noAccessCheck = (args[7] != 0);
- 58 const Method* meth;
- 59 Object* result;
- 60
- 61 /*
- 62 * "If the underlying method is static, the class that declared the
- 63 * method is initialized if it has not already been initialized."
- 64 */
- 65 meth = dvmSlotToMethod(declaringClass, slot);
- 66 assert(meth != NULL);
- 67
- 68 if (dvmIsStaticMethod(meth)) {
- 69 if (!dvmIsClassInitialized(declaringClass)) {
- 70 if (!dvmInitClass(declaringClass))
- 71 goto init_failed;
- 72 }
- 73 } else {
- 74 /* looks like interfaces need this too? */
- 75 if (dvmIsInterfaceClass(declaringClass) &&
- 76 !dvmIsClassInitialized(declaringClass))
- 77 {
- 78 if (!dvmInitClass(declaringClass))
- 79 goto init_failed;
- 80 }
- 81
- 82 /* make sure the object is an instance of the expected class */
- 83 if (!dvmVerifyObjectInClass(methObj, declaringClass)) {
- 84 assert(dvmCheckException(dvmThreadSelf()));
- 85 RETURN_VOID();
- 86 }
- 87
- 88 /* do the virtual table lookup for the method */
- 89 meth = dvmGetVirtualizedMethod(methObj->clazz, meth);
- 90 if (meth == NULL) {
- 91 assert(dvmCheckException(dvmThreadSelf()));
- 92 RETURN_VOID();
- 93 }
- 94 }
- 95
- 96 /*
- 97 * If the method has a return value, "result" will be an object or
- 98 * a boxed primitive.
- 99 */
- 100 result = dvmInvokeMethod(methObj, meth, argList, params, returnType,
- 101 noAccessCheck);
- 102
- 103 RETURN_PTR(result);
- 104
- 105init_failed:
- 106 /*
- 107 * If initialization failed, an exception will be raised.
- 108 */
- 109 ALOGD("Method.invoke() on bad class %s failed",
- 110 declaringClass->descriptor);
- 111 assert(dvmCheckException(dvmThreadSelf()));
- 112 RETURN_VOID();
- 113}
- 645/*
- 646 * Invoke a method, using the specified arguments and return type, through
- 647 * one of the reflection interfaces. Could be a virtual or direct method
- 648 * (including constructors). Used for reflection.
- 649 *
- 650 * Deals with boxing/unboxing primitives and performs widening conversions.
- 651 *
- 652 * "invokeObj" will be null for a static method.
- 653 *
- 654 * If the invocation returns with an exception raised, we have to wrap it.
- 655 */
- 656Object* dvmInvokeMethod(Object* obj, const Method* method,
- 657 ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
- 658 bool noAccessCheck)
- 659{
- 660 ClassObject* clazz;
- 661 Object* retObj = NULL;
- 662 Thread* self = dvmThreadSelf();
- 663 s4* ins;
- 664 int verifyCount, argListLength;
- 665 JValue retval;
- 666 bool needPop = false;
- 667
- 668 /* verify arg count */
- 669 if (argList != NULL)
- 670 argListLength = argList->length;
- 671 else
- 672 argListLength = 0;
- 673 if (argListLength != (int) params->length) {
- 674 dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
- 675 "wrong number of arguments; expected %d, got %d",
- 676 params->length, argListLength);
- 677 return NULL;
- 678 }
- 679
- 680 clazz = callPrep(self, method, obj, !noAccessCheck);
- 681 if (clazz == NULL)
- 682 return NULL;
- 683 needPop = true;
- 684
- 685 /* "ins" for new frame start at frame pointer plus locals */
- 686 ins = ((s4*)self->interpSave.curFrame) +
- 687 (method->registersSize - method->insSize);
- 688 verifyCount = 0;
- 689
- 690 //ALOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
- 691
- 692 /* put "this" pointer into in0 if appropriate */
- 693 if (!dvmIsStaticMethod(method)) {
- 694 assert(obj != NULL);
- 695 *ins++ = (s4) obj;
- 696 verifyCount++;
- 697 }
- 698
- 699 /*
- 700 * Copy the args onto the stack. Primitive types are converted when
- 701 * necessary, and object types are verified.
- 702 */
- 703 DataObject** args = (DataObject**)(void*)argList->contents;
- 704 ClassObject** types = (ClassObject**)(void*)params->contents;
- 705 for (int i = 0; i < argListLength; i++) {
- 706 int width = dvmConvertArgument(*args++, *types++, ins);
- 707 if (width < 0) {
- 708 dvmPopFrame(self); // throw wants to pull PC out of stack
- 709 needPop = false;
- 710 throwArgumentTypeMismatch(i, *(types-1), *(args-1));
- 711 goto bail;
- 712 }
- 713
- 714 ins += width;
- 715 verifyCount += width;
- 716 }
- 717
- 718#ifndef NDEBUG
- 719 if (verifyCount != method->insSize) {
- 720 ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
- 721 method->insSize, clazz->descriptor, method->name);
- 722 assert(false);
- 723 goto bail;
- 724 }
- 725#endif
- 726
- 727 if (dvmIsNativeMethod(method)) { **********************
- 728 TRACE_METHOD_ENTER(self, method);
- 729 /*
- 730 * Because we leave no space for local variables, "curFrame" points
- 731 * directly at the method arguments.
- 732 */
- 733 (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval, **********************
- 734 method, self);
- 735 TRACE_METHOD_EXIT(self, method);
- 736 } else {
- 737 dvmInterpret(self, method, &retval); **********************
- 738 }
- 739
- 740 /*
- 741 * Pop the frame immediately. The "wrap" calls below can cause
- 742 * allocations, and we don't want the GC to walk the now-dead frame.
- 743 */
- 744 dvmPopFrame(self);
- 745 needPop = false;
- 746
- 747 /*
- 748 * If an exception is raised, wrap and replace. This is necessary
- 749 * because the invoked method could have thrown a checked exception
- 750 * that the caller wasn't prepared for.
- 751 *
- 752 * We might be able to do this up in the interpreted code, but that will
- 753 * leave us with a shortened stack trace in the top-level exception.
- 754 */
- 755 if (dvmCheckException(self)) {
- 756 dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
- 757 } else {
- 758 /*
- 759 * If this isn't a void method or constructor, convert the return type
- 760 * to an appropriate object.
- 761 *
- 762 * We don't do this when an exception is raised because the value
- 763 * in "retval" is undefined.
- 764 */
- 765 if (returnType != NULL) {
- 766 retObj = (Object*)dvmBoxPrimitive(retval, returnType);
- 767 dvmReleaseTrackedAlloc(retObj, NULL);
- 768 }
- 769 }
- 770
- 771bail:
- 772 if (needPop) {
- 773 dvmPopFrame(self);
- 774 }
- 775 return retObj;
- 776}
Why it is for main? In the Dalvik_java_lang_reflect_Method_invokeNative call stage.
(gdb) disass Dalvik_java_lang_reflect_Method_invokeNative
Dump of assembler code for function Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*):
0x40cd2866 <+0>: stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x40cd286a <+4>: mov r2, r0
0x40cd286c <+6>: ldr r6, [r0, #12]
0x40cd286e <+8>: mov r4, r1
0x40cd2870 <+10>: ldr.w r8, [r0, #4]
0x40cd2874 <+14>: ldr.w r9, [r0, #8]
0x40cd2878 <+18>: ldr r5, [r0, #16]
0x40cd287a <+20>: ldr.w r11, [r0, #20]
0x40cd287e <+24>: ldr.w r10, [r0, #28]
0x40cd2882 <+28>: mov r0, r6
0x40cd2884 <+30>: ldr r1, [r2, #24]
0x40cd2886 <+32>: bl 0x40cd897c <dvmSlotToMethod(ClassObject*, int)>
0x40cd288a <+36>: ldr r3, [r0, #4]
0x40cd288c <+38>: mov r7, r0
0x40cd288e <+40>: lsls r2, r3, #28
0x40cd2890 <+42>: bpl.n 0x40cd28a2 <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+60>
0x40cd2892 <+44>: ldr r0, [r6, #44] ; 0x2c
0x40cd2894 <+46>: cmp r0, #7
0x40cd2896 <+48>: beq.n 0x40cd28ce <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+104>
0x40cd2898 <+50>: mov r0, r6
0x40cd289a <+52>: bl 0x40cd562c <dvmInitClass(ClassObject*)>
0x40cd289e <+56>: cbnz r0, 0x40cd28ce <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+104>
0x40cd28a0 <+58>: b.n 0x40cd28ea <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+132>
0x40cd28a2 <+60>: ldr r1, [r6, #32]
0x40cd28a4 <+62>: lsls r3, r1, #22
0x40cd28a6 <+64>: bpl.n 0x40cd28b6 <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+80>
0x40cd28a8 <+66>: ldr r3, [r6, #44] ; 0x2c
0x40cd28aa <+68>: cmp r3, #7
0x40cd28ac <+70>: beq.n 0x40cd28b6 <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+80>
0x40cd28ae <+72>: mov r0, r6
0x40cd28b0 <+74>: bl 0x40cd562c <dvmInitClass(ClassObject*)>
0x40cd28b4 <+78>: cbz r0, 0x40cd28ea <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+132>
0x40cd28b6 <+80>: mov r0, r8
0x40cd28b8 <+82>: mov r1, r6
0x40cd28ba <+84>: bl 0x40ccfb38 <dvmVerifyObjectInClass(Object*, ClassObject*)>
0x40cd28be <+88>: cbz r0, 0x40cd28ea <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+132>
0x40cd28c0 <+90>: mov r1, r7
0x40cd28c2 <+92>: ldr.w r0, [r8]
0x40cd28c6 <+96>: bl 0x40cd5f44 <dvmGetVirtualizedMethod(ClassObject const*, Method const*)>
0x40cd28ca <+100>: mov r7, r0
0x40cd28cc <+102>: cbz r0, 0x40cd28ea <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+132>
0x40cd28ce <+104>: adds.w r2, r10, #0
0x40cd28d2 <+108>: mov r0, r8
0x40cd28d4 <+110>: mov r1, r7
0x40cd28d6 <+112>: mov r3, r5
0x40cd28d8 <+114>: it ne
0x40cd28da <+116>: movne r2, #1
0x40cd28dc <+118>: str r2, [sp, #4]
0x40cd28de <+120>: mov r2, r9
0x40cd28e0 <+122>: str.w r11, [sp]
0x40cd28e4 <+126>: bl 0x40ccb7c8 <dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)>
=> 0x40cd28e8 <+130>: str r0, [r4, #0]
0x40cd28ea <+132>: ldmia.w sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, pc}
and source code
- /*
- 42 * private Object invokeNative(Object obj, Object[] args, Class declaringClass,
- 43 * Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck)
- 44 *
- 45 * Invoke a static or virtual method via reflection.
- 46 */
- 47static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,
- 48 JValue* pResult)
- 49{
- 50 // ignore thisPtr in args[0]
- 51 Object* methObj = (Object*) args[1]; // null for static methods
- 52 ArrayObject* argList = (ArrayObject*) args[2];
- 53 ClassObject* declaringClass = (ClassObject*) args[3];
- 54 ArrayObject* params = (ArrayObject*) args[4];
- 55 ClassObject* returnType = (ClassObject*) args[5];
- 56 int slot = args[6];
- 57 bool noAccessCheck = (args[7] != 0);
- 58 const Method* meth;
- 59 Object* result;
- 60
- 61 /*
- 62 * "If the underlying method is static, the class that declared the
- 63 * method is initialized if it has not already been initialized."
- 64 */
- 65 meth = dvmSlotToMethod(declaringClass, slot);
- 66 assert(meth != NULL);
- 67
- 68 if (dvmIsStaticMethod(meth)) {
- 69 if (!dvmIsClassInitialized(declaringClass)) {
- 70 if (!dvmInitClass(declaringClass))
- 71 goto init_failed;
- 72 }
- 73 } else {
- 74 /* looks like interfaces need this too? */
- 75 if (dvmIsInterfaceClass(declaringClass) &&
- 76 !dvmIsClassInitialized(declaringClass))
- 77 {
- 78 if (!dvmInitClass(declaringClass))
- 79 goto init_failed;
- 80 }
- 81
- 82 /* make sure the object is an instance of the expected class */
- 83 if (!dvmVerifyObjectInClass(methObj, declaringClass)) {
- 84 assert(dvmCheckException(dvmThreadSelf()));
- 85 RETURN_VOID();
- 86 }
- 87
- 88 /* do the virtual table lookup for the method */
- 89 meth = dvmGetVirtualizedMethod(methObj->clazz, meth);
- 90 if (meth == NULL) {
- 91 assert(dvmCheckException(dvmThreadSelf()));
- 92 RETURN_VOID();
- 93 }
- 94 }
- 95
- 96 /*
- 97 * If the method has a return value, "result" will be an object or
- 98 * a boxed primitive.
- 99 */
- 100 result = dvmInvokeMethod(methObj, meth, argList, params, returnType,
- 101 noAccessCheck);
- 102
- 103 RETURN_PTR(result);
- 104
- 105init_failed:
- 106 /*
- 107 * If initialization failed, an exception will be raised.
- 108 */
- 109 ALOGD("Method.invoke() on bad class %s failed",
- 110 declaringClass->descriptor);
- 111 assert(dvmCheckException(dvmThreadSelf()));
- 112 RETURN_VOID();
- 113}
Though the arg meth in calling dvmInvokeMethod is optimized out, but it can be seen in register r7 or r1 before calling it.
Using the value of r7 and r1, try to get method content.
With the field name and shorty, it can be concluded that r7 maybe the correct Mothod var, while r1 maybe has been corrupted.
(gdb) print *(Method*)0x40e1cc38 ---- r1
$9 = {clazz = 0x40d10d34 <gNativeInterface>, accessFlags = 0, methodIndex = 1, registersSize = 0, outsSize = 12304, insSize = 16397, name = 0x0, prototype = {
dexFile = 0x5c46cc80, protoIdx = 0}, shorty = 0x12b "", insns = 0x7379732f, jniArgInfo = 795698548, nativeFunc = 0x6d617266, fastJni = 101, noRef = 119, shouldTrace = 111,
registerMap = 0x6f632f6b, inProfile = 114}
(gdb) print *(Method*)0x570782b8 ---- r7
$10 = {clazz = 0x40e77390, accessFlags = 9, methodIndex = 0, registersSize = 4, outsSize = 2, insSize = 1,name = 0x58ceaed3 "main",prototype = {dexFile = 0x400d3f78,
protoIdx = 10543}, shorty = 0x58c5520c "VL", insns = 0x58736098, jniArgInfo = 0, nativeFunc = 0x0, fastJni = false, noRef = false, shouldTrace = false, registerMap = 0x0,
inProfile = false}
(gdb) print *(ClassObject*)0x40e77390 ---- obj->clazz
$15 = {<Object> = {clazz = 0x40e1d1e8, lock = 0}, instanceData = {0, 0, 0, 0}, descriptor = 0x58bc0812 "Landroid/app/ActivityThread;", descriptorAlloc = 0x0,
accessFlags = 196625, serialNumber = 1342177820, pDvmDex = 0x5128a000, status = CLASS_INITIALIZED, verifyErrorClass = 0x0, initThreadId = 1, objectSize = 180,
elementClass = 0x0, arrayDim = 0, primitiveType = PRIM_NOT, super = 0x40e1d890, classLoader = 0x0, initiatingLoaderList = {initiatingLoaders = 0x0, initiatingLoaderCount = 0},
interfaceCount = 0, interfaces = 0x0, directMethodCount = 83, directMethods = 0x57077330, virtualMethodCount = 59, virtualMethods = 0x57078560, vtableCount = 70,
vtable = 0x57079250, iftableCount = 0, iftable = 0x0, ifviPoolCount = 0, ifviPool = 0x0, ifieldCount = 43, ifieldRefCount = 37, ifields = 0x57076fd0, refOffsets = 3,
sourceFile = 0x58b79596 "ActivityThread.java", sfieldCount = 21, sfields = 0x40e77430}
Frame #9 is "main" of ZygoteInit.
(gdb) up
#9 0x40ccb698 in dvmCallMethodV (self=0x400d3010, method=0x5705cb88, obj=<optimized out>, fromJni=<optimized out>, pResult=0xbeb30aa8, args=...)
at dalvik/vm/interp/Stack.cpp:526
526 dalvik/vm/interp/Stack.cpp: No such file or directory.
(gdb) print method
$11 = (const Method *) 0x5705cb88
(gdb) print *method
$12 = {clazz = 0x40e6ce48, accessFlags = 9, methodIndex = 0, registersSize = 6, outsSize = 3, insSize = 1,name = 0x58ceaed3 "main", prototype = {dexFile = 0x400d3f78,
protoIdx = 10543}, shorty = 0x58c5520c "VL", insns = 0x58a59484, jniArgInfo = 0, nativeFunc = 0x0, fastJni = false, noRef = false, shouldTrace = false, registerMap = 0x0,
inProfile = false}
(gdb) disass 0x58a59484
No function contains specified address.
(gdb) print *(ClassObject*)0x40e6ce48 ---- obj->clazz
$13 = {<Object> = {clazz = 0x40e1d1e8, lock = 0}, instanceData = {0, 0, 0, 0}, descriptor = 0x58bf0c5a "Lcom/android/internal/os/ZygoteInit;", descriptorAlloc = 0x0,
accessFlags = 196609, serialNumber = 1342177773, pDvmDex = 0x5128a000, status = CLASS_INITIALIZED, verifyErrorClass = 0x0, initThreadId = 1, objectSize = 8,
elementClass = 0x0, arrayDim = 0, primitiveType = PRIM_NOT, super = 0x40e1d890, classLoader = 0x0, initiatingLoaderList = {initiatingLoaders = 0x0, initiatingLoaderCount = 0},
interfaceCount = 0, interfaces = 0x0, directMethodCount = 29, directMethods = 0x5705c958, virtualMethodCount = 0, virtualMethods = 0x0, vtableCount = 11, vtable = 0x5705cfb8,
iftableCount = 0, iftable = 0x0, ifviPoolCount = 0, ifviPool = 0x0, ifieldCount = 0, ifieldRefCount = 0, ifields = 0x0, refOffsets = 0,
sourceFile = 0x58c5e5af "ZygoteInit.java", sfieldCount = 17, sfields = 0x40e6cee8}
(gdb)
===============================================================================================
- How dvm calls native method
- How dvm calls native method
- How to Create a JAVA Native Method
- How Many Calls? UVA
- [JNI] How to get the java's native method body?
- JNI/NDK develop guide(2) How JVM find native method
- UVA 10518 How Many Calls?
- UVA 10518 How Many Calls?
- UVA 10518 How Many Calls?
- UVA 10518 How Many Calls?
- uva 10518How Many Calls?
- uva 10518 How Many Calls?
- Native Method
- Native Method
- Native Method
- Native Method
- Native Method
- dvm
- 由NSString的copy和strong/retain引出o-c的copy机制 (一)
- JAVA菜单快捷键
- [LeetCode]Reverse Words in a String
- 可执行文件(ELF)格式的理解
- POJ 1265 Area (计算几何)(Pick定理)
- How dvm calls native method
- 输入字系统
- 参数
- 每个企业,每个职场人士,都像一个正弦波
- cocos2d-x 2.2使用 cocostudio
- 申请.TK域名,并使用DNSPOD解析的方法
- (libgdx小结)自定义动画
- Mysql字符集设置
- C++中的静态成员变量