(二)Andfixの手書き実現
14226 ワード
前のAndfixの記事(一)Andfixの熱修復原理では、AndfixはAndroid版に基づいて本来メンテナンスする必要があるので、Android版を適切に配合する必要があると述べています.ここではAndroid 5に基づいています.1バージョンを例に、Andfixの手書き実装を簡単に紹介します.
一、修復後のjavaクラスのdexファイルを生成する
クラスAのメソッドBにバグがある場合は、新しいA_を作成します.fixedクラス、修正後のBメソッドを追加します.ここでのBメソッドは修復後、再コンパイルしてdexファイルを生成し、app/build/intermediates/javac/debug/complieDebugJavaWithJavac/classes/パッケージ名パスの下にすべてのクラスのclassがあり、完全なパッケージ名フォルダをコピーし、フォルダに修正後のクラスのclassファイルのみを残します.
dxコマンドを使用してdexファイルを生成します(環境変数を構成する必要があります.具体的な方法:
)
その後、構成されたパスの下でdexファイルが生成されます(このファイルをサーバに配置します).
二、DexManager管理クラス管理dexの置換を作成する
プロジェクトコードに戻る:
新しいDexManager管理クラス管理dexの置換
修正方法を入手するには、修正後の方法にカスタム注釈を追加し、プログラムにこの方法がどのクラスに置き換えるかを教える方法で、カスタム注釈は以下の通りです.
fixClass(Class fixClazz)メソッドを見つけて置き換えます.
replaceはnativeメソッドです.
native層コード、ArtMethod構造体を利用して、方法置換を実現する:
一、修復後のjavaクラスのdexファイルを生成する
クラスAのメソッドBにバグがある場合は、新しいA_を作成します.fixedクラス、修正後のBメソッドを追加します.ここでのBメソッドは修復後、再コンパイルしてdexファイルを生成し、app/build/intermediates/javac/debug/complieDebugJavaWithJavac/classes/パッケージ名パスの下にすべてのクラスのclassがあり、完全なパッケージ名フォルダをコピーし、フォルダに修正後のクラスのclassファイルのみを残します.
dxコマンドを使用してdexファイルを生成します(環境変数を構成する必要があります.具体的な方法:
)
その後、構成されたパスの下でdexファイルが生成されます(このファイルをサーバに配置します).
二、DexManager管理クラス管理dexの置換を作成する
プロジェクトコードに戻る:
新しいDexManager管理クラス管理dexの置換
// dex , class
DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),new File(mContext.getCacheDir(),"opt").getAbsolutePath(),Context.MODE_PRIVATE);
Enumeration<String> entries = dexFile.entries();
while (entries.hasMoreElements()) {
String className = entries.nextElement();
Class fixedClass = dexFile.loadClass(className, mContext.getClassLoader());
if (fixedClass != null) {
fixClass(fixedClass);
}
}
修正方法を入手するには、修正後の方法にカスタム注釈を追加し、プログラムにこの方法がどのクラスに置き換えるかを教える方法で、カスタム注釈は以下の通りです.
@MethodReplace(className = " .A",methodName = "B")
fixClass(Class fixClazz)メソッドを見つけて置き換えます.
Method[] methods = fixClazz.getDeclaredMethods();
MethodReplace methodReplace;
String className;
String methodName;
Class<?> bugClass;
Method bugMethod;
for (Method fixMethod : methods) {
methodReplace = fixMethod.getAnnotation(MethodReplace.class);
if (methodReplace == null) {
continue;
}
Log.e(TAG, " : " + fixMethod.getDeclaringClass() + "@" + fixMethod.getName());
className = methodReplace.className();
methodName = methodReplace.methodName();
if (!TextUtils.isEmpty(className) && !TextUtils.isEmpty(methodName)) {
try {
bugClass = Class.forName(className);
bugMethod =
bugClass.getDeclaredMethod(methodName, fixMethod.getParameterTypes());
replace(bugMethod, fixMethod);
Log.e(TAG, " !");
} catch (Exception e) {
e.printStackTrace();
}
}else {
Log.e(TAG, "/ ");
}
}
replaceはnativeメソッドです.
private native void replace(Method bugMethod, Method fixMethod);
native層コード、ArtMethod構造体を利用して、方法置換を実現する:
extern "C"
JNIEXPORT void JNICALL
Java_com_netease_andfix_DexManager_replace(JNIEnv *env, jobject instance, jobject bugMethod,
jobject fixMethod) {
env->FindClass()
//ba ( bug )
art::mirror::ArtMethod *bugArtMethod = reinterpret_cast<:mirror::artmethod>(env->FromReflectedMethod(
bugMethod));
// ( )
art::mirror::ArtMethod *fixArtMethod = reinterpret_cast<:mirror::artmethod>(env->FromReflectedMethod(
fixMethod));
reinterpret_cast<:mirror::class>(fixArtMethod->declaring_class_)->class_loader_ =
reinterpret_cast<:mirror::class>(bugArtMethod->declaring_class_)->class_loader_; //for plugin classloader
reinterpret_cast<:mirror::class>(fixArtMethod->declaring_class_)->clinit_thread_id_ =
reinterpret_cast<:mirror::class>(bugArtMethod->declaring_class_)->clinit_thread_id_;
reinterpret_cast<:mirror::class>(fixArtMethod->declaring_class_)->status_ =
reinterpret_cast<:mirror::class>(bugArtMethod->declaring_class_)->status_ - 1;
reinterpret_cast<:mirror::class>(fixArtMethod->declaring_class_)->super_class_ = 0;
//
bugArtMethod->declaring_class_ = fixArtMethod->declaring_class_;
bugArtMethod->dex_cache_resolved_methods_ = fixArtMethod->dex_cache_resolved_methods_;
bugArtMethod->access_flags_ = fixArtMethod->access_flags_;
bugArtMethod->dex_cache_resolved_types_ = fixArtMethod->dex_cache_resolved_types_;
bugArtMethod->dex_code_item_offset_ = fixArtMethod->dex_code_item_offset_;
bugArtMethod->method_index_ = fixArtMethod->method_index_;
bugArtMethod->dex_method_index_ = fixArtMethod->dex_method_index_;
bugArtMethod->ptr_sized_fields_.entry_point_from_interpreter_ = fixArtMethod->ptr_sized_fields_.entry_point_from_interpreter_;
bugArtMethod->ptr_sized_fields_.entry_point_from_jni_ = fixArtMethod->ptr_sized_fields_.entry_point_from_jni_;
bugArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = fixArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
__android_log_print(ANDROID_LOG_ERROR, "AndFix","replace_5_1: %d , %d",
static_cast(bugArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_),
fixArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_);
}