VirtualAPK是由滴滴公司發佈的一款插件化的Android APK框架。 其使用的也是動態代理的方式實現的。請看下面官方給的框架圖: java
從圖中能夠發現,在Core和Manager之間添加了一層代理。android
public class VAApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); long start = System.currentTimeMillis(); PluginManager.getInstance(base).init(); Log.d("ryg", "use time:" + (System.currentTimeMillis() - start)); } @Override public void onCreate() { super.onCreate(); } }
首先宿主APK重寫了Application,而且重寫了attachBaseContext方法,此方法是在onCreate以前調用的。在attachBaseContext裏面初始化了PluginManager,先看看在建立PluginManager的時候作了什麼:app
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(); }
剛開始是對mApplication和mContext的賦值,這個就很少說了。咱們主要說說hookCurrentProcess()
的實現:框架
protected void hookCurrentProcess() { hookInstrumentationAndHandler(); hookSystemServices(); hookDataBindingUtil(); }
這裏調用了三個方法,你們該猜到這是代理初始化的地方,先看hookInstrumentationAndHandler()
的實現:ide
protected void hookInstrumentationAndHandler() { try { ActivityThread activityThread = ActivityThread.currentActivityThread(); Instrumentation baseInstrumentation = activityThread.getInstrumentation(); 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); } }
這裏是先獲取了ActivityThread
的Instrumenttation
的實例,而後建立本身的VAInstrumentation
,並將系統的Instrumenttation
做爲本身的變量,而後再把本身的VAInstrumentation
設置到系統裏面:ui
Reflector.with(activityThread).field("mInstrumentation").set(instrumentation);
Reflector.with(mainHandler).field("mCallback").set(instrumentation);
VAInstrumentation
已經繼承了系統的Instrumentation
以及Handler.Callback
,並在繼承的類裏面重寫了插件apk須要的方法:this
@Override public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) { injectIntent(intent); return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode); } @Override public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { injectIntent(intent); return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode, options); } @Override public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options) { injectIntent(intent); return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode, options); } @Override public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String target, Intent intent, int requestCode, Bundle options) { injectIntent(intent); return mBase.execStartActivity(who, contextThread, token, target, intent, requestCode, options); } protected void injectIntent(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); } }
相比系統的調用多了injectIntent(Intent intent)
的調用,這個方法主要是尋找插件裏面相應的component,並將intent填寫完整。 這一就能夠完成插件裏面組件的無感知調用。插件
下面再看對service的代理:代理
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); } }
方法其實和上面是相似的,首先獲取系統的ActivityManager
,而後再將代理的activityManagerProxy
注入到系統裏面:code
Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);
這樣要是再啓動組件的時候就會調用到咱們的代理類裏面,代理類裏面能夠去尋找插件裏面的類。以·startService
爲例:
protected Object startService(Object proxy, Method method, Object[] args) throws Throwable { IApplicationThread appThread = (IApplicationThread) args[0]; Intent target = (Intent) args[1]; ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0); if (null == resolveInfo || null == resolveInfo.serviceInfo) { // is host service return method.invoke(this.mActivityManager, args); } return startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE); }
再看startDelegateServiceForTarget
的實現:
protected ComponentName startDelegateServiceForTarget(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) { Intent wrapperIntent = wrapperTargetIntent(target, serviceInfo, extras, command); return mPluginManager.getHostContext().startService(wrapperIntent); }
這個會啓動插件裏面的Service。
最後一個是數據的綁定,主要對插件裏面資源的注入:
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); } } }
將代理的DataBinderMapperProxy
設置到系統裏面:
reflector.set(callback);
經過主動的將插件的資源路徑插入到系統的map裏面:
@Override public void onAddedLoadedPlugin(LoadedPlugin plugin) { try { String clsName = "android.databinding.DataBinderMapper_" + plugin.getPackageName().replace('.', '_'); Log.d(TAG, "Try to find the class: " + clsName); Class cls = Class.forName(clsName, true, plugin.getClassLoader()); Object obj = cls.newInstance(); addMapper((DataBinderMapper) obj); } catch (Exception e) { Log.w(TAG, e); } }
在獲取的過程當中就能夠從這裏取到資源信息:
@Override public int getLayoutId(String tag) { int layoutId; for (DataBinderMapper mapper : getCache()) { layoutId = mapper.getLayoutId(tag); if (layoutId != 0) { return layoutId; } } return 0; }
插件的加載是在主Activity啓動的時候作了加載:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = (TextView)findViewById(R.id.textView); String cpuArch; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { cpuArch = Build.SUPPORTED_ABIS[0]; } else { cpuArch = Build.CPU_ABI; } textView.setText(cpuArch); Log.d("ryg", "onCreate cpu arch is "+ cpuArch); Log.d("ryg", "onCreate classloader is "+ getClassLoader()); if (hasPermission()) { Log.d(TAG,"loadPlugin"); this.loadPlugin(this); } else { requestPermission(); } }
private void loadPlugin(Context base) { if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { Toast.makeText(this, "sdcard was NOT MOUNTED!", Toast.LENGTH_SHORT).show(); } PluginManager pluginManager = PluginManager.getInstance(base); File apk = new File(Environment.getExternalStorageDirectory(), "Test.apk"); if (apk.exists()) { try { pluginManager.loadPlugin(apk); Log.i(TAG, "Loaded plugin from apk: " + apk); } catch (Exception e) { e.printStackTrace(); } } else { try { File file = new File(base.getFilesDir(), "Test.apk"); java.io.InputStream inputStream = base.getAssets().open("Test.apk", 2); java.io.FileOutputStream outputStream = new java.io.FileOutputStream(file); byte[] buf = new byte[1024]; int len; while ((len = inputStream.read(buf)) > 0) { outputStream.write(buf, 0, len); } outputStream.close(); inputStream.close(); pluginManager.loadPlugin(file); Log.i(TAG, "Loaded plugin from assets: " + file); } catch (Exception e) { e.printStackTrace(); } } }
從上面兩段代碼能夠看出,從外部存儲器加載了一個叫Test.apk
的文件。這個就是插件的apk,這個APK是一個完成的APK,能夠本身獨立運行。可是在這裏它並無安裝,只是存放在外部存儲器上。