タイトルについて
「同じパッケージのクラス」とは、同じパッケージ アクセスを共有するクラスを意味します。クラスabcFooはクラスabBarへのパッケージ アクセスを持っていないことに注意してください。前者の修飾子がデフォルトの場合、後者は前者にアクセスできないためです。
問題
同じパッケージ内の 2 つのクラスを 2 つの dex ファイルに分割すると、それらを正しくロードしても、実行中にエラーが発生します。logcat は次のようになります。
I/dalvikvm( 6498): DexOpt: 不正なメソッド アクセス (Lcom/fish47/multidex/Foo;.isWholeWord (Lcom/fish47/multidex/Foo;)Z から Lcom/fish47/multidex/TestMatchWord を呼び出す;)
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の値に注意してください。2 つのクラスが同じ dex ファイルからのものでない場合、その値は0xdead3333に設定されます。
vm/analysis/Optimize.c ==> 行: 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;
}
}
これはトリックです。2 つのクラスが同じパッケージ内にあり、互いにアクセス可能であるが公開されていない場合、checkAccess(...)メソッドが最後に false を返すようにします。
vm/oo/AccessCheck.c ==> 行: 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 ==> 行: 39 - 83
bool dvmInSamePackage(const ClassObject* class1, const ClassObject* class2)
{
...
/* class loaders must match */
if (class1->classLoader != class2->classLoader)
return false;
...
}