- VirtualApk的Activity启动,是通过动态代理hook Activity启动流程,动态替换为插桩的activity,来绕过系统对插件中未注册在manifest的activity的检查。
- 在使用VirtualApk时,首先要在Application的attachBaseContext(Context base)方法中调用 PluginManager.getInstance(base).init();通过查看源码,我们可以看到,最终会调用PluginManger的构造方法。
PluginManager
- PluginManger中调用了两个方法,createComponentsHandler()创建ComponentsHandler对象 和hookCurrentProcess();
/**
* 1.此方法存储App 的 Context
* 2.调用了 createComponentsHandler()和hookCurrentProcess()
* @param context
*/
protected PluginManager(Context context) {
if (context instanceof Application) {
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();
hookCurrentProcess();
}
- createComponentsHandler()
public ComponentsHandler(PluginManager pluginManager) {
mPluginManager = pluginManager;
mContext = pluginManager.getHostContext();
}
- hookCurrentProcess() 调用了三个hook方法。就是这几个hook起到了动态替换activity来绕过系统检查,启动插件中的activity。
/**
* 调用了三个hook方法。初始化hook
*/
protected void hookCurrentProcess() {
hookInstrumentationAndHandler();
hookSystemServices();
hookDataBindingUtil();
}
- hookInstrumentationAndHandler()
- 拦截Instrumentation 和 Handler的CallBack方法。
protected void hookInstrumentationAndHandler() {
try {
ActivityThread activityThread = ActivityThread.currentActivityThread();
Instrumentation baseInstrumentation = activityThread.getInstrumentation();
// if (baseInstrumentation.getClass().getName().contains("lbe")) {
// // reject executing in paralell space, for example, lbe.
// System.exit(0);
// }
final VAInstrumentation instrumentation = createInstrumentation(baseInstrumentation);
Reflector.with(activityThread).field("mInstrumentation").set(instrumentation);
Handler mainHandler = Reflector.with(activityThread).method("getHandler").call();
Reflector.with(mainHandler).field("mCallback").set(instrumentation);
this.mInstrumentation = instrumentation;
Log.d(TAG, "hookInstrumentationAndHandler succeed : " + mInstrumentation);
} catch (Exception e) {
Log.w(TAG, e);
}
}
- hookSystemServices();
- hookSystemServices, 动态代理ActivityManager对象,实现在ActivityManagerProxy类中,拦截startService,stopService等方法。
/** * hookSystemServices, but need to compatible with Android O in future. */ protected void hookSystemServices() { try { Singleton<IActivityManager> defaultSingleton; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { defaultSingleton = Reflector.on(ActivityManager.class).field("IActivityManagerSingleton").get(); } else { defaultSingleton = Reflector.on(ActivityManagerNative.class).field("gDefault").get(); } IActivityManager origin = defaultSingleton.get(); IActivityManager activityManagerProxy = (IActivityManager) Proxy.newProxyInstance( mContext.getClassLoader() , new Class[]{IActivityManager.class} , createActivityManagerProxy(origin)); // Hook IActivityManager from ActivityManagerNative Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy); if (defaultSingleton.get() == activityManagerProxy) { this.mActivityManager = activityManagerProxy; Log.d(TAG, "hookSystemServices succeed : " + mActivityManager); } } catch (Exception e) { Log.w(TAG, e); } }
- hookDataBindingUtil();
protected void hookDataBindingUtil() {
Reflector.QuietReflector reflector = Reflector.QuietReflector.on("android.databinding.DataBindingUtil").field("sMapper");
Object old = reflector.get();
if (old != null) {
try {
Callback callback = Reflector.on("android.databinding.DataBinderMapperProxy").constructor().newInstance();
reflector.set(callback);
addCallback(callback);
Log.d(TAG, "hookDataBindingUtil succeed : " + callback);
} catch (Reflector.ReflectedException e) {
Log.w(TAG, e);
}
}
}
VAInstrumentation
frameWork通过Instrumentation来创建启动Activity,这个动态代理类的作用就是在启动的时候,拦截特定的方法,启动插件中的activity。
- injectIntent(Intent intent)方法
protected void injectIntent(Intent intent) {
//将intent由隐式转换为显示。
mPluginManager.getComponentsHandler().transformIntentToExplicitAsNeeded(intent);
// null component is an implicitly intent
if (intent.getComponent() != null) {
Log.i(TAG, String.format("execStartActivity[%s : %s]", intent.getComponent().getPackageName(), intent.getComponent().getClassName()));
// resolve intent with Stub Activity if needed
this.mPluginManager.getComponentsHandler().markIntentIfNeeded(intent);
}
}
- this.mPluginManager.getComponentsHandler().markIntentIfNeeded(intent); 如果是插件,将信息存储在Intent中。
public void markIntentIfNeeded(Intent intent) {
if (intent.getComponent() == null) {
return;
}
String targetPackageName = intent.getComponent().getPackageName();
String targetClassName = intent.getComponent().getClassName();
// search map and return specific launchmode stub activity
if (!targetPackageName.equals(mContext.getPackageName()) && mPluginManager.getLoadedPlugin(targetPackageName) != null) {
intent.putExtra(Constants.KEY_IS_PLUGIN, true);
intent.putExtra(Constants.KEY_TARGET_PACKAGE, targetPackageName);
intent.putExtra(Constants.KEY_TARGET_ACTIVITY, targetClassName);
dispatchStubActivity(intent);
}
}
- 分发宿主中插桩的Activity,并根据插件中Activity的launchMode和Theme,来选取合适的StubActivity,并将主题等信息设置到stubActivity中。
private void dispatchStubActivity(Intent intent) {
ComponentName component = intent.getComponent();
String targetClassName = intent.getComponent().getClassName();
LoadedPlugin loadedPlugin = mPluginManager.getLoadedPlugin(intent);
ActivityInfo info = loadedPlugin.getActivityInfo(component);
if (info == null) {
throw new RuntimeException("can not find " + component);
}
int launchMode = info.launchMode;
Resources.Theme themeObj = loadedPlugin.getResources().newTheme();
themeObj.applyStyle(info.theme, true);
String stubActivity = mStubActivityInfo.getStubActivity(targetClassName, launchMode, themeObj);
Log.i(TAG, String.format("dispatchStubActivity,[%s -> %s]", targetClassName, stubActivity));
intent.setClassName(mContext, stubActivity);
}
- newActivity()用于创建一个Activity
- public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {...}
- 先用当前的classloader去加载Activity,如果catch到ClassNotFoundException,则说明宿主Apk中不包含当前要启动的这个class,这时就用插件中的classLoader去加载这个class。
- 用插件的classloader去加载时,如果根据刚才injectIntent方法中的component找不到plugin且是debug状态,则抛出异常ActivityNotFoundException("error intent: " + intent.toURI());如果不是debug,则启动StubActivity。
- 最后将activity加入到list集合中。
@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
try {
cl.loadClass(className);
Log.i(TAG, String.format("newActivity[%s]", className));
} catch (ClassNotFoundException e) {
ComponentName component = PluginUtil.getComponent(intent);
if (component == null) {
return newActivity(mBase.newActivity(cl, className, intent));
}
String targetClassName = component.getClassName();
Log.i(TAG, String.format("newActivity[%s : %s/%s]", className, component.getPackageName(), targetClassName));
LoadedPlugin plugin = this.mPluginManager.getLoadedPlugin(component);
if (plugin == null) {
// Not found then goto stub activity.
boolean debuggable = false;
try {
Context context = this.mPluginManager.getHostContext();
debuggable = (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
} catch (Throwable ex) {
}
if (debuggable) {
throw new ActivityNotFoundException("error intent: " + intent.toURI());
}
Log.i(TAG, "Not found. starting the stub activity: " + StubActivity.class);
return newActivity(mBase.newActivity(cl, StubActivity.class.getName(), intent));
}
Activity activity = mBase.newActivity(plugin.getClassLoader(), targetClassName, intent);
activity.setIntent(intent);
// for 4.1+
Reflector.QuietReflector.with(activity).field("mResources").set(plugin.getResources());
return newActivity(activity);
}
return newActivity(mBase.newActivity(cl, className, intent));
}
- callActivityOnCreate()方法,在调用原本的callActivityOnCreate方法时,先调用了 injectActivity(activity);方法。
@Override
public void callActivityOnCreate(Activity activity, Bundle icicle) {
injectActivity(activity);
mBase.callActivityOnCreate(activity, icicle);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
injectActivity(activity);
mBase.callActivityOnCreate(activity, icicle, persistentState);
}
- injectActivity(activity);方法
- 取出Intent原本的想启动的activity信息Component,创建新的Intent wrapperIntent,设置给activity对象。
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);
}
}
}
- 在启动activcity返回时是使用Handler发送消息到主队列,因为之前已经通过反射给handler设置了callback对象,查看handler源码。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
//先执行callback的handleMessage(msg)方法。
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- VAInstrumentation的callback的具体实现
- 可以看到,方法始终返回false,所以上面handler中的dispatchMessage(msg)在msg没有callback的情况下,始终会调用 handleMessage(msg)去处理消息。
- 而handler的callback则在这里替换了activity主题。
@Override
public boolean handleMessage(Message msg) {
if (msg.what == LAUNCH_ACTIVITY) {
// ActivityClientRecord r
Object r = msg.obj;
try {
Reflector reflector = Reflector.with(r);
Intent intent = reflector.field("intent").get();
intent.setExtrasClassLoader(mPluginManager.getHostContext().getClassLoader());
ActivityInfo activityInfo = reflector.field("activityInfo").get();
if (PluginUtil.isIntentFromPlugin(intent)) {
int theme = PluginUtil.getTheme(mPluginManager.getHostContext(), intent);
if (theme != 0) {
Log.i(TAG, "resolve theme, current theme:" + activityInfo.theme + " after :0x" + Integer.toHexString(theme));
activityInfo.theme = theme;
}
}
} catch (Exception e) {
Log.w(TAG, e);
}
}
return false;
}
总结
上面这些是VA框架,对于Activity启动的一部分内容。实现主要是通过动态代理技术,在Activity启动过程中,将插件信息存储在Intent中,而传递给系统的是宿主中注册StubActivity,在系统返回时,通过handler的callback,取出Inent中存储的插件信息,创建新的Intent设置给Intent,再去启动。达到启动插件中Activity的目的。
网友评论