当前位置:   article > 正文

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

android 插件化架构图

前言

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

插件化基础知识点

插件应用安装

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

  1. public class PluginLoadedApk {
  2. public static final ConcurrentMap<String, Vector<Method>> sMethods = new ConcurrentHashMap<String, Vector<Method>>(1);
  3. private static final String TAG = "PluginLoadedApk";
  4. /* 保存注入到宿主ClassLoader的插件 */
  5. private static Set<String> sInjectedPlugins = Collections.synchronizedSet(new HashSet<String>());
  6. /* 保存所有的插件ClassLoader */
  7. private static Map<String, DexClassLoader> sAllPluginClassLoader = new ConcurrentHashMap<>();
  8. /* 宿主的Context */
  9. private final Context mHostContext;
  10. /* 宿主的ClassLoader */
  11. private final ClassLoader mHostClassLoader;
  12. /* 宿主的Resource对象 */
  13. private final Resources mHostResource;
  14. /* 宿主的包名 */
  15. private final String mHostPackageName;
  16. /* 插件的路径 */
  17. private final String mPluginPath;
  18. /* 插件运行的进程名 */
  19. private final String mProcessName;
  20. /* 插件ClassLoader的parent */
  21. private ClassLoader mParent;
  22. /* 插件的类加载器 */
  23. private DexClassLoader mPluginClassLoader;
  24. /* 插件的Resource对象 */
  25. private Resources mPluginResource;
  26. /* 插件的AssetManager对象 */
  27. private AssetManager mPluginAssetManager;
  28. /* 插件的全局默认主题 */
  29. private Resources.Theme mPluginTheme;
  30. /* 插件的详细信息,主要通过解析AndroidManifest.xml获得 */
  31. private PluginPackageInfo mPluginPackageInfo;
  32. /* 插件工程的包名 */
  33. private String mPluginPackageName;
  34. /* 插件的Application */
  35. private Application mPluginApplication;
  36. /* 自定义插件Context,主要用来改写其中的一些方法从而改变插件行为 */
  37. private PluginContextWrapper mPluginAppContext;
  38. /* 自定义Instrumentation,对Activity跳转进行拦截 */
  39. private PluginInstrument mPluginInstrument;
  40. ...
  41. }
  42. 复制代码

插件的安装分为内置插件(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,优化加载速度

类加载

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实现插件资源的加载。

  1. try{
  2. AssetManager am = AssetManager.class.newInstance();
  3. Method addAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
  4. addAssetPath.setAccessible(true);
  5. addAssetPath.invoke(am, pluginApkPath);
  6. Resources pluginResources = new Resources(am, hostResource.getDisplayMetrics(), hostResources.getConfiguration());
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. 复制代码

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

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

插件化中资源使用限制

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

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

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

Apk打包流程

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

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

  • 插件的资源和宿主的资源通过不同的资源分段区分
  • 在插件化中,如果插件需要引用宿主的资源,则需要将宿主的资源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 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 P(api 28)对Activity的启动过程做了修改;在Android P之前,是在H类的handleMessage方法的switch分支语句中,有专门处理启动Activity的逻辑

  1. public void handleMessage(Message msg) {
  2. switch (msg.what) {
  3. case LAUNCH_ACTIVITY: {
  4. final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
  5. r.packageInfo = getPackageInfoNoCheck(
  6. r.activityInfo.applicationInfo, r.compatInfo);
  7. handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
  8. } break;
  9. //以下省略很多代码
  10. }
  11. }
  12. 复制代码

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

  1. public class LaunchActivityItem extends ClientTransactionItem {
  2. @Override
  3. public void execute(ClientTransactionHandler client, IBinder token,
  4. PendingTransactionActions pendingActions) {
  5. ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
  6. mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
  7. mPendingResults, mPendingNewIntents, mIsForward,
  8. mProfilerInfo, client);
  9. client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
  10. }
  11. }
  12. 复制代码

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 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启动

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

BroadCastReceiver插件化

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

Hook点:
  • 静态广播转换为动态广播

ContentProvider插件化

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

Neptune源码分析

Neptune类

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

  • init()方法
  1. /**
  2. * 初始化Neptune插件环境
  3. *
  4. * @param application 宿主的Appliction
  5. * @param config 配置信息
  6. */
  7. public static void init(Application application, NeptuneConfig config) {
  8. sHostContext = application;
  9. sGlobalConfig = config != null ? config
  10. : new NeptuneConfig.NeptuneConfigBuilder().build();
  11. PluginDebugLog.setIsDebug(sGlobalConfig.isDebug());
  12. boolean hookInstr = VersionUtils.hasPie() || sGlobalConfig.getSdkMode() != NeptuneConfig.LEGACY_MODE;
  13. if (hookInstr) {
  14. //Hook Instrumentation
  15. hookInstrumentation();
  16. }
  17. // 调用getInstance()方法会初始化bindService,管理插件安装的Service
  18. PluginPackageManagerNative.getInstance(sHostContext).setPackageInfoManager(sGlobalConfig.getPluginInfoProvider());
  19. // 注册插件卸载监听广播
  20. PluginManager.registerUninstallReceiver(sHostContext);
  21. }
  22. 复制代码
  • launchPlugin()方法
  1. /**
  2. * 启动插件
  3. *
  4. * @param mHostContext 主工程的上下文
  5. * @param mIntent 需要启动的组件的Intent
  6. * @param mServiceConnection bindService时需要的ServiceConnection,如果不是bindService的方式启动组件,传入Null
  7. * @param mProcessName 需要启动的插件运行的进程名称,插件方可以在Application的android:process指定
  8. * 如果没有指定,则有插件中心分配
  9. */
  10. public static void launchPlugin(final Context mHostContext,
  11. final Intent mIntent,
  12. final ServiceConnection mServiceConnection,
  13. final String mProcessName) {
  14. final String packageName = tryParsePkgName(mHostContext, mIntent);
  15. if (TextUtils.isEmpty(packageName)) {
  16. if (null != mHostContext) {
  17. deliver(mHostContext, false, mHostContext.getPackageName(), ErrorType.ERROR_PLUGIN_LOAD_NO_PKGNAME_INTENT);
  18. }
  19. PluginDebugLog.runtimeLog(TAG, "enterProxy packageName is null return! packageName: " + packageName);
  20. return;
  21. }
  22. // 处理不同进程跳转
  23. final String targetProcessName = TextUtils.isEmpty(mProcessName) ?
  24. ProcessManager.chooseDefaultProcess(mHostContext, packageName) : mProcessName;
  25. String currentProcess = FileUtils.getCurrentProcessName(mHostContext);
  26. if (!TextUtils.equals(currentProcess, targetProcessName)) {
  27. // 启动进程和目标进程不一致,需要先启动目标进程,初始化PluginLoadedApk
  28. Intent transIntent = new Intent();
  29. transIntent.setAction(IntentConstant.ACTION_START_PLUGIN);
  30. //目标进程的Service中重新通过mIntent启动插件
  31. transIntent.putExtra(IntentConstant.EXTRA_START_INTENT_KEY, mIntent);
  32. transIntent.putExtra(IntentConstant.EXTRA_TARGET_PROCESS, targetProcessName);
  33. try {
  34. String proxyServiceName = ComponentFinder.matchServiceProxyByFeature(targetProcessName);
  35. transIntent.setClass(mHostContext, Class.forName(proxyServiceName));
  36. mHostContext.startService(transIntent);
  37. } catch (ClassNotFoundException e) {
  38. e.printStackTrace();
  39. }
  40. return;
  41. }
  42. LinkedBlockingQueue<Intent> cacheIntents = PActivityStackSupervisor.getCachedIntent(packageName);
  43. //该插件有其他任务排队中,mIntent添加到队尾
  44. if (cacheIntents != null && cacheIntents.size() > 0) {
  45. cacheIntents.add(mIntent);
  46. PluginDebugLog.runtimeLog(TAG, "LoadingMap is not empty, Cache current intent, intent: " + mIntent + ", packageName: " + packageName);
  47. return;
  48. }
  49. boolean isLoadAndInit = isPluginLoadedAndInit(packageName);
  50. if (!isLoadAndInit) {
  51. if (null == cacheIntents) {
  52. cacheIntents = new LinkedBlockingQueue<Intent>();
  53. PActivityStackSupervisor.addCachedIntent(packageName, cacheIntents);
  54. }
  55. // 缓存这个intent,等待PluginLoadedApk加载到内存之后再启动这个Intent
  56. PluginDebugLog.runtimeLog(TAG, "Environment is initializing and loading, cache current intent first, intent: " + mIntent);
  57. cacheIntents.add(mIntent);
  58. } else {
  59. PluginDebugLog.runtimeLog(TAG, "Environment is already ready, launch current intent directly: " + mIntent);
  60. //可以直接启动组件
  61. readyToStartSpecifyPlugin(mHostContext, mServiceConnection, mIntent, true);
  62. return;
  63. }
  64. // 处理插件的依赖关系
  65. final PluginLiteInfo info = PluginPackageManagerNative.getInstance(mHostContext.getApplicationContext())
  66. .getPackageInfo(packageName);
  67. //获取插件的依赖关系
  68. final List<String> mPluginRefs = PluginPackageManagerNative.getInstance(mHostContext)
  69. .getPluginRefs(packageName);
  70. if (info != null && mPluginRefs != null
  71. && mPluginRefs.size() > 0) {
  72. PluginDebugLog.runtimeLog(TAG,
  73. "start to check dependence installation size: " + mPluginRefs.size());
  74. //依赖的总数量
  75. final AtomicInteger count = new AtomicInteger(mPluginRefs.size());
  76. for (String pkgName : mPluginRefs) {
  77. PluginDebugLog.runtimeLog(TAG, "start to check installation pkgName: " + pkgName);
  78. final PluginLiteInfo refInfo = PluginPackageManagerNative.getInstance(mHostContext.getApplicationContext())
  79. .getPackageInfo(pkgName);
  80. PluginPackageManagerNative.getInstance(mHostContext.getApplicationContext()).packageAction(refInfo,
  81. new IInstallCallBack.Stub() {
  82. @Override
  83. public void onPackageInstalled(PluginLiteInfo packageInfo) {
  84. //未ready的依赖数量
  85. count.getAndDecrement();
  86. PluginDebugLog.runtimeLog(TAG, "check installation success pkgName: " + refInfo.packageName);
  87. if (count.get() == 0) {
  88. PluginDebugLog.runtimeLog(TAG,
  89. "start Check installation after check dependence packageName: "
  90. + packageName);
  91. //真正加载插件
  92. checkPkgInstallationAndLaunch(mHostContext, info, mServiceConnection, mIntent, targetProcessName);
  93. }
  94. }
  95. @Override
  96. public void onPackageInstallFail(PluginLiteInfo info, int failReason) throws RemoteException {
  97. PluginDebugLog.runtimeLog(TAG,
  98. "check installation failed pkgName: " + info.packageName + " failReason: " + failReason);
  99. count.set(-1);
  100. }
  101. });
  102. }
  103. } else if (info != null) {
  104. PluginDebugLog.runtimeLog(TAG, "start Check installation without dependence packageName: " + packageName);
  105. //真正加载插件
  106. checkPkgInstallationAndLaunch(mHostContext, info, mServiceConnection, mIntent, targetProcessName);
  107. } else {
  108. //异常case
  109. PluginDebugLog.runtimeLog(TAG, "pluginLiteInfo is null packageName: " + packageName);
  110. PActivityStackSupervisor.clearLoadingIntent(packageName);
  111. if (PluginDebugLog.isDebug()) {
  112. throw new IllegalStateException("pluginLiteInfo is null when launchPlugin " + packageName);
  113. }
  114. }
  115. }
  116. 复制代码
  1. /**
  2. * 真正启动一个组件
  3. *
  4. * @param mHostContext 主工程Context
  5. * @param mLoadedApk 需要启动的插件的PluginLoadedApk
  6. * @param mIntent 需要启动组件的Intent
  7. * @param mConnection bindService时需要的ServiceConnection,如果不是bindService的方式启动组件,传入Null
  8. */
  9. private static void doRealLaunch(Context mHostContext,
  10. PluginLoadedApk mLoadedApk,
  11. Intent mIntent,
  12. ServiceConnection mConnection) {
  13. String targetClassName = "";
  14. ComponentName mComponent = mIntent.getComponent();
  15. if (mComponent != null) {
  16. //显式启动
  17. targetClassName = mComponent.getClassName();
  18. PluginDebugLog.runtimeLog(TAG, "launchIntent_targetClassName:" + targetClassName);
  19. if (TextUtils.isEmpty(targetClassName)) {
  20. targetClassName = mLoadedApk.getPluginPackageInfo().getDefaultActivityName();
  21. }
  22. }
  23. String pkgName = mLoadedApk.getPluginPackageName();
  24. Class<?> targetClass = null;
  25. if (!TextUtils.isEmpty(targetClassName)
  26. && !TextUtils.equals(targetClassName, IntentConstant.EXTRA_VALUE_LOADTARGET_STUB)) {
  27. try {
  28. //插件ClassLoader加载类
  29. targetClass = mLoadedApk.getPluginClassLoader().loadClass(targetClassName);
  30. } catch (Exception e) {
  31. deliver(mHostContext, false,
  32. pkgName, ErrorType.ERROR_PLUGIN_LOAD_COMP_CLASS);
  33. PluginDebugLog.runtimeLog(TAG, "launchIntent loadClass failed for targetClassName: "
  34. + targetClassName);
  35. executeNext(mLoadedApk, mConnection, mHostContext);
  36. return;
  37. }
  38. }
  39. String action = mIntent.getAction();
  40. if (TextUtils.equals(action, IntentConstant.ACTION_PLUGIN_INIT)
  41. || TextUtils.equals(targetClassName, IntentConstant.EXTRA_VALUE_LOADTARGET_STUB)) {
  42. PluginDebugLog.runtimeLog(TAG, "launchIntent load target stub!");
  43. //通知插件初始化完毕
  44. if (targetClass != null && BroadcastReceiver.class.isAssignableFrom(targetClass)) {
  45. Intent newIntent = new Intent(mIntent);
  46. newIntent.setComponent(null);
  47. newIntent.putExtra(IntentConstant.EXTRA_TARGET_PACKAGE_KEY, pkgName);
  48. newIntent.setPackage(mHostContext.getPackageName());
  49. //通过广播通知插件加载完成
  50. mHostContext.sendBroadcast(newIntent);
  51. }
  52. // 表示后台加载,不需要处理该Intent
  53. executeNext(mLoadedApk, mConnection, mHostContext);
  54. return;
  55. }
  56. mLoadedApk.changeLaunchingIntentStatus(true);
  57. PluginDebugLog.runtimeLog(TAG, "launchIntent_targetClass: " + targetClass);
  58. if (targetClass != null && Service.class.isAssignableFrom(targetClass)) {
  59. //处理的是Service, 宿主启动插件Service只能通过显式启动
  60. ComponentFinder.switchToServiceProxy(mLoadedApk, mIntent, targetClassName);
  61. if (mConnection == null) {
  62. mHostContext.startService(mIntent);
  63. } else {
  64. mHostContext.bindService(mIntent, mConnection,
  65. mIntent.getIntExtra(IntentConstant.BIND_SERVICE_FLAGS, Context.BIND_AUTO_CREATE));
  66. }
  67. } else {
  68. //处理的是Activity
  69. ComponentFinder.switchToActivityProxy(pkgName,
  70. mIntent, -1, mHostContext);
  71. PActivityStackSupervisor.addLoadingIntent(pkgName, mIntent);
  72. Context lastActivity = null;
  73. PActivityStackSupervisor mActivityStackSupervisor =
  74. mLoadedApk.getActivityStackSupervisor();
  75. lastActivity = mActivityStackSupervisor.getAvailableActivity();
  76. if (mHostContext instanceof Activity) {
  77. mHostContext.startActivity(mIntent);
  78. } else if (lastActivity != null) {
  79. // Clear the Intent.FLAG_ACTIVITY_NEW_TASK
  80. int flag = mIntent.getFlags();
  81. flag = flag ^ Intent.FLAG_ACTIVITY_NEW_TASK;
  82. mIntent.setFlags(flag);
  83. lastActivity.startActivity(mIntent);
  84. } else {
  85. // Add the Intent.FLAG_ACTIVITY_NEW_TASK
  86. mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  87. mHostContext.startActivity(mIntent);
  88. }
  89. }
  90. // 执行下一个Intent
  91. executeNext(mLoadedApk, mConnection, mHostContext);
  92. }
  93. 复制代码
  1. /**
  2. * 异步初始化插件,宿主静默加载插件
  3. *
  4. * @deprecated 不建议使用
  5. */
  6. @Deprecated
  7. public static void initPluginAsync(final Context mHostContext,
  8. final String packageName,
  9. final String processName,
  10. final org.qiyi.pluginlibrary.listenter.IPluginStatusListener mListener) {
  11. // 插件已经加载
  12. if (PluginManager.isPluginLoadedAndInit(packageName)) {
  13. if (mListener != null) {
  14. mListener.onInitFinished(packageName);
  15. }
  16. return;
  17. }
  18. BroadcastReceiver recv = new BroadcastReceiver() {
  19. public void onReceive(Context ctx, Intent intent) {
  20. String curPkg = IntentUtils.getTargetPackage(intent);
  21. if (IntentConstant.ACTION_PLUGIN_INIT.equals(intent.getAction()) && TextUtils.equals(packageName, curPkg)) {
  22. PluginDebugLog.runtimeLog(TAG, "收到自定义的广播org.qiyi.pluginapp.action.TARGET_LOADED");
  23. //插件初始化结束
  24. if (mListener != null) {
  25. mListener.onInitFinished(packageName);
  26. }
  27. mHostContext.getApplicationContext().unregisterReceiver(this);
  28. }
  29. }
  30. };
  31. PluginDebugLog.runtimeLog(TAG, "注册自定义广播org.qiyi.pluginapp.action.TARGET_LOADED");
  32. IntentFilter filter = new IntentFilter();
  33. filter.addAction(IntentConstant.ACTION_PLUGIN_INIT);
  34. //注册广播
  35. mHostContext.getApplicationContext().registerReceiver(recv, filter);
  36. Intent intent = new Intent();
  37. intent.setAction(IntentConstant.ACTION_PLUGIN_INIT);
  38. intent.setComponent(new ComponentName(packageName, recv.getClass().getName()));
  39. //发送一个启动插件的intent
  40. launchPlugin(mHostContext, intent, processName);
  41. }
  42. 复制代码

NeptuneInstrument(PluginInstrument)类

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

  1. /**
  2. * 负责转移插件的跳转目标<br>
  3. * 用于Hook插件Activity中Instrumentation
  4. *
  5. * @see android.app.Activity#startActivity(android.content.Intent)
  6. */
  7. public class PluginInstrument extends Instrumentation {
  8. private static final String TAG = "PluginInstrument";
  9. private static ConcurrentMap<String, Vector<Method>> sMethods = new ConcurrentHashMap<String, Vector<Method>>(5);
  10. Instrumentation mHostInstr;
  11. private String mPkgName;
  12. private ReflectionUtils mInstrumentRef;
  13. /**
  14. * 插件的Instrumentation
  15. */
  16. public PluginInstrument(Instrumentation hostInstr) {
  17. this(hostInstr, "");
  18. }
  19. public PluginInstrument(Instrumentation hostInstr, String pkgName) {
  20. mHostInstr = hostInstr;
  21. mInstrumentRef = ReflectionUtils.on(hostInstr);
  22. mPkgName = pkgName;
  23. }
  24. /**
  25. * 如果是PluginInstrumentation,拆装出原始的HostInstr
  26. *
  27. * @param instrumentation
  28. * @return
  29. */
  30. public static Instrumentation unwrap(Instrumentation instrumentation) {
  31. if (instrumentation instanceof PluginInstrument) {
  32. return ((PluginInstrument) instrumentation).mHostInstr;
  33. }
  34. return instrumentation;
  35. }
  36. /**
  37. * @Override
  38. */
  39. public ActivityResult execStartActivity(
  40. Context who, IBinder contextThread, IBinder token, Activity target,
  41. Intent intent, int requestCode, Bundle options) {
  42. ...
  43. }
  44. /**
  45. * @Override
  46. */
  47. public ActivityResult execStartActivity(
  48. Context who, IBinder contextThread, IBinder token, Activity target,
  49. Intent intent, int requestCode) {
  50. ...
  51. }
  52. /**
  53. * @Override For below android 6.0
  54. */
  55. public ActivityResult execStartActivityAsCaller(
  56. Context who, IBinder contextThread, IBinder token, Activity target,
  57. Intent intent, int requestCode, Bundle options, int userId) {
  58. ...
  59. }
  60. /**
  61. * @Override For android 6.0
  62. */
  63. public ActivityResult execStartActivityAsCaller(
  64. Context who, IBinder contextThread, IBinder token, Activity target,
  65. Intent intent, int requestCode, Bundle options,
  66. boolean ignoreTargetSecurity, int userId) {
  67. ...
  68. }
  69. /**
  70. * @Override
  71. */
  72. public void execStartActivitiesAsUser(
  73. Context who, IBinder contextThread, IBinder token, Activity target,
  74. Intent[] intents, Bundle options, int userId) {
  75. ...
  76. }
  77. /**
  78. * @Override For below android 6.0, start activity from Fragment
  79. */
  80. public ActivityResult execStartActivity(
  81. Context who, IBinder contextThread, IBinder token, Fragment target,
  82. Intent intent, int requestCode, Bundle options) {
  83. ...
  84. }
  85. /**
  86. * @Override For android 6.0, start activity from Fragment
  87. */
  88. public ActivityResult execStartActivity(
  89. Context who, IBinder contextThread, IBinder token, String target,
  90. Intent intent, int requestCode, Bundle options) {
  91. ...
  92. }
  93. }
  94. 复制代码
  1. /**
  2. * 自定义的全局的Instrumentation
  3. * 负责转移插件的跳转目标和创建插件的Activity实例
  4. * 用于Hook ActivityThread中的全局Instrumentation
  5. */
  6. public class NeptuneInstrument extends PluginInstrument {
  7. private static final String TAG = "NeptuneInstrument";
  8. private PluginActivityRecoveryHelper mRecoveryHelper = new PluginActivityRecoveryHelper();
  9. public NeptuneInstrument(Instrumentation hostInstr) {
  10. super(hostInstr);
  11. }
  12. @Override
  13. public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  14. ...
  15. }
  16. @Override
  17. public void callActivityOnCreate(Activity activity, Bundle icicle) {
  18. ...
  19. }
  20. @Override
  21. public void callActivityOnDestroy(Activity activity) {
  22. ...
  23. }
  24. @Override
  25. public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
  26. ...
  27. }
  28. /**
  29. * 将Activity反射相关操作分发给插件Activity的基类
  30. */
  31. private boolean dispatchToBaseActivity(Activity activity) {
  32. //这个模式已弃用
  33. return Neptune.getConfig().getSdkMode() == NeptuneConfig.INSTRUMENTATION_BASEACT_MODE
  34. && activity instanceof IPluginBase;
  35. }
  36. }
  37. 复制代码

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

  1. @Override
  2. public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  3. if (className.startsWith(ComponentFinder.DEFAULT_ACTIVITY_PROXY_PREFIX)) {
  4. // 插件代理Activity,替换回插件真实的Activity
  5. String[] result = IntentUtils.parsePkgAndClsFromIntent(intent);
  6. String packageName = result[0];
  7. String targetClass = result[1];
  8. PluginDebugLog.runtimeLog(TAG, "newActivity: " + className + ", targetClass: " + targetClass);
  9. if (!TextUtils.isEmpty(packageName)) {
  10. //找到对应插件
  11. PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(packageName);
  12. if (loadedApk != null && targetClass != null) {
  13. Activity activity = mHostInstr.newActivity(loadedApk.getPluginClassLoader(), targetClass, intent);
  14. activity.setIntent(intent);
  15. if (!dispatchToBaseActivity(activity)) {
  16. // 这里需要替换Resources,是因为ContextThemeWrapper会缓存一个Resource对象,而在Activity#attach()和
  17. // Activity#onCreate()之间,系统会调用Activity#setTheme()初始化主题,Android 4.1+
  18. //替换成插件的Resource资源
  19. ReflectionUtils.on(activity).setNoException("mResources", loadedApk.getPluginResource());
  20. }
  21. return activity;
  22. } else if (loadedApk == null) {
  23. // loadedApk 为空,可能是正在恢复进程,跳转到 RecoveryActivity
  24. return mHostInstr.newActivity(cl, mRecoveryHelper.selectRecoveryActivity(className), intent);
  25. }
  26. }
  27. }
  28. return mHostInstr.newActivity(cl, className, intent);
  29. }
  30. 复制代码
  1. @Override
  2. public void callActivityOnCreate(Activity activity, Bundle icicle) {
  3. boolean isRecovery = activity instanceof TransRecoveryActivity0;
  4. if (isRecovery) {
  5. //插件加载中的Activity,使用宿主的Instrument
  6. mRecoveryHelper.saveIcicle(activity, icicle);
  7. mHostInstr.callActivityOnCreate(activity, null);
  8. return;
  9. }
  10. final Intent intent = activity.getIntent();
  11. String[] result = IntentUtils.parsePkgAndClsFromIntent(intent);
  12. boolean isLaunchPlugin = false;
  13. if (IntentUtils.isIntentForPlugin(intent)) {
  14. String packageName = result[0];
  15. String targetClass = result[1];
  16. if (!TextUtils.isEmpty(packageName)) {
  17. PluginDebugLog.runtimeLog(TAG, "callActivityOnCreate: " + packageName);
  18. PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(packageName);
  19. if (loadedApk != null) {
  20. icicle = mRecoveryHelper.recoveryIcicle(activity, icicle);
  21. // 设置 extra 的 ClassLoader,不然可能会出现 BadParcelException, ClassNotFound
  22. if (icicle != null) {
  23. icicle.setClassLoader(loadedApk.getPluginClassLoader());
  24. }
  25. if (!dispatchToBaseActivity(activity)) {
  26. // 如果分发给插件Activity的基类了,就不需要在这里反射hook替换相关成员变量了
  27. try {
  28. ReflectionUtils activityRef = ReflectionUtils.on(activity);
  29. //设置为插件资源
  30. activityRef.setNoException("mResources", loadedApk.getPluginResource());
  31. //设置插件的Application
  32. activityRef.setNoException("mApplication", loadedApk.getPluginApplication());
  33. Context pluginContext = new PluginContextWrapper(activity.getBaseContext(), packageName);
  34. //替换为PluginContextWrapper,处理inflate相关
  35. ReflectionUtils.on(activity, ContextWrapper.class).set("mBase", pluginContext);
  36. // 5.0以下ContextThemeWrapper内会保存一个mBase,也需要反射替换掉
  37. ReflectionUtils.on(activity, ContextThemeWrapper.class).setNoException("mBase", pluginContext);
  38. //替换为插件的Instrumentation
  39. ReflectionUtils.on(activity).setNoException("mInstrumentation", loadedApk.getPluginInstrument());
  40. // 修改插件Activity的ActivityInfo, theme, window等信息
  41. PluginActivityControl.changeActivityInfo(activity, targetClass, loadedApk);
  42. } catch (Exception e) {
  43. PluginDebugLog.runtimeLog(TAG, "callActivityOnCreate with exception: " + e.getMessage());
  44. }
  45. }
  46. if (activity.getParent() == null) {
  47. //Activity栈的逻辑是怎么处理的?
  48. loadedApk.getActivityStackSupervisor().pushActivityToStack(activity);
  49. }
  50. isLaunchPlugin = true;
  51. }
  52. }
  53. IntentUtils.resetAction(intent); //恢复Action
  54. }
  55. try {
  56. mHostInstr.callActivityOnCreate(activity, icicle);
  57. if (isLaunchPlugin) {
  58. NotifyCenter.notifyPluginStarted(activity, intent);
  59. NotifyCenter.notifyPluginActivityLoaded(activity);
  60. }
  61. //check是否需要hook callActivityOnRestoreInstanceState方法
  62. mRecoveryHelper.mockActivityOnRestoreInstanceStateIfNeed(this, activity);
  63. } catch (Exception e) {
  64. ErrorUtil.throwErrorIfNeed(e);
  65. if (isLaunchPlugin) {
  66. NotifyCenter.notifyStartPluginError(activity);
  67. }
  68. activity.finish();
  69. }
  70. }
  71. 复制代码
  1. @Override
  2. public void callActivityOnDestroy(Activity activity) {
  3. mHostInstr.callActivityOnDestroy(activity);
  4. if (activity.getParent() != null) {
  5. return;
  6. }
  7. final Intent intent = activity.getIntent();
  8. String pkgName = IntentUtils.parsePkgNameFromActivity(activity);
  9. if (IntentUtils.isIntentForPlugin(intent)
  10. || intent == null) {
  11. // intent为null时,如果能够从Activity中解析出pkgName,也应该是插件的页面
  12. if (!TextUtils.isEmpty(pkgName)) {
  13. PluginDebugLog.runtimeLog(TAG, "callActivityOnDestroy: " + pkgName);
  14. PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(pkgName);
  15. if (loadedApk != null) {
  16. //退出插件的Activity栈
  17. loadedApk.getActivityStackSupervisor().popActivityFromStack(activity);
  18. }
  19. }
  20. }
  21. }
  22. 复制代码
  1. @Override
  2. public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
  3. if (activity instanceof TransRecoveryActivity0) {
  4. mRecoveryHelper.saveSavedInstanceState(activity, savedInstanceState);
  5. return;
  6. }
  7. if (IntentUtils.isIntentForPlugin(activity.getIntent())) {
  8. String pkgName = IntentUtils.parsePkgAndClsFromIntent(activity.getIntent())[0];
  9. PluginLoadedApk loadedApk = PluginManager.getPluginLoadedApkByPkgName(pkgName);
  10. if (loadedApk != null && savedInstanceState != null) {
  11. //用插件的ClassLoader恢复数据
  12. savedInstanceState.setClassLoader(loadedApk.getPluginClassLoader());
  13. }
  14. }
  15. mHostInstr.callActivityOnRestoreInstanceState(activity, savedInstanceState);
  16. }
  17. 复制代码

插件Activity任务栈

  1. /**
  2. * 插件的Activity栈抽象, 和系统的{@link com.android.server.am.ActivityStack}类似
  3. */
  4. public class PActivityStack {
  5. private final LinkedList<Activity> mActivities;
  6. // taskAffinity
  7. private String taskName;
  8. PActivityStack(String taskName) {
  9. this.taskName = taskName;
  10. mActivities = new LinkedList<>();
  11. }
  12. /**
  13. * 获取当前任务栈的名称
  14. */
  15. public String getTaskName() {
  16. return taskName;
  17. }
  18. public LinkedList<Activity> getActivities() {
  19. return mActivities;
  20. }
  21. public int size() {
  22. return mActivities.size();
  23. }
  24. public synchronized boolean isEmpty() {
  25. return mActivities.isEmpty();
  26. }
  27. // 放入链表的前面
  28. public synchronized void push(Activity activity) {
  29. mActivities.addFirst(activity);
  30. }
  31. public synchronized void insertFirst(Activity activity) {
  32. mActivities.addLast(activity);
  33. }
  34. public synchronized boolean pop(Activity activity) {
  35. return mActivities.remove(activity);
  36. }
  37. public synchronized Activity getTop() {
  38. return mActivities.getFirst();
  39. }
  40. /**
  41. * 清空当前任务栈里的Activity
  42. */
  43. public void clear(boolean needFinish) {
  44. Iterator<Activity> iterator = mActivities.iterator();
  45. while (iterator.hasNext()) {
  46. Activity activity = iterator.next();
  47. if (activity != null && needFinish
  48. && !FileUtils.isFinished(activity)) {
  49. activity.finish();
  50. }
  51. iterator.remove();
  52. }
  53. }
  54. }
  55. 复制代码

PActivityStackSupervisor管理Activity任务栈

  1. /**
  2. * 处理Activity的launchMode,给Intent添加相关的Flags
  3. */
  4. public void dealLaunchMode(Intent intent) {
  5. if (null == intent) {
  6. return;
  7. }
  8. String targetActivity = IntentUtils.getTargetClass(intent);
  9. if (TextUtils.isEmpty(targetActivity)) {
  10. return;
  11. }
  12. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode target activity: " + intent + " source: "
  13. + targetActivity);
  14. // 不支持LAUNCH_SINGLE_INSTANCE
  15. ActivityInfo info = mLoadedApk.getPluginPackageInfo().getActivityInfo(targetActivity);
  16. if (info == null || info.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
  17. return;
  18. }
  19. boolean isSingleTop = info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
  20. || (intent.getFlags() & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0;
  21. boolean isSingleTask = info.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
  22. boolean isClearTop = (intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0;
  23. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode isSingleTop " + isSingleTop + " isSingleTask "
  24. + isSingleTask + " isClearTop " + isClearTop);
  25. int flag = intent.getFlags();
  26. PluginDebugLog.runtimeLog(TAG, "before flag: " + Integer.toHexString(intent.getFlags()));
  27. if ((isSingleTop || isSingleTask) && (flag & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {
  28. flag = flag ^ Intent.FLAG_ACTIVITY_SINGLE_TOP;
  29. }
  30. if ((isSingleTask || isClearTop) && (flag & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
  31. flag = flag ^ Intent.FLAG_ACTIVITY_CLEAR_TOP;
  32. }
  33. intent.setFlags(flag);
  34. PluginDebugLog.runtimeLog(TAG, "after flag: " + Integer.toHexString(intent.getFlags()));
  35. if (isSingleTop && !isClearTop) {
  36. // 判断栈顶是否为需要启动的Activity, 只需要处理前台栈
  37. Activity activity = null;
  38. if (!mFocusedStack.isEmpty()) {
  39. activity = mFocusedStack.getTop();
  40. }
  41. boolean hasSameActivity = false;
  42. String proxyClsName = ComponentFinder.findActivityProxy(mLoadedApk, info);
  43. if (activity != null) {
  44. // 栈内有实例, 可能是ProxyActivity,也可能是插件真实的Activity
  45. //Fix: 新的实现中只有插件真实的Activity
  46. if (TextUtils.equals(proxyClsName, activity.getClass().getName())
  47. || TextUtils.equals(targetActivity, activity.getClass().getName())) {
  48. String key = getActivityStackKey(activity);
  49. if (!TextUtils.isEmpty(key) && TextUtils.equals(targetActivity, key)) {
  50. intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  51. hasSameActivity = true;
  52. }
  53. }
  54. }
  55. if (hasSameActivity) {
  56. handleOtherPluginActivityStack(activity, mFocusedStack);
  57. }
  58. } else if (isSingleTask || isClearTop) {
  59. PActivityStack targetStack; // 需要搜索的任务栈
  60. boolean fromBackStack = false;
  61. if (isClearTop) {
  62. targetStack = mFocusedStack;
  63. } else {
  64. // singleTask
  65. if (mLastFocusedStack != null
  66. && TextUtils.equals(mLastFocusedStack.getTaskName(), matchTaskName(info.taskAffinity))) {
  67. // 后台栈和Activity的taskAffinity匹配
  68. targetStack = mLastFocusedStack;
  69. fromBackStack = true;
  70. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode search in background stack: " + info.taskAffinity);
  71. } else {
  72. // 前台栈中搜索
  73. targetStack = mFocusedStack;
  74. }
  75. }
  76. // 查找栈中是否存在已有实例
  77. Activity found = null;
  78. // 遍历已经起过的activity
  79. for (Activity activity : targetStack.getActivities()) {
  80. String proxyClsName = ComponentFinder.findActivityProxy(mLoadedApk, info);
  81. if (activity != null) {
  82. if (TextUtils.equals(proxyClsName, activity.getClass().getName())
  83. || TextUtils.equals(targetActivity, activity.getClass().getName())) {
  84. String key = getActivityStackKey(activity);
  85. if (!TextUtils.isEmpty(key) && TextUtils.equals(targetActivity, key)) {
  86. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode found:" + IntentUtils.dump(activity));
  87. found = activity;
  88. break;
  89. }
  90. }
  91. }
  92. }
  93. // 栈中已经有当前activity
  94. if (found != null) {
  95. // 处理其他插件的逻辑
  96. // 在以这两种SingleTask, ClearTop flag启动情况下,在同一个栈的情况下
  97. handleOtherPluginActivityStack(found, targetStack);
  98. // 处理当前插件的Activity
  99. List<Activity> popActivities = new ArrayList<Activity>(5);
  100. for (Activity activity : targetStack.getActivities()) {
  101. if (activity == found) {
  102. if (isSingleTask || isSingleTop) {
  103. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode add single top flag!");
  104. intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  105. }
  106. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode add clear top flag!");
  107. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  108. break;
  109. }
  110. popActivities.add(activity);
  111. }
  112. for (Activity act : popActivities) {
  113. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode popActivities finish " + IntentUtils.dump(act));
  114. popActivityFromStack(act);
  115. if (!FileUtils.isFinished(act)) {
  116. act.finish();
  117. }
  118. }
  119. // 如果Activity是在后台堆栈中找到的,需要合并前后台栈
  120. if (fromBackStack) {
  121. // https://developer.android.com/guide/components/activities/tasks-and-back-stack
  122. // 把返回栈中的Activity全部推到前台
  123. PActivityStack sysForeStack = findAssociatedStack(mFocusedStack);
  124. PActivityStack sysBackStack = findAssociatedStack(mLastFocusedStack);
  125. mergeActivityStack(sysBackStack, sysForeStack);
  126. // 处理插件自身的栈
  127. mergeActivityStack(mLastFocusedStack, mFocusedStack);
  128. // 切换前后台堆栈
  129. switchToBackStack(mFocusedStack, mLastFocusedStack);
  130. }
  131. mLoadedApk.quitApp(false);
  132. } else {
  133. // 堆栈里没有找到,遍历还未启动cache中的activity记录
  134. LinkedBlockingQueue<Intent> records = sIntentCacheMap
  135. .get(mLoadedApk.getPluginPackageName());
  136. if (null != records) {
  137. Iterator<Intent> recordIterator = records.iterator();
  138. String notLaunchTargetClassName = null;
  139. while (recordIterator.hasNext()) {
  140. Intent record = recordIterator.next();
  141. if (null != record) {
  142. if (null != record.getComponent()) {
  143. notLaunchTargetClassName = record.getComponent().getClassName();
  144. }
  145. if (TextUtils.equals(notLaunchTargetClassName, targetActivity)) {
  146. PluginDebugLog.runtimeLog(TAG, "sIntentCacheMap found: " + targetActivity);
  147. if (isSingleTask || isSingleTop) {
  148. intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  149. }
  150. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  151. break;
  152. }
  153. }
  154. }
  155. }
  156. // 遍历启动过程中的activity记录
  157. List<Intent> loadingIntents = sIntentLoadingMap.get(mLoadedApk.getPluginPackageName());
  158. if (null != loadingIntents) {
  159. Iterator<Intent> loadingRecordIterator = loadingIntents.iterator();
  160. String notLaunchTargetClassName = null;
  161. while (loadingRecordIterator.hasNext()) {
  162. Intent record = loadingRecordIterator.next();
  163. if (null != record) {
  164. notLaunchTargetClassName = IntentUtils.getTargetClass(record);
  165. if (TextUtils.equals(notLaunchTargetClassName, targetActivity)) {
  166. PluginDebugLog.runtimeLog(TAG,
  167. "sIntentLoadingMap found: " + targetActivity);
  168. if (isSingleTask || isSingleTop) {
  169. intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  170. }
  171. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  172. break;
  173. }
  174. }
  175. }
  176. }
  177. if (isSingleTask) {
  178. // 是否需要放到单独的任务栈
  179. String taskName = matchTaskName(info.taskAffinity);
  180. if (!TextUtils.equals(mFocusedStack.getTaskName(), taskName)) {
  181. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode push activity into separated stack: " + taskName);
  182. PActivityStack stack = mActivityStacks.get(taskName);
  183. if (stack == null) {
  184. // 创建一个新的任务栈
  185. stack = new PActivityStack(taskName);
  186. mActivityStacks.put(taskName, stack);
  187. }
  188. // 切换前后台栈
  189. switchToBackStack(mFocusedStack, stack);
  190. } else {
  191. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode push activity into current stack: " + taskName);
  192. }
  193. }
  194. }
  195. }
  196. PluginDebugLog.runtimeLog(TAG, "dealLaunchMode end: " + intent + " "
  197. + targetActivity);
  198. }
  199. 复制代码

处理插件中的广播

  1. /**
  2. * 动态注册插件中的静态Receiver
  3. */
  4. private void installStaticReceiver() {
  5. if (mPluginPackageInfo == null || mHostContext == null) {
  6. return;
  7. }
  8. Map<String, PluginPackageInfo.ReceiverIntentInfo> mReceiverIntentInfos =
  9. mPluginPackageInfo.getReceiverIntentInfos();
  10. if (mReceiverIntentInfos != null) {
  11. Set<Map.Entry<String, PluginPackageInfo.ReceiverIntentInfo>> mEntrys =
  12. mReceiverIntentInfos.entrySet();
  13. Context mGlobalContext = mHostContext.getApplicationContext();
  14. for (Map.Entry<String, PluginPackageInfo.ReceiverIntentInfo> mEntry : mEntrys) {
  15. PluginPackageInfo.ReceiverIntentInfo mReceiverInfo = mEntry.getValue();
  16. if (mReceiverInfo != null) {
  17. try {
  18. BroadcastReceiver mReceiver =
  19. BroadcastReceiver.class.cast(mPluginClassLoader.
  20. loadClass(mReceiverInfo.mInfo.name).newInstance());
  21. List<IntentFilter> mFilters = mReceiverInfo.mFilter;
  22. if (mFilters != null) {
  23. for (IntentFilter mItem : mFilters) {
  24. mGlobalContext.registerReceiver(mReceiver, mItem);
  25. }
  26. }
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  32. }
  33. }
  34. 复制代码

处理插件中的Service

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

  1. @Override
  2. public ComponentName startService(Intent service) {
  3. PluginDebugLog.log(TAG, "startService: " + service);
  4. PluginLoadedApk mLoadedApk = getPluginLoadedApk();
  5. if (mLoadedApk != null) {
  6. ComponentFinder.switchToServiceProxy(mLoadedApk, service);
  7. }
  8. return super.startService(service);
  9. }
  10. @Override
  11. public boolean stopService(Intent name) {
  12. PluginDebugLog.log(TAG, "stopService: " + name);
  13. PluginLoadedApk mLoadedApk = getPluginLoadedApk();
  14. if (mLoadedApk != null) {
  15. String actServiceClsName = "";
  16. if (name.getComponent() != null) {
  17. actServiceClsName = name.getComponent().getClassName();
  18. } else {
  19. ServiceInfo mServiceInfo = getPluginPackageInfo().resolveService(name);
  20. if (mServiceInfo != null) {
  21. actServiceClsName = mServiceInfo.name;
  22. }
  23. }
  24. PluginServiceWrapper plugin = PServiceSupervisor
  25. .getServiceByIdentifer(PluginServiceWrapper.getIdentify(getPluginPackageName(), actServiceClsName));
  26. if (plugin != null) {
  27. plugin.updateServiceState(PluginServiceWrapper.PLUGIN_SERVICE_STOPED);
  28. plugin.tryToDestroyService();
  29. return true;
  30. }
  31. }
  32. return super.stopService(name);
  33. }
  34. @Override
  35. public boolean bindService(Intent service, ServiceConnection conn, int flags) {
  36. PluginDebugLog.log(TAG, "bindService: " + service);
  37. PluginLoadedApk mLoadedApk = getPluginLoadedApk();
  38. if (mLoadedApk != null) {
  39. ComponentFinder.switchToServiceProxy(mLoadedApk, service);
  40. }
  41. if (conn != null) {
  42. if (mLoadedApk != null && service != null) {
  43. String serviceClass = IntentUtils.getTargetClass(service);
  44. String packageName = mLoadedApk.getPluginPackageName();
  45. if (!TextUtils.isEmpty(serviceClass) && !TextUtils.isEmpty(packageName)) {
  46. PServiceSupervisor.addServiceConnectionByIdentifer(packageName + "." + serviceClass, conn);
  47. }
  48. }
  49. }
  50. return super.bindService(service, conn, flags);
  51. }
  52. @Override
  53. public void unbindService(ServiceConnection conn) {
  54. super.unbindService(conn);
  55. PServiceSupervisor.removeServiceConnection(conn);
  56. PluginDebugLog.log(TAG, "unbindService: " + conn);
  57. }
  58. 复制代码

总结

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

转载于:https://juejin.im/post/5cd6f1bce51d456e3963198c

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/300648
推荐阅读
相关标签
  

闽ICP备14008679号