源码分析 — VirtualAPK框架(一)之初始化

一、概述

文章看过千百遍,不如源码走一遍。
一则,提升阅读源码的能力;
二则,在阅读源码的过程中学会思考,理解其实现原理;
如是,便有了此文。

1.1 相关技术点

  1. 设计模式 — 动态代理模式
  2. 源码分析 — Activity的清单注册校验
  3. 源码分析 — ActivityThread(二)之ActivityThread的浅析
  4. 源码分析 — Activity的启动流程
  5. 源码分析 — PackageManagerService(一)之启动流程
  6. 源码分析 — PackageManagerService(二)之resolveIntent()
  7. 源码分析 — Binder机制(一)(进程间通信)
  8. 源码分析 — Binder机制(二)之IActivityManager

1.2 参考

1.3 版本

  • Android Framework: Api 23
  • VirtualAPK: com.didi.virtualapk:core 0.9.0

二、插件框架初始化

2.1 时序图

这里写图片描述

2.2 框架初始化的源码分析

在Application中开始初始化插件框架:PluginManager.getInstance(application).init()

// PluginManager.class
public static PluginManager getInstance(Context base) {
    if (sInstance == null) {
        synchronized (PluginManager.class) {
            if (sInstance == null)
                // 首次进来要初始化
                sInstance = new PluginManager(base);
        }
    }
    return sInstance;
}

// PluginManager.class
private PluginManager(Context context) {
    Context app = context.getApplicationContext();
    if (app == null) {
        this.mContext = context;
    } else {
        this.mContext = ((Application)app).getBaseContext();
    }
    // 这里初始化是核心
    prepare();
}

// PluginManager.class
private void prepare() {
    Systems.sHostContext = getHostContext();
    //利用Hook技术,替换ActivityThread中的Instrumentation对象
    this.hookInstrumentationAndHandler();
    //利用Hook技术,替换ActivityManagerNative中的gDefault对象中的IActivityManager对象
    this.hookSystemServices();
}

// PluginManager.class
private void hookInstrumentationAndHandler() {
    try {
        Instrumentation baseInstrumentation = ReflectUtil.getInstrumentation(this.mContext);
        if (baseInstrumentation.getClass().getName().contains("lbe")) {
            // reject executing in paralell space, for example, lbe.
            System.exit(0);
        }
        /*
         * 创建Instrumentation的代理类VAInstrumentation;
         * (将Instrumentation作为参数传入,这样可以在调用系统逻辑之前进行预处理)
         */
        final VAInstrumentation instrumentation = new VAInstrumentation(this, baseInstrumentation);
        Object activityThread = ReflectUtil.getActivityThread(this.mContext);
        ReflectUtil.setInstrumentation(activityThread, instrumentation);
        ReflectUtil.setHandlerCallback(this.mContext, instrumentation);
        this.mInstrumentation = instrumentation;
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// PluginManager.class
private void hookSystemServices() {
    try {
        /*
         * 通过反射获取持有 ActivityManagerProxy(AMP) 对象的单例对象 Singleton ;
         * (这部分可以看:[源码分析 — Binder机制(二)之IActivityManager]
         * (https://blog.csdn.net/love667767/article/details/79653077))
         */
        Singleton<IActivityManager> defaultSingleton = (Singleton<IActivityManager>) 
                    ReflectUtil.getField(ActivityManagerNative.class, null, "gDefault");
        /*
         * 自己创建一个AMP代理类,将系统原有的AMP作为一个参数传入;
         * 好处:
         * 在调用系统AMP之前会先调用我们自己创建的AMP,然后进行一些预处理,
         * 最后调用系统的AMP,我们的代理类,其实质就是系统AMP的代理);
         */
        IActivityManager activityManagerProxy = 
                    ActivityManagerProxy.newInstance(this, defaultSingleton.get());
        /*
         * Hook IActivityManager from ActivityManagerNative
         * 这里创建了自己的 AMP 类后,当然要将它设置回 Singleton 单例了,
         * 这样子我们自己实现的 AMP 才能生效;
         */
        ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), 
                            defaultSingleton, "mInstance", activityManagerProxy);

        if (defaultSingleton.get() == activityManagerProxy) {
            this.mActivityManager = activityManagerProxy;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

三、插件的加载

3.1 加载插件的示例代码

在底座(宿主)Apk中加载插件的代码片段:

// 加载plugin.apk插件包
private void loadPlugin() {
    PluginManager pluginManager = PluginManager.getInstance(this);
    // 指明被加载的插件所在路径
    File apk = new File(getExternalStorageDirectory(), "app-release.apk");
    if (apk.exists()) {
        try {
            // 加载插件Apk
            pluginManager.loadPlugin(apk);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.2 插件初始化源码分析

/**
 * PluginManager.class
 * 
 * 加载插件Apk包,然后调用插件Apk的Application;
 * 注意:加载的文件必须以.apk为后缀;
 */
public void loadPlugin(File apk) throws Exception {
    if (null == apk) {
        throw new IllegalArgumentException("error : apk is null.");
    }

    if (!apk.exists()) {
        throw new FileNotFoundException(apk.getAbsolutePath());
    }
    // 1.加载插件Apk,然后解析其文件结构
    LoadedPlugin plugin = LoadedPlugin.create(this, this.mContext, apk);
    if (null != plugin) {
        this.mPlugins.put(plugin.getPackageName(), plugin);
        // 2.调用插件里面的Application(插件内的Application已经被插件框架托管)
        plugin.invokeApplication();
    } else {
        throw  new RuntimeException("Can't load plugin which is invalid: " + apk.getAbsolutePath());
    }
}
// LoadedPlugin.class
public static LoadedPlugin create(PluginManager pluginManager, Context host, File apk) throws Exception {
    return new LoadedPlugin(pluginManager, host, apk);
}


LoadedPlugin(PluginManager pluginManager, Context context, File apk) 
                            throws PackageParser.PackageParserException {
    this.mPluginManager = pluginManager;
    this.mHostContext = context;
    this.mLocation = apk.getAbsolutePath();
    /*
     * 1.关键:通过系统的PackageParser.parsePackage()方法去解析Apk文件;
     * 参考:[PackageManagerService(一)之启动流程](https://blog.csdn.net/love667767/article/details/79595237)
     * 
     * 说明:由于系统版本的适配问题,这里框架做了一层封装,根据版本的不同做了不同的处理;
     */
    this.mPackage = PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);
    this.mPackage.applicationInfo.metaData = this.mPackage.mAppMetaData;
    this.mPackageInfo = new PackageInfo();
    this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo;
    // ...
    // 插件包的管理对象
    this.mPackageManager = new PluginPackageManager();
    // 插件包的Context
    this.mPluginContext = new PluginContext(this);
    this.mNativeLibDir = context.getDir(Constants.NATIVE_DIR, Context.MODE_PRIVATE);
    // 资源获取
    this.mResources = createResources(context, apk);
    this.mAssets = this.mResources.getAssets();
    // 创建插件的ClassLoader
    this.mClassLoader = createClassLoader(context, apk, this.mNativeLibDir, context.getClassLoader());
    // 将插件中Lib库的依赖包拷贝到底座(宿主)中;
    tryToCopyNativeLib(apk);

    /*
     * 2.下面这部分跟PackageManagerService(PMS)逻辑类似,就是将插件清单文件解析出来的信息存入到
     * mInstrumentationInfos、mActivityInfos、mServiceInfos、mProviderInfos、mReceiverInfos字段中;
     */
    // Cache instrumentations
    Map<ComponentName, InstrumentationInfo> instrumentations = new HashMap<ComponentName, InstrumentationInfo>();
    for (PackageParser.Instrumentation instrumentation : this.mPackage.instrumentation) {
        instrumentations.put(instrumentation.getComponentName(), instrumentation.info);
    }
    this.mInstrumentationInfos = Collections.unmodifiableMap(instrumentations);
    this.mPackageInfo.instrumentation = instrumentations.values().toArray(new InstrumentationInfo[instrumentations.size()]);

    // Cache activities
    Map<ComponentName, ActivityInfo> activityInfos = new HashMap<ComponentName, ActivityInfo>();
    for (PackageParser.Activity activity : this.mPackage.activities) {
        activityInfos.put(activity.getComponentName(), activity.info);
    }
    this.mActivityInfos = Collections.unmodifiableMap(activityInfos);
    this.mPackageInfo.activities = activityInfos.values().toArray(new ActivityInfo[activityInfos.size()]);

    // Cache services
    Map<ComponentName, ServiceInfo> serviceInfos = new HashMap<ComponentName, ServiceInfo>();
    for (PackageParser.Service service : this.mPackage.services) {
        serviceInfos.put(service.getComponentName(), service.info);
    }
    this.mServiceInfos = Collections.unmodifiableMap(serviceInfos);
    this.mPackageInfo.services = serviceInfos.values().toArray(new ServiceInfo[serviceInfos.size()]);

    // Cache providers
    Map<String, ProviderInfo> providers = new HashMap<String, ProviderInfo>();
    Map<ComponentName, ProviderInfo> providerInfos = new HashMap<ComponentName, ProviderInfo>();
    for (PackageParser.Provider provider : this.mPackage.providers) {
        providers.put(provider.info.authority, provider.info);
        providerInfos.put(provider.getComponentName(), provider.info);
    }
    this.mProviders = Collections.unmodifiableMap(providers);
    this.mProviderInfos = Collections.unmodifiableMap(providerInfos);
    this.mPackageInfo.providers = providerInfos.values().toArray(new ProviderInfo[providerInfos.size()]);

    // Register broadcast receivers dynamically
    Map<ComponentName, ActivityInfo> receivers = new HashMap<ComponentName, ActivityInfo>();
    for (PackageParser.Activity receiver : this.mPackage.receivers) {
        receivers.put(receiver.getComponentName(), receiver.info);

        try {
            BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
            for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
                // 这里将插件清单文件中的静态广播动态注册到底座(宿主)中;
                this.mHostContext.registerReceiver(br, aii);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    this.mReceiverInfos = Collections.unmodifiableMap(receivers);
    this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值