Android插件化原理分析(基于Neptune框架)

栏目: IOS · Android · 发布时间: 6年前

内容简介:Android插件化不算是一门新技术,发展了有一些年头了。不同公司的插件化方案大体原理上很相似。本文通过阅读爱奇艺的所谓的插件其实本质上也是一个apk。在原生的Android应用中,apk在运行时会被映射成一个插件的安装分为内置插件(asset目录,sdcard)和线上插件两部分。

Android插件化不算是一门新技术,发展了有一些年头了。不同公司的插件化方案大体原理上很相似。本文通过阅读爱奇艺的 Neptune 框架来介绍插件化的整体思路和流程。

插件化基础知识点

插件应用安装

所谓的插件其实本质上也是一个apk。在原生的Android应用中,apk在运行时会被映射成一个 LoadedApk 对象。插件在安装之后也会被映射成类似的 PluginLoadedApk 对象,统一管理插件的相关信息。

public class PluginLoadedApk {
    public static final ConcurrentMap<String, Vector<Method>> sMethods = new ConcurrentHashMap<String, Vector<Method>>(1);
    private static final String TAG = "PluginLoadedApk";
    /* 保存注入到宿主ClassLoader的插件 */
    private static Set<String> sInjectedPlugins = Collections.synchronizedSet(new HashSet<String>());
    /* 保存所有的插件ClassLoader */
    private static Map<String, DexClassLoader> sAllPluginClassLoader = new ConcurrentHashMap<>();

    /* 宿主的Context */
    private final Context mHostContext;
    /* 宿主的ClassLoader */
    private final ClassLoader mHostClassLoader;
    /* 宿主的Resource对象 */
    private final Resources mHostResource;
    /* 宿主的包名 */
    private final String mHostPackageName;
    /* 插件的路径 */
    private final String mPluginPath;
    /* 插件运行的进程名 */
    private final String mProcessName;
    /* 插件ClassLoader的parent */
    private ClassLoader mParent;
    /* 插件的类加载器 */
    private DexClassLoader mPluginClassLoader;
    /* 插件的Resource对象 */
    private Resources mPluginResource;
    /* 插件的AssetManager对象 */
    private AssetManager mPluginAssetManager;
    /* 插件的全局默认主题 */
    private Resources.Theme mPluginTheme;
    /* 插件的详细信息,主要通过解析AndroidManifest.xml获得 */
    private PluginPackageInfo mPluginPackageInfo;
    /* 插件工程的包名 */
    private String mPluginPackageName;
    /* 插件的Application */
    private Application mPluginApplication;
    /* 自定义插件Context,主要用来改写其中的一些方法从而改变插件行为 */
    private PluginContextWrapper mPluginAppContext;
    /* 自定义Instrumentation,对Activity跳转进行拦截 */
    private PluginInstrument mPluginInstrument;
    ...
}    
复制代码

插件的安装分为内置插件(asset目录,sdcard)和线上插件两部分。

  • 内置插件:
    • 约定存放在assets/pluginapp/<plugin_pkg_name>.apk形式,安装时解压到/data/data/<host_pkg_name>/app_pluginapp目录
    • sdcard插件,允许调试模式下安装,以<plugin_pkg_name>.apk命名
  • 线上插件:直接将插件下载到sdcard目录上,然后拷贝到/data/data/<host_pkg_name>/app_pluginapp目录下;为了减少拷贝操作,可以直接下载到/data/data/<hots_pkg_name>/app_pluginapp目录;

插件的安装通过运行在独立进程的Service完成,主要防止部分机型dexopt hang住主进程。

dexopt

Android根据系统版本不同会采用两种虚拟机。Dalvik虚拟机是JIT方式解释执行dex字节码;ART虚拟机是AOT方式将dex字节码转化为oat机器码。

  • Dalvik是运行时解释dex文件,安装比较快,开启应用比较慢,应用占用空间小
  • ART是安装的时候字节码预编译成机器码存储在本地,执行的时候直接就可以运行的,安装慢,开启应用快,占用空间大;

如果当前运行在Dalvik虚拟机下,Dalvik会对classes.dex进行一次“翻译”,“翻译”的过程也就是守护进程installd的函数dexopt来对dex字节码进行优化,实际上也就是由dex文件生成odex文件,最终odex文件被保存在手机的VM缓存目录data/dalvik-cache下(注意!这里所生成的odex文件依旧是以dex为后缀名,格式如:system@priv-app@Settings@Settings.apk@classes.dex)。如果当前运行于ART模式下, ART同样会在首次进入系统的时候调用/system/bin/dexopt(此处应该是dex2oat工具吧)工具来将dex字节码翻译成本地机器码,保存在data/dalvik-cache下。 那么这里需要注意的是,无论是对dex字节码进行优化,还是将dex字节码翻译成本地机器码,最终得到的结果都是保存在相同名称的一个odex文件里面的,但是前者对应的是一个.dex文件(表示这是一个优化过的dex),后者对应的是一个.oat文件。通过这种方式,原来任何通过绝对路径引用了该odex文件的代码就都不需要修改了。 由于在系统首次启动时会对应用进行安装,那么在预置APK比较多的情况下,将会大大增加系统首次启动的时间。

对于插件安装来说,插件的安装通过运行在独立进程的Service完成,主要防止部分机型dexopt hang住主进程。

插件安装过程主要执行以下几步:

  1. 拷贝apk到内置存储区,重命名为<plugin_pkg_name>.apk
  2. 解压apk中的so库到app_pluginapp/<plugin_pkg_name>/lib目录
  3. dexopt优化插件dex,Android 7.0以上第一次会使用解释模式执行dex,优化加载速度

类加载

Android插件化原理分析(基于Neptune框架)

Java中的类都是通过ClassLoader加载的,而Android中类的加载也离不开ClassLoadder。在Android系统中,主要的ClassLoader有三个:

  • BootClassLoader:Android系统启动时用来预加载常用的类
  • PathClassLoader:用来加载系统和应用程序中的类,如果是非系统应用程序类,则会加载/data/app目录下的dex、apk或jar文件
  • DexClassLoader:可以加载指定路径的dex、apk或jar文件,支持从SD卡进行加载,是插件化的技术基础

类加载的双亲委派机制

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

关于插件中类的加载机制有两种处理方式,一种是单类加载机制,另一种是多类加载机制;单类加载器机制,即所有插件APP的类都通过宿主的ClassLoader(即PathClassLoader)进行加载,与MultiDex、Qzone热修复技术类似,通过Dex前插后者后插的方式实现。采用单类加载器模型,随着业务团队和插件的增加,很容易出现类重复问题,无法保证所有类都是独一无二的。多类加载器机制是指每个插件都由一个新的类加载器实例来加载,组件间的类是完全隔离,不能直接互相访问。

利用ClassLoader的双亲委派机制,多类加载有两种思路:

  • 自定义代理的ClassLoader设置为PathClassLoader的父类加载器,那么自定义的类加载器就能代理所有的类加载行为;在代理ClassLoader内部做类加载的逻辑分发,先尝试从宿主的ClassLoader加载,再尝试插件的ClassLoader加载。(好处:只需要在启动时hook ClassLoader,添加DelegateClassLoader,后续的类加载由DelegateClassLoader分发;对于未加载的插件,可以通过包名匹配,先触发插件加载,再加载类)
  • 每个 PluginLoadedApk 维护一个 PluginClassLoader 实例,其父ClassLoader是PathClassLoader;在类加载时,先尝试从宿主的ClassLoader加载,再尝试本插件的ClassLoader加载。(好处:每个插件维护自己的 PluginLoadedApk ,不存在分发,类隔离做的更好)

资源加载

Android APP运行除了类还有资源,运行时需要加载资源;对于Android来说,资源是通过AssetManager和Resources这两个类管理。App在运行时查找资源是通过当前Context的Resource实例中查找,在Resource内部是通过AssetManager管理当前的资源,AssetManager维护了资源包路径的数组。插件化的原理,就是将插件的资源路径添加到AssetManager的资源路径数组中,通过反射AssetManager的隐藏方法addAssetPath实现插件资源的加载。

try{
    AssetManager am = AssetManager.class.newInstance();
    Method addAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
    addAssetPath.setAccessible(true);
    addAssetPath.invoke(am, pluginApkPath);
    Resources pluginResources = new Resources(am, hostResource.getDisplayMetrics(), hostResources.getConfiguration());
} catch (Exception e) {
    e.printStackTrace();
}
复制代码

各种插件化方案的资源加载原理都是一样,区别主要在于不同插件的资源管理,是公用一套资源还是插件独立资源,插件和宿主的资源访问ID冲突问题。

  • 公用一套资源需要采用固定资源id及ID分段机制避免冲突
  • 独立资源方案,不同插件管理自己的资源

插件化中资源使用限制

限制:插件不能使用自己的转场动画,只能使用宿主、系统定义的转场动画。

转场动画最终会调用到 IActivityManager ,发起IPC请求,与AMS交互

public void overridePendingTransition(IBinder token, String packageName,
            int enterAnim, int exitAnim) throws RemoteException;
复制代码

Apk打包流程

先附上两张Android原生打包流程图

Android插件化原理分析(基于Neptune框架)

Android插件化原理分析(基于Neptune框架)

在插件编译打包时,需要完成以下几件事:

  • 插件的资源和宿主的资源通过不同的资源分段区分
  • 在插件化中,如果插件需要引用宿主的资源,则需要将宿主的资源id进行固定
  • 处理插件aapt的编译产物,不将宿主的资源打入apk中
  • 处理Manifest文件,将占坑的四大组件写入Manifest文件中
  • 在字节码层面对代码做修改

Hook点

  • Hook MergeResources Task,将public.xml文件拷贝至资源merge完成的目录
  • Hook ProcessAndroidResources Task,修改生成的arsc文件。
  • Hook ManifestProcessorTask, 在Manifest中插入特定信息。
  • Hook dexTask/Transform,最源代码的修改

四大组件的插件化

Activity的插件化

Activity启动可以分为两个阶段:往AMS发起启动Activity的请求、AMS校验后执行Activity启动。

往AMS发起请求

Android插件化原理分析(基于Neptune框架)

在Android 8.0(api 26)以下,应用往AMS发起启动Activity请求的流程如上。在Android 8.0及以上版本,AMN、AMP已经被弃用,而是使用 ActivityManager 类; 参考文章

Hook点:

  • Hook Instrumentation类,代理execStartActivity方法
  • Hook AMN(<26)/ActivityManager(>=26),动态代理IActivityManager接口的实例对象

AMS校验后启动Activity

Android插件化原理分析(基于Neptune框架)

Android P(api 28)对Activity的启动过程做了修改;在Android P之前,是在H类的handleMessage方法的switch分支语句中,有专门处理启动Activity的逻辑

public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                } break;
            
            //以下省略很多代码
            }
        }
复制代码

在Android P中,启动Activity的这部分逻辑,被转移到了LaunchActivityItem类的execute方法中

public class LaunchActivityItem extends ClientTransactionItem {

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    }
}
复制代码

Android P把H类中的100-109这10个消息都删除了,取而代之的是159这个消息,名为EXECUTE_TRANSACTION。收敛了Activity相关的message分发。

Hook点:

  • Hook H类,将占坑Activity替换成真实的Activity(需要做Android P的适配)
  • Hook Instrumentation类,替换成自定义的Instrument,重写newActivity、callActivityOnCreate等方法

Service的插件化

Service启动可以分为两个阶段:往AMS发起启动Service的请求、AMS校验后执行Service启动。

往AMS发起启动Service的请求

Android插件化原理分析(基于Neptune框架)

在Android 8.0(api 26)以下,应用往AMS发起启动Service请求的流程如上。在Android 8.0及以上版本,AMN、AMP已经被弃用,而是使用ActivityManager类。

Hook点

  • Hook ContextWrapper;替换成自定义的ContextWrapper,将Service替换成占坑的Service
  • Hook AMN(<26)/ActivityManager(>=26),动态代理IActivityManager接口的实例对象

AMS校验后执行Service启动

Android插件化原理分析(基于Neptune框架)

Hook点:

  • 在占坑Service的onStartCommand提取真实Service信息,并分发执行真实Service逻辑
  • Hook handleServiceCreate方法,发射获取ServiceInfo,修改ServiceInfo的name字段为真实Service的名字。加载真实的Service类。

BroadCastReceiver插件化

Android插件化原理分析(基于Neptune框架)

广播分为静态广播、动态广播。动态广播在运行时向AMS注册相关信息。

Hook点:

  • 静态广播转换为动态广播

ContentProvider插件化

Android插件化原理分析(基于Neptune框架)

Hook点:

  • Hook AMN(<26)/ActivityManager(>=26),动态代理IActivityManager接口的实例对象;将目标ContentProvider的信息放在query参数中

Neptune源码分析

Neptune类

Neptune 类是整个插件系统的入口类,主要方法如下

  • init()方法
/**
     * 初始化Neptune插件环境
     *
     * @param application  宿主的Appliction
     * @param config  配置信息
     */
    public static void init(Application application, NeptuneConfig config) {

        sHostContext = application;
        sGlobalConfig = config != null ? config
                : new NeptuneConfig.NeptuneConfigBuilder().build();

        PluginDebugLog.setIsDebug(sGlobalConfig.isDebug());

        boolean hookInstr = VersionUtils.hasPie() || sGlobalConfig.getSdkMode() != NeptuneConfig.LEGACY_MODE;
        if (hookInstr) {
            //Hook Instrumentation
            hookInstrumentation();
        }

        // 调用getInstance()方法会初始化bindService,管理插件安装的Service
        PluginPackageManagerNative.getInstance(sHostContext).setPackageInfoManager(sGlobalConfig.getPluginInfoProvider());
        // 注册插件卸载监听广播
        PluginManager.registerUninstallReceiver(sHostContext);
    }
复制代码
  • launchPlugin()方法
/**
     * 启动插件
     *
     * @param mHostContext       主工程的上下文
     * @param mIntent            需要启动的组件的Intent
     * @param mServiceConnection bindService时需要的ServiceConnection,如果不是bindService的方式启动组件,传入Null
     * @param mProcessName       需要启动的插件运行的进程名称,插件方可以在Application的android:process指定
     *                           如果没有指定,则有插件中心分配
     */
    public static void launchPlugin(final Context mHostContext,
                                    final Intent mIntent,
                                    final ServiceConnection mServiceConnection,
                                    final String mProcessName) {
        final String packageName = tryParsePkgName(mHostContext, mIntent);
        if (TextUtils.isEmpty(packageName)) {
            if (null != mHostContext) {
                deliver(mHostContext, false, mHostContext.getPackageName(), ErrorType.ERROR_PLUGIN_LOAD_NO_PKGNAME_INTENT);
            }
            PluginDebugLog.runtimeLog(TAG, "enterProxy packageName is null return! packageName: " + packageName);
            return;
        }
        // 处理不同进程跳转
        final String targetProcessName = TextUtils.isEmpty(mProcessName) ?
                ProcessManager.chooseDefaultProcess(mHostContext, packageName) : mProcessName;
        String currentProcess = FileUtils.getCurrentProcessName(mHostContext);
        if (!TextUtils.equals(currentProcess, targetProcessName)) {
            // 启动进程和目标进程不一致,需要先启动目标进程,初始化PluginLoadedApk
            Intent transIntent = new Intent();
            transIntent.setAction(IntentConstant.ACTION_START_PLUGIN);
            //目标进程的Service中重新通过mIntent启动插件
            transIntent.putExtra(IntentConstant.EXTRA_START_INTENT_KEY, mIntent);
            transIntent.putExtra(IntentConstant.EXTRA_TARGET_PROCESS, targetProcessName);
            try {
                String proxyServiceName = ComponentFinder.matchServiceProxyByFeature(targetProcessName);
                transIntent.setClass(mHostContext, Class.forName(proxyServiceName));
                mHostContext.startService(transIntent);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return;
        }

        LinkedBlockingQueue<Intent> cacheIntents = PActivityStackSupervisor.getCachedIntent(packageName);
        //该插件有其他任务排队中,mIntent添加到队尾
        if (cacheIntents != null && cacheIntents.size() > 0) {
            cacheIntents.add(mIntent);
            PluginDebugLog.runtimeLog(TAG, "LoadingMap is not empty, Cache current intent, intent: " + mIntent + ", packageName: " + packageName);
            return;
        }

        boolean isLoadAndInit = isPluginLoadedAndInit(packageName);
        if (!isLoadAndInit) {
            if (null == cacheIntents) {
                cacheIntents = new LinkedBlockingQueue<Intent>();
                PActivityStackSupervisor.addCachedIntent(packageName, cacheIntents);
            }
            // 缓存这个intent,等待PluginLoadedApk加载到内存之后再启动这个Intent
            PluginDebugLog.runtimeLog(TAG, "Environment is initializing and loading, cache current intent first, intent: " + mIntent);
            cacheIntents.add(mIntent);
        } else {
            PluginDebugLog.runtimeLog(TAG, "Environment is already ready, launch current intent directly: " + mIntent);
            //可以直接启动组件
            readyToStartSpecifyPlugin(mHostContext, mServiceConnection, mIntent, true);
            return;
        }

        // 处理插件的依赖关系
        final PluginLiteInfo info = PluginPackageManagerNative.getInstance(mHostContext.getApplicationContext())
                .getPackageInfo(packageName);
                //获取插件的依赖关系
        final List<String> mPluginRefs = PluginPackageManagerNative.getInstance(mHostContext)
                .getPluginRefs(packageName);
        if (info != null && mPluginRefs != null
                && mPluginRefs.size() > 0) {
            PluginDebugLog.runtimeLog(TAG,
                    "start to check dependence installation size: " + mPluginRefs.size());
            //依赖的总数量
            final AtomicInteger count = new AtomicInteger(mPluginRefs.size());
            for (String pkgName : mPluginRefs) {
                PluginDebugLog.runtimeLog(TAG, "start to check installation pkgName: " + pkgName);
                final PluginLiteInfo refInfo = PluginPackageManagerNative.getInstance(mHostContext.getApplicationContext())
                        .getPackageInfo(pkgName);

                PluginPackageManagerNative.getInstance(mHostContext.getApplicationContext()).packageAction(refInfo,
                        new IInstallCallBack.Stub() {
                            @Override
                            public void onPackageInstalled(PluginLiteInfo packageInfo) {
                                //未ready的依赖数量
                                count.getAndDecrement();
                                PluginDebugLog.runtimeLog(TAG, "check installation success pkgName: " + refInfo.packageName);
                                if (count.get() == 0) {
                                    PluginDebugLog.runtimeLog(TAG,
                                            "start Check installation after check dependence packageName: "
                                                    + packageName);
                                    //真正加载插件
                                    checkPkgInstallationAndLaunch(mHostContext, info, mServiceConnection, mIntent, targetProcessName);
                                }
                            }

                            @Override
                            public void onPackageInstallFail(PluginLiteInfo info, int failReason) throws RemoteException {
                                PluginDebugLog.runtimeLog(TAG,
                                        "check installation failed pkgName: " + info.packageName + " failReason: " + failReason);
                                count.set(-1);
                            }
                        });
            }
        } else if (info != null) {
            PluginDebugLog.runtimeLog(TAG, "start Check installation without dependence packageName: " + packageName);
            //真正加载插件
            checkPkgInstallationAndLaunch(mHostContext, info, mServiceConnection, mIntent, targetProcessName);
        } else {
            //异常case
            PluginDebugLog.runtimeLog(TAG, "pluginLiteInfo is null packageName: " + packageName);
            PActivityStackSupervisor.clearLoadingIntent(packageName);
            if (PluginDebugLog.isDebug()) {
                throw new IllegalStateException("pluginLiteInfo is null when launchPlugin " + packageName);
            }
        }
    }
复制代码
/**
     * 真正启动一个组件
     *
     * @param mHostContext 主工程Context
     * @param mLoadedApk   需要启动的插件的PluginLoadedApk
     * @param mIntent      需要启动组件的Intent
     * @param mConnection  bindService时需要的ServiceConnection,如果不是bindService的方式启动组件,传入Null
     */
    private static void doRealLaunch(Context mHostContext,
                                     PluginLoadedApk mLoadedApk,
                                     Intent mIntent,
                                     ServiceConnection mConnection) {

        String targetClassName = "";
        ComponentName mComponent = mIntent.getComponent();
        if (mComponent != null) {
            //显式启动
            targetClassName = mComponent.getClassName();
            PluginDebugLog.runtimeLog(TAG, "launchIntent_targetClassName:" + targetClassName);
            if (TextUtils.isEmpty(targetClassName)) {
                targetClassName = mLoadedApk.getPluginPackageInfo().getDefaultActivityName();
            }
        }

        String pkgName = mLoadedApk.getPluginPackageName();
        Class<?> targetClass = null;
        if (!TextUtils.isEmpty(targetClassName)
                && !TextUtils.equals(targetClassName, IntentConstant.EXTRA_VALUE_LOADTARGET_STUB)) {
            try {
                //插件ClassLoader加载类
                targetClass = mLoadedApk.getPluginClassLoader().loadClass(targetClassName);
            } catch (Exception e) {
                deliver(mHostContext, false,
                        pkgName, ErrorType.ERROR_PLUGIN_LOAD_COMP_CLASS);
                PluginDebugLog.runtimeLog(TAG, "launchIntent loadClass failed for targetClassName: "
                        + targetClassName);
                executeNext(mLoadedApk, mConnection, mHostContext);
                return;
            }
        }

        String action = mIntent.getAction();

        if (TextUtils.equals(action, IntentConstant.ACTION_PLUGIN_INIT)
                || TextUtils.equals(targetClassName, IntentConstant.EXTRA_VALUE_LOADTARGET_STUB)) {
            PluginDebugLog.runtimeLog(TAG, "launchIntent load target stub!");
            //通知插件初始化完毕
            if (targetClass != null && BroadcastReceiver.class.isAssignableFrom(targetClass)) {
                Intent newIntent = new Intent(mIntent);
                newIntent.setComponent(null);
                newIntent.putExtra(IntentConstant.EXTRA_TARGET_PACKAGE_KEY, pkgName);
                newIntent.setPackage(mHostContext.getPackageName());
                //通过广播通知插件加载完成
                mHostContext.sendBroadcast(newIntent);
            }
            // 表示后台加载,不需要处理该Intent
            executeNext(mLoadedApk, mConnection, mHostContext);
            return;
        }

        mLoadedApk.changeLaunchingIntentStatus(true);
        PluginDebugLog.runtimeLog(TAG, "launchIntent_targetClass: " + targetClass);
        if (targetClass != null && Service.class.isAssignableFrom(targetClass)) {
            //处理的是Service, 宿主启动插件Service只能通过显式启动
            ComponentFinder.switchToServiceProxy(mLoadedApk, mIntent, targetClassName);
            if (mConnection == null) {
                mHostContext.startService(mIntent);
            } else {
                mHostContext.bindService(mIntent, mConnection,
                        mIntent.getIntExtra(IntentConstant.BIND_SERVICE_FLAGS, Context.BIND_AUTO_CREATE));
            }
        } else {
            //处理的是Activity
            ComponentFinder.switchToActivityProxy(pkgName,
                    mIntent, -1, mHostContext);
            PActivityStackSupervisor.addLoadingIntent(pkgName, mIntent);
            Context lastActivity = null;
            PActivityStackSupervisor mActivityStackSupervisor =
                    mLoadedApk.getActivityStackSupervisor();
            lastActivity = mActivityStackSupervisor.getAvailableActivity();
            if (mHostContext instanceof Activity) {
                mHostContext.startActivity(mIntent);
            } else if (lastActivity != null) {
                // Clear the Intent.FLAG_ACTIVITY_NEW_TASK
                int flag = mIntent.getFlags();
                flag = flag ^ Intent.FLAG_ACTIVITY_NEW_TASK;
                mIntent.setFlags(flag);
                lastActivity.startActivity(mIntent);
            } else {
                // Add the Intent.FLAG_ACTIVITY_NEW_TASK
                mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                mHostContext.startActivity(mIntent);
            }
        }
        // 执行下一个Intent
        executeNext(mLoadedApk, mConnection, mHostContext);
    }
复制代码
/**
     * 异步初始化插件,宿主静默加载插件
     *
     * @deprecated 不建议使用
     */
    @Deprecated
    public static void initPluginAsync(final Context mHostContext,
                                       final String packageName,
                                       final String processName,
                                       final org.qiyi.pluginlibrary.listenter.IPluginStatusListener mListener) {
        // 插件已经加载
        if (PluginManager.isPluginLoadedAndInit(packageName)) {
            if (mListener != null) {
                mListener.onInitFinished(packageName);
            }
            return;
        }

        BroadcastReceiver recv = new BroadcastReceiver() {
            public void onReceive(Context ctx, Intent intent) {
                String curPkg = IntentUtils.getTargetPackage(intent);
                if (IntentConstant.ACTION_PLUGIN_INIT.equals(intent.getAction()) && TextUtils.equals(packageName, curPkg)) {
                    PluginDebugLog.runtimeLog(TAG, "收到自定义的广播org.qiyi.pluginapp.action.TARGET_LOADED");
                    //插件初始化结束
                    if (mListener != null) {
                        mListener.onInitFinished(packageName);
                    }
                    mHostContext.getApplicationContext().unregisterReceiver(this);
                }
            }
        };
        PluginDebugLog.runtimeLog(TAG, "注册自定义广播org.qiyi.pluginapp.action.TARGET_LOADED");
        IntentFilter filter = new IntentFilter();
        filter.addAction(IntentConstant.ACTION_PLUGIN_INIT);
        //注册广播
        mHostContext.getApplicationContext().registerReceiver(recv, filter);

        Intent intent = new Intent();
        intent.setAction(IntentConstant.ACTION_PLUGIN_INIT);
        intent.setComponent(new ComponentName(packageName, recv.getClass().getName()));
        //发送一个启动插件的intent
        launchPlugin(mHostContext, intent, processName);
    }
复制代码

NeptuneInstrument(PluginInstrument)类

Hook系统原生的Instrument,替换成NeptuneInstrument。 NeptuneInstrument 继承 PluginInstrumentPluginInstrument 负责往AMS发送的请求, NeptuneInstrument 负责AMS返回的结果处理。

/**
 * 负责转移插件的跳转目标<br>
 * 用于Hook插件Activity中Instrumentation
 *
 * @see android.app.Activity#startActivity(android.content.Intent)
 */
public class PluginInstrument extends Instrumentation {
    private static final String TAG = "PluginInstrument";

    private static ConcurrentMap<String, Vector<Method>> sMethods = new ConcurrentHashMap<String, Vector<Method>>(5);
    Instrumentation mHostInstr;
    private String mPkgName;
    private ReflectionUtils mInstrumentRef;

    /**
     * 插件的Instrumentation
     */
    public PluginInstrument(Instrumentation hostInstr) {
        this(hostInstr, "");
    }

    public PluginInstrument(Instrumentation hostInstr, String pkgName) {
        mHostInstr = hostInstr;
        mInstrumentRef = ReflectionUtils.on(hostInstr);
        mPkgName = pkgName;
    }

    /**
     * 如果是PluginInstrumentation,拆装出原始的HostInstr
     *
     * @param instrumentation
     * @return
     */
    public static Instrumentation unwrap(Instrumentation instrumentation) {
        if (instrumentation instanceof PluginInstrument) {
            return ((PluginInstrument) instrumentation).mHostInstr;
        }
        return instrumentation;
    }

    /**
     * @Override
     */
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {

        ...
    }

    /**
     * @Override
     */
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode) {
        ...
    }

    /**
     * @Override For below android 6.0
     */
    public ActivityResult execStartActivityAsCaller(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options, int userId) {
        ...
    }

    /**
     * @Override For android 6.0
     */
    public ActivityResult execStartActivityAsCaller(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options,
            boolean ignoreTargetSecurity, int userId) {
        ...
    }

    /**
     * @Override
     */
    public void execStartActivitiesAsUser(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent[] intents, Bundle options, int userId) {
        ...
    }

    /**
     * @Override For below android 6.0, start activity from Fragment
     */
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Fragment target,
            Intent intent, int requestCode, Bundle options) {
        ...
    }

    /**
     * @Override For android 6.0, start activity from Fragment
     */
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, String target,
            Intent intent, int requestCode, Bundle options) {
       ...
    }
}

复制代码
/**
 * 自定义的全局的Instrumentation
 * 负责转移插件的跳转目标和创建插件的Activity实例
 * 用于Hook ActivityThread中的全局Instrumentation
 */
public class NeptuneInstrument extends PluginInstrument {

    private static final String TAG = "NeptuneInstrument";
    private PluginActivityRecoveryHelper mRecoveryHelper = new PluginActivityRecoveryHelper();

    public NeptuneInstrument(Instrumentation hostInstr) {
        super(hostInstr);
    }

    @Override
    public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        ...
    }

    @Override
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        ...
    }

    @Override
    public void callActivityOnDestroy(Activity activity) {
        ...
    }

    @Override
    public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
        ...
    }

    /**
     * 将Activity反射相关操作分发给插件Activity的基类
     */
    private boolean dispatchToBaseActivity(Activity activity) {

        //这个模式已弃用
        return Neptune.getConfig().getSdkMode() == NeptuneConfig.INSTRUMENTATION_BASEACT_MODE
                && activity instanceof IPluginBase;
    }
}
复制代码

NeptuneInstrument 类中的几个方法有一些特殊的逻辑处理,下面单独分析:

@Override
    public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        if (className.startsWith(ComponentFinder.DEFAULT_ACTIVITY_PROXY_PREFIX)) {
            // 插件代理Activity,替换回插件真实的Activity
            String[] result = IntentUtils.parsePkgAndClsFromIntent(intent);
            String packageName = result[0];
            String targetClass = result[1];

            PluginDebugLog.runtimeLog(TAG, "newActivity: " + className + ", targetClass: " + targetClass);
            if (!TextUtils.isEmpty(packageName)) {
                //找到对应插件
                PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(packageName);
                if (loadedApk != null && targetClass != null) {
                    Activity activity = mHostInstr.newActivity(loadedApk.getPluginClassLoader(), targetClass, intent);
                    activity.setIntent(intent);

                    if (!dispatchToBaseActivity(activity)) {
                        // 这里需要替换Resources,是因为ContextThemeWrapper会缓存一个Resource对象,而在Activity#attach()和
                        // Activity#onCreate()之间,系统会调用Activity#setTheme()初始化主题,Android 4.1+
                        //替换成插件的Resource资源
                        ReflectionUtils.on(activity).setNoException("mResources", loadedApk.getPluginResource());
                    }

                    return activity;
                } else if (loadedApk == null) {
                    // loadedApk 为空,可能是正在恢复进程,跳转到 RecoveryActivity
                    return mHostInstr.newActivity(cl, mRecoveryHelper.selectRecoveryActivity(className), intent);
                }
            }
        }
        return mHostInstr.newActivity(cl, className, intent);
    }
复制代码
@Override
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        boolean isRecovery = activity instanceof TransRecoveryActivity0;
        if (isRecovery) {
        //插件加载中的Activity,使用宿主的Instrument
            mRecoveryHelper.saveIcicle(activity, icicle);
            mHostInstr.callActivityOnCreate(activity, null);
            return;
        }
        final Intent intent = activity.getIntent();
        String[] result = IntentUtils.parsePkgAndClsFromIntent(intent);
        boolean isLaunchPlugin = false;
        if (IntentUtils.isIntentForPlugin(intent)) {
            String packageName = result[0];
            String targetClass = result[1];
            if (!TextUtils.isEmpty(packageName)) {
                PluginDebugLog.runtimeLog(TAG, "callActivityOnCreate: " + packageName);
                PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(packageName);
                if (loadedApk != null) {
                    icicle = mRecoveryHelper.recoveryIcicle(activity, icicle);
                    // 设置 extra 的 ClassLoader,不然可能会出现 BadParcelException, ClassNotFound
                    if (icicle != null) {
                        icicle.setClassLoader(loadedApk.getPluginClassLoader());
                    }
                    if (!dispatchToBaseActivity(activity)) {
                        // 如果分发给插件Activity的基类了,就不需要在这里反射hook替换相关成员变量了
                        try {
                            ReflectionUtils activityRef = ReflectionUtils.on(activity);
                            //设置为插件资源
                            activityRef.setNoException("mResources", loadedApk.getPluginResource());
                            //设置插件的Application
                            activityRef.setNoException("mApplication", loadedApk.getPluginApplication());
                            Context pluginContext = new PluginContextWrapper(activity.getBaseContext(), packageName);
                            //替换为PluginContextWrapper,处理inflate相关
                            ReflectionUtils.on(activity, ContextWrapper.class).set("mBase", pluginContext);
                            // 5.0以下ContextThemeWrapper内会保存一个mBase,也需要反射替换掉
                            ReflectionUtils.on(activity, ContextThemeWrapper.class).setNoException("mBase", pluginContext);
                            //替换为插件的Instrumentation
                            ReflectionUtils.on(activity).setNoException("mInstrumentation", loadedApk.getPluginInstrument());

                            // 修改插件Activity的ActivityInfo, theme, window等信息
                            PluginActivityControl.changeActivityInfo(activity, targetClass, loadedApk);
                        } catch (Exception e) {
                        PluginDebugLog.runtimeLog(TAG, "callActivityOnCreate with exception: " + e.getMessage());
                        }

                    }

                    if (activity.getParent() == null) {
                    //Activity栈的逻辑是怎么处理的?
                        loadedApk.getActivityStackSupervisor().pushActivityToStack(activity);
                    }
                    isLaunchPlugin = true;
                }
            }
            IntentUtils.resetAction(intent);  //恢复Action
        }

        try {
            mHostInstr.callActivityOnCreate(activity, icicle);

            if (isLaunchPlugin) {
                NotifyCenter.notifyPluginStarted(activity, intent);
                NotifyCenter.notifyPluginActivityLoaded(activity);
            }
            //check是否需要hook callActivityOnRestoreInstanceState方法
            mRecoveryHelper.mockActivityOnRestoreInstanceStateIfNeed(this, activity);
        } catch (Exception e) {
            ErrorUtil.throwErrorIfNeed(e);
            if (isLaunchPlugin) {
                NotifyCenter.notifyStartPluginError(activity);
            }
            activity.finish();
        }
    }
复制代码
@Override
    public void callActivityOnDestroy(Activity activity) {
        mHostInstr.callActivityOnDestroy(activity);
        if (activity.getParent() != null) {
            return;
        }

        final Intent intent = activity.getIntent();
        String pkgName = IntentUtils.parsePkgNameFromActivity(activity);
        if (IntentUtils.isIntentForPlugin(intent)
                || intent == null) {
            // intent为null时,如果能够从Activity中解析出pkgName,也应该是插件的页面
            if (!TextUtils.isEmpty(pkgName)) {
                PluginDebugLog.runtimeLog(TAG, "callActivityOnDestroy: " + pkgName);
                PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(pkgName);
                if (loadedApk != null) {
                //退出插件的Activity栈
                    loadedApk.getActivityStackSupervisor().popActivityFromStack(activity);
                }
            }
        }
    }
复制代码
@Override
    public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
        if (activity instanceof TransRecoveryActivity0) {
            mRecoveryHelper.saveSavedInstanceState(activity, savedInstanceState);
            return;
        }
        if (IntentUtils.isIntentForPlugin(activity.getIntent())) {
            String pkgName = IntentUtils.parsePkgAndClsFromIntent(activity.getIntent())[0];
            PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(pkgName);
            if (loadedApk != null && savedInstanceState != null) {
            //用插件的ClassLoader恢复数据
                savedInstanceState.setClassLoader(loadedApk.getPluginClassLoader());
            }
        }
        mHostInstr.callActivityOnRestoreInstanceState(activity, savedInstanceState);
    }
复制代码

插件Activity任务栈

/**
 * 插件的Activity栈抽象, 和系统的{@link com.android.server.am.ActivityStack}类似
 */
public class PActivityStack {
    private final LinkedList<Activity> mActivities;
    // taskAffinity
    private String taskName;

    PActivityStack(String taskName) {
        this.taskName = taskName;
        mActivities = new LinkedList<>();
    }

    /**
     * 获取当前任务栈的名称
     */
    public String getTaskName() {
        return taskName;
    }

    public LinkedList<Activity> getActivities() {
        return mActivities;
    }

    public int size() {
        return mActivities.size();
    }

    public synchronized boolean isEmpty() {
        return mActivities.isEmpty();
    }

    // 放入链表的前面
    public synchronized void push(Activity activity) {
        mActivities.addFirst(activity);
    }

    public synchronized void insertFirst(Activity activity) {
        mActivities.addLast(activity);
    }

    public synchronized boolean pop(Activity activity) {
        return mActivities.remove(activity);
    }

    public synchronized Activity getTop() {
        return mActivities.getFirst();
    }

    /**
     * 清空当前任务栈里的Activity
     */
    public void clear(boolean needFinish) {
        Iterator<Activity> iterator = mActivities.iterator();
        while (iterator.hasNext()) {
            Activity activity = iterator.next();
            if (activity != null && needFinish
                    && !FileUtils.isFinished(activity)) {
                activity.finish();
            }
            iterator.remove();
        }
    }
}
复制代码

PActivityStackSupervisor 管理Activity任务栈

/**
     * 处理Activity的launchMode,给Intent添加相关的Flags
     */
    public void dealLaunchMode(Intent intent) {
        if (null == intent) {
            return;
        }

        String targetActivity = IntentUtils.getTargetClass(intent);
        if (TextUtils.isEmpty(targetActivity)) {
            return;
        }

        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode target activity: " + intent + " source: "
                + targetActivity);
        // 不支持LAUNCH_SINGLE_INSTANCE
        ActivityInfo info = mLoadedApk.getPluginPackageInfo().getActivityInfo(targetActivity);
        if (info == null || info.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
            return;
        }
        boolean isSingleTop = info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                || (intent.getFlags() & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0;
        boolean isSingleTask = info.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
        boolean isClearTop = (intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0;
        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode isSingleTop " + isSingleTop + " isSingleTask "
                + isSingleTask + " isClearTop " + isClearTop);
        int flag = intent.getFlags();
        PluginDebugLog.runtimeLog(TAG, "before flag: " + Integer.toHexString(intent.getFlags()));
        if ((isSingleTop || isSingleTask) && (flag & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {
            flag = flag ^ Intent.FLAG_ACTIVITY_SINGLE_TOP;
        }
        if ((isSingleTask || isClearTop) && (flag & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
            flag = flag ^ Intent.FLAG_ACTIVITY_CLEAR_TOP;
        }
        intent.setFlags(flag);
        PluginDebugLog.runtimeLog(TAG, "after flag: " + Integer.toHexString(intent.getFlags()));

        if (isSingleTop && !isClearTop) {
            // 判断栈顶是否为需要启动的Activity, 只需要处理前台栈
            Activity activity = null;
            if (!mFocusedStack.isEmpty()) {
                activity = mFocusedStack.getTop();
            }
            boolean hasSameActivity = false;
            String proxyClsName = ComponentFinder.findActivityProxy(mLoadedApk, info);
            if (activity != null) {
                // 栈内有实例, 可能是ProxyActivity,也可能是插件真实的Activity
                //Fix: 新的实现中只有插件真实的Activity
                if (TextUtils.equals(proxyClsName, activity.getClass().getName())
                        || TextUtils.equals(targetActivity, activity.getClass().getName())) {
                    String key = getActivityStackKey(activity);

                    if (!TextUtils.isEmpty(key) && TextUtils.equals(targetActivity, key)) {
                        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        hasSameActivity = true;
                    }
                }
            }
            if (hasSameActivity) {
                handleOtherPluginActivityStack(activity, mFocusedStack);
            }
        } else if (isSingleTask || isClearTop) {

            PActivityStack targetStack; // 需要搜索的任务栈
            boolean fromBackStack = false;
            if (isClearTop) {
                targetStack = mFocusedStack;
            } else {
                // singleTask
                if (mLastFocusedStack != null
                        && TextUtils.equals(mLastFocusedStack.getTaskName(), matchTaskName(info.taskAffinity))) {
                    // 后台栈和Activity的taskAffinity匹配
                    targetStack = mLastFocusedStack;
                    fromBackStack = true;
                    PluginDebugLog.runtimeLog(TAG, "dealLaunchMode search in background stack: " + info.taskAffinity);
                } else {
                    // 前台栈中搜索
                    targetStack = mFocusedStack;
                }
            }
            // 查找栈中是否存在已有实例
            Activity found = null;
            // 遍历已经起过的activity
            for (Activity activity : targetStack.getActivities()) {
                String proxyClsName = ComponentFinder.findActivityProxy(mLoadedApk, info);
                if (activity != null) {
                    if (TextUtils.equals(proxyClsName, activity.getClass().getName())
                            || TextUtils.equals(targetActivity, activity.getClass().getName())) {
                        String key = getActivityStackKey(activity);
                        if (!TextUtils.isEmpty(key) && TextUtils.equals(targetActivity, key)) {
                            PluginDebugLog.runtimeLog(TAG, "dealLaunchMode found:" + IntentUtils.dump(activity));
                            found = activity;
                            break;
                        }
                    }
                }
            }

            // 栈中已经有当前activity
            if (found != null) {
                // 处理其他插件的逻辑
                // 在以这两种SingleTask, ClearTop flag启动情况下,在同一个栈的情况下
                handleOtherPluginActivityStack(found, targetStack);

                // 处理当前插件的Activity
                List<Activity> popActivities = new ArrayList<Activity>(5);
                for (Activity activity : targetStack.getActivities()) {
                    if (activity == found) {
                        if (isSingleTask || isSingleTop) {
                            PluginDebugLog.runtimeLog(TAG, "dealLaunchMode add single top flag!");
                            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        }
                        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode add clear top flag!");
                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        break;
                    }
                    popActivities.add(activity);
                }

                for (Activity act : popActivities) {
                    PluginDebugLog.runtimeLog(TAG, "dealLaunchMode popActivities finish " + IntentUtils.dump(act));
                    popActivityFromStack(act);
                    if (!FileUtils.isFinished(act)) {
                        act.finish();
                    }
                }

                // 如果Activity是在后台堆栈中找到的,需要合并前后台栈
                if (fromBackStack) {
                    // https://developer.android.com/guide/components/activities/tasks-and-back-stack
                    // 把返回栈中的Activity全部推到前台
                    PActivityStack sysForeStack = findAssociatedStack(mFocusedStack);
                    PActivityStack sysBackStack = findAssociatedStack(mLastFocusedStack);
                    mergeActivityStack(sysBackStack, sysForeStack);
                    // 处理插件自身的栈
                    mergeActivityStack(mLastFocusedStack, mFocusedStack);
                    // 切换前后台堆栈
                    switchToBackStack(mFocusedStack, mLastFocusedStack);
                }

                mLoadedApk.quitApp(false);
            } else {
                // 堆栈里没有找到,遍历还未启动cache中的activity记录
                LinkedBlockingQueue<Intent> records = sIntentCacheMap
                        .get(mLoadedApk.getPluginPackageName());
                if (null != records) {
                    Iterator<Intent> recordIterator = records.iterator();
                    String notLaunchTargetClassName = null;
                    while (recordIterator.hasNext()) {
                        Intent record = recordIterator.next();
                        if (null != record) {
                            if (null != record.getComponent()) {
                                notLaunchTargetClassName = record.getComponent().getClassName();
                            }
                            if (TextUtils.equals(notLaunchTargetClassName, targetActivity)) {
                                PluginDebugLog.runtimeLog(TAG, "sIntentCacheMap found: " + targetActivity);
                                if (isSingleTask || isSingleTop) {
                                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                                }
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                break;
                            }
                        }
                    }
                }
                // 遍历启动过程中的activity记录
                List<Intent> loadingIntents = sIntentLoadingMap.get(mLoadedApk.getPluginPackageName());
                if (null != loadingIntents) {
                    Iterator<Intent> loadingRecordIterator = loadingIntents.iterator();
                    String notLaunchTargetClassName = null;
                    while (loadingRecordIterator.hasNext()) {
                        Intent record = loadingRecordIterator.next();
                        if (null != record) {
                            notLaunchTargetClassName = IntentUtils.getTargetClass(record);
                            if (TextUtils.equals(notLaunchTargetClassName, targetActivity)) {
                                PluginDebugLog.runtimeLog(TAG,
                                        "sIntentLoadingMap found: " + targetActivity);
                                if (isSingleTask || isSingleTop) {
                                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                                }
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                break;
                            }
                        }
                    }
                }

                if (isSingleTask) {
                    // 是否需要放到单独的任务栈
                    String taskName = matchTaskName(info.taskAffinity);
                    if (!TextUtils.equals(mFocusedStack.getTaskName(), taskName)) {
                        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode push activity into separated stack: " + taskName);
                        PActivityStack stack = mActivityStacks.get(taskName);
                        if (stack == null) {
                            // 创建一个新的任务栈
                            stack = new PActivityStack(taskName);
                            mActivityStacks.put(taskName, stack);
                        }
                        // 切换前后台栈
                        switchToBackStack(mFocusedStack, stack);
                    } else {
                        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode push activity into current stack: " + taskName);
                    }
                }
            }
        }
        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode end: " + intent + " "
                + targetActivity);
    }
复制代码

处理插件中的广播

/**
     * 动态注册插件中的静态Receiver
     */
    private void installStaticReceiver() {
        if (mPluginPackageInfo == null || mHostContext == null) {
            return;
        }
        Map<String, PluginPackageInfo.ReceiverIntentInfo> mReceiverIntentInfos =
                mPluginPackageInfo.getReceiverIntentInfos();
        if (mReceiverIntentInfos != null) {
            Set<Map.Entry<String, PluginPackageInfo.ReceiverIntentInfo>> mEntrys =
                    mReceiverIntentInfos.entrySet();
            Context mGlobalContext = mHostContext.getApplicationContext();
            for (Map.Entry<String, PluginPackageInfo.ReceiverIntentInfo> mEntry : mEntrys) {
                PluginPackageInfo.ReceiverIntentInfo mReceiverInfo = mEntry.getValue();
                if (mReceiverInfo != null) {
                    try {
                        BroadcastReceiver mReceiver =
                                BroadcastReceiver.class.cast(mPluginClassLoader.
                                        loadClass(mReceiverInfo.mInfo.name).newInstance());
                        List<IntentFilter> mFilters = mReceiverInfo.mFilter;
                        if (mFilters != null) {
                            for (IntentFilter mItem : mFilters) {
                                mGlobalContext.registerReceiver(mReceiver, mItem);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
复制代码

处理插件中的Service

PluginContextWrapper 类中完成了startService等方法的代理

@Override
    public ComponentName startService(Intent service) {
        PluginDebugLog.log(TAG, "startService: " + service);
        PluginLoadedApk mLoadedApk = getPluginLoadedApk();
        if (mLoadedApk != null) {
            ComponentFinder.switchToServiceProxy(mLoadedApk, service);
        }
        return super.startService(service);
    }

    @Override
    public boolean stopService(Intent name) {
        PluginDebugLog.log(TAG, "stopService: " + name);
        PluginLoadedApk mLoadedApk = getPluginLoadedApk();
        if (mLoadedApk != null) {
            String actServiceClsName = "";
            if (name.getComponent() != null) {
                actServiceClsName = name.getComponent().getClassName();
            } else {
                ServiceInfo mServiceInfo = getPluginPackageInfo().resolveService(name);
                if (mServiceInfo != null) {
                    actServiceClsName = mServiceInfo.name;
                }
            }

            PluginServiceWrapper plugin = PServiceSupervisor
                    .getServiceByIdentifer(PluginServiceWrapper.getIdentify(getPluginPackageName(), actServiceClsName));
            if (plugin != null) {
                plugin.updateServiceState(PluginServiceWrapper.PLUGIN_SERVICE_STOPED);
                plugin.tryToDestroyService();
                return true;
            }
        }
        return super.stopService(name);
    }

    @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        PluginDebugLog.log(TAG, "bindService: " + service);
        PluginLoadedApk mLoadedApk = getPluginLoadedApk();
        if (mLoadedApk != null) {
            ComponentFinder.switchToServiceProxy(mLoadedApk, service);
        }
        if (conn != null) {
            if (mLoadedApk != null && service != null) {
                String serviceClass = IntentUtils.getTargetClass(service);
                String packageName = mLoadedApk.getPluginPackageName();
                if (!TextUtils.isEmpty(serviceClass) && !TextUtils.isEmpty(packageName)) {
                    PServiceSupervisor.addServiceConnectionByIdentifer(packageName + "." + serviceClass, conn);
                }
            }
        }
        return super.bindService(service, conn, flags);
    }

    @Override
    public void unbindService(ServiceConnection conn) {
        super.unbindService(conn);
        PServiceSupervisor.removeServiceConnection(conn);
        PluginDebugLog.log(TAG, "unbindService: " + conn);
    }
复制代码

总结

Neptune 框架注释比较清晰。但是由于 Neptune 框架代码存在两套对Activity插件化的方案实现(版本迭代,一套老的,一套新的),】,导致代码逻辑不是很统一。在阅读代码的时候,把握住Hook思路,只看相关的代码,还是比较容易理解的。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Analytics 2.0

Web Analytics 2.0

Avinash Kaushik / Sybex / 2009-10-26 / USD 39.99

The bestselling book Web Analytics: An Hour A Day was the first book in the analytics space to move beyond clickstream analysis. Web Analytics 2.0 will significantly evolve the approaches from the fir......一起来看看 《Web Analytics 2.0》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试