【发布时间】:2013-08-16 12:45:30
【问题描述】:
关于标题
“同一个包的类”是指共享同一个包访问的类。请注意类 a.b.c.Foo 没有包访问类 a.b.Bar 的事实。因为如果前者的修饰符是默认的,后者就无法访问前者。
问题
如果我将同一个包中的两个类拆分成两个dex文件,即使加载正确,运行时也会报错,logcat喜欢:
I/dalvikvm(6498):DexOpt:非法方法访问(从 Lcom/fish47/multidex/TestMatchWord 调用 Lcom/fish47/multidex/Foo;.isWholeWord (Lcom/fish47/multidex/Foo;)Z;)
I/dalvikvm(6498):找不到方法 com.fish47.multidex.core.Foo.isWholeWord,引用自方法 com.fish47.multidex.core.TestMatchWord.test_english
W/dalvikvm(6498): VFY: 无法解析虚拟方法 758: Lcom/fish47/multidex/Foo;.isWholeWord (Lcom/fish47/multidex/Foo;)Z
猜想
这是弹出以下错误消息的代码:
vm/analysis/Optimize.c ==> line: 697 - 714
/* access allowed? */
tweakLoader(referrer, resMethod->clazz);
bool allowed = dvmCheckMethodAccess(referrer, resMethod);
untweakLoader(referrer, resMethod->clazz);
if (!allowed) {
IF_LOGI() {
char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
resMethod->clazz->descriptor, resMethod->name, desc,
referrer->descriptor);
free(desc);
}
if (pFailure != NULL)
*pFailure = VERIFY_ERROR_ACCESS_METHOD;
return NULL;
}
注意resClass->classLoader的值。如果这两个类不是来自同一个 dex 文件,则其值将设置为 0xdead3333。
vm/analysis/Optimize.c ==> line: 285 - 299
static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
{
if (!gDvm.optimizing)
return;
assert(referrer->classLoader == NULL);
assert(resClass->classLoader == NULL);
if (!gDvm.optimizingBootstrapClass) {
/* class loader for an array class comes from element type */
if (dvmIsArrayClass(resClass))
resClass = resClass->elementClass;
if (referrer->pDvmDex != resClass->pDvmDex)
resClass->classLoader = (Object*) 0xdead3333;
}
}
这是一个技巧,它让 checkAccess(...) 方法最后返回 false,如果两个类在同一个包中,可以互相访问但不公开。
vm/oo/AccessCheck.c ==> line: 88 - 116
static bool checkAccess(const ClassObject* accessFrom,
const ClassObject* accessTo, u4 accessFlags)
{
/* quick accept for public access */
if (accessFlags & ACC_PUBLIC)
return true;
/* quick accept for access from same class */
if (accessFrom == accessTo)
return true;
/* quick reject for private access from another class */
if (accessFlags & ACC_PRIVATE)
return false;
/*
* Semi-quick test for protected access from a sub-class, which may or
* may not be in the same package.
*/
if (accessFlags & ACC_PROTECTED)
if (dvmIsSubClass(accessFrom, accessTo))
return true;
/*
* Allow protected and private access from other classes in the same
* package.
*/
return dvmInSamePackage(accessFrom, accessTo);
}
vm/oo/AccessCheck.c ==> line: 39 - 83
bool dvmInSamePackage(const ClassObject* class1, const ClassObject* class2)
{
...
/* class loaders must match */
if (class1->classLoader != class2->classLoader)
return false;
...
}
【问题讨论】:
标签: java android classloader dalvik dex