Small插件源码分析

导读

目标读者
使用方式
机制原理
关键概念
关键流程
涉及文件
Hook点列表
Small源码解析参考
Android源码参考

目标读者:

1.快速了解small原理机制的人
2.自己,知识梳理和记忆
对于想学代码解析的同学,这里可以当作一个概要或引言,相信会对你的学习起到事半功倍的效果。也可以读完代码后来这里理理整体思路。(其实,对于开源软件或者非自己写的项目,我推荐的学习路径是先了解整体机制,核心重点,然后再研读代码。不过说实话,符合这个思路的文章不多,当然,也可能是我没找到。)
幸运的是,你遇到了^_^

使用方式:

建议还是简单看一下使用方式,先有一个感觉。
大家直接看官方文档吧,还是比较简单的:http://code.wequick.net/Small/cn/quickstart

机制原理:

Small主要通过Hook Android framework层的关键逻辑,达到将插件资源和代码无缝的集成到主工程中。主要要解决的是三个问题:1. 代码加载;2. 资源加载;3. android既有机制支持,如Activity。

主要解决方案是:

1. 代码加载的解决方案:
Hook DexClassLoader:加入插件代码,包括java和native
Hook PathClassLoader:低版本的native lib是通过pathclassLoader。高版本都在DexClassLoader中
2. 资源加载的解决方案:
Hook AssetManager:加入插件资源
3. android既有机制支持的解决方案:
Hook Instrumentation: 启动startActivity时将目标realactivity替换成占桩的stubactivity,利用AMS机制进行正常的启动activity流程。
Hook Handler.Callback:将AMS调用的stubactivity替换成realactivity。与前面的instrumentation配合,完成AMS的欺骗。
Hook TaskStackBuilder: pendingintent的支持。因为这个启动不是通过instrumentation的startactivity


small插件hook关键点,绿色的是hook关键点

关键概念:

为了体系化的呈现热更新,让接入方很容易的接入,small作者提出了几个概念来组织整套逻辑。
Small:外观类,使用入口。比如:preSetup(), setup()这两个是环境配置,关键就是前面hook点的实施;openUri():activity跳转
Bundle:这个类比较杂,建议分成两部分看。
一部分概念是每个插件的映射体,即每一个module都映射成了一个bundle,所以bundle里存着每一个apk的相关信息,比如manifest,dex,native lib等;
另一部分对应整个流程的管理,比如small的presetup和setup与bundlerlauncher的串联都是在这个逻辑流程里。
这里还要说一下bundle.json,这个是bundle加载的入口,也是bundle和module的映射引导逻辑。bundle从bundle.json中找到各个module,并对module进行解析。同时bundle.json也规定了不同模块的跳转逻辑。
BundleLauncher:每一个bundler的处理者。因为bundle对应着各种类型,比如host apk,plugin apk,
BundleParser:manifest的解析者。small中manifest的解析是自己做的,逻辑在这个类里面。
ActivityLauncher->BundlerLauncher:host apk中activity的launcher
ApkBundleLauncher->SoBundlerLauncher->BundlerLauncher: 插件中activity的launcher
WebBundleLauncher->SoBundlerLauncher->BundlerLauncher:插件中html的launcher

各关键概念之间的关系:

Small是整体入口,通过bundle加载bundle.json并管理整个插件的hook,加载,解析流程。
Small也是跳转的入口,内部通过bundle.json制定的规则,找到对应的bundlelauncher,然后启动跳转

关键流程:

ActivityLauncher的流程

ActivityLauncher的流程

ApkBundleLauncher的主要流程

ApkBundleLauncher的流程

OpenUri的流程


openUri的流程

涉及文件:

bundle.json的读取顺序
Cache: SharedPreference: small.xml(key=bundle.json, value=*)
Patch: data/user/0/packagename/files/bundle.json
Asset: assets/bundle.json

bundle source:支持打包到asset中,也支持so模式(系统安装时会自动帮你加载,帮你提速)
asset base file: /data/user/0/packagename/app_small_base/pkg.apk
asset patch file: /data/user/0/packagename/app_small_patch/pkg.apk 
library base file: /data/app/packagename/lib/arbi/libpkg.so
library patch file: /data/app/packagename/app_small_patch/libpkg.so

bundle target:
ApkBundleLauncher extract path: /data/user/0/packagename/files/storage/pkg/

Hook 点列表:

DexClassLoader//Java Class
PathClassLoader//Native library
AssetManager//Resource中AssetManager的path
Instrumentation//ActivityThread中的mInstrumentation

ClassLoader Hook

V9

DexClassLoader.java(dalvik/src/main/java/dalvik/system/DexClassLoader.java)
mFiles(File[])
mPaths(String[])
mZips(ZipFile[])
mDexs(DexFile[])
PathClassLoader.java
libraryPathElements(List)

V14

DexClassLoader.java
pathList(DexPathList).dexElements[](dalvik.system.DexPathList$Element[])
pathList(DexPathList).nativeLibraryDirectories(File[])

v23

DexClassLoader.java
pathList(DexPathList).dexElements[](dalvik.system.DexPathList$Element[])
pathList(DexPathList).nativeLibraryDirectories(File[])
pathList(DexPathList).nativeLibraryPathElements(alvik.system.DexPathList$Element[])

v26

DexClassLoader.java
pathList(DexPathList).dexElements[](dalvik.system.DexPathList$Element[]//构造方法有变化)
pathList(DexPathList).nativeLibraryDirectories(File[])
pathList(DexPathList).nativeLibraryPathElements(dalvik.system.DexPathList$NativeLibraryElement[])

AssetManager Hook

获得AssetManager:
1.<24  直接new AssetManager
2.>=24 从application.getAssets
增加新的asset path
1.<28 AssetManager.addAssetPath
2.>=28 AssetManager.addAssetPaths
AssetManager.ensureStringBlocks

ResourcesManager.java
mActiveResources(ArrayMap >)
ActivityThread.java
mActiveResources(ArrayMap >)

替换每一个Resources里的resource为前面处理后的AssetManager
resources.updateConfiguration(resources.getConfiguration(), resources.getDisplayMetrics());
v>21:resources.mTypedArrayPool(android.util.pools.SynchronizedPool).acquire()

这是hook ResourceManager中的resource,除此之外,还需要hook Activity的resource
activity.getResources().mResourcesImpl(android.content.res.ResourcesImpl.java).mAssets(AssetManager)

ActivityThread Hook

获得ActivityThread的两种方式:
android.app.ActivityThread.currentActivityThread()
context.@mLoadedApk.@mActivityThread

android.app.ActivityThread.currentActivityThread()
android.app.ActivityThread.currentApplication()
android.app.ActivityThread$ApplicationThread.scheduleRelaunchActivity()
android.app.ActivityThread$CreateServiceData.info
android.app.ActivityThread$ActivityClientRecord.intent
android.app.ActivityThread$ActivityClientRecord.activityInfo

Launch Activity之前update ActivityInfo,update Theme,update Resource

Small源码解析参考:

源码:
https://github.com/wequick/Small
如果是新版android studio,记得下载这个branch:
https://github.com/wequick/Small/tree/support-android-gradle-3.0
源码解析文章比较多,我这里就不罗嗦了,大家自己查阅即可。
https://www.jianshu.com/p/3724ee20ad99
https://www.jianshu.com/p/b2843950aae8
如果之前没接触过hook,可以看这边文章了解一下
https://www.cnblogs.com/codingblock/p/6580364.html

Android源码参考:

http://androidxref.com/2.3.7/xref/frameworks/base/core/java/android/content/pm/PackageParser.java
http://androidxref.com/2.3.7/xref/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java

http://androidxref.com/7.0.0_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
http://androidxref.com/7.0.0_r1/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
http://androidxref.com/7.0.0_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/app/ActivityThread.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/app/ResourcesManager.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/content/res/Resources.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/content/res/ResourcesImpl.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/content/res/AssetManager.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/content/pm/ApplicationInfo.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/content/pm/PackageInfo.java
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/content/pm/ActivityInfo.java

你可能感兴趣的:(Small插件源码分析)