AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

滴滴开源 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:291169

评论

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

autocad2023破解版下载 含cad2023中文汉化包 Mac&Windows系统

Rose

vm虚拟机 mac版下载 vm虚拟机 含VMware Fusion Pro 12永久许可密钥

Rose

NineData云原生智能数据管理平台新功能发布|2024年4月版

NineData

sql 数据迁移 数据备份 NineData 对比工具

B站千万级长连接实时消息系统的架构设计与实践

JackJiang

即时通讯;IM;网络编程

苹果mac好用的SSh终端工具:SecureCRT for mac附最新许可文件

Rose

Tuxera NTFS 2021破解版下载 Mac版NTFS工具推荐

Rose

AWS RDS & ElasticCache 监控可观测最佳实践

观测云

AWS

油猴浏览器辅助插件 Tampermonkey for Mac安装教程

Rose

JetBrains Rider 2024永久注册码 mac/win 跨平台.NET IDE集成开发

Rose

ClickHouse沙龙来了,NineData将分享数据管理与同步的关键技术!

NineData

Clickhouse Meetup 杭州 NineData 迁移同步

如何申请 https证书

zhumingwu

Desktop Goose for Mac(抖音桌面宠物鹅),让你的苹果电脑桌面更加生动有趣!

Rose

MacDroid for mac:轻松实现mac与安卓设备数据互通

Rose

苹果M1/M2电脑安装Lightroom Classic 2022(LRC2022) 后打开闪退怎么办?

Rose

得物质量管理体系的建设与应用

得物技术

测试 质量 企业号 2024年5月 PK 榜

如何汇报自动化测试的成果

老张

研发效能 自动化测试

API主导的商业模式是否将在AI时代蓬勃发展?

幂简集成

AI API

记一次被黑的经验教训

zhumingwu

适用于Windows、Mac平台:Sublime Text代码编辑器 含注册码

Rose

什么是蜜罐,在当前网络安全形势下,蜜罐能提供哪些帮助

德迅云安全杨德俊

漆包线行业你了解多少?专业漆包线行业MES生产管理系统

万界星空科技

制造业 mes 万界星空科技 漆包线mes 漆包线

NineData亮相GOPS大会:揭秘新时代企业级数据库DevOps最佳实践

NineData

数据库 DevOps 工具 NineData SQL IDE

腾讯、阿里、B站最新面经汇总,有的妥妥的凉经

王中阳Go

golang 面试题 大厂面经 Go进阶

【iOS逆向与安全】iOS远程大师:通过H5后台远程查看和协助iPhone设备

小陈

移动端 逆向 iOS逆向 ios安全 逆向技术

MES给制造业带来看得见的效益

万界星空科技

数字化 工业互联网 制造业 mes 万界星空科技

抖音商品详情:短视频电商的新风向

Noah

教你如何搞定springboot集成kafka

华为云开发者联盟

kafka springboot 华为云 华为云开发者联盟 企业号2024年5月PK榜

立即注册 | 线上讲座:基于 NGINX 为现代应用构筑三大安全防线

NGINX开源社区

nginx DevOps DOS攻击 OWASP十大漏洞 NGINX PLUS

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