Android7.0中的ResourceNotFoundException

背景

随着Android N的出现,适配7.0的问题也成为了各大产品头疼的问题。而最近在我们的平台上面收到了7.0的Crash。具体的栈如下:

Crash栈

而我们发现0x7303003这个ID是插件中的资源ID,但是在已经安装加载的插件列表中发现,这个插件是已经加载过了的。并且只有7.0的系统会出现该Crash。

发现问题

当出现该问题的时候,我们怀疑是因为指向资源的所有路径中没有指向该插件而导致的。随后,我们发现在进入WebView,再退出来后,从Resource中获取到的AssetManager对象被替换了。

插件资源原理

所有的插件资源都是通过AssetManager获取的,而AssetManager会通过addAssetPath函数将所有插件的路径添加到AssetManager中,从而使得在运行时,可以通过ID去所有的资源路径中进行查找,找到后就加载,否则报出ResourceNotFoundException。

跟踪源码

WebView的创建非常复杂,而在ensureProviderCreated()函数中,会创建WebViewProvider对象,而创建的过程可以缩减成:
mProvider=WebViewChromiumFactoryProvider.createWebView()

WebView构造函数

而在创建WebView的时候,实际上是将WebView委托到了WebViewChromium中。
创建WebView

在WebViewChromium初始化的时候,会调用addWebViewAssetPath将路径添加到AssetManager中。
WebViewChromium构造函数

在WebViewDelegate.java类中,添加WebView的资源路径。

其中:
newAssetPath:/system/app/WebViewGoogle/WebViewGoogle.apk,查看WebViewFactory.getLoadedPackageInfo()的源码可以看到,其实这个sourceDir获取到的应该是用户设定的浏览器的APK的路径,由于我们默认是Chrome所以指向的路径是Google WebView的APK。
Context.getApplicationInfo().getBaseResourcePath:获取到的是本应用的APK路径。
也就是说,WebView中会判断WebView的路径是否在SharedLibraryFiles中,如果存在的话,那么就直接返回了,如果不存在的话,那么就需要将它的路径添加到主包的资源路径中,以达到可以访问WebView中资源的效果。
而在Activity使用资源的时候,使用到的都是ContextImpl.java中的Resource。在其构造函数中,会初始化已经类似于静态变量Resource,全局只有一个。
ContextImpl中初始化资源的地方

其中mainThread是ActivityThread,每个进程都只有一个。
最终会判断LoadedApk.getResources中获取到的Resource是否为空,所以当mResources不为空的时候,就直接返回了:
LoadedApk.getResources

在ActivityThread.getTopLevelResources中,最终通过:
mResourcesManager.getResources来获取到的Resources对象
Paste_Image.png

而ResourceManager中,有一个ArrayMap,用来存储ResourcesKey和ResourcesImpl的映射表:
private final ArrayMap<ResourcesKey, WeakReference<ResourcesImpl>> mResourceImpls = new ArrayMap<>();
而ResourcesImpl中只是对AssetManager、Drawable获取等的一层封装,以后可能会是一个APP会有多种Resources对象。
所以第一次创建的时候,就会创建一个新的ResourcesKey来对应一个ResourcesImpl,并且传入各种路径参数。
创建ResourcesKey

而在getOrCreateResources函数中,会通过Key去查找ResourcesImpl是否存在,如果存在的话,那么就直接返回了,而在查找的时候,会根据ResourcesKey.equals方法去比较Map中的Key。而ResourcesKey中的equals函数已经被重写了。
ResourcesKey.equals

如果为空的话,就会创建一个ResourcesImpl对象,添加到上面的Map中去。
所以,在appendLibAssetForMainAssetPath函数中,首先会遍历所有的ResourceImpl,判断ResourceKey中的mResDir是否为主包的路径,如果主包路径中的mLibDirs中没有WebView.apk的路径,则会将/system/app/WebViewGoogle/WebViewGoogle.apk添加到原有路径后,并且创建新的ResourcesKey中。导致在后面逻辑中判断ResourceKey对象已经变了,导致重新创建了ResourceImpl对象,导致重新创建了AssetManager。
查询是否需要更新ResourceKey

如果ResourceKey变了的话,那么就会创建新的ResourceImpl,并且更新到Map中。
更新ResourceKey对应的ResourceImpl

于是,上面的问题就得到了答案,如果WebView.apk的路径不在Application.sharedLibarary中的话,那么则会创建一个新的ResourceKey,但是由于libAssets中的路径已经发生改变,导致ResourcesKey匹配不到原来的ResourceImpl,被认为是新的,所以导致了创建新的ResourcesImpl,从而创建了新的AssetManager,而之前的插件路径也都不复存在了。

解决方案

在添加插件路径的时候,需要把WebView.apk的路径添加到sharedLibraryFiles字段中, 这样的话,就不会有需要更新的ResourceImpl了,可以避免过去,不过可以看看还有没有更好的办法。比如说是否有AndroidManifest.xml文件中配置一下,就可以将WebView.apk的路径添加进来。也没有再深追了。


解决方案

但是在部分机型上面发现还会出现该问题,最终我们选择的解决方案是在Application的时候创建一个WebView对象,让静态方法先执行,虽然会影响一些启动速度,但是可以解决该问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • Android与资源管理相关的类Resouces和AssetManager很有必要清楚他们的创建过程。 与资源查找...
    小爨阅读 3,087评论 4 14
  • 昨天晚上我和爸爸妈妈商量好,今天早上去看日出。临睡前我问妈妈:“你早上能起的来吗?”妈妈说:“可以。”我心...
    我自己喜欢的事活着阅读 360评论 0 0
  • 1浮动元素有什么特征?对父容器、其他浮动元素、普通元素、文字分别有什么影响? 特征:浮动元素会脱离文档流,按照指定...
    淡然7698阅读 198评论 0 0
  • 好久没去游泳,今日入水体会:1、水温一下子不适应。2、没有水感了。这太恐怖了。3、竟然有了游向深水区的恐惧感。4...
    Miss文小姐阅读 193评论 1 0