抖音字体大小设置方法安卓 抖音字体大小设置方法( 三 )


从实现来看,getPathStrategy 方法主要是进行 FileProvider 关联 xml 文件的解析,解析结果将会赋值给 mStrategy 变量 。进一步分析我们会发现 mStrategy 会在 FileProvider 的 query、getType、openFile 等接口进行文件路径校验时用到,而我们的 query、getType、openFile 等接口在启动阶段是不会被调用到的,因此 FileProvider attachInfo 方法中的 getPathStrategy 是完全没有必要的,我们完全可以在 query、getType、openFile 等接口被调用到的时候再去执行 getPathStrategy 逻辑 。

抖音字体大小设置方法安卓 抖音字体大小设置方法


优化方案
FileProvider 是 androidx 中的代码,我们无法直接修改,但是它会参与我们的代码编译,我们可以在编译阶段通过修改字节码的方式去修改它的实现,具体的实现方案为:
对 ContentProvider 的 attachInfo 方法进行插桩,在执行原有实现前将参数 ProviderInfo 的 grantUriPermissions 设置为 false,然后调用原实现并进行异常捕获,在调用完成后再对 ProviderInfo 的 grantUriPermissions 设置回 true,利用 grantUriPermissions 的检查绕过 getPathStrategy 的执行 。(这里之所以没有使用 ProviderInfo 的 exported 异常检测绕过 getPathStrategy 调用是因为在 attachInfo 的 super 方法中会对 ProviderInfo 的 exported 属性进行缓存)
public void attachInfo(@NonNull Context context, @NonNull ProviderInfo info) {
super.attachInfo(context, info);
// Sanity check our security
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
if (!info.grantUriPermissions) {
throw new SecurityException("Provider must grant uri permissions");
}
mStrategy = getPathStrategy(context, info.authority);
}
2. 对 FileProvider 的 query、getType、openFile 等方法进行插桩,在调用原方法之前首先进行 getPathStrategy 的初始化,完成初始化之后再调用原始实现 。
单个 FileProvider 的耗时虽然不多,但是对于一些大型的 app,为了模块解耦其可能会有多个 FileProvider,在这种情况下 FileProvider 优化的收益还是比较可观的 。与 FileProvider 类似,Google 提供的 WorkManager 也会存在初始化的 ContentProvider,我们可以采用类似的方式进行优化 。
1.3 启动任务重构与任务调度
启动的第三个阶段是 Application 的 onCreate 阶段,这个阶段是启动任务执行的高峰阶段,该阶段的优化就是针对各类启动任务的优化,具有极强的业务关联性,这里简单介绍一下我们优化的大概思路 。
抖音字体大小设置方法安卓 抖音字体大小设置方法


抖音启动任务优化的核心思想是代码价值最大化和资源利用率最大化 。其中代码价值最大化主要是确定哪些任务应该在启动阶段执行,它的核心目标是将不应该在启动阶段执行的任务从启动阶段去除掉;资源利用率最大化则是在启动阶段任务已经确定的情况下,尽可能多的去利用系统资源以达到减少任务执行耗时的目的 。对于单个任务而言,我们需要去优化它的内部实现,减少它本身的资源消耗以提供更多资源给其他任务执行,对于多个任务则是通过合理的调度以充分利用系统的资源 。
从落地角度而言我们主要围绕两个事情开展:启动任务重构与任务调度 。
启动任务重构
由于业务复杂度较高且前期对启动任务的管控较为宽松,抖音启动阶段的任务有超过 300 个,这种情况下对启动阶段的任务进行调度能够在一定程度上提升启动速度,但是仍然比较难将启动速度提升到一个较高的水平,因此启动优化中非常重要的一个方向就是减少启动任务 。
为此我们将启动任务分成了配置任务、预加载任务和功能任务三大类 。其中配置任务主要用于对各类 sdk 进行初始化,在它没有执行之前相关的 sdk 是无法工作的;预加载任务主要是为了对后续的某些功能进行预热,以提升后续功能的执行速度;功能任务则是在进程启动这一生命周期执行的与功能相关的任务 。对于这三类任务我们采用了不同的改造方式:

推荐阅读