dependencies {
classpath 'com.didi.virtualapk:gradle:0.9.8.6'
}
apply plugin: 'com.didi.virtualapk.host'
dependencies {
implementation 'com.didi.virtualapk:core:0.9.8'
}
public class VirtualApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
PluginManager.getInstance(base).init();
}
}
classpath 'com.didi.virtualapk:gradle:0.9.8.6'
apply plugin: 'com.didi.virtualapk.plugin'
virtualApk{
// 插件资源表中的packageId,需要确保不同插件有不同的packageId
// 范围 0x1f - 0x7f
packageId = 0x6f
// 宿主工程application模块的路径,插件的构建需要依赖这个路径
// targetHost可以设置绝对路径或相对路径
targetHost = '../../../VirtualAPkDemo/app'
// 默认为true,如果插件有引用宿主的类,那么这个选项可以使得插件和宿主保持混淆一致
//这个标志会在加载插件时起作用
applyHostMapping = true
}
signingConfigs {
release {
storeFile file('/Users/wuliangliang/AndroidSubjectStudyProject/PluginProject/VirtualAPkDemo/keystore/keystore')
storePassword '123456'
keyAlias = 'key'
keyPassword '123456'
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
执行assemablePlugin 产生Plugin文件
将插件Plugin安装到手机中
adb push ./app/build/outputs/plugin/release/com.alex.kotlin.virtualplugin_20190729172001.apk /sdcard/plugin_test.apk
private void loadApk() {
File apkFile = new File(Environment.getExternalStorageDirectory(), "Test.apk");
if (apkFile.exists()) {
try {
PluginManager.getInstance(this).loadPlugin(apkFile);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在插件下载或安装到设备后,获取插件的文件,调用PluginManager.loadPlugin()加载插件,PluginManager会完成所有的代码解析和资源加载,详细内容后面的源码分析;
2. 执行界面跳转至插件中
final String pkg = "com.alex.kotlin.virtualplugin”; //插件Plugin的包名
Intent intent = new Intent();
intent.setClassName(pkg, "com.alex.kotlin.virtualplugin.MainPluginActivity”); //目标Activity的全路径
startActivity(intent);
PluginManager.getInstance(base).init();
public static PluginManager getInstance(Context base) {
if (sInstance == null) {
synchronized (PluginManager.class) {
if (sInstance == null) {
sInstance = createInstance(base); // 调用createInstance()方法创建PluginManager,单例对外提供
}
}
}
return sInstance;
}
private static PluginManager createInstance(Context context) {
try {
//1、获取metaData
Bundle metaData = context.getPackageManager()
.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA)
.metaData;
if (metaData == null) {
return new PluginManager(context); //2、
}
String factoryClass = metaData.getString("VA_FACTORY”); //3、此处获取的是什么?
if (factoryClass == null) {
return new PluginManager(context);
}
//4、创建PluginManager
PluginManager pluginManager = Reflector.on(factoryClass).method("create", Context.class).call(context);
if (pluginManager != null) {
return pluginManager;
}
} catch (Exception e) {
Log.w(TAG, "Created the instance error!", e);
}
return new PluginManager(context);
}
createInstance()执行逻辑:
protected PluginManager(Context context) {
if (context instanceof Application) { // 1、
this.mApplication = (Application) context;
this.mContext = mApplication.getBaseContext();
} else {
final Context app = context.getApplicationContext();
if (app == null) {
this.mContext = context;
this.mApplication = ActivityThread.currentApplication();
} else {
this.mApplication = (Application) app;
this.mContext = mApplication.getBaseContext();
}
}
mComponentsHandler = createComponentsHandler(); //2、
hookCurrentProcess(); //3、
}
PluginManager()执行流程:
protected void hookCurrentProcess() {
hookInstrumentationAndHandler();
hookSystemServices();
}
ActivityThread activityThread = ActivityThread.currentActivityThread();
Instrumentation baseInstrumentation = activityThread.getInstrumentation(); //1、
final VAInstrumentation instrumentation = createInstrumentation(baseInstrumentation); //2、
//3、
Reflector.with(activityThread).field("mInstrumentation").set(instrumentation);
//4、
Handler mainHandler = Reflector.with(activityThread).method("getHandler").call();
Reflector.with(mainHandler).field("mCallback").set(instrumentation);
this.mInstrumentation = instrumentation; // 赋值 PluginManager的mInstrumentation
执行流程:
Singleton<IActivityManager> defaultSingleton;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//1、
//8.0 以上获取IActivityManagerSingleton,采用AIDL获取AMS
defaultSingleton = Reflector.on(ActivityManager.class).field("IActivityManagerSingleton").get();
} else {
//8.0 之前获取gDefault,使用代理执行AMS
defaultSingleton = Reflector.on(ActivityManagerNative.class).field("gDefault").get();
}
IActivityManager origin = defaultSingleton.get(); //2
IActivityManager activityManagerProxy = (IActivityManager) Proxy.newProxyInstance(mContext.getClassLoader(), new Class[]{IActivityManager.class},createActivityManagerProxy(origin));//3
Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy); // 4、
if (defaultSingleton.get() == activityManagerProxy) {
this.mActivityManager = activityManagerProxy;//5、
}
hook系统服务在Hook 技术 文章中已经接收过程了,这里简单介绍逻辑:
由四大组件启动过程源码分析,Hook了Instrumentation对象就可以完成对Activity的创建过程的修改,Hook了系统的IActivityManager可以实现对AMS工作的拦截,而AMS对四大组件的整个工作过程至关重要,也就是说我们已经掌控了四大组件;
public void loadPlugin(File apk) throws Exception {
//1、
LoadedPlugin plugin = createLoadedPlugin(apk);
//2、
this.mPlugins.put(plugin.getPackageName(), plugin);
}
loadPlugin()中主要完成两件事:
public LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws Exception {
//1、保存安装包的APk路径、pluginManager、context
this.mPluginManager = pluginManager;
this.mHostContext = context;
this.mLocation = apk.getAbsolutePath();
//2、解析Plugin的AndroidManifest.xml文件
this.mPackage = PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);
this.mPackage.applicationInfo.metaData = this.mPackage.mAppMetaData;
//3、创建并实例化PackageInfo对象
this.mPackageInfo = new PackageInfo();
this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo;
this.mPackageInfo.applicationInfo.sourceDir = apk.getAbsolutePath();
if (Build.VERSION.SDK_INT >= 28
|| (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0)) {
try {
this.mPackageInfo.signatures = this.mPackage.mSigningDetails.signatures;
} catch (Throwable e) {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
this.mPackageInfo.signatures = info.signatures;
}
} else {
this.mPackageInfo.signatures = this.mPackage.mSignatures;
}
//保存包名
this.mPackageInfo.packageName = this.mPackage.packageName;
this.mPackageInfo.versionCode = this.mPackage.mVersionCode;
this.mPackageInfo.versionName = this.mPackage.mVersionName;
this.mPackageInfo.permissions = new PermissionInfo[0];
//4、创建插件中自己的PackManager
this.mPackageManager = createPluginPackageManager();
//5、创建插件中自己的PluginContext
this.mPluginContext = createPluginContext(null);
this.mNativeLibDir = getDir(context, Constants.NATIVE_DIR);
//获取so文件路径
this.mPackage.applicationInfo.nativeLibraryDir = this.mNativeLibDir.getAbsolutePath();
//6、创建Resource和ClassLoader对象
this.mResources = createResources(context, getPackageName(), apk);
//7、创建ClassLoader对象
this.mClassLoader = createClassLoader(context, apk, this.mNativeLibDir, context.getClassLoader());
tryToCopyNativeLib(apk);
Map<ComponentName, ActivityInfo> activityInfos = new HashMap<ComponentName, ActivityInfo>();
for (PackageParser.Activity activity : this.mPackage.activities) {
activity.info.metaData = activity.metaData;
activityInfos.put(activity.getComponentName(), activity.info); // 8、缓存插件中解析的Activity
}
this.mPackageInfo.activities = activityInfos.values().toArray(new ActivityInfo[activityInfos.size()]);
Map<ComponentName, ServiceInfo> serviceInfos = new HashMap<ComponentName, ServiceInfo>();
for (PackageParser.Service service : this.mPackage.services) {
serviceInfos.put(service.getComponentName(), service.info); // 9、缓存插件中解析的服务Service
}
this.mPackageInfo.services = serviceInfos.values().toArray(new ServiceInfo[serviceInfos.size()]);
Map<String, ProviderInfo> providers = new HashMap<String, ProviderInfo>();
Map<ComponentName, ProviderInfo> providerInfos = new HashMap<ComponentName, ProviderInfo>();
for (PackageParser.Provider provider : this.mPackage.providers) {
providers.put(provider.info.authority, provider.info);
providerInfos.put(provider.getComponentName(), provider.info); // 10、缓存插件中解析的ContentProvider
}
this.mPackageInfo.providers = providerInfos.values().toArray(new ProviderInfo[providerInfos.size()]);
// 11、缓存插件中解析的广播,对于静态注册的广播改为动态注册
Map<ComponentName, ActivityInfo> receivers = new HashMap<ComponentName, ActivityInfo>();
for (PackageParser.Activity receiver : this.mPackage.receivers) {
receivers.put(receiver.getComponentName(), receiver.info);
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
this.mHostContext.registerReceiver(br, aii); // 注册广播
}
}
this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]);
invokeApplication(); // 12、初始化Plugin的Application
}
protected class PluginPackageManager extends PackageManager {
protected PackageManager mHostPackageManager = mHostContext.getPackageManager(); //1
@Override
public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName); // 2
if (null != plugin) {
return plugin.mPackageInfo; // 3
}
return this.mHostPackageManager.getPackageInfo(packageName, flags); //4
}
}
PluginPackageManager继成PackageManager重些其中的方法,在调用方法时判断获取的是插件APK还是宿主APK,并对应处理返回,具体如下:
public PluginContext createPluginContext(Context context) {
if (context == null) {
return new PluginContext(this); //1、由前面知道传入contetx为null,执行此处传递LoadedPlugin对象
}
return new PluginContext(this, context);
}
class PluginContext extends ContextWrapper { // 1、继承ContextWrapper,用于在Activity中使用替换原来的Context
private final LoadedPlugin mPlugin;
public PluginContext(LoadedPlugin plugin) {
super(plugin.getPluginManager().getHostContext()); // 赋值mBase对象,此处使用HostContext
this.mPlugin = plugin; // 保存插件创建的Plugin对象
}
@Override
public Context getApplicationContext() {
return this.mPlugin.getApplication();
}
private Context getHostContext() {
return getBaseContext();
}
@Override
public ContentResolver getContentResolver() {
return new PluginContentResolver(getHostContext());
}
@Override
public ClassLoader getClassLoader() {
return this.mPlugin.getClassLoader();
}
@Override
public Resources getResources() {
return this.mPlugin.getResources();
}
@Override
public void startActivity(Intent intent) {
// 重写startActivity处理Intent
ComponentsHandler componentsHandler = mPlugin.getPluginManager().getComponentsHandler();
componentsHandler.transformIntentToExplicitAsNeeded(intent);
super.startActivity(intent);
}
}
在Activity中一些资源和服务都是通过Context获取的,而Context是ContextWrapper的子类,在PluginContext中同样继承ContextWrapper,重写一系列的Context方法,在加载插件时使用PluginContext替代插件APK中的Context、控制插件中资源和一些类的获取,例如代码中的getResources()、getContentResolver()等;
protected Resources createResources(Context context, String packageName, File apk) throws Exception {
if (Constants.COMBINE_RESOURCES) {// 1
return ResourcesManager.createResources(context, packageName, apk); // 2
} else {
Resources hostResources = context.getResources();
AssetManager assetManager = createAssetManager(context, apk);
return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());//3
}
}
由Android系统知道,程序在启动时将资源加载到程序对应的Resource中,此处就是收动将插件apk中的资源加载到resource中,执行流程:
public static synchronized Resources createResources(Context hostContext, String packageName, File apk) throws Exception {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //1、处理7.0 之后 Resource的创建
return createResourcesForN(hostContext, packageName, apk);
}
//2、处理7.0 之前,使用AssetManager添加资源
Resources resources = ResourcesManager.createResourcesSimple(hostContext, apk.getAbsolutePath());
ResourcesManager.hookResources(hostContext, resources);
return resources;
}
private static Resources createResourcesForN(Context context, String packageName, File apk) throws Exception {
String newAssetPath = apk.getAbsolutePath(); // Plugin apk的路径
ApplicationInfo info = context.getApplicationInfo();
String baseResDir = info.publicSourceDir; // host的文件路径
info.splitSourceDirs = append(info.splitSourceDirs, newAssetPath); //2、
LoadedApk loadedApk = Reflector.with(context).field("mPackageInfo").get(); //3、
Reflector rLoadedApk = Reflector.with(loadedApk).field("mSplitResDirs");
String[] splitResDirs = rLoadedApk.get();
rLoadedApk.set(append(splitResDirs, newAssetPath));
final ResourcesManager resourcesManager = android.app.ResourcesManager.getInstance();
ArrayMap<ResourcesKey, WeakReference<ResourcesImpl>> originalMap = //4、Reflector.with(resourcesManager).field("mResourceImpls").get();
synchronized (resourcesManager) {
HashMap<ResourcesKey, WeakReference<ResourcesImpl>> resolvedMap = new HashMap<>();
if (Build.VERSION.SDK_INT >= 28
|| (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0)) { // P Preview
ResourcesManagerCompatForP.resolveResourcesImplMap(originalMap, resolvedMap, context, loadedApk);
} else {
ResourcesManagerCompatForN.resolveResourcesImplMap(originalMap, resolvedMap, baseResDir, newAssetPath);
}
originalMap.clear();
originalMap.putAll(resolvedMap);
}
android.app.ResourcesManager.getInstance().appendLibAssetForMainAssetPath(baseResDir, packageName + ".vastub");
//5、
Resources newResources = context.getResources();
for (LoadedPlugin plugin : PluginManager.getInstance(context).getAllLoadedPlugins()) {
plugin.updateResources(newResources);
}
return newResources;
}
Resource的创建流程:
Resources resources = ResourcesManager.createResourcesSimple(hostContext, apk.getAbsolutePath());//创建Resource对象
ResourcesManager.hookResources(hostContext, resources); // 反射更新设置宿主Context中的resource
private static Resources createResourcesSimple(Context hostContext, String apk) throws Exception {
Resources hostResources = hostContext.getResources();
Resources newResources = null;
AssetManager assetManager;
Reflector reflector = Reflector.on(AssetManager.class).method("addAssetPath", String.class); //1、
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // Android 5.0 之前
assetManager = AssetManager.class.newInstance();
reflector.bind(assetManager);
//2、
final int cookie1 = reflector.call(hostContext.getApplicationInfo().sourceDir);
} else {
assetManager = hostResources.getAssets(); //3、
reflector.bind(assetManager);
}
final int cookie2 = reflector.call(apk); // 4、
List<LoadedPlugin> pluginList = PluginManager.getInstance(hostContext).getAllLoadedPlugins();
for (LoadedPlugin plugin : pluginList) { // 5、
final int cookie3 = reflector.call(plugin.getLocation());
}
//6、适配不同的手机类型,创建新的Resource对象
if (isMiUi(hostResources)) {
newResources = MiUiResourcesCompat.createResources(hostResources, assetManager);
} else if (isVivo(hostResources)) {
newResources = VivoResourcesCompat.createResources(hostContext, hostResources, assetManager);
} else if (isNubia(hostResources)) {
newResources = NubiaResourcesCompat.createResources(hostResources, assetManager);
} else if (isNotRawResources(hostResources)) {
newResources = AdaptationResourcesCompat.createResources(hostResources, assetManager);
} else {
newResources = new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}
// 7、将所有LoadedPlugin同步到新的newResources
for (LoadedPlugin plugin : pluginList) {
plugin.updateResources(newResources);
}
return newResources;
}
实现原理:创建一个新的AssetManager对象,使用AssetManager的addAssetPath()依次将所有插件和宿主中的资源路径添加到对象中,根据新的AssetManager对象创建Resource对象,具体细节:
protected ClassLoader createClassLoader(Context context, File apk, File libsDir, ClassLoader parent) throws Exception {
File dexOutputDir = getDir(context, Constants.OPTIMIZE_DIR);
String dexOutputPath = dexOutputDir.getAbsolutePath();//1、获取原APP中的dex文件路径
//2、创建DexClassLoader对象,同时加载host已经存在的dex文件和插件apk中的文件
DexClassLoader loader = new DexClassLoader(apk.getAbsolutePath(), dexOutputPath, libsDir.getAbsolutePath(), parent);
if (Constants.COMBINE_CLASSLOADER) {
DexUtil.insertDex(loader, parent, libsDir);//3、将所有的dex资源合并到宿主的ClassLoader中
}
return loader;
}
createClassLoader()中先获取当前app和插件的dex文件路径,然后创建DexClassLoader同时加载两个文件中的所有资源,在调用DexUtil.insertDex()合并dex资源,关于ClassLoader不了解的点击Android热修复之路(一)——ClassLoader
public static void insertDex(DexClassLoader dexClassLoader, ClassLoader baseClassLoader, File nativeLibsDir) throws Exception {
Object baseDexElements = getDexElements(getPathList(baseClassLoader)); // 1、获取传入的host默认的ClassLoader中加载的Elements集合
Object newDexElements = getDexElements(getPathList(dexClassLoader)); //2、获取dexClassLoader中加载的Elements(host & plugin)
Object allDexElements = combineArray(baseDexElements, newDexElements); // 3、合并Elements
Object pathList = getPathList(baseClassLoader);
Reflector.with(pathList).field("dexElements").set(allDexElements); // 4、反射设置合并后的Elements集合
insertNativeLibrary(dexClassLoader, baseClassLoader, nativeLibsDir);
}
this.mPackage = PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);
this.mPackage.applicationInfo.metaData = this.mPackage.mAppMetaData;
//3、创建并实例化PackageInfo对象
this.mPackageInfo = new PackageInfo();
Map<ComponentName, ActivityInfo> receivers = new HashMap<ComponentName, ActivityInfo>();
for (PackageParser.Activity receiver : this.mPackage.receivers) {
receivers.put(receiver.getComponentName(), receiver.info);
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
this.mHostContext.registerReceiver(br, aii);
}
}
public void invokeApplication() throws Exception {
final Exception[] temp = new Exception[1];
RunUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
mApplication = makeApplication(false, mPluginManager.getInstrumentation()); //
} catch (Exception e) {
temp[0] = e;
}
}
}, true);
}
protected Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) throws Exception {
String appClass = this.mPackage.applicationInfo.className;
if (forceDefaultAppClass || null == appClass) {
appClass = "android.app.Application”; //设置执行的类
}
//
this.mApplication = instrumentation.newApplication(this.mClassLoader, appClass, this.getPluginContext());
mApplication.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksProxy());
//调用Application的onCreate(),此处执行的是插件APK中的Application
instrumentation.callApplicationOnCreate(this.mApplication);
return this.mApplication;
}
在makeApplication()内部调用instrumentation.newApplication()创建Application对象和执行Application的onCreate(),关于instrumentation中如何创建的参考(四大组件的启动过程)
Activity在启动过程中调用Instrumentation的execStartActivity(),在VAInstrumentation中重写此方法拦截启动Activity过程,在此方法中修改处理Intent
@Override
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
injectIntent(intent); //1、
return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode); //2、调用原来逻辑继续执行
}
protected void injectIntent(Intent intent) {
//此处调用的getComponentsHandler()就是拿到前面创建的ComponentsHandler对象
mPluginManager.getComponentsHandler().transformIntentToExplicitAsNeeded(intent);
if (intent.getComponent() != null) {
this.mPluginManager.getComponentsHandler().markIntentIfNeeded(intent);
}
}
public Intent transformIntentToExplicitAsNeeded(Intent intent) {
ComponentName component = intent.getComponent();
if (component == null || component.getPackageName().equals(mContext.getPackageName())) {
ResolveInfo info = mPluginManager.resolveActivity(intent); // 1
if (info != null && info.activityInfo != null) {
component = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); //2
intent.setComponent(component);
}
}
return intent;
}
public void markIntentIfNeeded(Intent intent) {
String targetPackageName = intent.getComponent().getPackageName(); //1、 名
String targetClassName = intent.getComponent().getClassName();
if (!targetPackageName.equals(mContext.getPackageName()) && mPluginManager.getLoadedPlugin(targetPackageName) != null) {
intent.putExtra(Constants.KEY_IS_PLUGIN, true); //2、
intent.putExtra(Constants.KEY_TARGET_PACKAGE, targetPackageName);
intent.putExtra(Constants.KEY_TARGET_ACTIVITY, targetClassName);
dispatchStubActivity(intent); //3、
}
}
在markIntentIfNeeded()中:
private void dispatchStubActivity(Intent intent) {
ComponentName component = intent.getComponent();
String targetClassName = intent.getComponent().getClassName();
LoadedPlugin loadedPlugin = mPluginManager.getLoadedPlugin(intent); // 1、
ActivityInfo info = loadedPlugin.getActivityInfo(component); //2、
int launchMode = info.launchMode; // 3、
Resources.Theme themeObj = loadedPlugin.getResources().newTheme();
themeObj.applyStyle(info.theme, true);
//4、
String stubActivity = mStubActivityInfo.getStubActivity(targetClassName, launchMode, themeObj);
intent.setClassName(mContext, stubActivity); //5、
}
在VirtualAPk的注册清单中提前注册好了不同条件的占位Activity,dispatchStubActivity()中主要从VirtualAPk中选择合适的占位Activity:
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
try {
cl.loadClass(className); // 1、ClassLoader加载类名
} catch (ClassNotFoundException e) { // 2、抛出ClassNotFoundException,表示启动插件Activity
ComponentName component = PluginUtil.getComponent(intent);
String targetClassName = component.getClassName(); //3、
LoadedPlugin plugin = this.mPluginManager.getLoadedPlugin(component);
// 4、创建Plugin的Activity真正的实例
Activity activity = mBase.newActivity(plugin.getClassLoader(), targetClassName, intent);
activity.setIntent(intent);
//5、
Reflector.QuietReflector.with(activity).field("mResources").set(plugin.getResources());
return newActivity(activity);
}
return newActivity(mBase.newActivity(cl, className, intent)); // 对于ClassLoader中查找到的直接调用原来方法初始化Activity
}
在Activity的启动过程中会回调newActivity()创建对象,所以在VAInstrumentation重写此方法:
public ActivityManagerProxy(PluginManager pluginManager, IActivityManager activityManager) {
this.mPluginManager = pluginManager;
this.mActivityManager = activityManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startService".equals(method.getName())) {
try {
return startService(proxy, method, args); // 处理启动服务
}
} else if ("stopService".equals(method.getName())) {
try {
return stopService(proxy, method, args); // 处理停止服务
}
} else if ("stopServiceToken".equals(method.getName())) {
try {
return stopServiceToken(proxy, method, args);
}
} else if ("bindService".equals(method.getName())) {
try {
return bindService(proxy, method, args); // 处理绑定服务
}
} else if ("unbindService".equals(method.getName())) {
try {
return unbindService(proxy, method, args); // 处理解绑服务
}
}
try {
return method.invoke(this.mActivityManager, args);
}
}
由前面Pluginmanager初始化过程知道VirtualAPk Hook了系统的AMS,Hook中传递的Binder对象就是ActivityManagerProxy对象,所以AMS对Service的任何操作都会经过此处的invoke(),我们就可以在invoke()方法中干涉启动过程;
protected Object startService(Object proxy, Method method, Object[] args) throws Throwable {
IApplicationThread appThread = (IApplicationThread) args[0]; // 1、
Intent target = (Intent) args[1];
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);//2、查找处理Intent,务
if (null == resolveInfo || null == resolveInfo.serviceInfo) {
return method.invoke(this.mActivityManager, args); //3、
}
return startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);//4、处理
}
protected ComponentName startDelegateServiceForTarget(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
Intent wrapperIntent = wrapperTargetIntent(target, serviceInfo, extras, command); //5、构造代理服务的Intent
return mPluginManager.getHostContext().startService(wrapperIntent); //6、
}
在ActivityManagerProxy的invoke()中拦截到startService()后调用startService(),在startService()中执行一下逻辑:
protected Intent wrapperTargetIntent(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
target.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));
String pluginLocation = mPluginManager.getLoadedPlugin(target.getComponent()).getLocation();//1、
boolean local = PluginUtil.isLocalService(serviceInfo); // 2、
Class<? extends Service> delegate = local ? LocalService.class : RemoteService.class;//3、
Intent intent = new Intent();
intent.setClass(mPluginManager.getHostContext(), delegate); // 3、
intent.putExtra(RemoteService.EXTRA_TARGET, target);
intent.putExtra(RemoteService.EXTRA_COMMAND, command);
intent.putExtra(RemoteService.EXTRA_PLUGIN_LOCATION, pluginLocation);
return intent;
}
构造代理服务Intent的流程如下:
public int onStartCommand(Intent intent, int flags, int startId) {
Intent target = intent.getParcelableExtra(EXTRA_TARGET); //1、
ComponentName component = target.getComponent();
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
target.setExtrasClassLoader(plugin.getClassLoader());
switch (command) {
case EXTRA_COMMAND_START_SERVICE: {
ActivityThread mainThread = ActivityThread.currentActivityThread();
IApplicationThread appThread = mainThread.getApplicationThread();
Service service;
if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
service = this.mPluginManager.getComponentsHandler().getService(component); // 2、
} else {
try {
service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance(); //3、
Application app = plugin.getApplication();
IBinder token = appThread.asBinder();
Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);
IActivityManager am = mPluginManager.getActivityManager();
attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am); //4、
service.onCreate();
this.mPluginManager.getComponentsHandler().rememberService(component, service); //5、
} catch (Throwable t) {
return START_STICKY;
}
}
//6、执行插件Service的onStartCommand()传入参数
service.onStartCommand(target, 0, this.mPluginManager.getComponentsHandler().getServiceCounter(service).getAndIncrement());
break;
}
}
return START_STICKY;
}
LocalService启动后,程序执行到onStartCommand()中,在onStartCommand()会创建插件Service的实例并完成服务的分发:
case EXTRA_COMMAND_STOP_SERVICE: {
//1、获取Service并移除当前缓存
Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
if (null != service) {
try {
service.onDestroy(); //2、调用onDestroy()
}
}
break;
}
protected Object bindService(Object proxy, Method method, Object[] args) throws Throwable {
Intent target = (Intent) args[2];
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
Bundle bundle = new Bundle();
PluginUtil.putBinder(bundle, "sc", (IBinder) args[4]); // 1、保存绑定时传入的ServiceConnection对象
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, bundle, RemoteService.EXTRA_COMMAND_BIND_SERVICE);
mPluginManager.getComponentsHandler().remberIServiceConnection((IBinder) args[4], target); // 2、缓存IServiceConnection
return 1;
}
public void remberIServiceConnection(IBinder iServiceConnection, Intent intent) {
synchronized (this.mBoundServices) {
mBoundServices.put(iServiceConnection, intent); //
}
}
case EXTRA_COMMAND_BIND_SERVICE: {
ActivityThread mainThread = ActivityThread.currentActivityThread();
IApplicationThread appThread = mainThread.getApplicationThread();
Service service = null;
if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
service = this.mPluginManager.getComponentsHandler().getService(component);
} else {
try {
service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();
......
try {
IBinder binder = service.onBind(target); // 1、回调Service的onBind()
IBinder serviceConnection = PluginUtil.getBinder(intent.getExtras(), "sc");
IServiceConnection iServiceConnection = IServiceConnection.Stub.asInterface(serviceConnection);
if (Build.VERSION.SDK_INT >= 26) {
iServiceConnection.connected(component, binder, false);//2、获取传入的serviceConnection,回调connected()
} else {
Reflector.QuietReflector.with(iServiceConnection).method("connected", ComponentName.class, IBinder.class).call(component, binder);
}
}
break;
}
绑定服务整体过程和启动类似,只是多了两个步骤:
protected Object unbindService(Object proxy, Method method, Object[] args) throws Throwable {
IBinder iServiceConnection = (IBinder) args[0];
Intent target = mPluginManager.getComponentsHandler().forgetIServiceConnection(iServiceConnection);
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_UNBIND_SERVICE);
return true;
}
public Intent forgetIServiceConnection(IBinder iServiceConnection) {
synchronized (this.mBoundServices) {
Intent intent = this.mBoundServices.remove(iServiceConnection);
return intent;
}
}
case EXTRA_COMMAND_UNBIND_SERVICE: {
Service service = this.mPluginManager.getComponentsHandler().forgetService(component); // 获取服务
if (null != service) {
try {
service.onUnbind(target); // 解绑服务
service.onDestroy();
}
}
break;
}
Uri bookUri = Uri.parse("content://com.didi.virtualapk.demo.book.provider/book”); // 查找的Uri
LoadedPlugin plugin = PluginManager.getInstance(this).getLoadedPlugin(pkg); // 1、获取插件的LoadedPlugin
bookUri = PluginContentResolver.wrapperUri(plugin, bookUri); //2、替换Uri,用于启动宿主代理的ContentProvider
//3、获取ContentResolver对象,执行查询
Cursor bookCursor = getContentResolver().query(bookUri, new String[]{"_id", "name"}, null, null, null);
<provider
android:exported="false"
android:name="com.didi.virtualapk.delegate.RemoteContentProvider"
android:authorities="${applicationId}.VirtualAPK.Provider"
android:process=":daemon" />
public static Uri wrapperUri(LoadedPlugin loadedPlugin, Uri pluginUri) {
String pkg = loadedPlugin.getPackageName(); //1、
String pluginUriString = Uri.encode(pluginUri.toString());
StringBuilder builder = new StringBuilder(RemoteContentProvider.getUri(loadedPlugin.getHostContext()));//2、
//3、
builder.append("/?plugin=" + loadedPlugin.getLocation());
builder.append("&pkg=" + pkg);
builder.append("&uri=" + pluginUriString);
//4、创建Uri
Uri wrapperUri = Uri.parse(builder.toString());
return wrapperUri;
}
public static String getAuthority(Context context) {
return context.getPackageName() + ".VirtualAPK.Provider”; // 创建代理Provider启动权限
}
public static String getUri(Context context) {
return "content://" + getAuthority(context);
}
和代理Service大致相似,Provider的使用也分为两部分,处理启动的Intent和启动Provider的代理分发,Intent处理主要将请求的Uri转换为启动代理Provider的Uri,同时保存插件的请求信息:
@Override
public ContentResolver getContentResolver() {
return new PluginContentResolver(getHostContext());
}
由前面的PluginContext知道,在插件的四大组件中使用PluginContext代替Context。对于插件此处调用的是PluginContext中的getContentResolver(),创建PluginContentResolver对象
public class PluginContentResolver extends ContentResolverWrapper {
private PluginManager mPluginManager;
public PluginContentResolver(Context context) {
super(context);
mPluginManager = PluginManager.getInstance(context);
}
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
//2、处理插件中的Provider
if (mPluginManager.resolveContentProvider(auth, 0) != null) {
return mPluginManager.getIContentProvider();
}
return super.acquireProvider(context, auth);
}
}
PluginContentResolver继承ContentResolverWrapper类,作为插件中使用的ContentProvider,由Provider的工作过程知道(ContentProvider使用和工作过程详解),系统在获取Provider对象时会调用getIContentProvider()
public synchronized IContentProvider getIContentProvider() {
if (mIContentProvider == null) {
hookIContentProviderAsNeeded(); //Hook ContentProvider 拦截请求
}
return mIContentProvider;
}
protected void hookIContentProviderAsNeeded() {
Uri uri = Uri.parse(RemoteContentProvider.getUri(mContext));
mContext.getContentResolver().call(uri, "wakeup", null, null);
try {
Field authority = null;
Field provider = null;
ActivityThread activityThread = ActivityThread.currentActivityThread();
//1、
Map providerMap = Reflector.with(activityThread).field("mProviderMap").get();
Iterator iter = providerMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
String auth;
if (auth.equals(RemoteContentProvider.getAuthority(mContext))) { //2、
if (provider == null) {
provider = val.getClass().getDeclaredField("mProvider");
provider.setAccessible(true);
}
IContentProvider rawProvider = (IContentProvider) provider.get(val);
//3、代理指定的Provider
IContentProvider proxy = IContentProviderProxy.newInstance(mContext, rawProvider);
mIContentProvider = proxy;
break;
}
}
}
}
Hook ContentProvider的过程:
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
ContentProvider provider = getContentProvider(uri); // 1、获取真正执行的Provider对象
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI)); //2、获取启动Plugin真正的Uri
if (provider != null) {
return provider.query(pluginUri, projection, selection, selectionArgs, sortOrder);//3、
}
return null;
}
在宿主代理Provider中:
private ContentProvider getContentProvider(final Uri uri) {
final PluginManager pluginManager = PluginManager.getInstance(getContext());
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI)); // 1、
final String auth = pluginUri.getAuthority(); // 2、
ContentProvider cachedProvider = sCachedProviders.get(auth); // 3、
if (cachedProvider != null) {
return cachedProvider;
}
synchronized (sCachedProviders) {
LoadedPlugin plugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG)); //4、
if (plugin == null) {
try {
pluginManager.loadPlugin(new File(uri.getQueryParameter(KEY_PLUGIN))); // 5、
}
}
final ProviderInfo providerInfo = pluginManager.resolveContentProvider(auth, 0); // 6、
if (providerInfo != null) {
RunUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
LoadedPlugin loadedPlugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG)); // 7、
ContentProvider contentProvider = (ContentProvider) Class.forName(providerInfo.name).newInstance(); // 8、
contentProvider.attachInfo(loadedPlugin.getPluginContext(), providerInfo); // 9、
sCachedProviders.put(auth, contentProvider); //10、
}
}
}, true);
return sCachedProviders.get(auth);
}
}
return null;
}
前面的整个过程都是在操纵代理Provider,真正牵涉到插件的Provider就在此处,整个创建Provider和执行方法流程如下:
到此整个VirtualApk的使用和源码分析就到此结束了,从开始接触到现在源码分析整个过程拖了好久,通过整个流程的学习对之前的源码知识也有了更好的巩固,希望对想学习插件化的同学有所帮助;