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).

[cpp] view plaincopyprint?
  1. 1181   dvmPlatformInvoke(env,  
  2. 1182            (ClassObject*) staticMethodClass,  
  3. 1183            method->jniArgInfo, method->insSize, modArgs, method->shorty,  
  4. 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

[cpp] view plaincopyprint?
  1. 37Function prototype:  
  2. 38  
  3. 39void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,  
  4. 40    const u4* argv, const char* signature, void* func, JValue* pReturn)  
  5.   
  6.   
  7. 88 * On entry:  
  8. 89 *   r0  JNIEnv (can be left alone)  
  9. 90 *   r1  clazz (NULL for virtual method calls, non-NULL for static)  
  10. 91 *   r2  arg info  
  11. 92 *   r3  argc (number of 32-bit values in argv)  
  12. 93 *   [sp]     argv  
  13. 94 *   [sp,#4]  short signature  
  14. 95 *   [sp,#8]  func  
  15. 96 *   [sp,#12] pReturn  
  16.   
  17. 134     * stack looks like:  
  18. 135     *  
  19. 136     *  pReturn  
  20. 137     *  func  
  21. 138     *  shorty  
  22. 139     *  argv        <-- sp on entry  
  23. 140     *  lr          <-- fp  
  24. 141     *  fp  
  25. 142     *  r9...r7  
  26. 143     *  r6          <-- sp after reg save  
  27.   
  28. 236.Lcopy_done:  
  29. 237    /* 
  30. 238     * Currently: 
  31. 239     *  r0-r3  args (JNIEnv*, thisOrClass, arg0, arg1) 
  32. 240     *  r6  return type (enum DalvikJniReturnType) 
  33. 241     *  r9  original argv 
  34. 242     *  fp  frame pointer 
  35. 243     * 
  36. 244     * The stack copy is complete.  Grab the first two words off of argv 
  37. 245     * and tuck them into r2/r3.  If the first arg is 32-bit and the second 
  38. 246     * arg is 64-bit, then r3 "holds" a pad word and the load is unnecessary 
  39. 247     * but harmless. 
  40. 248     * 
  41. 249     * If there are 0 or 1 arg words in argv, we will be loading uninitialized 
  42. 250     * data into the registers, but since nothing tries to use it it's also 
  43. 251     * harmless (assuming argv[0] and argv[1] point to valid memory, which 
  44. 252     * is a reasonable assumption for Dalvik's interpreted stacks). 
  45. 253     */  
  46. 254    ldmia   r9, {r2-r3}                 @ r2/r3<- argv[0]/argv[1]  
  47. 255  
  48. 256    ldr     ip, [fp, #8+FP_ADJ]         @ ip<- func  
  49. 257#ifdef __ARM_HAVE_BLX  
  50. 258    blx     ip                          @ call func  ******* call the jni function ********  
  51. 259#else  
  52. 260    mov     lr, pc                      @ call func the old-fashioned way  
  53. 261    bx      ip  
  54. 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.

[cpp] view plaincopyprint?
  1. 2150 * Pull the interesting pieces out of a DexMethod.  
  2. 2151 *  
  3. 2152 * The DEX file isn't going anywhere, so we don't need to make copies of  
  4. 2153 * the code area.  
  5. 2154 */  
  6. 2155static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod, @ dalvik/vm/oo/Class.cpp  
  7. 2156    Method* meth)  
  8. 2157{  
  9. 2158    DexFile* pDexFile = clazz->pDvmDex->pDexFile;  
  10. 2159    const DexMethodId* pMethodId;  
  11. 2160    const DexCode* pDexCode;  
  12. 2161  
  13. 2162    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);  
  14. 2163  
  15. 2164    meth->name = dexStringById(pDexFile, pMethodId->nameIdx);  
  16. 2165    dexProtoSetFromMethodId(&meth->prototype, pDexFile, pMethodId);  
  17. 2166    meth->shorty = dexProtoGetShorty(&meth->prototype);  
  18. 2167    meth->accessFlags = pDexMethod->accessFlags;  
  19. 2168    meth->clazz = clazz;  
  20. 2169    meth->jniArgInfo = 0;  
  21. 2170  
  22. 2171    if (dvmCompareNameDescriptorAndMethod("finalize""()V", meth) == 0) {  
  23. 2172        /* 
  24. 2173         * The Enum class declares a "final" finalize() method to 
  25. 2174         * prevent subclasses from introducing a finalizer.  We don't 
  26. 2175         * want to set the finalizable flag for Enum or its subclasses, 
  27. 2176         * so we check for it here. 
  28. 2177         * 
  29. 2178         * We also want to avoid setting it on Object, but it's easier 
  30. 2179         * to just strip that out later. 
  31. 2180         */  
  32. 2181        if (clazz->classLoader != NULL ||  
  33. 2182            strcmp(clazz->descriptor, "Ljava/lang/Enum;") != 0)  
  34. 2183        {  
  35. 2184            SET_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);  
  36. 2185        }  
  37. 2186    }  
  38. 2187  
  39. 2188    pDexCode = dexGetCode(pDexFile, pDexMethod);  
  40. 2189    if (pDexCode != NULL) {  
  41. 2190        /* integer constants, copy over for faster access */  
  42. 2191        meth->registersSize = pDexCode->registersSize;  
  43. 2192        meth->insSize = pDexCode->insSize;  
  44. 2193        meth->outsSize = pDexCode->outsSize;  
  45. 2194  
  46. 2195        /* pointer to code area */  
  47. 2196        meth->insns = pDexCode->insns;  
  48. 2197    } else {  
  49. 2198        /* 
  50. 2199         * We don't have a DexCode block, but we still want to know how 
  51. 2200         * much space is needed for the arguments (so we don't have to 
  52. 2201         * compute it later).  We also take this opportunity to compute 
  53. 2202         * JNI argument info. 
  54. 2203         * 
  55. 2204         * We do this for abstract methods as well, because we want to 
  56. 2205         * be able to substitute our exception-throwing "stub" in. 
  57. 2206         */  
  58. 2207        int argsSize = dvmComputeMethodArgsSize(meth);  
  59. 2208        if (!dvmIsStaticMethod(meth))  
  60. 2209            argsSize++;  
  61. 2210        meth->registersSize = meth->insSize = argsSize;  
  62. 2211        assert(meth->outsSize == 0);  
  63. 2212        assert(meth->insns == NULL);  
  64. 2213  
  65. 2214        if (dvmIsNativeMethod(meth)) {    *****************  
  66. 2215            meth->nativeFunc = dvmResolveNativeMethod;  *****************  
  67. 2216            meth->jniArgInfo = computeJniArgInfo(&meth->prototype); *****************  
  68. 2217        }  
  69. 2218    }  
  70. 2219}  


On running, dvmCallMethodV is used to transfer execution from java to native.

[java] view plaincopyprint?
  1. /* 
  2. 434 * Issue a method call with a variable number of arguments.  We process 
  3. 435 * the contents of "args" by scanning the method signature. 
  4. 436 * 
  5. 437 * Pass in NULL for "obj" on calls to static methods. 
  6. 438 * 
  7. 439 * We don't need to take the class as an argument because, in Dalvik, 
  8. 440 * we don't need to worry about static synchronized methods. 
  9. 441 */  
  10. 442void dvmCallMethodV(Thread* self, const Method* method, Object* obj, @ dalvik/vm/interp/Stack.cpp  
  11. 443    bool fromJni, JValue* pResult, va_list args)  
  12. 444{  
  13. 445    const char* desc = &(method->shorty[1]); // [0] is the return type.  
  14. 446    int verifyCount = 0;  
  15. 447    ClassObject* clazz;  
  16. 448    u4* ins;  
  17. 449  
  18. 450    clazz = callPrep(self, method, obj, false);  
  19. 451    if (clazz == NULL)  
  20. 452        return;  
  21. 453  
  22. 454    /* "ins" for new frame start at frame pointer plus locals */  
  23. 455    ins = ((u4*)self->interpSave.curFrame) +  
  24. 456           (method->registersSize - method->insSize);  
  25. 457  
  26. 458    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);  
  27. 459  
  28. 460    /* put "this" pointer into in0 if appropriate */  
  29. 461    if (!dvmIsStaticMethod(method)) {  
  30. 462#ifdef WITH_EXTRA_OBJECT_VALIDATION  
  31. 463        assert(obj != NULL && dvmIsHeapAddress(obj));  
  32. 464#endif  
  33. 465        *ins++ = (u4) obj;  
  34. 466        verifyCount++;  
  35. 467    }  
  36. 468  
  37. 469    while (*desc != '\0') {  
  38. 470        switch (*(desc++)) {  
  39. 471            case 'D'case 'J': {  
  40. 472                u8 val = va_arg(args, u8);  
  41. 473                memcpy(ins, &val, 8);       // EABI prevents direct store  
  42. 474                ins += 2;  
  43. 475                verifyCount += 2;  
  44. 476                break;  
  45. 477            }  
  46. 478            case 'F': {  
  47. 479                /* floats were normalized to doubles; convert back */  
  48. 480                float f = (float) va_arg(args, double);  
  49. 481                *ins++ = dvmFloatToU4(f);  
  50. 482                verifyCount++;  
  51. 483                break;  
  52. 484            }  
  53. 485            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */  
  54. 486                void* arg = va_arg(args, void*);  
  55. 487                assert(obj == NULL || dvmIsHeapAddress(obj));  
  56. 488                jobject argObj = reinterpret_cast<jobject>(arg);  
  57. 489                if (fromJni)  
  58. 490                    *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);  
  59. 491                else  
  60. 492                    *ins++ = (u4) argObj;  
  61. 493                verifyCount++;  
  62. 494                break;  
  63. 495            }  
  64. 496            default: {  
  65. 497                /* Z B C S I -- all passed as 32-bit integers */  
  66. 498                *ins++ = va_arg(args, u4);  
  67. 499                verifyCount++;  
  68. 500                break;  
  69. 501            }  
  70. 502        }  
  71. 503    }  
  72. 504  
  73. 505#ifndef NDEBUG  
  74. 506    if (verifyCount != method->insSize) {  
  75. 507        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,  
  76. 508            method->insSize, clazz->descriptor, method->name);  
  77. 509        assert(false);  
  78. 510        goto bail;  
  79. 511    }  
  80. 512#endif  
  81. 513  
  82. 514    //dvmDumpThreadStack(dvmThreadSelf());  
  83. 515  
  84. 516    if (dvmIsNativeMethod(method)) {      ***************  
  85. 517        TRACE_METHOD_ENTER(self, method);  
  86. 518        /* 
  87. 519         * Because we leave no space for local variables, "curFrame" points 
  88. 520         * directly at the method arguments. 
  89. 521         */  
  90. 522        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, ***************  
  91. 523                              method, self);  
  92. 524        TRACE_METHOD_EXIT(self, method);  
  93. 525    } else {  
  94. 526        dvmInterpret(self, method, pResult);     ***************  
  95. 527    }  
  96. 528  
  97. 529#ifndef NDEBUG  
  98. 530bail:  
  99. 531#endif  
  100. 532    dvmPopFrame(self);  
  101. 533}  


Like dynamic symbol resolve, resolver function as native function slot entry.resolve once!!!

[cpp] view plaincopyprint?
  1. 70void dvmResolveNativeMethod(const u4* args, JValue* pResult,  
  2. 71    const Method* method, Thread* self)  
  3. 72{  
  4. 73    ClassObject* clazz = method->clazz;  
  5. 74  
  6. 75    /* 
  7. 76     * If this is a static method, it could be called before the class 
  8. 77     * has been initialized. 
  9. 78     */  
  10. 79    if (dvmIsStaticMethod(method)) {  
  11. 80        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {  
  12. 81            assert(dvmCheckException(dvmThreadSelf()));  
  13. 82            return;  
  14. 83        }  
  15. 84    } else {  
  16. 85        assert(dvmIsClassInitialized(clazz) ||  
  17. 86               dvmIsClassInitializing(clazz));  
  18. 87    }  
  19. 88  
  20. 89    /* start with our internal-native methods */  
  21. 90    DalvikNativeFunc infunc = dvmLookupInternalNativeMethod(method);  
  22. 91    if (infunc != NULL) {  
  23. 92        /* resolution always gets the same answer, so no race here */  
  24. 93        IF_LOGVV() {  
  25. 94            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);  
  26. 95            LOGVV("+++ resolved native %s.%s %s, invoking",  
  27. 96                clazz->descriptor, method->name, desc);  
  28. 97            free(desc);  
  29. 98        }  
  30. 99        if (dvmIsSynchronizedMethod(method)) {  
  31. 100            ALOGE("ERROR: internal-native can't be declared 'synchronized'");  
  32. 101            ALOGE("Failing on %s.%s", method->clazz->descriptor, method->name);  
  33. 102            dvmAbort();     // harsh, but this is VM-internal problem  
  34. 103        }  
  35. 104        DalvikBridgeFunc dfunc = (DalvikBridgeFunc) infunc;  
  36. 105        dvmSetNativeFunc((Method*) method, dfunc, NULL);   ********************  
  37. 106        dfunc(args, pResult, method, self);  
  38. 107        return;  
  39. 108    }  
  40. 109  
  41. 110    /* now scan any DLLs we have loaded for JNI signatures */  
  42. 111    void* func = lookupSharedLibMethod(method);  
  43. 112    if (func != NULL) {  
  44. 113        /* found it, point it at the JNI bridge and then call it */  
  45. 114        dvmUseJNIBridge((Method*) method, func);    ********************  
  46. 115        (*method->nativeFunc)(args, pResult, method, self);  
  47. 116        return;  
  48. 117    }  
  49. 118  
  50. 119    IF_ALOGW() {  
  51. 120        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);  
  52. 121        ALOGW("No implementation found for native %s.%s:%s",  
  53. 122            clazz->descriptor, method->name, desc);  
  54. 123        free(desc);  
  55. 124    }  
  56. 125  
  57. 126    dvmThrowUnsatisfiedLinkError("Native method not found", method);  
  58. 127}  
  59.   
  60.   
  61. 827/* 
  62. 828 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns" 
  63. 829 * to point at the actual function. 
  64. 830 */  
  65. 831void dvmUseJNIBridge(Method* method, void* func) {  
  66. 832    method->shouldTrace = shouldTrace(method);  
  67. 833  
  68. 834    // Does the method take any reference arguments?  
  69. 835    method->noRef = true;  
  70. 836    const char* cp = method->shorty;  
  71. 837    while (*++cp != '\0') { // Pre-increment to skip return type.  
  72. 838        if (*cp == 'L') {  
  73. 839            method->noRef = false;  
  74. 840            break;  
  75. 841        }  
  76. 842    }  
  77. 843  
  78. 844    DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;  
  79. 845    dvmSetNativeFunc(method, bridge, (const u2*) func);  
  80. 846}  
  81.   
  82.   
  83. /* 
  84. 4532 * Replace method->nativeFunc and method->insns with new values.  This is 
  85. 4533 * commonly performed after successful resolution of a native method. 
  86. 4534 * 
  87. 4535 * There are three basic states: 
  88. 4536 *  (1) (initial) nativeFunc = dvmResolveNativeMethod, insns = NULL 
  89. 4537 *  (2) (internal native) nativeFunc = <impl>, insns = NULL 
  90. 4538 *  (3) (JNI) nativeFunc = JNI call bridge, insns = <impl> 
  91. 4539 * 
  92. 4540 * nativeFunc must never be NULL for a native method. 
  93. 4541 * 
  94. 4542 * The most common transitions are (1)->(2) and (1)->(3).  The former is 
  95. 4543 * atomic, since only one field is updated; the latter is not, but since 
  96. 4544 * dvmResolveNativeMethod ignores the "insns" field we just need to make 
  97. 4545 * sure the update happens in the correct order. 
  98. 4546 * 
  99. 4547 * A transition from (2)->(1) would work fine, but (3)->(1) will not, 
  100. 4548 * because both fields change.  If we did this while a thread was executing 
  101. 4549 * in the call bridge, we could null out the "insns" field right before 
  102. 4550 * the bridge tried to call through it.  So, once "insns" is set, we do 
  103. 4551 * not allow it to be cleared.  A NULL value for the "insns" argument is 
  104. 4552 * treated as "do not change existing value". 
  105. 4553 */  
  106. 4554void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func,  
  107. 4555    const u2* insns)  
  108. 4556{  
  109. 4557    ClassObject* clazz = method->clazz;  
  110. 4558  
  111. 4559    assert(func != NULL);  
  112. 4560  
  113. 4561    /* just open up both; easier that way */  
  114. 4562    dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);  
  115. 4563    dvmLinearReadWrite(clazz->classLoader, clazz->directMethods);  
  116. 4564  
  117. 4565    if (insns != NULL) {  
  118. 4566        /* update both, ensuring that "insns" is observed first */  
  119. 4567        method->insns = insns;  
  120. 4568        android_atomic_release_store((int32_t) func,  
  121. 4569            (volatile int32_t*)(void*) &method->nativeFunc);  
  122. 4570    } else {  
  123. 4571        /* only update nativeFunc */  
  124. 4572        method->nativeFunc = func;  
  125. 4573    }  
  126. 4574  
  127. 4575    dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);  
  128. 4576    dvmLinearReadOnly(clazz->classLoader, clazz->directMethods);  
  129. 4577}  
  130.   
  131.   
  132. /* 
  133. 1117 * General form, handles all cases. 
  134. 1118 */  
  135. 1119void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {  
  136. 1120    u4* modArgs = (u4*) args;  
  137. 1121    jclass staticMethodClass = NULL;  
  138. 1122  
  139. 1123    u4 accessFlags = method->accessFlags;  
  140. 1124    bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;  
  141. 1125  
  142. 1126    //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,  
  143. 1127    //    method->clazz->descriptor, method->name, method->shorty);  
  144. 1128  
  145. 1129    /* 
  146. 1130     * Walk the argument list, creating local references for appropriate 
  147. 1131     * arguments. 
  148. 1132     */  
  149. 1133    int idx = 0;  
  150. 1134    Object* lockObj;  
  151. 1135    if ((accessFlags & ACC_STATIC) != 0) {  
  152. 1136        lockObj = (Object*) method->clazz;  
  153. 1137        /* add the class object we pass in */  
  154. 1138        staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);  
  155. 1139    } else {  
  156. 1140        lockObj = (Object*) args[0];  
  157. 1141        /* add "this" */  
  158. 1142        modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);  
  159. 1143    }  
  160. 1144  
  161. 1145    if (!method->noRef) {  
  162. 1146        const char* shorty = &method->shorty[1];        /* skip return type */  
  163. 1147        while (*shorty != '\0') {  
  164. 1148            switch (*shorty++) {  
  165. 1149            case 'L':  
  166. 1150                //ALOGI("  local %d: 0x%08x", idx, modArgs[idx]);  
  167. 1151                if (modArgs[idx] != 0) {  
  168. 1152                    modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);  
  169. 1153                }  
  170. 1154                break;  
  171. 1155            case 'D':  
  172. 1156            case 'J':  
  173. 1157                idx++;  
  174. 1158                break;  
  175. 1159            default:  
  176. 1160                /* Z B C S I -- do nothing */  
  177. 1161                break;  
  178. 1162            }  
  179. 1163            idx++;  
  180. 1164        }  
  181. 1165    }  
  182. 1166  
  183. 1167    if (UNLIKELY(method->shouldTrace)) {  
  184. 1168        logNativeMethodEntry(method, args);  
  185. 1169    }  
  186. 1170    if (UNLIKELY(isSynchronized)) {  
  187. 1171        dvmLockObject(self, lockObj);  
  188. 1172    }  
  189. 1173  
  190. 1174    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);  
  191. 1175  
  192. 1176    ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */  
  193. 1177    assert(method->insns != NULL);  
  194. 1178  
  195. 1179    JNIEnv* env = self->jniEnv;  
  196. 1180    COMPUTE_STACK_SUM(self);  
  197. 1181    dvmPlatformInvoke(env,  
  198. 1182            (ClassObject*) staticMethodClass,  
  199. 1183            method->jniArgInfo, method->insSize, modArgs, method->shorty,  
  200. 1184            (void*) method->insns, pResult);  
  201. 1185    CHECK_STACK_SUM(self);  
  202. 1186  
  203. 1187    dvmChangeStatus(self, oldStatus);  
  204. 1188  
  205. 1189    convertReferenceResult(env, pResult, method, self);  
  206. 1190  
  207. 1191    if (UNLIKELY(isSynchronized)) {  
  208. 1192        dvmUnlockObject(self, lockObj);  
  209. 1193    }  
  210. 1194    if (UNLIKELY(method->shouldTrace)) {  
  211. 1195        logNativeMethodExit(method, self, *pResult);  
  212. 1196    }  
  213. 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.

[java] view plaincopyprint?
  1. 506    public Object invoke(Object receiver, Object... args) @ libcore/luni/src/main/java/java/lang/reflect/Method.java  
  2. 507            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {  
  3. 508        if (args == null) {  
  4. 509            args = EmptyArray.OBJECT;  
  5. 510        }  
  6. 511        return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);  
  7. 512    }  
  8.   
  9. 41/* 
  10. 42 * private Object invokeNative(Object obj, Object[] args, Class declaringClass, 
  11. 43 *   Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck) 
  12. 44 * 
  13. 45 * Invoke a static or virtual method via reflection. 
  14. 46 */  
  15. 47static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,  
  16. 48    JValue* pResult)  
  17. 49{  
  18. 50    // ignore thisPtr in args[0]  
  19. 51    Object* methObj = (Object*) args[1];        // null for static methods  
  20. 52    ArrayObject* argList = (ArrayObject*) args[2];  
  21. 53    ClassObject* declaringClass = (ClassObject*) args[3];  
  22. 54    ArrayObject* params = (ArrayObject*) args[4];  
  23. 55    ClassObject* returnType = (ClassObject*) args[5];  
  24. 56    int slot = args[6];  
  25. 57    bool noAccessCheck = (args[7] != 0);  
  26. 58    const Method* meth;  
  27. 59    Object* result;  
  28. 60  
  29. 61    /* 
  30. 62     * "If the underlying method is static, the class that declared the 
  31. 63     * method is initialized if it has not already been initialized." 
  32. 64     */  
  33. 65    meth = dvmSlotToMethod(declaringClass, slot);  
  34. 66    assert(meth != NULL);  
  35. 67  
  36. 68    if (dvmIsStaticMethod(meth)) {  
  37. 69        if (!dvmIsClassInitialized(declaringClass)) {  
  38. 70            if (!dvmInitClass(declaringClass))  
  39. 71                goto init_failed;  
  40. 72        }  
  41. 73    } else {  
  42. 74        /* looks like interfaces need this too? */  
  43. 75        if (dvmIsInterfaceClass(declaringClass) &&  
  44. 76            !dvmIsClassInitialized(declaringClass))  
  45. 77        {  
  46. 78            if (!dvmInitClass(declaringClass))  
  47. 79                goto init_failed;  
  48. 80        }  
  49. 81  
  50. 82        /* make sure the object is an instance of the expected class */  
  51. 83        if (!dvmVerifyObjectInClass(methObj, declaringClass)) {  
  52. 84            assert(dvmCheckException(dvmThreadSelf()));  
  53. 85            RETURN_VOID();  
  54. 86        }  
  55. 87  
  56. 88        /* do the virtual table lookup for the method */  
  57. 89        meth = dvmGetVirtualizedMethod(methObj->clazz, meth);  
  58. 90        if (meth == NULL) {  
  59. 91            assert(dvmCheckException(dvmThreadSelf()));  
  60. 92            RETURN_VOID();  
  61. 93        }  
  62. 94    }  
  63. 95  
  64. 96    /* 
  65. 97     * If the method has a return value, "result" will be an object or 
  66. 98     * a boxed primitive. 
  67. 99     */  
  68. 100    result = dvmInvokeMethod(methObj, meth, argList, params, returnType,  
  69. 101                noAccessCheck);  
  70. 102  
  71. 103    RETURN_PTR(result);  
  72. 104  
  73. 105init_failed:  
  74. 106    /* 
  75. 107     * If initialization failed, an exception will be raised. 
  76. 108     */  
  77. 109    ALOGD("Method.invoke() on bad class %s failed",  
  78. 110        declaringClass->descriptor);  
  79. 111    assert(dvmCheckException(dvmThreadSelf()));  
  80. 112    RETURN_VOID();  
  81. 113}  
  82.   
  83. 645/* 
  84. 646 * Invoke a method, using the specified arguments and return type, through 
  85. 647 * one of the reflection interfaces.  Could be a virtual or direct method 
  86. 648 * (including constructors).  Used for reflection. 
  87. 649 * 
  88. 650 * Deals with boxing/unboxing primitives and performs widening conversions. 
  89. 651 * 
  90. 652 * "invokeObj" will be null for a static method. 
  91. 653 * 
  92. 654 * If the invocation returns with an exception raised, we have to wrap it. 
  93. 655 */  
  94. 656Object* dvmInvokeMethod(Object* obj, const Method* method,  
  95. 657    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,  
  96. 658    bool noAccessCheck)  
  97. 659{  
  98. 660    ClassObject* clazz;  
  99. 661    Object* retObj = NULL;  
  100. 662    Thread* self = dvmThreadSelf();  
  101. 663    s4* ins;  
  102. 664    int verifyCount, argListLength;  
  103. 665    JValue retval;  
  104. 666    bool needPop = false;  
  105. 667  
  106. 668    /* verify arg count */  
  107. 669    if (argList != NULL)  
  108. 670        argListLength = argList->length;  
  109. 671    else  
  110. 672        argListLength = 0;  
  111. 673    if (argListLength != (int) params->length) {  
  112. 674        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,  
  113. 675            "wrong number of arguments; expected %d, got %d",  
  114. 676            params->length, argListLength);  
  115. 677        return NULL;  
  116. 678    }  
  117. 679  
  118. 680    clazz = callPrep(self, method, obj, !noAccessCheck);  
  119. 681    if (clazz == NULL)  
  120. 682        return NULL;  
  121. 683    needPop = true;  
  122. 684  
  123. 685    /* "ins" for new frame start at frame pointer plus locals */  
  124. 686    ins = ((s4*)self->interpSave.curFrame) +  
  125. 687        (method->registersSize - method->insSize);  
  126. 688    verifyCount = 0;  
  127. 689  
  128. 690    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);  
  129. 691  
  130. 692    /* put "this" pointer into in0 if appropriate */  
  131. 693    if (!dvmIsStaticMethod(method)) {  
  132. 694        assert(obj != NULL);  
  133. 695        *ins++ = (s4) obj;  
  134. 696        verifyCount++;  
  135. 697    }  
  136. 698  
  137. 699    /* 
  138. 700     * Copy the args onto the stack.  Primitive types are converted when 
  139. 701     * necessary, and object types are verified. 
  140. 702     */  
  141. 703    DataObject** args = (DataObject**)(void*)argList->contents;  
  142. 704    ClassObject** types = (ClassObject**)(void*)params->contents;  
  143. 705    for (int i = 0; i < argListLength; i++) {  
  144. 706        int width = dvmConvertArgument(*args++, *types++, ins);  
  145. 707        if (width < 0) {  
  146. 708            dvmPopFrame(self);      // throw wants to pull PC out of stack  
  147. 709            needPop = false;  
  148. 710            throwArgumentTypeMismatch(i, *(types-1), *(args-1));  
  149. 711            goto bail;  
  150. 712        }  
  151. 713  
  152. 714        ins += width;  
  153. 715        verifyCount += width;  
  154. 716    }  
  155. 717  
  156. 718#ifndef NDEBUG  
  157. 719    if (verifyCount != method->insSize) {  
  158. 720        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,  
  159. 721            method->insSize, clazz->descriptor, method->name);  
  160. 722        assert(false);  
  161. 723        goto bail;  
  162. 724    }  
  163. 725#endif  
  164. 726  
  165. 727    if (dvmIsNativeMethod(method)) {      **********************  
  166. 728        TRACE_METHOD_ENTER(self, method);  
  167. 729        /* 
  168. 730         * Because we leave no space for local variables, "curFrame" points 
  169. 731         * directly at the method arguments. 
  170. 732         */  
  171. 733        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval, **********************  
  172. 734                              method, self);  
  173. 735        TRACE_METHOD_EXIT(self, method);  
  174. 736    } else {  
  175. 737        dvmInterpret(self, method, &retval);     **********************  
  176. 738    }  
  177. 739  
  178. 740    /* 
  179. 741     * Pop the frame immediately.  The "wrap" calls below can cause 
  180. 742     * allocations, and we don't want the GC to walk the now-dead frame. 
  181. 743     */  
  182. 744    dvmPopFrame(self);  
  183. 745    needPop = false;  
  184. 746  
  185. 747    /* 
  186. 748     * If an exception is raised, wrap and replace.  This is necessary 
  187. 749     * because the invoked method could have thrown a checked exception 
  188. 750     * that the caller wasn't prepared for. 
  189. 751     * 
  190. 752     * We might be able to do this up in the interpreted code, but that will 
  191. 753     * leave us with a shortened stack trace in the top-level exception. 
  192. 754     */  
  193. 755    if (dvmCheckException(self)) {  
  194. 756        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");  
  195. 757    } else {  
  196. 758        /* 
  197. 759         * If this isn't a void method or constructor, convert the return type 
  198. 760         * to an appropriate object. 
  199. 761         * 
  200. 762         * We don't do this when an exception is raised because the value 
  201. 763         * in "retval" is undefined. 
  202. 764         */  
  203. 765        if (returnType != NULL) {  
  204. 766            retObj = (Object*)dvmBoxPrimitive(retval, returnType);  
  205. 767            dvmReleaseTrackedAlloc(retObj, NULL);  
  206. 768        }  
  207. 769    }  
  208. 770  
  209. 771bail:  
  210. 772    if (needPop) {  
  211. 773        dvmPopFrame(self);  
  212. 774    }  
  213. 775    return retObj;  
  214. 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

[cpp] view plaincopyprint?
  1. /* 
  2. 42 * private Object invokeNative(Object obj, Object[] args, Class declaringClass, 
  3. 43 *   Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck) 
  4. 44 * 
  5. 45 * Invoke a static or virtual method via reflection. 
  6. 46 */  
  7. 47static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,  
  8. 48    JValue* pResult)  
  9. 49{  
  10. 50    // ignore thisPtr in args[0]  
  11. 51    Object* methObj = (Object*) args[1];        // null for static methods  
  12. 52    ArrayObject* argList = (ArrayObject*) args[2];  
  13. 53    ClassObject* declaringClass = (ClassObject*) args[3];  
  14. 54    ArrayObject* params = (ArrayObject*) args[4];  
  15. 55    ClassObject* returnType = (ClassObject*) args[5];  
  16. 56    int slot = args[6];  
  17. 57    bool noAccessCheck = (args[7] != 0);  
  18. 58    const Method* meth;  
  19. 59    Object* result;  
  20. 60  
  21. 61    /* 
  22. 62     * "If the underlying method is static, the class that declared the 
  23. 63     * method is initialized if it has not already been initialized." 
  24. 64     */  
  25. 65    meth = dvmSlotToMethod(declaringClass, slot);  
  26. 66    assert(meth != NULL);  
  27. 67  
  28. 68    if (dvmIsStaticMethod(meth)) {  
  29. 69        if (!dvmIsClassInitialized(declaringClass)) {  
  30. 70            if (!dvmInitClass(declaringClass))  
  31. 71                goto init_failed;  
  32. 72        }  
  33. 73    } else {  
  34. 74        /* looks like interfaces need this too? */  
  35. 75        if (dvmIsInterfaceClass(declaringClass) &&  
  36. 76            !dvmIsClassInitialized(declaringClass))  
  37. 77        {  
  38. 78            if (!dvmInitClass(declaringClass))  
  39. 79                goto init_failed;  
  40. 80        }  
  41. 81  
  42. 82        /* make sure the object is an instance of the expected class */  
  43. 83        if (!dvmVerifyObjectInClass(methObj, declaringClass)) {  
  44. 84            assert(dvmCheckException(dvmThreadSelf()));  
  45. 85            RETURN_VOID();  
  46. 86        }  
  47. 87  
  48. 88        /* do the virtual table lookup for the method */  
  49. 89        meth = dvmGetVirtualizedMethod(methObj->clazz, meth);  
  50. 90        if (meth == NULL) {  
  51. 91            assert(dvmCheckException(dvmThreadSelf()));  
  52. 92            RETURN_VOID();  
  53. 93        }  
  54. 94    }  
  55. 95  
  56. 96    /* 
  57. 97     * If the method has a return value, "result" will be an object or 
  58. 98     * a boxed primitive. 
  59. 99     */  
  60. 100    result = dvmInvokeMethod(methObj, meth, argList, params, returnType,  
  61. 101                noAccessCheck);  
  62. 102  
  63. 103    RETURN_PTR(result);  
  64. 104  
  65. 105init_failed:  
  66. 106    /* 
  67. 107     * If initialization failed, an exception will be raised. 
  68. 108     */  
  69. 109    ALOGD("Method.invoke() on bad class %s failed",  
  70. 110        declaringClass->descriptor);  
  71. 111    assert(dvmCheckException(dvmThreadSelf()));  
  72. 112    RETURN_VOID();  
  73. 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)
===============================================================================================



0 0
原创粉丝点击