精华内容
下载资源
问答
  • java热修复实例

    千次阅读 2017-04-21 17:36:02
    关于java热修复的一次尝试

    闲来无事试一下java的热修复。主要的原理是通过动态加载class文件的方式,参考文章为在 Java 中运用动态挂载实现 Bug 的热修复动态替换目标进程的Java类

    两篇文章分别在原理和实践上给出了详细的说明,这里做一下实例的整理并对遇到的问题和两篇文章中一些没有提到的注意事项进行一下说明

     

     

    被替换的类的准备

    先写一个要被替换掉的类libUtil,里面只有一个静态方法printString,打印一句话

     

    public class libUtil {
       public static void printString(String s){
          System.out.println("this is a bug string : "+s);
       }
    }

     

    然后是测试类,需要完成以下工作

    1. 打印进程号,方便热修复时新建的虚拟机attach到这个进程上

    2.      不停的调用要被替换掉的类的方法,以便我们可以清晰的看到热修复的效果

     

    测试类如下:

     

    import java.lang.management.ManagementFactory;
     
    public class testHotSwap {
       public static void main(String[] args) {
          testStatic t=(newtestHotSwap()).new testStatic();
          while(true){
             try{
                Thread.sleep(5000);
                String name = ManagementFactory.getRuntimeMXBean().getName();
                System.out.println(name);
                // get pid  
                String pid = name.split("@")[0];
                System.out.println("Pid is:" + pid);
                t.print();
             }
             catch(InterruptedException e){}
          }
       }
       class testStatic{
          public void print(){
             libUtil.printString("did u miss me ?");
          }
       }
    }

     

     

     

     

     

    热修复的准备

    接下来我们需要完成三件事:

    1.      写一个进程去启动一个虚拟机并attach到已上线的进程上去

    2.      写一个修复类去覆盖有问题的类

    3.      写一个代理类,通过代理类的接口去实现热修复,其中这个代理类是要打包成jar文件的形式

     

    首先来写一个修复类,这个修复类需要与原来的类在包名,类名,修饰符上完全一致,否则在classRedefine过程中会产生classname don’t match 的异常

    代码如下:

     

    public class libUtil {
       public static void printString(String s){
          System.out.println("this is a fixed string : "+s);
       }
    }

     

    然后来写代理类,其中需要特别注意的有以下几点:

    1.      必须含有static的代理main方法

    2.      打成jar包后的Manifest.mf文件中必须含有以下两行:

    l agent class: Agent-Class:testHotSwapDebug.debugJar
    
    l Can-Redefine-Classes: true

    Agent class指定了代理类的包名类名

    Can redefineclass属性使得这个包可以对已载入的class进行redefine

     

     

    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.lang.instrument.ClassDefinition;
    import java.lang.instrument.Instrumentation;
     
    public class debugJar {
       public static void agentmain(String arg, Instrumentation inst)
                throws Exception {
            // only if header utility is on the classpath; otherwise,
            // a class can be found within any classloader by iterating
            // over the return value ofInstrumentation::getAllLoadedClasses
          // 需要打成jar包并修改manifest.mf 添加一行指定agent class : Agent-Class:testHotSwapDebug.debugJar 
          //还需要加一行 :Can-Redefine-Classes: true
            Class<?> libUtil = Class.forName("processWithBug.libUtil");
     
            // copy the contents of typo.fix into abyte array
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            InputStream input=null;
            try  {
               input =new FileInputStream("C:\\Users\\Administrator\\workspace\\testHotSwapDebug\\bin\\processWithBug\\libUtil.class");//包名类名都要与原来的一致   
                byte[] buffer = new byte[1024];
                int length;
                while ((length = input.read(buffer)) != -1) {
                    output.write(buffer, 0, length);
                }
            }catch(Exception e){
              if(input==null)
                 System.out.println("class input is null");
              else
                 e.printStackTrace();
            }
     
            // Apply the redefinition
            inst.redefineClasses(
                    new ClassDefinition(libUtil, output.toByteArray()));
        }
     
    }

    接下来是用来attach到已有进程的类,注意事项有以下几点:

    1. 需要在工程中引入tools.jar,这个jar包在jdklib文件夹下,但一般ide的运行环境为jre,所以需要特别添加进环境变量里面

    2. 需要将attach.dll进行动态加载,同样attach.dlljdk的一个bin目录下,需要拷贝到运行目录下,忘记具体在哪了,可以在jdk目录下进行搜索,找到以后放到jre/bin下就可以了

     

    import java.io.File;
    import com.sun.tools.attach.VirtualMachine;
    
    public classtestFixBug {
      static
      {
         System.loadLibrary("attach");
         //需要将attach.dll放到java.library.path下  
      }
    
      public static void main(String[] args) {
         String processId = "17244";//需要修改为要被修复进程的pid
         String jarFileName ="fixBug.jar";//有agentmain修复类的jar包名
         File f=new File(jarFileName);
         System.out.println(f.getAbsolutePath());
         VirtualMachine virtualMachine;
         try {
            virtualMachine =VirtualMachine.attach(processId);
            virtualMachine.loadAgent(jarFileName, "World!");
            virtualMachine.detach();
         } catch(Exception e){
            e.printStackTrace();
         }
      }
    }

     

     

     

     

     

     

    运行结果

    先运行要被替换的类的测试进程

    11368@SKY-20150127GHW
    Pid is:11368
    this is a bugstring : did u miss me ? 

     

     

     

     

     

    运行attach的进程:

    11368@SKY-20150127GHW
    Pid is:11368
    thisis a bug string : did u miss me ?
    11368@SKY-20150127GHW
    Pid is:11368
    thisis a bug string : did u miss me ?
    11368@SKY-20150127GHW
    Pid is:11368
    thisis a fixed string : did u miss me ?
    11368@SKY-20150127GHW
    Pid is:11368
    this is a fixedstring : did u miss me ?

     

     

     

     

     

     

    一些奇怪的小现象

    当static方法直接在main中调用时不能被热修复,准确的说redefine成功了却没有效果。猜测是static块中调用static方法在编译时就已经固定了无法用动态重定义的方法产生影响

    展开全文
  • ./gradlew clean nuwaQihooDebugPatch -P NuwaDir=/Users/jason/Documents/nuwa java verison must be same using android studio and terminal run following command to push patch.jar to sdcard. adb push ...

    687474703a2f2f376676696f762e636f6d312e7a302e676c622e636c6f7564646e2e636f6d2f6e7577612e6a7067

    Nuwa

    68747470733a2f2f6170692e62696e747261792e636f6d2f7061636b616765732f6a61736f6e726f73732f6d6176656e2f6e7577612f696d616765732f646f776e6c6f61642e737667

    Nuwa is a goddess in ancient Chinese mythology best known for repairing the pillar of heaven.

    With this Nuwa project,you can also have the repairing power, fix your android applicaiton without have to publish a new APK to the appstore.

    Features

    Support both dalvik and art runtime.

    Support productFlavor and buildType.

    Support proguard and multidex.

    Pure java implementation.

    Run the Sample

    in master branch, run and install the app.

    it shows『hello world』.

    copy sample/build/outputs/nuwa dir to somewhere for later use.

    for example: /Users/jason/Documents/nuwa

    change to bugfix branch, run the following command in terminal to generate patch.jar.

    ./gradlew clean nuwaQihooDebugPatch -P NuwaDir=/Users/jason/Documents/nuwa

    java verison must be same using android studio and terminal

    run following command to push patch.jar to sdcard.

    adb push sample/build/outputs/nuwa/qihoo/debug/patch.jar /sdcard/

    restart your application (kill the process).

    it shows『patch success』.

    Integration

    Get Gradle Plugin

    add following to the build.gradle of your root project.

    classpath 'cn.jiajixin.nuwa:gradle:1.2.2'

    build.gradle maybe look like this:

    ```

    buildscript {

    repositories {

    jcenter()

    }

    dependencies {

    classpath 'com.android.tools.build:gradle:1.2.3'

    classpath 'cn.jiajixin.nuwa:gradle:1.2.2'

    }

    }

    ```

    add following to your build.gradle:

    apply plugin: "cn.jiajixin.nuwa"

    Get Nuwa SDK

    gradle dependency: dependencies {

    compile 'cn.jiajixin.nuwa:nuwa:1.0.0'

    }

    Use Nuwa SDK

    add following to your application class: @Override

    protected void attachBaseContext(Context base) {

    super.attachBaseContext(base);

    Nuwa.init(this);

    }

    load the patch file according to your needs: Nuwa.loadPatch(this,patchFile)

    I plan to provide the management of patch file later.

    ProGuard

    add follwing to you proguardFile if you are using proguard:

    -keep class cn.jiajixin.nuwa.** { *; }

    Nuwa DSL

    You can add nuwa extension to your build.gradle. Generally, you don't need this. nuwa{

    }

    Nuwa extension support following DSL object.

    includePackage:HashSet

    The internal name of a class is its fully qualified name, where '.' are replaced by '/'. For example:

    cn/jiajixin/nuwasample/MainActivity.class

    Using includePackage,you can only fix those classes whose internal name starts with includePackage.For example:

    includePackage = ['cn/jiajixin/nuwasample'] Default, Nuwa can fix classes which not from the android support library.

    excludeClass:HashSet

    All Application subclasses should not be injected by Nuwa.

    Default, Nuwa will automatically exclude the application declared in your manifest file. You need to exclude others using excludeClass

    Using excludeClass, you can not fix those classes whose internal name ends with excludeClass.For example:

    excludeClass = ['BaseApplication.class']

    debugOn:boolean

    whether use Nuwa in debug mode, default totrue.

    Generate Patch

    For how to generate patch file, please reference the first three steps of Run the Sample.

    There are two types of gradle task to generate patch file:

    nuwaPatches

    this task will generate multi patch.jar for all variant.

    nuwa${variant.name.capitalize()}Patch

    this task will generate one patch.jar for specific variant.

    How it Works

    Inspired by QZone hotfix solution from this article.

    inject into all classes one java bytecode referring the Hack.class from a different dex, which can avoid CLASS_ISPREVERIFIED error when replacing class.

    generate patch.jar according to mapping.txt and classes hash of last published APK.

    Nuwa

    inject the Hack.class.

    inject the patch.jar into head of BaseDexClassLoader's pathList.

    Later Plan

    provide patch file management

    improve security of Nuwa

    License

    Copyright (c) 2015, jiajixin.cn

    展开全文
  • 注意标题 Java层原理和实现###在说到热修复之前,先简单说下android的apk生成的一个原理,我们都是知道android是Java语言写的,那么.java文件和.class文件大部分人应该都不会陌生,其实从Java文件到apk文件经历了...

    注意标题 Java层原理和实现###

    在说到热修复之前,先简单说下android的apk生成的一个原理,我们都是知道android是Java语言写的,那么.java文件和.class文件大部分人应该都不会陌生,其实从Java文件到apk文件经历了以下的过程

    70

    这是java文件到apk文件的四部曲,其实.java .class .apk文件我们都非常熟悉,我们写的代码是java,.java文件经过编译之后变成.class文件,.apk文件android手机可以直接安装,但是 .dex文件是个神马鬼?其实..apk文件是.dex文件编译过来的 ,最通俗的解释。

    然后我们就说说热修复:热修复主要是修复一些非常紧急的问题,比如说严重的逻辑错误或是严重的闪退等,或者像当年某宝屏蔽某快递一样,热修复的本质又是啥子了 ??? 用一句非常通俗易懂的话就是:运行时,方法替换

    70

    讲多了 。。 都是浮云, 原理知道了之后我们就来撸代码。。。。。 首先我们得明确一点,运行时方法替换这种事情Java是办不了的。。。 ,还有就是,你要使用热修复,那么很显然,你必须未雨绸缪先做好准备,也就是在软件设计的最初级策划阶段就要考虑进去,不可能说我线上版本出现了问题,我之前代码没有集成热修复工具,我现在要热修复,我只能微微一笑,根本不鸟 。。。。

    开始撸代码 。。。。

    70

    新建项目的时候 C++ 支持,勾上 ,上面说到 runtim的时候替换方法,这个Java解决不了, 只能有 C 来解决了 。。。。。

    1 定义native方法

    刚刚说了 ,热修复的本质是两个方法在runtime的时刻动态交换, 所以我们需要搞一个类让两个Java方法交换 ,当然这个方法肯定是 native的 。。。

    package hebiao.online.hot;

    import java.lang.reflect.Method;

    /** * Created by apple on 2018/3/17. */

    public class MethodUtil {

    static {

    System.loadLibrary("native-lib");

    }

    /** * *@param m1 原来的方法 *@param m2 新的方法 ,dex 文件中的方法 */

    public static native void changeMethod(Method m1,Method m2);

    }

    既然有 native方法 那么必须有对应的 C++ 的 代码和方法

    #include

    extern "C"{

    JNIEXPORT void JNICALL

    Java_hebiao_online_hot_MethodUtil_changeMethod(JNIEnv *env, jclass type, jobject m1, jobject m2) {

    }

    }

    70

    方法交换我们搞完了 , 注意这里 C++ 的方法我没有实现,我们的主题是 Java层面上的原理和实现,C++ 实现真心蛋疼,毕竟C++ 不是Java程序猿的专长

    2 定义被修复的标记

    方法交换我们撸好之后,我们需要干的第二个事情就是 ,定义被修复的标记 ,也就是告诉更新包(即.dex)文件更新的位置,以及要替换的部分

    package hebiao.online.hot;

    import java.lang.annotation.ElementType;

    import java.lang.annotation.Retention;

    import java.lang.annotation.RetentionPolicy;

    import java.lang.annotation.Target;

    @Target(ElementType.METHOD) /// 作用的方法上

    @Retention(RetentionPolicy.RUNTIME) /// 运行时,这个不解释

    public @interface HotFixInterface {

    String clazz(); /// 被修复的类

    String method(); /// 被修复的方法

    }

    3 生成补丁文件 .dex

    这一步是比较重要的 ,在生成补丁文件之前,我们先来看看要被修复的文件

    70

    以上是 ,要被修复的文件中的要被修复的方法 , 我们看下补丁文件 。。。

    70

    然后就是生产 .dex 文件了 。。。。 我们上面说到 .dex 是有 .class 文件生产的 也就是说我们首先要将.class文件编译出来 。。。。

    70

    70

    我们只需要这个 .class文件 ,可以把其他的 都删掉 。。。 像这样 。。。

    70

    然后就是 ,把.class 文件 编译成 .dex 文件了 。。。 这个其实 android studio提供了 一个编译工具 。。。

    70

    有一个 叫 dx 的 工具 , AS 自带的 。。 注意版本就行 。。。。 那么怎么使用了????

    70

    首先进入到 debug的目录 ,然后执行

    appledeiMac:debug apple$ pwd

    /Users/apple/Desktop/hot/app/build/intermediates/classes/debug

    appledeiMac:debug apple$ /Development/AS/build-tools/26.0.2/dx --dex --output=./hot.dex hebiao/online/hot/nact/MainActivity.class

    /Development/AS/build-tools/26.0.2/dx :根据你自己的环境变量

    –output=./hot.dex :输出目录

    hebiao/online/hot/nact/MainActivity.class class 的目录

    执行完之后 ,会发现多一个文件 。。

    70

    这个文件就是 热修复的更新包,也就是更新文件了 。。。。

    我们需要读取这个文件的里面的热修复方法,来修复本地存在的问题或在是错误

    4 加载补丁文件 .dex

    我们在生成 修复包的时候 发现热修复是通过注解来标记要修复的文件,我们可以通过读取.dex文件来找到哪个类中的哪个文件是要我们去修复。。。。我们来画一张图

    70

    这就是热修复的 整个的 一张图 。。。。。。

    package hebiao.online.hot;

    import android.content.Context;

    import java.io.File;

    import java.lang.reflect.Method;

    import java.util.Enumeration;

    import dalvik.system.DexFile;

    /**

    * Created by apple on 2018/3/17.

    */

    public class DexFileManager {

    private Context context;

    public DexFileManager(Context c){

    this.context = c;

    }

    /**

    * 加载 dex文件

    */

    public void loadDexFile(File file) {

    try{

    /**

    * 加载dex文件 ,三个参数

    * 第一个参数 : 文件绝对路径

    * 第二个参数: 临时缓存文件

    * 第三个参数:默认

    */

    DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),new File(context.getCacheDir(),"opt").getAbsolutePath(),Context.MODE_PRIVATE);

    /**

    * 遍历 dex中的类

    */

    Enumeration entry = dexFile.entries();

    while (entry.hasMoreElements()){

    String className = entry.nextElement();

    System.out.println(" ++$########### " +className);

    Class fixClass = dexFile.loadClass(className,context.getClassLoader());

    fixMethonAction(fixClass);

    }

    }catch (Exception e){

    }

    }

    /**

    * 撸这个类,

    * @param fixClass ,这个类是 dex 文件中的 ;注意!!!!!!

    */

    private void fixMethonAction(Class fixClass) throws Exception{

    /**

    * 找到 dex文件中类的所有方法

    */

    Method[] methods = fixClass.getDeclaredMethods();

    for (Method m: methods) {

    // HotFixInterface hf = m.getAnnotation(HotFixInterface.class);

    HotFixInterface hf = m.getAnnotation(HotFixInterface.class);

    if (hf == null){

    continue;

    }

    /**

    * 若找到 dex文件中类 的注解,则说明这个方法需要被修复或替换

    */

    String wrongClassName = hf.clazz();

    String wrongMethodName = hf.method();

    /**

    * 获取 旧的, 需要被修复的 方法

    */

    Class wrongClass = Class.forName(wrongClassName);

    Method wrongMethod = wrongClass.getDeclaredMethod(wrongMethodName,m.getParameterTypes());

    System.out.println( " ************** "+wrongClass.getName()+" wrongMethod === "+wrongMethod.getName());

    /**

    * 方法将 正确的方法和错误的方法交换 。。。

    */

    System.out.println("-------start---------111");

    MethodUtil.changeMethod(wrongMethod,m);

    }

    }

    }

    5 启动热修复

    你想怎么启动都行。 。。。。

    public void load(View v){

    DexFileManager dexFileManager = new DexFileManager(this);

    String name = getSdCardPath()+"/aaa/hot.dex";

    File file = new File(name);

    if (file.exists()){

    System.out.println("xxxxxxxxxxxxx 文件存在");

    dexFileManager.loadDexFile(file);

    }else {

    System.out.println("瞎了 。。。。 ");

    }

    }

    public static boolean isSdCardExist() {

    return Environment.getExternalStorageState().equals(

    Environment.MEDIA_MOUNTED);

    }

    public static String getSdCardPath() {

    boolean exist = isSdCardExist();

    String sdpath = "";

    if (exist) {

    sdpath = Environment.getExternalStorageDirectory()

    .getAbsolutePath();

    }

    return sdpath;

    }

    以上就是 热修复Java的 原理和实现, 但是 热修复的重点是理解这个流程 , 难点在 C++ 端 。。。。

    另外附上代码 : https://github.com/hebiao6446/hotFix

    展开全文
  • Android 热修复在Android的热修复中主要用来替换类,资源,so的过程;Java 虚拟机栈架构指令集的主要缺点是执行速度相对来说稍微慢一些;基于堆栈的机器需要更多指令,(内存)Android 虚拟机而基于寄存器(硬件在CPU...

    Android 热修复

    在Android的热修复中主要用来替换类,资源,so的过程;

    Java 虚拟机

    栈架构指令集的主要缺点是执行速度相对来说稍微慢一些;基于堆栈的机器需要更多指令,(内存)

    Android 虚拟机

    而基于寄存器(硬件在CPU内部)的机器指令更长

    速度: CPU - > 寄存器 -> 内存 -> 外存

    Android 目前有2中虚拟机, Dalvik 和 ART 虚拟机;

    Android 虚拟机和编译加载顺序

    Android 热修复其实主要是针对 Android 虚拟机加载类的一个过程,所以首先先我们应该知道 Android 常用的虚拟机是 Dalvik 虚拟和 ART 虚拟机;

    Android 4.0 之前是主要是的 Dalvik 虚拟机。 Android 4.4 之后开始支持 ART 虚拟机(可选), Android 5.0 之后就是 ART 虚拟机;

    Android 4.0 --> Android 4.4 --> Android 5.0 ---> Android 7.0

    Dalvik 虚拟机在 Android 2.2 的时候引入了 JIT (Just in time), 也就是一边运行,一边编译成机器码在运行;这种编译成机器码的过程在应用重启的时候需要重新编译成机器码再运行,有点浪费性能(不是持久化),重复翻译,编译,运行;

    在 Android 5.0 之后就使用完全使用 ART 虚拟机;因为在 AOT (ahead of time) 的操作在安装的时候把 dex 优化成odex; 在Android N (7) 之前是全量dex 优化成 odex, 这样导致安装 apk 的时候,或者系统更新重启的时候非常耗时,特别的慢;

    所以在 Android N 后引入了 JIT 和 AOT 的混合模式; 可以理解为“全时段的编译”(All-Of-the-Time compilation, 也叫 AOT;是不是发现有2个 AOT, 一开始我也很懵逼的;其实和Android 5.0 中的 AOT 是不太一样的;还有要注意的是Android N 之后的 JIT 和 Davlik 虚拟机中的JIT是不一样的,简单理解就是高级版的JIT;这个高级版本的 JIT 过程会把处理后的odex缓存到 base.art (有些地方也叫 image ) 中;等下次app启动的时候,就先直接把这个优化后的 base.art 加载到内存中;这样就不会重复的 JIT了;

    混合模式的理解

    ART 初期是使用全量的 AOT (aheader of time) 变成机器码(指令); 因为耗安装时间和系统升级后的启动时间;所以在 ART 的时候,先把dex 解释成中间态的,不编译成机器码。在运行的时候,或者充电的时候,只编译“热代码”

    Android N(7.x)开发者预览版包含了一个混合模式的运行时。应用在安装时不做编译,而是解释字节码,所以可以快速启动。ART中有一种新的、更快的解释器,通过一种新的JIT完成,但是这种JIT的信息不是持久化的。取而代之的是,代码在执行期间被分析,分析结果保存起来。然后,当设备空转和充电的时候,ART会执行针对“热代码”进行的基于分析的编译,其他代码不做编译。为了得到更优的代码,ART采用了几种技巧包括深度内联。

    对同一个应用可以编译数次,或者找到变“热”的代码路径或者对已经编译的代码进行新的优化,这取决于分析器在随后的执行中的分析数据。这个步骤仍被简称为AOT,可以理解为“全时段的编译”(All-Of-the-Time compilation)。

    源码类到机器执行的文件过程

    主要过程: java - (dex, class) - opt/oat -- odex;

    Davlik 虚拟机: java - dex - opt -- D 类型的 odex (优化过后的还是需要翻译); JIT

    ART虚拟机: java -- dex -- oat -- A 类型的 odex (机器码类型文件); AOT ( Ahead of time)

    混合模式: java -- dex -- oat -- (D类型的 odex, base.art: 热缓存,image) JIT(高级的JIT); AOT (All-Of-the-Time compilation)可以理解为“全时段的编译” ,profile

    注意以上的 A 类型 odex 和 D 类型的 odex,只是用来代码 2 种是不同的 odex,便于理解;

    补丁包

    补丁包主要有 class, 资源文件,so的改动;

    资源文件方案;替换 AssertManager, ---> 加载 resources.arsc

    os 还不清楚,没研究过, 可能使用classLoader 加载放入so 目录

    类 :底层替换和类加载器方案

    本文主要诉说类加载器的方案;

    类补丁生效原理

    底层替换方案 (阿里系)AndFix,

    类加器载方案 (腾讯系)QFix, tinker(粒度太细了), Sophix 使用类的替换(粒度大一点)

    因为 Android 有 2 款虚拟机,所以应该针对 2 款虚拟机加载过程进行分析和处理;

    Davlik 虚拟机的限制

    Android 在编译的时候有个 65536 (2的16次方)问题。受限于Dlv 虚拟机的限制;不只是方法名有限制,其实字段也是有限制的;

    Davlik Class resolved by unexpected DEX: 限制和处理方式

    if (!fromUnverifiedConstant && // 条件3

    IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED)) // 条件1

    {

    ClassObject* resClassCheck = resClass;

    if (dvmIsArrayClass(resClassCheck))

    resClassCheck = resClassCheck->elementClass;

    if (referrer->pDvmDex != resClassCheck->pDvmDex &&

    resClassCheck->classLoader != NULL) // 条件2

    {

    ALOGW("Class resolved by unexpected DEX:"

    " %s(%p):%p ref [%s] %s(%p):%p",

    referrer->descriptor, referrer->classLoader,

    referrer->pDvmDex,

    resClass->descriptor, resClassCheck->descriptor,

    resClassCheck->classLoader, resClassCheck->pDvmDex);

    ALOGW("(%s had used a different %s during pre-verification)",

    referrer->descriptor, resClass->descriptor);

    dvmThrowIllegalAccessError(

    "Class ref in pre-verified class resolved to unexpected "

    "implementation");

    return NULL;

    }

    }

    三个条件

    CLASS_ISPREVERIFIED 这个标记被打上的原理是,只要一个类里面和这个类的依赖都在一个dex中,那么这些类就被打上 PREVERIFIED 的标记;

    单独有个[特殊的.dex]这个 dex 里面只有一个类,且其他的dex中的类都引用一下这个单独 dex 里面的类,那么,项目中所有的类,就不会被打上 CLASS_ISPREVERIFIED 这个标记 dex 数组: [ 1.dex, 2.dex, 3.dex, 特殊的.dex(插桩类)]

    referrer->pDvmDex != resClassCheck->pDvmDex

    补丁类和引用类应该在同一个dex里面;

    fromUnverifiedConstant hook 使用 native 方式

    类加载器的双亲委派加载机制

    类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载

    相关日志

    12-07 10:05:27.859 11471-11471/app.mj.com.ihour I/MyApp: getClassLoader() : dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/app.mj.com.ihour-2/base.apk"],nativeLibraryDirectories=[/data/app/app.mj.com.ihour-2/lib/arm64, /system/lib64, /vendor/lib64]]]

    12-07 10:05:27.860 11471-11471/app.mj.com.ihour I/MyApp: getClassLoader().getParent(): java.lang.BootClassLoader@36e0624

    12-07 10:05:27.860 11471-11471/app.mj.com.ihour I/MyApp: getClassLoader().getParent().p: null

    参考文献

    主要参考图

    %E7%83%AD%E4%BF%AE%E5%A4%8D_%E5%AF%B9%E6%AF%94.jpeg

    qq2.jpeg

    qq.jpeg

    展开全文
  • Java代码变更怎么解决?热修复及调试如何实现?对于Java语言来说,如果涉及代码变更,一般情况下会选择重新...Java热修复 目前较火的热修复方案大致分为两派:阿里系:DeXposed、andfix:从底层二进制入手(C语言)...
  • ​ Java代码变更怎么解决?热修复及调试如何实现?对于Java语言来说,如果涉及代码... Java热修复 目前较火的热修复方案大致分为两派:阿里系:DeXposed、andfix:从底层二进制入手(C语言);腾讯系:tinker:从Java加...
  • 如需转载请评论或简信,并注明出处,未经允许不得转载目录...其实,不管是哪种热修复方案,肯定是如下几个步骤:下发补丁(内含修复好的class)到用户手机,即让app从服务器上下载(网络传输)app通过"某种方式",使补...
  • 下载dex文件,静默替换有问题的dex文件,进行修改热修复详解:1.确定那些文件是主类,不能出现问题的类;2.多分包;3.下载dex文件;4.写到本并且注入;二、注入详解:1.apk包安装完成之后存储路径:data/app/...
  • 一、 热修复框架简介、 1、类替换、 2、so 替换、 3、资源替换、 4、全平台支持、 5、生效时间、 6、性能损耗、 7、总结、 二、 将 Java 字节码文件打包到 Dex 文件、
  • java层实现Tinker热修复
  • 引言关于热修复,可以看看下面几篇文章。里面说了热修复的一些原理,这篇文章仅仅是工具的使用。关于热修复还是有很多坑的,例如跨平台支持不太好。而且AndFix而言好像只是支持2.3-6.0的Android版本。我在6.0上面...
  • 基于 安卓App热补丁动态修复技术介绍 github上开源了很多热修复的框架,大致有:原理在app打包的时候,阻止相关类被打上CLASS_ISPREVERIFIED标志;将存在bug的类打成一个patch.jar包;通过DexClassLoader从sdcard...
  • JAVA代码的热修复实现

    千次阅读 2017-06-29 18:41:58
    用于处理线上的一些逻辑bug的利器,这样,就不会为了一些几行代码的错误导致的bug,需要重新发版本重启服务器,而严重影响在线活跃,收入了。 1.实现一个代理类: ...import java.lang.instrument.I...
  • 使用Java实现实时热修复
  • 腾讯 QZone Muitidex方案 Multidex方案是 基于ClassLoader的 纯java实现 的 重启生效的热修复方案. 原理 Apk打包的时候可能生成多个classes.dex文件。JVM中 类加载器ClassLoader,在程序运行使用到某一个Class的...
  • Java热修复框架实践

    2017-10-09 08:39:33
    所以我们需要找个地方把原来的方法存起来,不过在具体实现的时候,会遇到一个问题,就是 Java的非static,非private的方法默认是虚方法,在调用这个方法的时候会有一个类似查找虚函数表的过程:mirror::
  • 0.前言热修复这项技术,基本上已经成为Android项目比较重要的模块了。主要因为项目在上线之后,都难免会有各种问题,而依靠发版去修复问题,成本太高了。现在热修复的技术基本上有阿里的AndFix、QZone的方案、美团...
  • ./gradlew clean nuwaQihooDebugPatch -P NuwaDir=/Users/jason/Documents/nuwa java verison must be same using android studio and terminal run following command to push patch.jar to sdcard. adb push ...
  • 在说到热修复之前,先简单说下android的apk生成的一个原理,我们都是知道android是Java语言写的,那么.java文件和.class文件大部分人应该都不会陌生,其实从Java文件到apk文件经历了以下的过程 这是java文件到...
  • 热修复技术之Java相关

    2019-11-21 13:29:21
    文章目录Java相关内部类编译:匿名内部类静态成员类加载时机clinitinit Java相关 内部类 我们所知道的: 非静态内部类持有外部类引用;静态内部类不持有外部类引用 编译: 内部类与外部类在编译期都是顶级类,此时...
  • 最近研究了一下阿里的AndFix框架,原理本身不复杂,但是深入探索后发现热修复这块原来有很多底层的知识和黑科技值得挖掘的,故形成本篇blog和大家分享。而AndFix框架本身的使用和集成可直接根据github的README来做,...
  • 修原理(java类加载机制) DexClassLoader在加载一个类时会先从自身DexPathList对象中的Element数组中获取(Element[] dexElements)到对应的类,之后再加载。采用的是数组遍历的方式,不过注意,遍历出来的是一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 667
精华内容 266
关键字:

java热修复

java 订阅