记录一次 AGP 调研过程中的思考,我从一个事故搞出了一个故事!

背景

看过我博客的老铁应该知道,我在 18 年五月写过一个小 gradle 插件https://github.com/yanbober/app-tiny-R-gradle-plugin,其作用就是将 app 生成的 R 常量进行内联操作。对,就是前不久很火的滴滴 booster 和字节跳动 ByteX 提供的 R 资源 inline 原理。

这两天因为项目要升级适配 AGP4.1.0 版本,顺手要调研 AGP 4.1.0 构建对子 module 及合成最终 app 的 intermediates 产物 R 变化问题。这个过程中却意外发现了一个有趣且有深度的事情,细思极恐,越想越有趣。好的事故往往都能成为好的故事。

先卖个关子

我们都知道,Android App 构建过程中 aapt2 会将资源生成对应R.class文件(AGP4.1.0 中间产物直接成为 jar,位于compile_and_runtime_not_namespaced_r_class_jar目录下),然后最终合并打包到 dex 中,这块不清楚的可以研究下我背景信息里提到的之前做的小项目。

现在我有几个灵魂拷问想问你:

  1. 资源生成的 R 文件格式是怎么样的?不同 module 下又有什么区别?(答不上的去看我那个小项目的 REDME 吧)
  2. 使用官方 multidex 方案情况下还会存在 method 或者 field 超过 65535 的情况吗?本质原因是为什么?
  3. App 资源个数(包括 string 个数等)是否存在上限?为什么?
  4. 我自己编写了一个 field 超过 65535 的类会有问题吗?能在官方 multidex 场景下使用吗?

上面这四个灵魂拷问你能深入回答下吗?不能的话就请继续往下看,带你玩波有趣的东西。

还原现场

上哪去搞那么多资源能一把搞炸 65535 个 field 呢?懒惰的我来波骚操作,打开我的 IDE,新建一个createR.sh文件,内容如下(不要在意用的原始 echo,因为懒惰,能用就行):

#!/bin/bash
# encoding=utf-8
# 【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题  未经允许严禁转载 https://blog.csdn.net/yanbober】echo "start generate string_r.xml";file_name="string_r.xml";echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" >> $file_name;
echo "<resources>" >> $file_name;for((i=1;i<=65536;i++));
doecho "<string name=\"public_r_$i\">TEST-$i</string>" >> $file_name;
doneecho "</resources>" >> $file_name;
echo "generate string_r.xml success!";

保存,敲下回车,执行一把等待中,去厕所带薪拉屎一会,回来文件 OK 了。内容如下,总共 65536 个 string 资源:

在这里插入图片描述
为了一次暴露所有问题,直接把这个资源文件扔到主模块的 values 下吧,接着点击一把 Android Studio 的运行,真相了:

在这里插入图片描述
上面报错可能出乎你意料了吧?为什么会出现这个错误呢?从 task 执行顺序可以确认,此时还未执行 javac 操作,还在进行 aapt2 的处理,资源合并 task 时抛出了异常,这个资源合并其实会做很多事,其中一个重要的事情就是通过 ASM 生成合并后的 R 文件。

你可能会问,哪里看出来是通过 ASM 生成的?我说我从 AGP 下载时的依赖看到的你信吗?其实很容易验证,你在执行构建时加上-s就行了,这样出错时会有详细调用栈,你能清晰的看到调用关系是 ASM 在生成字节码。

Class too large 是个什么鬼?你是不是一上来也觉得是类似 AGP 构建时对 multidex 的判断那样,在 AGP 源码里做了一个判断(官方埋雷?)。明确告诉你,不是的,不信你去 AGP 源码搜下,啥也搜不到。那它到底是咋回事呢?

隐秘的真相

现在我们一步一步来揭盖 Class too large 是什么!在执行构建时我们加上-s可以看到如下堆栈:

在这里插入图片描述

这货是在 task 使用 ASM 生成字节码时报的错,所以如上图,直接去 ASM 里面搜一下,果然搜到了哈。ASM 为什么要限制不能超过 0xFFFF 个呢?其实答案很明显了,如果你对 JVM 基础不熟悉的话,不妨继续往下看,我们看下这段 ASM 源码的注释:

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题  未经允许严禁转载 https://blog.csdn.net/yanbober】package org.objectweb.asm;/*** A {@link ClassVisitor} that generates classes in bytecode form. More* precisely this visitor generates a byte array conforming to the Java class* file format. It can be used alone, to generate a Java class "from scratch",* or with one or more {@link ClassReader ClassReader} and adapter class visitor* to generate a modified class from one or more existing Java classes.* * @author Eric Bruneton*/
public class ClassWriter extends ClassVisitor {/*** Index of the next item to be added in the constant pool.*/int index;/*** Returns the bytecode of the class that was build with this class writer.* * @return the bytecode of the class that was build with this class writer.*/public byte[] toByteArray() {if (index > 0xFFFF) {throw new RuntimeException("Class file too large!");}......}
}

可以看到,index 有个关键的注释Index of the next item to be added in the constant pool.,能 get 到问题原因了吗?constant pool啊,哈哈,这特么就真相了。

还不懂?那去补补 JVM 基础吧,周老师的神书前几章就足矣!

这里给两个直达链接简单科普常量池的:

《Java Class文件结构:常量池》
《Java Class文件中的常量池》

灵魂拷问的答案

到此我们整明白了来龙去脉和问题的本质,那我们现在来深度回答下一开始卖关子的问题。

  1. 资源生成的 R 文件格式是怎么样的?不同 module 下又有什么区别?

    去看 https://github.com/yanbober/app-tiny-R-gradle-plugin REDME 吧,很深度解析了。

  2. 使用官方 multidex 方案情况下还会存在 method 或者 field 超过 65535 的情况吗?本质原因是为什么?

    很明显,使用官方 multidex 方案情况下不会出现 method 或者 field 超过 65535 的情况,因为 JVM 这一层就已经限制了玩法规则。本质就是上面隐秘的真相。

  3. App 资源个数(包括 string 个数等)是否存在上限?为什么?

    存在的,单一类别(string/anim/drawable等)资源最终主 module 合并时生成的单个 class 文件内常量池总数不能超过 65536(不是资源 id,一个 class 还有其他东西占用常量池的),否则无法生成对应的 R,因为 ASM 字节码在生成合并 R 时常量池爆炸了。

  4. 我自己编写了一个 field 超过 65535 的类会有问题吗?能在官方 multidex 场景下使用吗?

    会有问题,无法编译通过,不符合 JVM Class 规范。既然无法编译通过,所以不存在在官方 multidex 场景下的使用,因为到不了分 dex 那一步就阵亡了。

会不会遇到世界末日

你以为故事到这就结束了?到这里不由得虎躯一震反思一下: “这锅会不会和当年 multidex 一样在未来航母级 app 某个时刻翻车呢?” 答案是有可能,但是短期不会,因为想要到达这个瓶颈就需要我们单一类型资源越界,这个其实目前还少有 app 到这个体量,即便航母 app 也不容易达到,除非你杠精一下。

这个问题的本质其实就回到了 google 官方一直对这个 R 的态度了,这玩意一直小变动,却总是不想办法从根源治理。远古 apt 时代子 module 的 R 里面 field 也是 static final 的常量,后来 google 为了加速构建,子 module 搞成非 static final(导致一些注解框架自己造一个 R2),主 module 合成,然后主 module 搞一份 static final 的,同时保留子 module 的非 static final,一直至今都叫R.java,然后 AGP4.1.0 版本这玩意直接不再出现R.java,而是一步到位R.jar的 class jar 了,而且子 module 的非 static final 的属性也不再给随机安插一个数值了,直接不赋值了。玩到这个版本还是没根治啊。

假若将来某一天真的重蹈覆辙 multidex 的道路怎么办?能想到的好方法就是 google 出马优化掉这玩意。否则我们作为三方 app 可能只能骚操作了,目前想到的两个骚操作就是:

  • 方案一:类似插件化,把越界资源编成多个 apk,hook 资源加载骗过呗,不过这玩意只是我先 YY 下,因为鬼知道骗过了 Class 常量池上限,会不会资源加载那块也埋雷了,这样就不好玩了。
  • 方案二:自己类似 java resources 一样造一套资源,不再参与 aapt2 编译,而是直接参与 java 编译打包,然后自己拖过映射多语言啥的场景,对外保留一个 nameId 获取和 android 的资源管理类对接。这个看起来是可行的,只是包大小和性能一定有影响,不然 google 当年也不会把它搞成resources.arsc和 R 索引了。

如上纯属自己的 YY,看看就好,别较真。

总结

歪打正着,本来是要去看别的问题的,一下被带到思考了一下这个问题,还行。可以看到,其实问题不复杂,也不难,稍微跟一下代码就能知道咋回事了,就一点,做事还得静下来,这样才能深度思考,然后才能若有所思。

日拱一卒,功不唐捐。今日已拱,哈哈。

【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

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

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

相关文章

hive中对子查询如in,exists等支持情况和使用

案例情况&#xff1a;同事使用公司数据探查跑一段代码&#xff0c;部分代码如下&#xff0c;报错&#xff0c;显示不支持in内的子查询。但是直接用虚拟机去跑的话代码没有任何报错&#xff0c;也出结果&#xff0c;很奇怪。 SELECT t1.SIGN_CODE AS bus_src,t1.ORGANIZATI…

overflow属性对before、after伪元素的影响

div中有before伪元素&#xff0c;如图&#xff1a; 当该div内容增多时&#xff0c;添加了纵向滚动条的样式&#xff0c;如下&#xff1a; max-height:300px; overflow: auto; 随后伪元素就消失了&#xff0c;如图&#xff0c;小箭头不见了。 overflow的说明&#xff1a; http…

如何提升对编程的兴趣,在编程中找到快乐?

上周有同学和我交流&#xff0c;问我怎么能在编程中找到快乐&#xff0c;提升编程的兴趣。 今天正好又是周末&#xff0c;对于这个问题&#xff0c;小编就要祭出大招了。 首先&#xff0c;打开浏览器&#xff0c;访问一个神奇的地址&#xff1a; https://github.com/ 。 对的…

一个会对对联的AI项目

编辑文章 声明&#xff1a;本文首发微信公众号【菜鸟要飞】&#xff0c;如有转载&#xff0c;请标明出处&#xff01; 快过年了&#xff0c;贴对联是必不可少的传统风俗。不知道各位读者有没有自己写过对联呢&#xff1f;写对联可不是一件简单的事情&#xff0c;如果不是满腹…

字符串匹配算法知多少?

文章目录 BF算法RK算法编辑器中的全局替换方法&#xff1a;BM算法坏字符好后缀规则代码实现 KMP算法 一说到字符串匹配算法&#xff0c;不知道会有多少小伙伴不由自主的想起那个kmp算法呢&#xff1f; 想到是很正常的&#xff0c;谁让它那么优秀呢。 BF算法 不要被事物的表面…

量化股票查询代码是什么?

量化股票查询代码是什么&#xff1f;接下来用一些代码来分析一下&#xff0c;如下&#xff1a; 做空95&#xff1a;HHV((HIGHLOWOPEN2*CLOSE)/5H-L,5),COLORBLUE;做空68: HHV((HIGH-LOWOPEN2*CLOSE)/5*2-L,5),COLORRED&#xff1b; 平衡点&#xff1a;LLV((HIGHLOWOPEN2*CLOSE…

voipdiscount免费拨打全球电话(无需手机注册)

我测试过了的&#xff0c;能给我手机打通&#xff0c;我也给无题打了的感觉还不错。现推荐给大家&#xff01; voipdiscount免费拨打全球电话&#xff08;无需手机注册&#xff09;通话效果极好到www.voipdiscount.com下载一个软件voipdiscount,申请一个用户&#xff08;不需手…

企业使用虚拟码号的优势!

其实用不用隐私码号&#xff0c;或者怎么用隐私码号&#xff0c;是和企业的基本业务场景有关的。我们在这将近5年的服务过程中&#xff0c;遇上的行业千差万别&#xff0c;需求也是完全不同。如果非要总结一些优势的话&#xff0c;那么简单的做个应用场景分类。 隐私码号&#…

VOS网络电话如何注册IMS

IMS注册需要IMS方提供账号的注册信息 比如 用户名称&#xff1a;862584372919 认证密码&#xff1a;123456 服务器地址&#xff1a;ims.jx.chinamobile.com 认证用户&#xff1a;862584372919 SIP代理&#xff1a;172.16.5.144 第一步: 在vos的业务管理—>注册管理中按下图…

趣图:程序员假发攻略

&#xff08;给程序员的那些事加星标&#xff0c;每天看趣图&#xff09; 15 号字 ↓↓↓ (漫画原作者&#xff1a;tango2010 投稿&#xff1a;遇见) 往期趣图&#xff08;点击下方图片可跳转阅读&#xff09; 关注「程序员的那些事」加星标&#xff0c;不错过趣图 &#xff0…

老大“秃”伤悲的年轻人,正靠假发维持最后的体面

本文转载自虎嗅网 如今90后的潮流&#xff0c;已经逐渐让人看不懂了。 现在见面第一句话都不是“今天你基金绿了吗&#xff1f;”“今天你cp发糖了吗&#xff1f;”&#xff0c;而是&#xff1a; “你今天戴的是假发吗&#xff1f;” 随着越来越多的90后涌入脱发大军&#…

计算机毕业设计php假发销售商城网站(源码+系统+mysql数据库+Lw文档)

项目介绍 假发销售网站使用php,mysql实现了如用户注册、用户登录、假发商品的预览查询、对假发商品的购买通过购物车实现、可进入留言本留言等等&#xff0c;从而实现了网站与客户之间的交流和沟通。 功能&#xff1a;客户功能和管理员功能两个部分。 设计题目&#xff1a;假…

c语言链表假发管理系统,C语言链表关键字检索

满意答案 a_xman 2014.09.20 采纳率&#xff1a;58% 等级&#xff1a;9 已帮助&#xff1a;1813人 /**************************** 包括头文件 *****************************/ #include #include /***************************** 函数声明 *****************************…

ios图形之矩阵操作

1 - (void)drawRect:(CGRect)rect2 {3 // 画四边形4 CGContextRef ctx UIGraphicsGetCurrentContext();5 6 // 保存上下文7 CGContextSaveGState(ctx);8 9 // 注意:设置矩阵操作必须在添加绘图信息之前 10 CGContextRotateCTM(ctx, M_PI_4); …

深度:数据解读百亿规模中老年假发市场发展趋势 国内外假发上市公司发展经验

在对中老年群体消费需求与消费心理进行持续深入研究过程中&#xff0c;AgeClub发现对脱发问题严重的中老年人来说&#xff0c;假发是最好的改变外表形象的选择&#xff0c;拥有巨大市场需求和发展潜力。 据中国健康促进与教育协会2016年公布的“中国脱发人群调查”&#xff0c…

怎么在php文件插入背景图片,怎么给视频文件添加背景图片?将视频放在图片上面播放...

都说“清明时节雨纷纷”&#xff0c;明天就是清明节了&#xff0c;小编抬头望望天空可真是没有一丝丝要下雨的节奏啊。清明节放假&#xff0c;大家有么有计划回家呢~反正小编是没计划的&#xff0c;小编的妈妈告诉小编说“你别回来除人……”&#xff0c;除人在小编家乡那边的意…

服务器图片加载慢_张云雷开工拍杂志,昕薇服务器一定优化好别崩,手机被卡已三回...

美好的九月第一天&#xff0c;也是周末&#xff0c;张云雷发微博&#xff0c;今天你们开学我开工&#xff0c;还没下班转场中&#xff0c;辫儿哥哥有才华呀&#xff0c;说话都一套一套的押韵。 他说摩羯座太难了&#xff0c;难不难不知道&#xff0c;就看出摩羯座的张云雷颜值要…

二元函数图像生成器_谷歌程序员自制秃头生成器:一键get张东升同款发型,今天你脱发了吗?...

文章来源于微信公众号&#xff1a;机器之心 作者 |Synced 原文链接&#xff1a;请点击 文章仅用于学习交流&#xff0c;如有侵权请联系删除 头可断&#xff0c;发型不能乱。 最近有一个男人的名字实在太火了&#xff0c;他叫「张东升」&#xff1b;比他本人更出名的&#xff0c…

时标网络图

认识时标网络图 时标网络图可解决的问题 一、 直接看关键路径、自由时差和总时差 自由时差&#xff1a;不影响任何紧后活动最早开始时间下本活动可推迟时间 总时差关键路径时长-活动所在最长路径 二、资源平滑-移动活动&#xff0c;通过浮动时间优化资源需求【重要】 三、计算…

假发重回颜值赛道,假发经济起风?

配图来自Canva可画 年轻人的爱美是从头到脚的精致装扮&#xff0c;谁能忍受自己拥有张东升同款秃头&#xff1f;即使是一丝一毫的发际线上移都会让人愤懑不已。看过张东升戴假发前后的样子&#xff0c;大家不得不相信头发对颜值的重要性。而一众明星又带火了挂耳染、漫画刘海等…