Android 热修复

Android 热修复

本文链接:https://blog.csdn.net/feather_wch/article/details/132052856

文章目录

  • Android 热修复
    • 方案对比
      • AndFix@Deprecate
      • Robust-即时生效
      • Tinker-非及时生效
    • ClassLoader
    • 实战一
      • 手动打补丁包
  • 热修复二

方案对比

AndFix@Deprecate

1、AndFix为什么可以实时生效?

在native层动态替换掉Java层的方法,通过native层hook java层代码。

2、如何拿到补丁包的有注解Method?

  1. 补丁包包含Test.class
  2. 类加载Test.class
  3. 反射Method
  4. 拿到注解(标记了要替换谁),找到目标类

3、如何完成两个对象的替换?bug method => fix method

Java层伪代码:

BugMethod.clazz = FixMethod.clazz

Native层代码:

replace(env, jobject bug, jobject fix)
{// 把bug method的所有属性,都替换为,补丁method的所有属性
}

4、后续拿到的都是修复后的Method.class类对象

Robust-即时生效

美团方案:抖音还在用,纯Java实现

  1. 对每个函数插入一段代码,字节码插桩技术。
  2. 编译阶段,在class字节码写代码
  3. 插入开关: 如果没有补丁包,就返回原先逻辑。有补丁包,交给补丁。
class State{public static ChangeQuickRedirect changeQuickRedirect;public long getIndex{if(changeQuickRedirect != null){return PatchProxy.accessDispatch(xxxx);}return 100;}
}
  1. 拿到补丁包内的类对State.changeQuickRedirect进行赋值
Class<StatePatch> clz = StatePatch.class; // 拿到补丁包的类
State.changeQuickRedirect = clz.newInstance(); // 赋值,影响开关的条件判断

相关类:PatchesInfoImpl.java、StatePatch.java

Tinker-非及时生效

1、关键词:DexDiff、增量更新
2、工具:
bsdiff 将两者区别信息,放到patch上

bsdiff 1.txt 2.txt patch
bspatch:合成 1.txt + patch = 2.txt

3、Tinker是差分包 + Bug Dex = 修复后Dex
4、热修复思路 => 将补丁Dex放到数组前面
5、什么时候热修复?越早越好,防止类更早加载,就失效了
6、补丁Dex什么时候删除?不能删。
7、Application有Bug怎么办?不能有Bug

ClassLoader

1、实现类:BootClassLoader、PathClassLoader、DexClassLoader、InMemoryClassLoader

2、下面类的ClassLoader是什么?

MainActivity.class.getClassLoader() // Path 我们
AppCompatActivity.class.getClassLoader() // Path 第三方
Application.class.getClassLoader() // Boot 系统
getClassLoader() // Path 应用

3、PathClassLoader原理

  1. parent => BootClassLoader
public class PathClassLoader extends BaseDexClassLoader {public PathClassLoader(String dexPath, ClassLoader parent) {}public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {}
}
  1. loadClass做了什么?双亲委派,先交给BootClassLoader去加载。
  2. findClass源码
// BaseDexClassLoader.javaDexPathList pathList; // 内部有一个dexElements数组,存储着该ClassLoader的所有dex/resources的路径public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {super(parent);this.pathList = new DexPathList(this, dexFiles);// DexPathList}protected Class<?> findClass(String name) throws ClassNotFoundException {Class c = pathList.findClass(name, suppressedExceptions); // DexPathList中查找if (c == null) {ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);throw cnfe;}return c;}
// DexPathList.javapublic Class<?> findClass(String name, List<Throwable> suppressed) {for (Element element : dexElements) {// Element内部的DexFile中查找Class<?> clazz = element.findClass(name, definingContext, suppressed);if (clazz != null) {return clazz;}}return null;}
// Element,DexPathList的静态内部类private Element[] dexElements;static class Element {private final File path;private final DexFile dexFile;// DexFilepublic Class<?> findClass(String name, ClassLoader definingContext,List<Throwable> suppressed) {return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed): null;}}

实战一

手动打补丁包

1、手动补丁包流程

  1. bug修复
  2. 编译项目,生成类的class文件(make project)
  3. 生成补丁包
dx --dex --output=patch.jar com/zte/tv5gshow/test/Bug.class

2、补丁包放入到DexFile数组

  1. 获取PathClassLoader对象
  2. 反射到DexPathList对象
  3. 反射到Element数组(oldElement)
  4. 把补丁包编程Element数组,patchElement:反射执行makePathElement()
  5. 合并oldElement + patchElement = newElement (Array.newInstance)
  6. 反射吧oldElement数组设置为newElement数组
    makePathElement()需要List File集合
File file = new File("/sdcard/patch.jar")
list.add(file);
// 作为List的参数传入

热修复二

1、PathClassLoader是哪里创建的?

ActivityThread中创建了PathClassLoader并且传入了Apk的dex路径
LoadedApk->ApplicaitonLoaders.getDefault().getClassLoader()
-> ClassLoaderFactory.createClassLoader
-> new PathClassLoader(dexPath, librarySearchPath, parent)

2、so修复 => DexPathList内部属性nativeLibraryPathElements

3、资源修复 => 和换肤一样

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/18286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32零基础入门教程03】GPIO输入输出之GPIO框图分析

本章节主要讲解点亮LED的基本原理&#xff0c;以及GPIO框图的讲解。 如何点亮LED&#xff08;输出&#xff09; 首先我们查看原理图&#xff0c;观察电路图中LED的连接情况&#xff0c;如下图可以看出我们的板子中LED一端通过限流电阻连接的PB0另一端连接的是高电平VCC&#xf…

排序进行曲-v2.0

小程一言 这篇文章是在排序进行曲1.0之后的续讲&#xff0c; 0之后的续讲,英语在上一篇讲的排序的基本概念与分类0之后的续讲, 英语在上一篇讲的排序的基本概念与分类这片主要是对0之后的续讲,英语在上一篇讲的排序的基本概念与分类这 篇主要是对几个简单的排序进行细致的分析…

JavaData:JDK8之前传统的日期和时间

Data JDK8之前传统的日期和时间 //目标:掌握Date日期类的使用。 //1、创建一个Date的对象:代表系统当前时间信息的。 Date d new Date(); system.out.println(d);//2、拿到时间毫秒值。 long time d.getTime(); system.out.println(time);//3、把时间毫秒值转换成日期对象:2…

企业电子招投标采购系统源码之首页设计

&#xfeff;功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&…

Unity-缓存池

一、.基础缓存池实现 继承的Singleton脚本为 public class Singleton<T> where T : new() {private static T _instance;public static T GetIstance(){if (_instance null)_instance new T();return _instance;} } 1.PoolManager using System.Collections; using S…

Pytest-BDD 行为驱动开发测试

文章目录 01 BDD02 pytest-BDD03 安装pytest-BDD04 pytest-bdd的框架结构05 pytest-bdd基础使用5.1 第一步:添加需求描述/用户场景5.1.1 BDD的表达语法5.1.2 创建`.feature`文件5.2 第二步:实现用户场景5.2.1 用户场景的解析/实现5.2.2 使用`scenarios`或`@scenario`关联用户…

python 测试磁盘读写速度和内存读写速度.

import time import os # from SpeedTest import perform_default_speedtest# 测试硬盘读写速度 def test_disk_speed():filename "./testfile.bin"# 生成一个1GB大小的测试文件with open(filename, "wb") as f:f.write(os.urandom(1024*1024*1024))# 从…

C语言手撕单链表

一、链表的概念 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;也就是内存存储不是像顺序表那么连续存储&#xff0c;而是以结点的形式一块一块存储在堆上的&#xff08;用动态内存开辟&#xff09;。 既然在内存上不是连续存储&#xff0c;那我们如何将这一…

Qt/C++音视频开发50-不同ffmpeg版本之间的差异处理

一、前言 ffmpeg的版本众多&#xff0c;从2010年开始计算的项目的话&#xff0c;基本上还在使用的有ffmpeg2/3/4/5/6&#xff0c;最近几年版本彪的比较厉害&#xff0c;直接4/5/6&#xff0c;大版本之间接口有一些变化&#xff0c;特别是一些废弃接口被彻底删除了&#xff0c;…

浙大数据结构第六周之Saving James Bond - Easy Version

题目详情&#xff1a; This time let us consider the situation in the movie "Live and Let Die" in which James Bond, the worlds most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake f…

Django学习记录:使用ORM操作MySQL数据库并完成数据的增删改查

Django学习记录&#xff1a;使用ORM操作MySQL数据库并完成数据的增删改查 数据库操作 MySQL数据库pymysql Django开发操作数据库更简单&#xff0c;内部提供了ORM框架。 安装第三方模块 pip install mysqlclientORM可以做的事&#xff1a; 1、创建、修改、删除数据库中的…

【腾讯云 Cloud studio 实战训练营】搭建Next框架博客——抛开电脑性能在云端编程(沉浸式体验)

文章目录 ⭐前言⭐进入cloud studio工作区指引&#x1f496; 注册coding账号&#x1f496; 选择cloud studio&#x1f496; cloud studio选择next.js&#x1f496; 安装react的ui框架&#xff08;tDesign&#xff09;&#x1f496; 安装axios&#x1f496; 代理请求跨域&#x…

动态爬虫IP与反爬虫技术的博弈:揭秘真实反爬虫事例引发的思考

作为一名长期从事爬虫行业动态IP解决方案服务商&#xff0c;我们深知动态IP代理在抗击反爬虫方面的重要性。在当今数字化时代&#xff0c;互联网数据的爆炸性增长让数据采集变得前所未有的重要。然而&#xff0c;随着数据价值的不断提升&#xff0c;反爬虫技术也日益增强&#…

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离(一)

说明&#xff1a;请先自行安装好docker再来看本篇文章&#xff0c;本篇文章主要实现通过使用docker部署mysql实现读写分离&#xff0c;并连接数据库测试。第二篇将实现使用Shardingjdbc实现springboot的读写分离实现。 基于Docker去创建Mysql的主从架构 #创建主从数据库文件夹…

Ubuntu 20.04 系统或图像界面卡死或完全无响应处理方法

Ubuntu 20.04 系统或图像界面卡死或完全无响应处理方法 问题背景无需重启方法安全重启方法 问题背景 Ubuntu 20.04在安装驱动程序时系统突然无响应&#xff0c;终端也无法运行&#xff1b;考虑到尽量不破坏系统&#xff0c;不希望强制上下电重启机器&#xff0c;以免损坏文件系…

版本控制和团队协作:前端工程化的关键要素

文章目录 版本控制系统介绍&#xff08;如 Git&#xff09;1. 分布式系统2. 分支管理3. 版本控制4. 快速和高效5. 社区和生态系统 分支管理和团队协作流程1. 主分支2. 功能分支3. 开发工作4. 合并到develop5. 发布准备6. 发布 持续集成与持续部署实践持续集成&#xff08;CI&am…

【前端知识】React 基础巩固(三十七)——自定义connect高阶组件

React 基础巩固(三十七)——自定义connect高阶组件 一、手撸一个自定义connect高阶组件 import { PureComponent } from "react"; import store from "../store";/*** connect的参数&#xff1a;* 参数一&#xff1a; 函数* 参数二&#xff1a; 函数* 返…

lc1074.元素和为目标值的子矩阵数量

创建二维前缀和数组 两个for循环&#xff0c;外循环表示子矩阵的左上角&#xff08;x1,y1&#xff09;&#xff0c;内循环表示子矩阵的右下角&#xff08;x2,y2&#xff09; 两个for循环遍历&#xff0c;计算子矩阵的元素总和 四个变量&#xff0c;暴力破解的时间复杂度为O(…

ChatGPT安全技术

前言 近期&#xff0c;Twitter 博主 lauriewired 声称他发现了一种新的 ChatGPT"越狱"技术&#xff0c;可以绕过 OpenAI 的审查过滤系统&#xff0c;让 ChatGPT 干坏事&#xff0c;如生成勒索软件、键盘记录器等恶意软件。 他利用了人脑的一种"Typoglycemia&q…

MySQL 5.7版本不支持ROW_NUMBER()函数

MySQL 5.7版本不支持ROW_NUMBER()函数。但是&#xff0c;你可以使用变量来手动实现这个功能。以下是一个示例查询语句&#xff1a; SELECT row_number:row_number1 AS row_num,column1, column2, ... FROM (SELECT row_number:0) AS t,your_table ORDER BY column1;在这个语句…