写点什么

滴滴开源 DroidAssist : 轻量级 Android 字节码编辑插件

  • 2019-09-16
  • 本文字数:2609 字

    阅读完需:约 9 分钟

滴滴开源 DroidAssist : 轻量级 Android 字节码编辑插件

近日,滴滴发布的开源项目 DroidAssist ,提供了一种简单易用、无侵入、配置化、轻量级的 Java 字节码操作方式,只需要在 XML 配置中添加简单的 Java 代码即可实现编译期对 Class 文件的动态修改。


DroidAssist 和其他 AOP 方案不同,它提供了一种简单易用、无侵入、配置化、轻量级的 Java 字节码操作方式,你不需要 Java 字节码的相关知识,只需要在 XML 配置中添加简单的 Java 代码即可实现编译期对 class 文件的动态修改,同时不需要引入其他额外的依赖。

起源

作为大型 APP 的代表,滴滴出行乘客端集成了较多的业务线,包含了大量的依赖库,每个版本都有多个团队向乘客端集成大量的代码,而且这些代码都是难以直接追溯到源码的,同时乘客端还有用户量大,日活高,迭代快等特点,这些情况对乘客端的开发和维护形成很大的挑战,主要体现在:问题防范难度大、问题规模大、后期维护成本高。


2018 年 5 月,乘客端团队进行卡顿专项优化, 其中有个问题是:由于安卓系统 SharedPreferences 自身机制,当频繁调用 SharedPreferences.apply() 方法时,可能会出现由 QueuedWork.waitToFinish() 造成的卡顿和 ANR。主要原因是系统在 Activity 的 onPause、onStop,以及 Service 的 start 和 stop 生命周期时会执行阻塞等待 QueuedWork 清空,推测系统是为了保证持久化成功率,从而确保用户离开组件之前完成 SharedPreferences 的文件写入。


分析原因之后,我们认为,乘客端 APP 相对处于单一的进程环境,去掉这个持久化阻塞也是可以的。为了解决这个问题,我们决定对系统的 SharedPreferences 进行改造,实现我们自己的 SharedPreferences。


但是随之而来的问题是,我们自定义的 SharedPreferences 怎么以最小的成本接入到乘客端呢?很容易想到以下两种方案:


  • 修改所有调用 Context.getSharedPreferences() 的代码,返回我们自己的 SharedPreferences 对象,缺点:改动太多,工作量太大,修改、还原成本太高。

  • 所有的 Application、Activity、Service 类都从统一的的 Base 基类派生,在基类中重写 getSharedPreferences 方法返回自定义 SharedPreferences 对象,和方法一相比,此方法代码改动较小,但是也存在是无法修改第三方库,而且工作量也比较大,修改、还原成本也很高的问题。


以上两种方式都具有较大的侵入性,会涉及到大量的源码以及依赖库的代码改动,后期维护和升级成本也比较高,为了寻找更加理想的解决方案,我们希望找到一种无侵入的 Mock 工具,能做到不修改代码就能 Mock 所有 getSharedPreferences()方法的调用返回结果,初步有如下两种实现思路:


  • Hook:Hook 技术需要一直处理各种厂商和机型的兼容性问题,有较大的稳定性风险。

  • AOP:AOP 类框架在编译期实现字节码操作,比较成熟稳定,可以考虑采用,但是经过分析发现,现有的 AOP 框架包括 AspectJ 并不能实现我们需要的 Mock 功能。


类似 SharedPreferences 替换这样的需求还有很多,于是我们决定自己开发一个 Android 平台 Mock 工具,经过调研之后,我们确定了字节码修改的技术方向,通过修改字节码实现这样的需求,由此 DroidAssist 应运而生。


项目地址:https:// github. com/didi/DroidAssist

示例

下面例子是背景中提到的 SharedPreferences 改造,添加如下 DroidAssist 配置,在项目编译后,所有调用 Context.getSharedPreferences() 的代码,将全部会被修改为返回自定义的 SharedPreferences 实例的代码:


1 <Replace>2     <MethodCall>3DroidAssist4<Source>android.content.SharedPreferences android.content.Context.getS5haredPreferences(java.lang.String,int)</Source>6    <Target>{$_= com.didi.quicksilver.QuicksilverPreferencesHelper.getShar7edPreferences($0,$$);}</Target>8  </MethodCall>9</Replace>
复制代码


处理前的 class:


1public class MainActivity extends Activity {2@Override3    protected void onCreate(Bundle savedInstanceState) {4        super.onCreate(savedInstanceState);5        SharedPreferences sp = getSharedPreferences("test", MODE_PRIVATE);6} }
复制代码


处理后的 class:


1public class MainActivity extends Activity {2    protected void onCreate(Bundle savedInstanceState) {3        super.onCreate(savedInstanceState);4        SharedPreferences sp = PreferencesHelper.getSharedPreferences(this5, "test", MODE_PRIVATE); // The target method return custom SharedPreferen6ces.7} }
复制代码


具体的使用方式及原理可参见 DroidAssist WIKI 。

特性

经过不断的打磨完善,DroidAssist 已经从最开始的 Mock 工具扩展成为具有完整 AOP 框架功能的工具,有如下特性。

简单易用

采用灵活的配置化方式,使用者只需要依赖一个插件,然后在配置文件中定义字节码处理方式,DroidAssist 就可以根据配置文件处理项目中所有的 class 文件。处理过程以及处理后的代码中都不需要添加额外的依赖,并且不会修改原始代码行号。

丰富的字节码处理功能

除了解决我们最初遇到的代码替换问题外,还扩展了其他的 AOP 功能,目前有 4 类 28 种代码修改方式。



  • 替换:把指定位置代码替换为指定代码

  • 插入:在指定位置的前后插入指定代码

  • 环绕:在指定位置环绕插入指定代码

  • 增强

  • TryCatch 对指定代码添加 try catch 代码

  • Timing 对指定代码添加耗时统计代码

简单易用

支持增量构建,处理速度快,只占用很少的构建时间。

Q&A

1. DroidAssist 可以实现什么功能?


DroidAssist 可以轻易实现诸如代码替换,代码插入等功能,滴滴出行 APP 利用 DroidAssist 实现了日志输出替换,系统 SharedPreferences 替换,SharedPreferences commit 替换为 apply,Dialog 展示保护,getDeviceId 接口替换,getPackageInfo 接口替换,getSystemService 接口替换,startActivity 保护,匿名线程重命名,线程池创建监控,主线程卡顿监控,文件夹创建监控,Activity 生命周期耗时统计,APP 启动耗时统计等功能。


2. DroidAssist 和 AspectJ 有什么区别?


DroidAssist 采用配置化方案,编写相关配置就可以实现 AOP 的功能,可以完全不用修改 Java 代码;DroidAssist 在使用上使用比较简单,不需要复杂的注解配置;DroidAssist 可以比较方便的实现 AspectJ 不容易实现的代码替换功能。一般情况下使用 DroidAssist 可以完成大部分功能,较复杂情况可以和 AspectJ 配合使用。


本文转载自公众号滴滴技术(ID:didi_tech)。


原文链接:


https://mp.weixin.qq.com/s/KYkazdohwIUse5uM37qPiQ


2019-09-16 22:291083

评论

发布
暂无评论
发现更多内容

零信任产品联动能力持续提升,全面整合协同运行

芯盾时代

iam 统一身份认证 零信任 mfa

Maxon Cinema 4D Studio S22 for mac(C4D动画设计工具)中文激活版

Mac相关知识分享

动画设计工具 C4D动画

支持m1/m2/m3 graphpad prism 10激活直装版下载 医学绘图工具

Rose

苹果电脑cpu性能提示|Turbo Boost Switcher Pro for mac 支持M1

Rose

望繁信科技荣获第六届“中国创翼”创业创新大赛二等奖,将代表上海市参加全国总决赛

望繁信科技

流程挖掘 流程智能 上海望繁信科技 现代企业服务 业务流程管理优化

NTFS Disk by Omi NTFS for mac(NTFS 磁盘管理器)v1.1.4中文版

Mac相关知识分享

磁盘管理器

小红书API接口最新指南:笔记详情数据接口的接入与使用

tbapi

小红书笔记详情接口 小红书API 小红书笔记详情数据采集

mac系统状态监控工具istat menus激活码 (istat menus中文版下载)

Rose

AE2021中文直装破解版下载 After Effects 2021安装包 支持M1/Intel

Rose

HarmonyOS SDK助力美团单车提供便捷流畅扫码新体验

HarmonyOS SDK

HarmonyOS

深入理解 RDMA 的软硬件交互机制

阿里技术

nvidia 分析 网卡 RDMA

MySQL UDF 提权初探

GreatSQL

ChatGPT 人工智能助理 Assistant

测试人

软件测试

axure rp8安装包下载 Axure RP 8 for Mac中文永久密钥分享

Rose

mac触摸板增强工具BetterTouchTool激活版

Rose

Reallusion Cartoon Animator for Mac(2D动画设计制作软件)中文激活版

Mac相关知识分享

Mac软件 动画设计软件 动画设计

极狐GitLab与无问芯穹达成战略合作,共探AI落地软件智能研发场景新机遇

极狐GitLab

人工智能 AI DevOps 极狐GitLab

[Paper Reading]: Self-Improving Alignment with LLM-as-a-Meta-Judge

吴京

LLM LLM-as-a-Judge

行业标准音频测试分析 | Rational Acoustics Smaart Suite v9注册版下载安装

Rose

黑神话悟空是什么游戏 黑神话悟空配置要求 苹果电脑怎么玩黑神话悟空 黑神话悟空和西游记的联系

阿拉灯神丁

游戏 Mac 软件 苹果电脑 CrossOver Mac下载 黑神话悟空

成就江旻憓奥运金牌的背后:权威型教养

心大陆多智能体

AI大模型 心理健康 数字心理

【最新注册码】CorelDRAW 2023中文激活下载 及cdr2023系统要求

Rose

在 Confluent Cloud 上使用 Databend Kafka Connect 构建实时数据流同步

Databend

ChatGPT 人工智能助理 Assistant

测吧(北京)科技有限公司

测试

测试工程师如何构建质量体系

测吧(北京)科技有限公司

测试

Carbon Copy Cloner for Mac(磁盘克隆/同步/备份软件)v6.1.1(7323)

Mac相关知识分享

磁盘克隆软件

终极自托管解决方案指南

NocoBase

开发工具 解决方案 云服务

深度解读昇腾CANN小shape算子计算优化技术,进一步减少调度开销

华为云开发者联盟

CANN 昇腾 企业号 8 月 PK 榜 2024企业号8月pk 算子优化

iOS数据恢复Disk Drill for Mac v5.4.1425中文版 含Disk Drill激活码

Rose

AirPods耳机管理工具AirBuddy for mac 兼容macOS14系统 支持m芯片

Rose

Mac角色扮演游戏:仙剑奇侠传四 for Mac v1.1 中文移植版

你的猪会飞吗

mac软件下载 mac破解软件下载 mac单机游戏

滴滴开源 DroidAssist : 轻量级 Android 字节码编辑插件_开源_江义旺_InfoQ精选文章