百度APP包体积经过一期优化,如无用资源清理,无用类下线,Xcode编译相关优化,体积已经有了明显的减少。但是优化后APP包体积在iPhone11上仍有350M的空间占用。
与此同时百度APP作为百度的旗舰APP,业务迭代非常多且迅速,体积优化和防劣化仍然是当前阶段的一个核心任务。因此百度APP开启了粒度更小,修复风险更高的无用方法清理相关工作。
期望通过无用方法清理,有效降低百度APP的包体积,同时删除项目中的无用方法,冗余代码,提高代码的整洁度。
针对无用方法清理,调研了各家厂商目前已公布的方案,主流方案基于Mach-O + LinkMap文件的分析,但是主要存在以下问题:
因为目前已公布方案存在如上不足,同时因为下线代码敏感度非常高,相关业务都很慎重。因此推动相关无用方法清理,识别准确度将非常重要,直接关系到相关业务下线无用代码的积极性,因此弃用了上述方案。
针对第二部分方案不足之处进行分析,可以看到其准确度低的核心问题是,针对产物进行分析,拿不到所有需要的信息,或者说还没有发现有效的手段去获取所期望获得的信息。而想要解决上面提到的问题,最佳途径就是获取到尽可能多的代码信息。既然从产物回溯不到所需要的,那么就可以考虑从源头也就是源码层面找到我们所需要的详细信息。
源码肯定包含了所有的信息,但是针对源码如何分析呢,主要有以下三种:
需要匹配源码的所有语法规则,才能够针对源码进行有效的分析,相当于写一个源码解析器,所以这个方案放弃
编译过程中产生的抽象语法树(AST)包含了需要的所有信息,并且clang也提供了命令行,使用该命令行能够直接获取到AST数据。但是clang 命令获取AST数据是以单个类为维度的,类与类之间的关系很难获取到,如继承关系,分类和主类的关系是无法获取的,所以这个方案同样放弃
既然通过clang命令生成的AST产物分析仍然不能满足需求,那么直接介入编译过程,从编译内部生成AST过程中获取需要的信息,最终这个方案被采用。通过libtooling 和 Swift Compiler自建编译套件针对AST进行分析,获取所需要的所有信息。
如上所述百度APP最终采用了libtooling 和 Swift Compiler 静态分析方案,那么下面就从原理和实现层面分别进行阐述。
本节先简单聊一下编译器的结构,编译流程,和静态分析是什么?
如图4-1 所示 LLVM 采用如上三段结构(Three Phase Design),分别是编译前端(Frontend),编译优化模块,编译器后端(Backend)。那么这三段结构如何对应到Xcode呢,如图4-2所示:
日常使用Xcode编译时,Xcode调用了两个编译器前端,分别为Clang 和 Swift,通过两个编译器前端构建出通用的编译产物,然后统一经过LLVM后端编译器进行目标文件生成。
通过Xcode的编译log,可以看到针对Objective-C,C, C++ 使用了clang进行编译,针对上述三种不同语言分别用不同编译参数控制:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
针对swift 文件则采用了swift编译器进行了编译:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend
针对这两个可执行文件大家可以自行解包Xcode,进行命令行调用,也可以通过其 --help指令查看其支持哪些编译参数或者功能。Xcode 内部编译器实际上是苹果对LLVM 和 Swift 开源版本的定制化版本, 和开源版本有一定的差异性。
如下图所示Clang 和 Swift 前端编译流程,可以看到Swift 编译处理流程多了SIL部分,实际里面还有一个SIL Guaranteed Transformations,当然SIL部分不是重点。从图4-3中可以看到Clang 和 Swift compiler 都会生成AST 且发现AST中包含了我们需要的绝大部分信息,并且Clang 和 Swift Compiler 也暴露了相关获取AST信息的接口,那么剩下的工作只有四点:
针对一门程序语言的使用而言,如图4-4所示,包含两个层面,一个层面是声明,另一个层面是调用。
声明类,协议,属性,方法,函数等等,同时声明的内容是为了被使用,所以同样声明的内容皆可调用,只不过是内部调用还是公开调用问题。
从技术角度而言,声明的所有内容 减去 被调用的声明内容,剩下的就是未被调用的内容,也就是我们需要的 无用方法。
当然技术层面的判别最终还是要进行业务判定,因为有的属于基础能力对外提供,至于是否要删除则需要进一步探讨。本文主要探讨技术层面问题。
从clang源码中可以知道声明和调用分别对应LLVM源码中的基类Decl 和 Expr,整体技术方案如下图 4-5所示,针对无用方法分为处理分为四层:
编译工具的呈现形式是一个类似Xcode自带clang的可执行文件,如图4-6 红框所示内容。
/Users/UserName/Documents/XcodeEdition/Xcode14.2/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
简单来说通过源码构建的编译工具具有Xcode clang 的部分功能,利用其编译过程中产生的AST对象进行抽象语法树分析,获取到所需要的编程语言的所有语法信息。
编译工具的搭建需要依赖LLVM提供的静态库或动态库,这些库通过自己构建LLVM源码来获得。可以从github获取LLVM源码路径,进入LLVM github界面后有可能会困惑需要构建哪个分支或者tag的代码呢,哪个版本和Xcode使用的clang是对应的?
目前Xcode的版本是 14.2 或者 14.3 ,使用命令 clang --version 可以看到Xcode用到的是clang 14,因此构建了release/14.x(没有找到对应关系,推理得出),构建成功后执行构建的clang --version 会发现开源版本clang 和 Xcode的小版本号是不一样的,这是因为Xcode 用的clang 苹果会基于开源代码进行定制,这从Xcode中clang 的依赖库或头文件数量。
另外从编译log也可以看到,Xcode clang支持的部分参数,开源clang是不支持的。尽管苹果有一些定制,但是总体影响有限。因此也不必过于在意小版本号是否一致。(初步验证了一下构建最新的release/16.x clang16 也可以)。
具体构建命令主要分两种,一个是Ninja 构建方式,一个是Xcode方式,需要Xcode调试源码可以选择Xcode模式,但是最终集成到编译工具中的静态库,一定要构建成Release模式,这样工具体积会降到最低,一些警告类异常也会被屏蔽掉。可以参照LLVM 开源库中的start guide 构建过程进行构建,其中涉及的组装命令可以自行拼接也可以用下面的命令:
构建过程
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build (这个build文件夹可以自行命名,不固定。针对不同目标可以创建不同文件夹进行不同构建,如 mkdir ninjaBuild 或 mkdir xcodeBuild)
cd build (or cd xcodeBuild)
cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Release ../llvm
cmake --build .
编译Xcode版本,Ninja替换为Xcode即可。
LLVM提供了两种工具 libclang 和 libtooling,百度APP采用的是 libtooling,其异同点如下所示:
最终选择 libtooling 形式,核心原因就是 libtooling 可以获取 AST 的所有信息,同时能够不依赖于Xcode 独立运行。工程的搭建本身并不复杂,还是属于API 使用层面,可以直接参照 libtooling的官方文档。
总体代码流程如图 4-8所示,主要核心点是五个部分:
数据存储结构采用 json 格式,以下为基础数据格式示例,可以根据实际需求拓展:
"objc(协议or类)@类名(类方法or实例方法)@方法名称":{
"identifier":"objc(协议or类)@类名(类方法or实例方法)@方法名称",
"isInstance":true,
"kind":16,
"location":{
"col":36,
"filename":"文件名称",
"line":147
},
"name":"方法名称",
"paramters":"参数",
"returnType":"返回值类型",
"sourceCode":"源码"
}
{
"declaration":{
"identifier":"objc(协议or类)@类名(类方法or实例方法)@方法名称",
"isInstance":true,
"kind":16,
"location":{
"col":列数,
"filename":"声明所在类名",
"line":行数
},
"name":"方法名称",
"paramters":"参数名称",
"returnType":"返回值类型",
"sourceCode":"源代码"
},
"kind":1,
"location":{
"col":5,
"filename":"当前所在文件名",
"line":15
}
}
1. 属性调用识别问题
针对 Objective-C 的属性,在编译后对应两个方法 get 和 set 一个是 ivar,调用方有可能只调用 get 或者 set 或者 ivar,所以当只发生一种调用时,就算这个属性被调用,当前属性不属于无用方法。需要在结果中把另外两个方法剥离。
2. 提取方法内容时同样需要对头文件进行提取
方法的实现不一定只在.m 文件中,如C++的头文件是可以进行方法实现的,Objective-C 的.h 文件 通过 inline 实现一些方法,在语法上也是可行的。所以进行方法提取时候关注实现文件,同时也要关注头文件。
3. 针对继承问题
子类实现父类方法等场景,在识别方法时,全部回溯其父类,以其父类名称作为 上文数据结构中 identifier 中类名部分,这样所有的方法都可以和其声明类匹配。
4. 过滤系统方法调用
LLVM提供了接口判断当前方法是否属于系统类。
5. 过滤业务类实现系统方法问题
针对当前类中所有的方法均在当前类 和 回溯其继承链条中的父类, 分别判断其是否属于系统方法,如果属于系统方法则直接过滤掉。
6. 针对协议方法的实现,目前还没有有效手段识别,当前方案是直接过滤掉协议方法,所有协议方法均视为已经调用
在提取方法时,判断当前interface 遵循了哪些协议,遍历协议中的方法,判断其是否为协议方法,是则标记为已调用。
7. 子类实现父类协议问题
回溯当前类的继承链条,在继承链条中判断遍历其所遵循的协议,判断其是否为协议方法。
8. 正常业务实现协议,应该明确标注当前类遵循了协议 如 interface \<conformprotocol>,但是实际场景中有很多代码在实现协议时并没有标注conformprotocol 这样就对协议方法的判断产生影响,如 6.7方案均失效了
如果组件中少量这种问题,当推动相关方修复此问题,需要明确遵循协议。但是如果有的组件这种场景较多,短期不会修复所有,那么就需要进行临时性适配。针对这类组件收集其当前组件所声明的协议的所有协议方法,用收集的协议方法和当前组件提取的所有声明做差集,存在误伤的可能,但结果是置信的(组件只是一个维度,也可以针对其关联组件进行相关处理,因为有时他实现的组件不一定在当前组件内,这就需要当前组件的依赖关系了)。
无用方法case很多,列举部分供大家参考。
这项技术实际上在百度APP早已经应用,因为笔者之前负责百度APP的接口变更审核,组件完整性校验,隐私合规调用链分析等均是依赖于此项技术,无用方法识别只是笔者在做体积优化时想到的其功能的一个延展。当然如上描述的技术问题,细节处理无用方法显然更细腻,case更多。后续文章会针对Swift无用方法分析,接口变更审核,组件完整性校验,隐私合规调用链分析等一一作出介绍。
本文由微信公众号百度Geek说原创,哈喽比特收录。
文章来源:https://mp.weixin.qq.com/s/3qWjzDpZGBIaxOQYLlL0xQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。