android c语言实现 热修复
生成修复dex包
1、dx --dex --output /Users/xieyuhai/Documents/Test/dx/out.dex /Users/xieyuhai/Documents/Test/dx/
2、推送修复好的out.dex文件到指定手机跟目录 adb -s emulator-5554 push out.dex /mnt/sdcard/
插件化开发的好处
1、宿主和插件分开编译
2、并发开发
3、动态更新插件
4、按需下载模块
5、方法数或变量数
dalvik 4.4 使用; 4.4以上使用的 art虚拟机
参考资源
/Users/xieyuhai/Documents/Source/android-4.4.4_r1/dalvik/vm/oo/Object.h
引用资源部分
1、android-4.4.4_r1\dalvik\libdex\DexFile.h
2、android-4.4.4_r1\dalvik\vm\oo\Object.h
/**
* 注解类
* Created by xieyuhai on 2017/11/16.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Replace {
String clazz();
String method();
}
/**
* 错误类
* Created by xieyuhai on 2017/11/16.
*/
public class Calculate {
public int calc() {
int i = 0;
int j = 10;
//模拟异常产生
return j / i;
}
public int calculate(int i) {
if (i != 0) {
throw new ArithmeticException();
}
int j = 10;
//模拟异常产生
return j / i;
}
}
/**
* 修复错误类、注解类及需要修复的函数设置
* Created by xieyuhai on 2017/11/16.
*/
public class Calculate {
@Replace(clazz = "com.xyh.fixframework.Calculate", method = "calc")
public int calc() {
//10/0
int i = 1;
int j = 10;
//模拟异常产生
return j / i;
}
@Replace(clazz = "com.xyh.fixframework.Calculate", method = "calculate")
public int calculate(int i) {
//10/0
int j = 10;
//模拟异常产生
return j / i;
}
}
/**
* 调用计算
* @param view
*/
public void cacl(View view) {
Calculate calcutor = new Calculate();
Log.e("TAG", "result: " + calcutor.calc());
Log.e("TAG", "result: " + calcutor.calculate(28090));
((Button) view).setText("result:" + calcutor.calc() + "");
}
/**
* 修复按钮-》
* @param view
*/
public void fix(View view) {
Log.e("TAG", "fix: " + Environment.getExternalStorageDirectory());
DexManager.getInstance().loadFile(new File(Environment.getExternalStorageDirectory(), "out.dex"));
Log.e("TAG", getString(R.string.success));
}
/**
* @param file
*/
public void loadFile(File file) {
try {
//加载修复dex文件
DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),
new File(context.getCacheDir(), "opt").getAbsolutePath(), Context.MODE_PRIVATE);
// 得到class --取出修复好的Method
Enumeration<String> entry = dexFile.entries();
// 循环修复
while (entry.hasMoreElements()) {
//拿到全类名
String className = entry.nextElement();
Class clazz = dexFile.loadClass(className, context.getClassLoader());
if (clazz != null) {
fixClazz(clazz);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 找出注解中的函数并对其进行修复
* 仅支持sdk18 及 以下的版本
*
* @param realClazz
*/
private void fixClazz(Class realClazz) {
//服务器修复好的 realClazz
Method[] methods = realClazz.getDeclaredMethods();
for (Method rightMethod : methods) {
Replace replace = rightMethod.getAnnotation(Replace.class);
if (replace == null) {
continue;
}
// 找到了修复好的Method 找到出bug的Method
String wrongClass = replace.clazz();
String wrongMethodName = replace.method();
try {
Class clazz = Class.forName(wrongClass);
Method wrongMethod = clazz.getDeclaredMethod(wrongMethodName, rightMethod.getParameterTypes());
if (Build.VERSION.SDK_INT <= 18) {
replace(Build.VERSION.SDK_INT, wrongMethod, rightMethod);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
/**
* 修复
*
* @param version sdk版本
* @param wrongMethod 错误的方法
* @param rightMethod 修复好的方法
*/
private native void replace(int version, Method wrongMethod, Method rightMethod);
#include <jni.h>
#include "dalvik.h"
typedef Object *(*FindObject )(void *thread, jobject jobj);
typedef void *(*FindThread)();
FindObject findObject;
FindThread findThread;
/**
* 修复
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_xyh_fixframework_DexManager_replace(JNIEnv *env,
jobject instance,
jint version,
jobject wrongMethod,
jobject rightMethod) {
// java虚拟机Method
// 首先 找到虚拟机对应的Method 结构体
Method *wrong = (Method *) env->FromReflectedMethod(wrongMethod);
Method *right = (Method *) env->FromReflectedMethod(rightMethod);
// 把right对应的Object 第一个成员变量ClassObject status
// ClassObject
// hook libdvm
void *dvm_hand = dlopen("libdvm.so", RTLD_NOW);
//根据 sdk 版本 10 决定
findObject = (FindObject) dlsym(dvm_hand,
version > 10 ? "_Z20dvmDecodeIndirectRefP6ThreadP8_jobject"
: "dvmDecodeIndirectRef");
findThread = (FindThread) dlsym(dvm_hand,
version > 10 ? "_Z13dvmThreadSelfv" : "dvmThreadSelf");
// 反射获取
jclass methodClass = env->FindClass("java/lang/reflect/Method");
jmethodID rightmid = env->GetMethodID(methodClass, "getDeclaringClass", "()Ljava/lang/Class;");
// method 所声明的Class
jobject ndkObject = env->CallObjectMethod(rightMethod, rightmid);
ClassObject *firstField = (ClassObject *) findObject(findThread(), ndkObject);
// 修改状态
firstField->status = CLASS_INITIALIZED;
// 使用对的参数替换错误的参数
wrong->accessFlags |= ACC_PUBLIC;
wrong->methodIndex = right->methodIndex;
wrong->jniArgInfo = right->jniArgInfo;
wrong->registersSize = right->registersSize;
wrong->outsSize = right->outsSize;
// 方法参数原型
wrong->prototype = right->prototype;
//
wrong->insns = right->insns;
wrong->nativeFunc = right->nativeFunc;
}