VirtualApk是对每个ContextImpl做了替换。
插件Resource的生成
protected Resources createResources(Context context, String packageName, File apk) throws Exception {
if (Constants.COMBINE_RESOURCES) {//合并式
return ResourcesManager.createResources(context, packageName, apk);
} else {//独立式
Resources hostResources = context.getResources();
AssetManager assetManager = createAssetManager(context, apk);
return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}
}
Resource的hook方式
继承ContextWrapper.java并重写getResource方法,返回构造的Resource对象,再对context进行替换。
class PluginContext extends ContextWrapper {
private final LoadedPlugin mPlugin;
public PluginContext(LoadedPlugin plugin) {
super(plugin.getPluginManager().getHostContext());
this.mPlugin = plugin;
}
public PluginContext(LoadedPlugin plugin, Context base) {
super(base);
this.mPlugin = plugin;
}
@Override
public Context getApplicationContext() {
return this.mPlugin.getApplication();
}
// @Override
// public ApplicationInfo getApplicationInfo() {
// return this.mPlugin.getApplicationInfo();
// }
private Context getHostContext() {
return getBaseContext();
}
@Override
public ContentResolver getContentResolver() {
return new PluginContentResolver(getHostContext());
}
@Override
public ClassLoader getClassLoader() {
return this.mPlugin.getClassLoader();
}
// @Override
// public String getPackageName() {
// return this.mPlugin.getPackageName();
// }
// @Override
// public String getPackageResourcePath() {
// return this.mPlugin.getPackageResourcePath();
// }
// @Override
// public String getPackageCodePath() {
// return this.mPlugin.getCodePath();
// }
@Override
public PackageManager getPackageManager() {
return this.mPlugin.getPackageManager();
}
@Override
public Object getSystemService(String name) {
// intercept CLIPBOARD_SERVICE,NOTIFICATION_SERVICE
if (name.equals(Context.CLIPBOARD_SERVICE)) {
return getHostContext().getSystemService(name);
} else if (name.equals(Context.NOTIFICATION_SERVICE)) {
return getHostContext().getSystemService(name);
}
return super.getSystemService(name);
}
@Override
public Resources getResources() {
return this.mPlugin.getResources();
}
@Override
public AssetManager getAssets() {
return this.mPlugin.getAssets();
}
@Override
public Resources.Theme getTheme() {
return this.mPlugin.getTheme();
}
@Override
public void startActivity(Intent intent) {
ComponentsHandler componentsHandler = mPlugin.getPluginManager().getComponentsHandler();
componentsHandler.transformIntentToExplicitAsNeeded(intent);
super.startActivity(intent);
}
}
Activity的资源替换
com.didi.virtualapk.internal.VAInstrumentation
public void callActivityOnCreate(Activity activity, Bundle icicle) {
injectActivity(activity);
mBase.callActivityOnCreate(activity, icicle);
}
protected void injectActivity(Activity activity) {
final Intent intent = activity.getIntent();
if (PluginUtil.isIntentFromPlugin(intent)) {
Context base = activity.getBaseContext();
try {
LoadedPlugin plugin = this.mPluginManager.getLoadedPlugin(intent);
Reflector.with(base).field("mResources").set(plugin.getResources());
Reflector reflector = Reflector.with(activity);
reflector.field("mBase").set(plugin.createPluginContext(activity.getBaseContext()));
reflector.field("mApplication").set(plugin.getApplication());
// set screenOrientation
ActivityInfo activityInfo = plugin.getActivityInfo(PluginUtil.getComponent(intent));
if (activityInfo.screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
activity.setRequestedOrientation(activityInfo.screenOrientation);
}
// for native activity
ComponentName component = PluginUtil.getComponent(intent);
Intent wrapperIntent = new Intent(intent);
wrapperIntent.setClassName(component.getPackageName(), component.getClassName());
activity.setIntent(wrapperIntent);
} catch (Exception e) {
Log.w(TAG, e);
}
}
}
Service的资源替换
com.didi.virtualapk.delegate.ActivityManagerProxy#wrapperTargetIntent
protected Intent wrapperTargetIntent(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
// fill in service with ComponentName
target.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));
String pluginLocation = mPluginManager.getLoadedPlugin(target.getComponent()).getLocation();
// start delegate service to run plugin service inside
boolean local = PluginUtil.isLocalService(serviceInfo);
Class<? extends Service> delegate = local ? LocalService.class : RemoteService.class;
Intent intent = new Intent();
intent.setClass(mPluginManager.getHostContext(), delegate);
intent.putExtra(RemoteService.EXTRA_TARGET, target);
intent.putExtra(RemoteService.EXTRA_COMMAND, command);
intent.putExtra(RemoteService.EXTRA_PLUGIN_LOCATION, pluginLocation);
if (extras != null) {
intent.putExtras(extras);
}
return intent;
}
public int onStartCommand(Intent intent, int flags, int startId) {
...
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);
} else {
try {
service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();
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);
service.onCreate();
this.mPluginManager.getComponentsHandler().rememberService(component, service);
} catch (Throwable t) {
return START_STICKY;
}
}
...
}
Application的资源替换
protected Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) throws Exception {
if (null != this.mApplication) {
return this.mApplication;
}
String appClass = this.mPackage.applicationInfo.className;
if (forceDefaultAppClass || null == appClass) {
appClass = "android.app.Application";
}
this.mApplication = instrumentation.newApplication(this.mClassLoader, appClass, this.getPluginContext());
// inject activityLifecycleCallbacks of the host application
mApplication.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksProxy());
instrumentation.callApplicationOnCreate(this.mApplication);
return this.mApplication;
}
ContentProvider的资源替换
private ContentProvider getContentProvider(final Uri uri) {
final PluginManager pluginManager = PluginManager.getInstance(getContext());
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
final String auth = pluginUri.getAuthority();
ContentProvider cachedProvider = sCachedProviders.get(auth);
if (cachedProvider != null) {
return cachedProvider;
}
synchronized (sCachedProviders) {
LoadedPlugin plugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG));
if (plugin == null) {
try {
pluginManager.loadPlugin(new File(uri.getQueryParameter(KEY_PLUGIN)));
} catch (Exception e) {
Log.w(TAG, e);
}
}
final ProviderInfo providerInfo = pluginManager.resolveContentProvider(auth, 0);
if (providerInfo != null) {
RunUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
LoadedPlugin loadedPlugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG));
ContentProvider contentProvider = (ContentProvider) Class.forName(providerInfo.name).newInstance();
contentProvider.attachInfo(loadedPlugin.getPluginContext(), providerInfo);
sCachedProviders.put(auth, contentProvider);
} catch (Exception e) {
Log.w(TAG, e);
}
}
}, true);
return sCachedProviders.get(auth);
}
}
return null;
}
网友评论