基本原理
LSPatch会替换掉清单中的appcomponentFactory,并在内部执行其自身的代码。
这是属性是安卓8加入的,所以lspatch的最低版本就是安卓8。
appcomponmentFactory的作用是减少instrumentation的工作量
众所周知,一个安卓程序,第一段被执行的代码就位于instrumentation,instrumentation负责整个程序的内部协作。
instrumentation尤为重量,所以在安卓8,谷歌提供了appcomponentFactory。前者关注程序所有的协作,而后者只关注四大组件的创建。
步骤解析
第一步就是拷贝LSPatch的源码
https://github.com/LSPosed/LSPatch
LSPAppComponentFactoryStub
有了上述的介绍,读者们应该清楚LSPatch第一段执行的代码就位于LSPAppComponentFactoryStub,
而他的代码在源码中位于meta-loader中。
大致流程如下
public class LSPAppComponentFactoryStub extends AppComponentFactory {
private static final String TAG = "LSPatch-MetaLoader";
private static final Map<String, String> archToLib = new HashMap<String, String>(4);
public static byte[] dex;
static {
try {
archToLib.put("arm", "armeabi-v7a");
archToLib.put("arm64", "arm64-v8a");
archToLib.put("x86", "x86");
archToLib.put("x86_64", "x86_64");
...
String libName = archToLib.get(arch);
// 获取是哪个架构的
boolean useManager = false;
String soPath;
// 读patch的config
try (var is = cl.getResourceAsStream(Constants.CONFIG_ASSET_PATH);
...
}
if (useManager) {
// 如果使用管理器(本地模式)
Log.i(TAG, "Bootstrap loader from manager");
var ipm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
ApplicationInfo manager = ipm.getApplicationInfo(Constants.MANAGER_PACKAGE_NAME, 0, Process.myUid() / 100000);
try (var zip = new ZipFile(new File(manager.sourceDir));
// 从管理器的apk中拿到assets/lspatch/loader.dex
var is = zip.getInputStream(zip.getEntry(Constants.LOADER_DEX_ASSET_PATH));
var os = new ByteArrayOutputStream()) {
transfer(is, os);
dex = os.toByteArray();
}
soPath = manager.sourceDir + "!/assets/lspatch/so/" + libName + "/liblspatch.so";
} else {
Log.i(TAG, "Bootstrap loader from embedment");
try (var is = cl.getResourceAsStream(Constants.LOADER_DEX_ASSET_PATH);
// 从被patch的apk中拿到assets/lspatch/loader.dex
var os = new ByteArrayOutputStream()) {
transfer(is, os);
dex = os.toByteArray();
}
soPath = cl.getResource(