Android插件化不算是一门新技术,发展了有一些年头了。不一样公司的插件化方案大致原理上很类似。本文经过阅读爱奇艺的Neptune
框架来介绍插件化的总体思路和流程。java
所谓的插件其实本质上也是一个apk。在原生的Android应用中,apk在运行时会被映射成一个LoadedApk
对象。插件在安装以后也会被映射成相似的PluginLoadedApk
对象,统一管理插件的相关信息。android
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)和线上插件两部分。api
插件的安装经过运行在独立进程的Service完成,主要防止部分机型dexopt hang住主进程。数组
Android根据系统版本不一样会采用两种虚拟机。Dalvik虚拟机是JIT方式解释执行dex字节码;ART虚拟机是AOT方式将dex字节码转化为oat机器码。缓存
若是当前运行在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比较多的状况下,将会大大增长系统首次启动的时间。app
对于插件安装来讲,插件的安装经过运行在独立进程的Service完成,主要防止部分机型dexopt hang住主进程。框架
插件安装过程主要执行如下几步:异步
Java中的类都是经过ClassLoader加载的,而Android中类的加载也离不开ClassLoadder。在Android系统中,主要的ClassLoader有三个:ide
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,若是父类加载器能够完成类加载任务,就成功返回;只有父类加载器没法完成此加载任务时,才本身去加载。函数
关于插件中类的加载机制有两种处理方式,一种是单类加载机制,另外一种是多类加载机制;单类加载器机制,即全部插件APP的类都经过宿主的ClassLoader(即PathClassLoader)进行加载,与MultiDex、Qzone热修复技术相似,经过Dex前插后者后插的方式实现。采用单类加载器模型,随着业务团队和插件的增长,很容易出现类重复问题,没法保证全部类都是独一无二的。多类加载器机制是指每一个插件都由一个新的类加载器实例来加载,组件间的类是彻底隔离,不能直接互相访问。
利用ClassLoader的双亲委派机制,多类加载有两种思路:
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冲突问题。
限制:插件不能使用本身的转场动画,只能使用宿主、系统定义的转场动画。
转场动画最终会调用到IActivityManager
,发起IPC请求,与AMS交互
public void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim) throws RemoteException;
复制代码
先附上两张Android原生打包流程图

在插件编译打包时,须要完成如下几件事:
Activity启动能够分为两个阶段:往AMS发起启动Activity的请求、AMS校验后执行Activity启动。
在Android 8.0(api 26)如下,应用往AMS发起启动Activity请求的流程如上。在Android 8.0及以上版本,AMN、AMP已经被弃用,而是使用ActivityManager
类;参考文章。
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分发。
Service启动能够分为两个阶段:往AMS发起启动Service的请求、AMS校验后执行Service启动。
在Android 8.0(api 26)如下,应用往AMS发起启动Service请求的流程如上。在Android 8.0及以上版本,AMN、AMP已经被弃用,而是使用ActivityManager类。
广播分为静态广播、动态广播。动态广播在运行时向AMS注册相关信息。
Neptune
类是整个插件系统的入口类,主要方法以下
/** * 初始化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);
}
复制代码
/** * 启动插件 * * @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);
}
复制代码
Hook系统原生的Instrument,替换成NeptuneInstrument。NeptuneInstrument
继承PluginInstrument
。 PluginInstrument
负责往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栈抽象, 和系统的{@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();
}
}
}
}
}
复制代码
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思路,只看相关的代码,仍是比较容易理解的。