android c语言实现 热修复 sdk18

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;

}



猜你喜欢

转载自blog.csdn.net/u010945409/article/details/78576151