VirtualApk源码分析-插件的加载

在进行插件化时,需要先将插件加载到当前进程中来,插件通常以APK的形式保存在SD卡上,VirtualApk加载插件的过程如下:PluginManager.loadPlugin---->LoadedPlugin.create,最终会创建LoadedPlugin对象,该对象就表示插件在内存中的存在形式。

LoadedPlugin内部保存了如下变量:

LoadedPlugin的内部变量

在创建LoadedPlugin的时候主要有如下操作,由于版面,这里分为Part1、Part2、Part3三个部分进行讲解。

Part1

Part1

PackageParser

在加载插件的时候,首先通过PackageParserCompat对插件APK进行解析,解析的时候巧妙得利用的Class加载中的双亲加载机制,先在PackageParserCompat中获取手机版本,然后再调用系统的PackageParser。

PackageParserCompat.parsePackage

接着根据版本调用不同的函数,例如:

解析APK

这里巧妙了利用的Class的双亲加载机制,PackageParser是android.content.pm包下面的类,App是访问不到的。VirtualApk利用双亲加载机制的特点,在自己的包下面新建了一个相同包名和类名的Class,并实现了相同的API,这样在加载PackageParser时,双亲机制会优先加载Framework的PackageParser,这样就将解析APK的操作交给系统了。

本地PackageParser

可以看到本地的PackageParser只是抛出异常,实际会调用Framework的parsePackage函数,完成APK解析。解析完成后就能获得APK的信息。接着创建插件的PluginContext、Resources、ClassLoader、Assets。

创建Resource

通过createResources函数可以创建插件的Resource。

createResources

这里传入的Context参数是宿主Context,VirtualApk提供了两种加载Resource的方式:

1、将插件宿主的Resource和插件Resource合并,宿主和插件使用同一个Resource,这样插件也能访问宿主的资源,宿主也能访问插件的资源。

ResourceManager.createResources

ResourceManager.createResources或许获取宿主Resources对象,然后反射创建AssetManager,然后在反射调用AssetManager.addAssetPath将宿主资源和插件的资源加进去(addAssetPath是hide函数,需要反射调用),最后再跟进不同的机型创建不同的Resources对象。ResourceManager.createResources之后调用了ResourcesManager.hookResources将宿主的Resource替换成合并后的Resources(反射替换ContexlImpl中mResources对象)。

hook掉宿主的Resource对象

2、为插件生成单独的Resources,宿主不能访问插件资源,但插件可以访问宿主资源。

反射创建Assetmanager

首先反射创建AssetManager并加入插件的资源,随后跟进AssetManager创建插件的Resources对象。

创建ClassLoader

ClassLoader主要是完成Class的加载,要加载插件APK内部的Class文件,就需要创建插件的ClassLoder对象。

创建插件ClassLoader

Android为加载dex文件提供了两个类加载器:PathClassLoader和DexClassLoader,其中PathClassLoder用于加载安装好的APK,DexClassLoader可以加载SD卡下的APK文件。这两个ClassLoader都继承自BaseDexClassLoader。

BaseDexClassLoader.findClass

BaseDexClassLoader.findClass将 加载Class的任务交给DexPathList

DexPathList,findClass

dexElements中存放了当前APK的多个dex文件,在加载Class的时候会按照dex的先后顺序完成Class的查找(插个题外话,QZone的热修复就是根据这个查找规则,将修复的Class放入一个全新的dex,然后将这个dex方法dexElements的第一个,这样就完成了修复)。

创建完插件的ClassLoder后,通过DexUtil.insertDex将插件的dex加入到宿主中去。

插件dex和宿主dex合并

拷贝SO

tryToCopyNativeLib实现SO的拷贝,将CPU-ABI对应的SO拷贝到宿主的context.getDir(Constants.NATIVE_DIR, Context.MODE_PRIVATE)目录下。

Part2

Part2

接下来将PackageParser解析到的InstrumentationInfo、ActivityInfo、ServiceInfo、ProviderInfo保存到本地的Map中。

Part3

Part3

如果用户在插件中注册了静态广播,在加载插件的时候会把静态广播动态注册给mHostContext,,相当于把静态的插件广播动态注册到宿主中了,这样就完成了广播的插件化。

至此,整个插件的加载已经完成,生成了LoadedPlugin对象,并保存到PluginManager中。

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

推荐阅读更多精彩内容