作者:刘天宇(谦风)
系列文章回顾《向工程腐化开炮 | proguard治理》《向工程腐化开炮 | manifest治理》《向工程腐化开炮:Java代码治理》《向工程腐化开炮|资源治理》。本文为系列文章第五篇,聚焦于动态链接库so,这一细分领域。对工程腐化,直接开炮!
在Android技术领域,动态链接库so一般使用c/c++开发,近年随着rust的“闪耀“,无论在aosp系统功能层面,还是app应用功能层面,都能看到其身影。但无论使用的开发语言是什么,最终在apk和运行时的存在形式,都是符合ELF格式的so文件。本文聚焦于动态链接库so本身,对abi不兼容、重复、冲突、无用导出符号,这几种腐化情况,进行工具研发以及治理实践。
基础知识
本章并不会讲解使用c/c++等语言,编写动态链接库so的相关知识,而是站在app整体层面,尝试以“外部”(非c/c++开发者)视角,来讲解近些年在Android架构工作中,了解到的一些有趣知识点。
1.1 c++标准模版库(STL)
当使用c++开发动态链接库so时,如果使用到C++标准模版库,就需要指定具体使用哪一个。有以下几种可供选择:
- libc++。LLVM的libc++是STL规范的一种实现,Android 5.0及以后版本os便开始使用此STL,更近一步,在ndkr18开始成为唯一可用STL。因此,libc++也是Android官方指定STL;
- gnustl&gnustl_port。这两个都是GNU项目提供的STL规范实现,在旧版本ndk中提供了相关支持,正如上述所讲,ndkr18后已废弃。在当前开发时尽量避免使用此STL;
- system。Android系统内置STL规范实现,仅提供new和delete,一般不使用。同样,也在ndkr18后废弃。
在选定具体STL后,还有两种链接方式可供选择:
- 静态链接。静态链接会将使用到的stl中代码,链接(拷贝)到so中;
- 动态链接。在链接时,并不会将stl代码拷贝到so中,而是将使用到的STL符号,保存在so的动态链接符号表中,在运行时绑定并调用这些STL中的符号(位于STL的so中)。
当app只有一个so时,建议使用静态链接方式,以减小包尺寸;当app包含多个so时,全部使用静态链接,stl代码实现会拷贝多份到不同so中,这会极大增加包大小,因此应该选择动态链接。但是需要注意的是,无论是多个so静态链接同一个STL,还是多个so动态链接多个不同STL,都会导致运行时功能异常,甚至引发crash的风险,因此,最佳方案是:仅使用一种链接方式&#