java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
来源:互联网 发布:js比较数值大小 编辑:程序博客网 时间:2024/05/16 19:27
机型信息:android4.0系列
0x01. 崩溃堆栈
"---java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementationcom.huawei.android.pushagent.c.a.e(Unknown Source)com.huawei.android.pushagent.c.a.f(Unknown Source)com.huawei.android.pushagent.c.c.b.b(Unknown Source)com.huawei.android.pushagent.c.c.b.a(Unknown Source)com.huawei.android.pushagent.c.c.c.run(Unknown Source)android.os.Handler.handleCallback(Handler.java:605)android.os.Handler.dispatchMessage(Handler.java:92)android.os.Looper.loop(Looper.java:137)com.huawei.android.pushagent.c.c.b.run(Unknown Source)"
0x02. 崩溃来源
dalvik/vm/oo/Resolve.cpp
/* * Find the class corresponding to "classIdx", which maps to a class name * string. It might be in the same DEX file as "referrer", in a different * DEX file, generated by a class loader, or generated by the VM (e.g. * array classes). * * Because the DexTypeId is associated with the referring class' DEX file, * we may have to resolve the same class more than once if it's referred * to from classes in multiple DEX files. This is a necessary property for * DEX files associated with different class loaders. * * We cache a copy of the lookup in the DexFile's "resolved class" table, * so future references to "classIdx" are faster. * * Note that "referrer" may be in the process of being linked. * * Traditional VMs might do access checks here, but in Dalvik the class * "constant pool" is shared between all classes in the DEX file. We rely * on the verifier to do the checks for us. * * Does not initialize the class. * * "fromUnverifiedConstant" should only be set if this call is the direct * result of executing a "const-class" or "instance-of" instruction, which * use class constants not resolved by the bytecode verifier. * * Returns NULL with an exception raised on failure. */ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx, bool fromUnverifiedConstant){ DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const char* className; /* * Check the table first -- this gets called from the other "resolve" * methods. */ resClass = dvmDexGetResolvedClass(pDvmDex, classIdx); if (resClass != NULL) return resClass; LOGVV("--- resolving class %u (referrer=%s cl=%p)", classIdx, referrer->descriptor, referrer->classLoader); /* * Class hasn't been loaded yet, or is in the process of being loaded * and initialized now. Try to get a copy. If we find one, put the * pointer in the DexTypeId. There isn't a race condition here -- * 32-bit writes are guaranteed atomic on all target platforms. Worst * case we have two threads storing the same value. * * If this is an array class, we'll generate it here. */ className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx); if (className[0] != '\0' && className[1] == '\0') { /* primitive type */ resClass = dvmFindPrimitiveClass(className[0]); } else { resClass = dvmFindClassNoInit(className, referrer->classLoader); //跟踪这个实现 } if (resClass != NULL) { /* * If the referrer was pre-verified, the resolved class must come * from the same DEX or from a bootstrap class. The pre-verifier * makes assumptions that could be invalidated by a wacky class * loader. (See the notes at the top of oo/Class.c.) * * The verifier does *not* fail a class for using a const-class * or instance-of instruction referring to an unresolveable class, * because the result of the instruction is simply a Class object * or boolean -- there's no need to resolve the class object during * verification. Instance field and virtual method accesses can * break dangerously if we get the wrong class, but const-class and * instance-of are only interesting at execution time. So, if we * we got here as part of executing one of the "unverified class" * instructions, we skip the additional check. * * Ditto for class references from annotations and exception * handler lists. */ if (!fromUnverifiedConstant && IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED)) { ClassObject* resClassCheck = resClass; if (dvmIsArrayClass(resClassCheck)) resClassCheck = resClassCheck->elementClass; if (referrer->pDvmDex != resClassCheck->pDvmDex && //resClass和referrer(入参)指向的pDvmDex对象不相等,说明这个类来自不同的dex文件. resClassCheck->classLoader != NULL) { ALOGW("Class resolved by unexpected DEX:" " %s(%p):%p ref [%s] %s(%p):%p", referrer->descriptor, referrer->classLoader, referrer->pDvmDex, resClass->descriptor, resClassCheck->descriptor, resClassCheck->classLoader, resClassCheck->pDvmDex); ALOGW("(%s had used a different %s during pre-verification)", referrer->descriptor, resClass->descriptor); dvmThrowIllegalAccessError( "Class ref in pre-verified class resolved to unexpected " "implementation"); //这里抛出的异常 return NULL; } } LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d", resClass->descriptor, referrer->descriptor, referrer->pDvmDex, referrer->classLoader, classIdx); /* * Add what we found to the list so we can skip the class search * next time through. * * TODO: should we be doing this when fromUnverifiedConstant==true? * (see comments at top of oo/Class.c) */ dvmDexSetResolvedClass(pDvmDex, classIdx, resClass); } else { /* not found, exception should be raised */ LOGVV("Class not found: %s", dexStringByTypeIdx(pDvmDex->pDexFile, classIdx)); assert(dvmCheckException(dvmThreadSelf())); } return resClass;}
dalvik/vm/oo/Class.cpp
/* * Find the named class (by descriptor), using the specified * initiating ClassLoader. * * The class will be loaded if it has not already been, as will its * superclass. It will not be initialized. * * If the class can't be found, returns NULL with an appropriate exception * raised. */ClassObject* dvmFindClassNoInit(const char* descriptor, Object* loader){ assert(descriptor != NULL); //assert(loader != NULL); LOGVV("FindClassNoInit '%s' %p", descriptor, loader); if (*descriptor == '[') { /* * Array class. Find in table, generate if not found. */ return dvmFindArrayClass(descriptor, loader); } else { /* * Regular class. Find in table, load if not found. */ if (loader != NULL) { return findClassFromLoaderNoInit(descriptor, loader); } else { return dvmFindSystemClassNoInit(descriptor); } }}
/* * Load the named class (by descriptor) from the specified class * loader. This calls out to let the ClassLoader object do its thing. * * Returns with NULL and an exception raised on error. */static ClassObject* findClassFromLoaderNoInit(const char* descriptor, Object* loader){ //ALOGI("##### findClassFromLoaderNoInit (%s,%p)", // descriptor, loader); Thread* self = dvmThreadSelf(); assert(loader != NULL); /* * Do we already have it? * * The class loader code does the "is it already loaded" check as * well. However, this call is much faster than calling through * interpreted code. Doing this does mean that in the common case * (365 out of 420 calls booting the sim) we're doing the * lookup-by-descriptor twice. It appears this is still a win, so * I'm keeping it in. */ ClassObject* clazz = dvmLookupClass(descriptor, loader, false); if (clazz != NULL) { LOGVV("Already loaded: %s %p", descriptor, loader); return clazz; } else { LOGVV("Not already loaded: %s %p", descriptor, loader); } char* dotName = NULL; StringObject* nameObj = NULL; /* convert "Landroid/debug/Stuff;" to "android.debug.Stuff" */ dotName = dvmDescriptorToDot(descriptor); if (dotName == NULL) { dvmThrowOutOfMemoryError(NULL); return NULL; } nameObj = dvmCreateStringFromCstr(dotName); if (nameObj == NULL) { assert(dvmCheckException(self)); goto bail; } dvmMethodTraceClassPrepBegin(); /* * Invoke loadClass(). This will probably result in a couple of * exceptions being thrown, because the ClassLoader.loadClass() * implementation eventually calls VMClassLoader.loadClass to see if * the bootstrap class loader can find it before doing its own load. */ LOGVV("--- Invoking loadClass(%s, %p)", dotName, loader); { const Method* loadClass = loader->clazz->vtable[gDvm.voffJavaLangClassLoader_loadClass]; JValue result; dvmCallMethod(self, loadClass, loader, &result, nameObj); //dvmCallMethod clazz = (ClassObject*) result.l; dvmMethodTraceClassPrepEnd(); Object* excep = dvmGetException(self); if (excep != NULL) {#if DVM_SHOW_EXCEPTION >= 2 ALOGD("NOTE: loadClass '%s' %p threw exception %s", dotName, loader, excep->clazz->descriptor);#endif dvmAddTrackedAlloc(excep, self); dvmClearException(self); dvmThrowChainedNoClassDefFoundError(descriptor, excep); dvmReleaseTrackedAlloc(excep, self); clazz = NULL; goto bail; } else if (clazz == NULL) { ALOGW("ClassLoader returned NULL w/o exception pending"); dvmThrowNullPointerException("ClassLoader returned null"); goto bail; } } /* not adding clazz to tracked-alloc list, because it's a ClassObject */ dvmAddInitiatingLoader(clazz, loader); LOGVV("--- Successfully loaded %s %p (thisldr=%p clazz=%p)", descriptor, clazz->classLoader, loader, clazz);bail: dvmReleaseTrackedAlloc((Object*)nameObj, NULL); free(dotName); return clazz;}
dvmCallMethod
dalvik/vm/interp/Stack.cpp
/* * Issue a method call. * * Pass in NULL for "obj" on calls to static methods. * * (Note this can't be inlined because it takes a variable number of args.) */void dvmCallMethod(Thread* self, const Method* method, Object* obj, JValue* pResult, ...){ va_list args; va_start(args, pResult); dvmCallMethodV(self, method, obj, false, pResult, args); va_end(args);}/* * Issue a method call with a variable number of arguments. We process * the contents of "args" by scanning the method signature. * * Pass in NULL for "obj" on calls to static methods. * * We don't need to take the class as an argument because, in Dalvik, * we don't need to worry about static synchronized methods. */void dvmCallMethodV(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, va_list args){ const char* desc = &(method->shorty[1]); // [0] is the return type. int verifyCount = 0; ClassObject* clazz; u4* ins; clazz = callPrep(self, method, obj, false); if (clazz == NULL) return; /* "ins" for new frame start at frame pointer plus locals */ ins = ((u4*)self->interpSave.curFrame) + (method->registersSize - method->insSize); //ALOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) {#ifdef WITH_EXTRA_OBJECT_VALIDATION assert(obj != NULL && dvmIsHeapAddress(obj));#endif *ins++ = (u4) obj; verifyCount++; } while (*desc != '\0') { switch (*(desc++)) { case 'D': case 'J': { u8 val = va_arg(args, u8); memcpy(ins, &val, 8); // EABI prevents direct store ins += 2; verifyCount += 2; break; } case 'F': { /* floats were normalized to doubles; convert back */ float f = (float) va_arg(args, double); *ins++ = dvmFloatToU4(f); verifyCount++; break; } case 'L': { /* 'shorty' descr uses L for all refs, incl array */ void* arg = va_arg(args, void*); assert(obj == NULL || dvmIsHeapAddress(obj)); jobject argObj = reinterpret_cast<jobject>(arg); if (fromJni) *ins++ = (u4) dvmDecodeIndirectRef(self, argObj); else *ins++ = (u4) argObj; verifyCount++; break; } default: { /* Z B C S I -- all passed as 32-bit integers */ *ins++ = va_arg(args, u4); verifyCount++; break; } } }#ifndef NDEBUG if (verifyCount != method->insSize) { ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; }#endif //dvmDumpThreadStack(dvmThreadSelf()); if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, method, self); TRACE_METHOD_EXIT(self, method); } else { dvmInterpret(self, method, pResult);//给pResult赋值 }#ifndef NDEBUGbail:#endif dvmPopFrame(self);}
/dalvik/vm/interp/Interp.cpp
/* * Main interpreter loop entry point. * * This begins executing code at the start of "method". On exit, "pResult" * holds the return value of the method (or, if "method" returns NULL, it * holds an undefined value). * * The interpreted stack frame, which holds the method arguments, has * already been set up. */void dvmInterpret(Thread* self, const Method* method, JValue* pResult){ InterpSaveState interpSaveState; ExecutionSubModes savedSubModes;#if defined(WITH_JIT) /* Target-specific save/restore */ double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT]; /* * If the previous VM left the code cache through single-stepping the * inJitCodeCache flag will be set when the VM is re-entered (for example, * in self-verification mode we single-step NEW_INSTANCE which may re-enter * the VM through findClassFromLoaderNoInit). Because of that, we cannot * assert that self->inJitCodeCache is NULL here. */#endif /* * Save interpreter state from previous activation, linking * new to last. */ interpSaveState = self->interpSave; self->interpSave.prev = &interpSaveState; /* * Strip out and save any flags that should not be inherited by * nested interpreter activation. */ savedSubModes = (ExecutionSubModes)( self->interpBreak.ctl.subMode & LOCAL_SUBMODE); if (savedSubModes != kSubModeNormal) { dvmDisableSubMode(self, savedSubModes); }#if defined(WITH_JIT) dvmJitCalleeSave(calleeSave);#endif#if defined(WITH_TRACKREF_CHECKS) self->interpSave.debugTrackedRefStart = dvmReferenceTableEntries(&self->internalLocalRefTable);#endif self->debugIsMethodEntry = true;#if defined(WITH_JIT) dvmJitCalleeSave(calleeSave); /* Initialize the state to kJitNot */ self->jitState = kJitNot;#endif /* * Initialize working state. * * No need to initialize "retval". */ self->interpSave.method = method; self->interpSave.curFrame = (u4*) self->interpSave.curFrame; self->interpSave.pc = method->insns; assert(!dvmIsNativeMethod(method)); /* * Make sure the class is ready to go. Shouldn't be possible to get * here otherwise. */ if (method->clazz->status < CLASS_INITIALIZING || method->clazz->status == CLASS_ERROR) { ALOGE("ERROR: tried to execute code in unprepared class '%s' (%d)", method->clazz->descriptor, method->clazz->status); dvmDumpThread(self, false); dvmAbort(); } typedef void (*Interpreter)(Thread*); Interpreter stdInterp; if (gDvm.executionMode == kExecutionModeInterpFast) stdInterp = dvmMterpStd;#if defined(WITH_JIT) else if (gDvm.executionMode == kExecutionModeJit) stdInterp = dvmMterpStd;#endif else stdInterp = dvmInterpretPortable; // Call the interpreter (*stdInterp)(self); *pResult = self->interpSave.retval; /* Restore interpreter state from previous activation */ self->interpSave = interpSaveState;#if defined(WITH_JIT) dvmJitCalleeRestore(calleeSave);#endif if (savedSubModes != kSubModeNormal) { dvmEnableSubMode(self, savedSubModes); }}
0x03. 分析
从上面的信息来看并没有得到更多的信息,仅仅是看到了,引用某个类的时候,系统检测到当前Resolve的类和其引用的类来自不同的dex文件.
根据这个结论推断:
0x01. 插件框架加载组件的dex有问题;
导致当前需要Resolve的class和其引用的class的dex搞错了?一个是老的插件里面的,一个是新的插件里面的?0x02. 插件框架加载组建的classloader有问题;
当前需要Resolve的class和其引用的class的classloader不是同一个,这时候class里面的同一个对象也是不相等?
目前能想到的就这两个情况.
0x04. 验证
找到崩溃用户,把Debug包发给用户,抓取用户的日志.根据日志信息验证分析结论.
阅读全文
0 0
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
- android开发问题:java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected imp
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementatio
- Class ref in pre-verified class resolved to unexpected implementation
- Data Binding & Espresso: IllegalAccessError: Class ref in pre-verified class resolved to unexpected
- Android XPosed框架 hook 中的IllegalAccessError: Class ref in pre-verified class resolved to unexpected
- 关于 java.lang.IllegaAccessError:Class ref in pre-verified class resoved to unexpected implementation
- java.lang.IllegaAccessError:Class ref in pre-verified class resoved to unexpected implementation
- android studio下导出jar(java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unex)
- AndroidRuntime: java.lang.IllegalAccessError: tried to access class android.content.res.StringBlock
- java.sql.SQLException: java.lang.IllegalAccessError: class sun.reflect.GeneratedConstructorAccessor2
- java.lang.IllegalAccessError: class com.google.protobuf.HBaseZeroCopyByteString
- java.lang.IllegalAccessError: class com.google.protobuf.HBaseZeroCopyByteString
- java.lang.IllegalAccessError: class com.google.protobuf.HBaseZeroCopyByteString
- Class resolved by unexpected DEX
- nested exception is java.lang.IllegalAccessError: tried to access method net.sf.ehcache.CacheManager.()V from class org.hibernat
- python selenium HTML测试报告
- SQLServer2008R2数据库连接不上怎么办?
- 存储过程报错1267
- mysql Failed to open file 'xxx.sql', error error: 2 解决方案
- python 数据离散化和面元划分
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
- 20171102
- MVP 模式简单易懂的介绍方式
- Linux压缩文件的二三事
- c语言经典笔试题01-关于素数
- RockChip px3se 使用wpa_spplicant连接wifi上网
- spoj 1811 LCS 后缀自动机
- softmax函数
- MongoDB Spark