AndFix使用感想

AndFix已经使用了一段时间了,但是到AndFix上看了一下,最近2个月都没有更新代码了,有141个issues和3个pull
request没人处理,其实AndFix的Contributors就俩个人,一个是rogerAce还有个是supern
lee
,虽然快要沦为了阿里的KPI项目,但是并不妨碍AndFix在业界的地位-一个低成本快速接入的Bugxiuf第一方案。

第二方案Nuwa,Nuwa的原理是修改了gradle的编译task流程,替换dex的方式来实现。但是可惜的是gradle
plugin在1.5以后取消了predexdebug这个task,而Nuwa恰恰是依赖这个task的,所以导致Nuwa在gradle plugin1.5版本后无法使用,而且Nuwa的作者是贾吉鑫也在一次技术分享的时候也表示,不再维护Nuwa,因为他感觉AndFix已经做的足够好,他不想把AndFix做的事情再做一次。

闲话扯完,网上AndFix的教程和解析已经很多,这里就仅分享一下我在AndFix中学到的东西。

SortedSet

1
2
private final SortedSet<Patch> mPatchs;
this.mPatchs = new ConcurrentSkipListSet();

SortedSet是个接口,它里面的(只有TreeSet这一个实现可用)中的元素一定是有序的。
保证迭代器按照元素递增顺序遍历的集合,可以按照元素的自然顺序(参见 Comparable)进行排序, 或者按照创建有序集合时提供的 Comparator进行排序。要采用此排序,

ConcurrentSkipListSet(在JavaSE 6新增的)提供的功能类似于TreeSet,能够并发的访问有序的set。因为ConcurrentSkipListSet是基于“跳跃列表(skip list)”实现的,只要多个线程没有同时修改集合的同一个部分,那么在正常读、写集合的操作中不会出现竞争现象。

mPatchs是一个有序并发Set,Set中的元素都必须实现 Comparable 接口,所以Patch实现了Comparable的compareTo方法,可见Patch是按照时间从小到大顺序

1
2
3
public int compareTo(Patch another) {
    return this.mTime.compareTo(another.getTime());
}

Patch生成

首先看一下Patch是什么?解压之后(盗图)

meta-inf文件夹为:

打开patch.mf文件可以发现两个apk的差异信息:

1
2
3
4
5
6
7
Manifest-Version: 1.0
Patch-Name: app-release-fix
To-File: app-release-online.apk
Created-Time: 30 Mar 2016 06:26:27 GMT
Created-By: 1.0 (ApkPatch)
Patch-Classes: com.qianmi.shine.activity.me.AboutActivity_CF
From-File: app-release-fix.apk

AndFix是如何把文件读取出来,并且初始化Patch的尼?Android大部分的文件都是压缩包,所以这里的处理也有一定的代表性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private void init() throws IOException {
      JarFile jarFile = null;
      InputStream inputStream = null;

      try {
          jarFile = new JarFile(this.mFile);
          JarEntry entry = jarFile.getJarEntry("META-INF/PATCH.MF");
          inputStream = jarFile.getInputStream(entry);
          Manifest manifest = new Manifest(inputStream);
          Attributes main = manifest.getMainAttributes();
          this.mName = main.getValue("Patch-Name");
          this.mTime = new Date(main.getValue("Created-Time"));
          this.mClassesMap = new HashMap();
          Iterator it = main.keySet().iterator();

          while(it.hasNext()) {
              Name attrName = (Name)it.next();
              String name = attrName.toString();
              if(name.endsWith("-Classes")) {
                  List strings = Arrays.asList(main.getValue(attrName).split(","));
                  if(name.equalsIgnoreCase("Patch-Classes")) {
                      this.mClassesMap.put(this.mName, strings);
                  } else {
                      this.mClassesMap.put(name.trim().substring(0, name.length() - 8), strings);
                  }
              }
          }
      } finally {
          if(jarFile != null) {
              jarFile.close();
          }

          if(inputStream != null) {
              inputStream.close();
          }

      }

  }

JarFile 类用于从任何可以使用 java.io.RandomAccessFile 打开的文件中读取 jar 文件的内容。它扩展了 java.util.zip.ZipFile 类,使之支持读取可选的 Manifest 条目。Manifest 可用于指定关于 jar 文件及其条目的元信息。

这里使用了JarFile来解压.patch文件,然后找到META-INF/PATCH.MF 然后找到Patch-Classes,这样就可以取出里面被修复的类,当然这些类都是在原来的包名+CF,当真正修复的时候执行this.mAndFixManager.fix(patch.getFile(), cl, classes)方法,里面patch.getFile()里面是dex,classes里面是指定修复的类。

fix

下面就是AndFix中最重要的一个方法了,核心的fix逻辑都在这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public synchronized void fix(File file, ClassLoader classLoader, List<String> classes) {
       if(this.mSupport) {
           if(this.mSecurityChecker.verifyApk(file)) {
               try {
                   File e = new File(this.mOptDir, file.getName());
                   boolean saveFingerprint = true;
                   if(e.exists()) {
                       if(this.mSecurityChecker.verifyOpt(e)) {
                           saveFingerprint = false;
                       } else if(!e.delete()) {
                           return;
                       }
                   }

                   DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(), e.getAbsolutePath(), 0);
                 。。。
                               clazz = dexFile.loadClass(entry, classLoader);
			  。。。
                                   this.fixClass(clazz, classLoader);
                       return;
                   }
               } catch (IOException var12) {
                   Log.e("AndFixManager", "pacth", var12);
               }
           }
       }
   }

mSupport- 是否支持热更新修复,简单看了一下,就是不支持yunOS,sdk在8~23都可以。

verifyApk- 对比一下签名信息,看dex是否合法,这里面的方法也很典型,自己写库的时候也可以用。

verifyOpt- 获取file的md5值看是否改变过

DexFile.loadDex

打开一个DEX文件,并提供一个文件来保存优化过的DEX数据。如果优化过的格式已存在并且是最新的,就直接使用它。如果不是,虚拟机将试图重新创建一个。该方法主要用于应用希望在通常的应用安装机制之外下载和执行DEX文件。不能在应用里直接调用该方法,而应该通过一个类装载器例如dalvik.system.DexClassLoader.
关于动态加载可以看看扩展

接下来就是找到带MethodReplace注解的方法,这个注解是在代码对比过程自动生成的,

1
2
3
4
5
6
7
8
MethodReplace methodReplace = (MethodReplace)method.getAnnotation(MethodReplace.class);
          if(methodReplace != null) {
              String clz = methodReplace.clazz();
              String meth = methodReplace.method();
              if(!isEmpty(clz) && !isEmpty(meth)) {
                  this.replaceMethod(classLoader, clz, meth, method);
              }
          }

replaceMethod传入的有class名字,方法的名字,方法本身,这样根据meth就有找到原来app中对应的方法

1
Method src1 = clazz.getDeclaredMethod(meth, method.getParameterTypes());

一个有bug的方法,一个修复后的方法,一招乾坤大罗移,

1
AndFix.addReplaceMethod(src1, method);

为啥说是乾坤大罗移是因为AndFix在C的层面将源方法(meth)的各个属性被替换成了新的方法(target)的各个属性,就完成了方法的替换,当虚拟机误以为方法还是之前的“方法”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extern void __attribute__ ((visibility ("hidden"))) dalvik_replaceMethod(
        JNIEnv* env, jobject src, jobject dest) {
    jobject clazz = env->CallObjectMethod(dest, jClassMethod);
    ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef_fnPtr(
            dvmThreadSelf_fnPtr(), clazz);
    clz->status = CLASS_INITIALIZED;

    Method* meth = (Method*) env->FromReflectedMethod(src);
    Method* target = (Method*) env->FromReflectedMethod(dest);
    LOGD("dalvikMethod: %s", meth->name);

    meth->clazz = target->clazz;
    meth->accessFlags |= ACC_PUBLIC;
    meth->methodIndex = target->methodIndex;
    meth->jniArgInfo = target->jniArgInfo;
    meth->registersSize = target->registersSize;
    meth->outsSize = target->outsSize;
    meth->insSize = target->insSize;

    meth->prototype = target->prototype;
    meth->insns = target->insns;
    meth->nativeFunc = target->nativeFunc;
}

至此,AndFix的整个过程就结束了,可见要完成这样的库,需要会写插件,NDK,还有对类的加载过程非常了解,最关键的是,从问题入手找解决方法的过程,试着想一下,如果你有了这些技术栈,现在需要解决动态修复的问题,你会怎么做?我可能会把整个类都替换掉,因为在我感觉中,一块代码的替换好像比一个类的替换要难,但是阿里的同学做到了。实在佩服佩服,也为阿里在开源届做的贡献点赞!!!!

时间: 2025-01-27 14:42:00

AndFix使用感想的相关文章

浅析:企业网站降权后恢复排名的感想

作为一个网站SEOer人员在自己优化的历程中可以说几乎每个站长都会经历,自己所优化的网站被降权的遭遇,在笔者看来这正是对一个合格的SEOer人员的考验,当大家遇到这样的问题时,可千万无需急躁,要静下心来认真回顾自己是怎么优化网站,是不是做了违规度娘算法的优化手法,如果自己能够诊断网站,最好自己对网站做个全方位的诊断,如果不会诊断可以向公司提出建议找专业的公司进行诊断<如A5站长网是国内知名站长网,该公司具有专业的网站诊断团队,可以向其寻求帮助>,找出被降权的原因所在,再制定相应的优化策略,对网

通过卖网站链接得到的一些感想

大家一定都卖过链接,也有一些辛酸的事吧,今天我就来谈谈一次卖链接的感想. 29号的时候,我去a5论坛上联系一个卖链接的QQ:19478923,我首先发我的站给他看,然后他问我好多钱,我说pr4和pr3两站30,然后他就马上说88,然后我又问他,你出多少钱,他说这两站(luzhuba.cn aabc.cn),各做三链接,一共给你40元. 我当时很生气的就回答他说"真想杀了你",你说一个pr4和一个pr3链接,上三个链接给40,你说是什么价格,那个听到了不会生气.这事还没完,他马上就乱骂人

暴雪公司欧洲员工自暴工作历程感想

在欧服官方论坛中,今天出现了一篇"特殊"的帖子,在这个帖子里,欧服官方GM与普通玩家们聊起了他在暴雪公司工作的历程以及他对暴雪公司的一些感想.    下面是全文翻译:    我2004年入职--现在看看我吧!    我经常轮班,GM是24小时的工作,整个组的同事们需要轮流在每个24小时里上班.这听上去非常累人,但你通常能被安排在固定的时段,这样你碰到的同事也是比较熟悉的.因此无论你哪天轮班或是周末,可以找到熟悉的人聊天.    来说说收入.无论如何我们都得考虑生活费.如果不是很奢侈的话

说说自己网站被K了之后的感想

网站百度收录为0,刚刚百度查过了,无奈,对于降权总是很纠结,不得不说一下自己的网站降权和K的问题了,最近的一些行为可能也影响了百度,可能影响它对于网站的收录问题,还是说一下自己网站降权的问题吧,其实有一些事情必须写出来才能更加的明白,笔下有黄金,也有自己对这个问题最深的感悟. 感想之一:直接原因,空间问题. 关于空间问题,应该是直接原因,空间被关了一天之后,然后网站就出问题,当然直接原因就在于空间,空间问题是我们由始至终都已经注意的问题,可是呢,有一些问题总是无法避免,弄的当时空间被整整关闭了一

经验分享:网站title标题修改后的感想

  对网站而言,title标题无疑是核心部分.对于搜多引擎而言,也是认识网站的前提和基础.因为它概括了整个网站的所有内容,可谓是网站的灵魂支柱.笔者在网站这个行业也有数年了,时常的会听到身边的站长朋友诉说的因为修改标题导致网站被降权.排名下降等等,所以笔者也建议大家如果不是万不得已的情况下,尽可能的不要去修改标题.好了,不罗嗦了,今天笔者与大家分享经验,因为修改title标题后的一些感想和实质性的经验. (一)修改主页标题后,导致快照不正常. 笔者手下的一个站点,建站一年来,大概修改了3次tit

实名网络营销微博论道之SEO行业感想

戏说互联网第1期 实名网络营销论坛创始人朱卫坤发起话题:对于SEO行业来说,seo已经慢慢变成白热化,虽然seo门槛很低,当你进入这个行业后,虽着时间的推移,不知道自己每天要发多少文章,要发多少外链,有时工作时间往往超过了12个小时!你们对seo行业有什么感想或者思路?或是对seo有什么期望? 互联网这个江湖很深,对于seo的发展动态来说,是网络营销中不可或缺的一项技能或者岗位,有人说seo快要灭亡.对于seo行业来说,笔者觉得可以与现实中的城管结合来谈,很多时候,觉得城管很烦人,很讨人厌,但是

基于J2ME的游戏开发总结和感想

功能和不足 本程序设计实现了手机上以J2ME为平台的一个射击类手机游戏的开发与实现,采用从外部文件读取图像.自动控制敌人机体运行的方式进行控制,具有一定的可玩性.复杂性和挑战性.经过了细心的调试和排错解决了绝大部分的问题. 就像几乎每一个软件都会有这样那样的不足,尤其是像本软件那样未经过精心测试,且开发团体很小,开发者知识面较窄,开发时间相对较短的非商业软件.即使是作为经典操作系统而被微软及整个软件行业引以为豪的各版本的Windows操作系统也时常会发生许多类型的错误和漏洞.本程序对于初涉此领域

【感想】DTCC大会有感

 好久没有沉淀文章了,感谢ITPUB 论坛赠送门票,4.15-4.18  去北京参加了DTCC 大会,没有能够全部参加所有的场次,选择了其中自己感兴趣的场次,主要是偏运维 和MySQL ,Oracle,云计算数据库相关的,说一下自己的一些感想和思考,有所不足 ,还请各位指正 . 先说总体感想     1 几个互联网公司涉及到水平拆分处理的时候 几乎全部采用了基于mysql proxy 开发 .类似于cobar 的中间件,同时也决定了 运维的自动化处理 比如扩容时的添加机器的方式 ,但是对于缩容

Android AndFix热补丁动态修复框架使用教程

简介 已经上线的项目发现BUG,紧急修复BUG发布新版本?No,也许你需要AndFix. AndFix 是阿里巴巴开源的 Android 应用热修复工具,帮助 Anroid 开发者修复应用的线上问题.Andfix 是 "Android hot-fix" 的缩写.支持 Android 2.3 - 6.0,ARM 和 x86 架构,dalvik 运行时和 art 运行时.AndFix 的分支是 .apatch 文件. GitHub地址 : https://github.com/alibab