The PathClassLoader is used to load classes in the three-party package, such as the classes in the clain-V4 or clain-v7 package. The BootClassLoader loads classes in the SDK

HookAMS and Handler start the plug-in Activity

HookAMS

Note that an Activity needs to be found in the AMS manifest file. If it cannot be found, it cannot be started. An Activity in a plug-in APK cannot be registered in the manifest file in the host APK, so you need to trick AMS into starting the Activity in the plug-in. This process is mainly to find a few Hook points!! Hook in the use of the process to find a good access to difficult to change variables.



In order to cheat AMS, you need to know what is used to start an Activity. In order to cheat AMS, you need to modify the Intent. Then you need to find the point where the Intent that starts the plug-in should be replaced with the Intent that pits the Activity in the manifest file. By looking at the source code of the Activity launch process, you can find that HookAMS is a better Hook point. The Hook position is the execStartActivity method in Instrumentation. The specific position is shown belowThis is the final location of the Hook. To trick AMS, simply hijack the startActivity method in AMS and replace the Intent before executing it. This prevents exceptions that the Activity cannot find. The specific Hook code is as follows:

/ * * * because when startActivity use ActivityManager. GetService () the method to obtain IActivityManager object, This object * in IActivityManagerSingleton mInstance inside, Fun hookAMS() {get the original IActivityManager object */ hookAMS() { / / get the ActivityManager IActivityManagerSingleton val activityManagerClazz = ActivityManager: : class. Java val singletonFiled  = activityManagerClazz.getDeclaredField("IActivityManagerSingleton") singletonFiled.isAccessible = true val ActivityManagerSingleton = singletonFiled. Get (null) // Obtain mInstance of Singleton val singletonClazz = Class.forName("android.util.Singleton") val mInstanceField = singletonClazz.getDeclaredField("mInstance") mInstanceField.isAccessible = true val mInstance = mInstanceField.get(activityManagerSingleton) / / get IActivityManager Class object val clazzIActivityManager = Class. Class.forname (" android. App. IActivityManager ") val proxyIActivityManager = Proxy.newProxyInstance( Thread.currentThread().contextClassLoader, ArrayOf (clazzIActivityManager)) {proxy, method, args -> Invoke (mInstance, * args)} / / replace system obtain IActivityManager object for the proxy object singletonFiled. Set (activityManagerSingleton, proxyIActivityManager) }Copy the code

The first step of the plug-in startup code is now almost complete. However, the above code can only run on Android phones under R (10). If the version is greater than R, it cannot replace the Intent in startActivity. Because Google natively shields the Singleton attribute in ActivityTaskManager from external reflection. Need to use other ways to implement the plug-in Activity so far I have not realized the hope that you have any good scheme to provide.

HookHandler

If you try to start the Activity in the plug-in, it will not raise an exception because it was not registered in the manifest file, but will still not be able to start the Activity in the plug-in. In addition, you need to replace the occupied Activity with the plug-in Activity to start the plug-in Activity. If you look at the system Activity processing flow, you will find that the final creation process of the Activity is handled by the Handler in the ActivityThread. So you can implement pit substitution with the Handler in HookActivityThread. The following code

Fun hookHandler () {/ / to get ActivityThread object val activityThreadClazz = Class. Class.forname (" android. App. ActivityThread ") val sCurrentActivityThreadField = activityThreadClazz.getDeclaredField("sCurrentActivityThread") sCurrentActivityThreadField.isAccessible = true val sCurrentActivityThread = sCurrentActivityThreadField.get(null) / / get the Handler object ActivityThread val mHField = activityThreadClazz. GetDeclaredField (" mH ") mHField. IsAccessible = true val MH = MHfield. get(sCurrentActivityThread) // Create a HookHandler object val HookHandler = HookHandler(mH as Android.os.handler) // Get Handler's CallBack object val handlerClazz = class.forname (" android.os.handler ") val mCallBackField = handlerClazz.getDeclaredField("mCallback") mCallBackField.isAccessible = true mCallBackField.set(mH,hookHandler) } class  HookHandler(handler:android.os.Handler):android.os.Handler.Callback{ val mHandler = handler val LAUNCH_ACTIVITY = 100 override fun handleMessage(p0: Message?) : Boolean { if(p0.what == LAUNCH_ACTIVITY){ val intentField = p0? .obj? .javaClass? .getDeclaredField("intent") val intent: Intent = intentField? .get(p0.obj) as Intent val pluginIntent = intent.getParcelableExtra<Intent>("TAG") intent.setComponent(pluginIntent.component) } Log.e("HookAMS","HookHandler handleMessage run ${p0?.what}") mHandler.handleMessage(p0) return true } }Copy the code

In this way, you can restore the Intent of the plug-in Activity, and then start the plug-in Activity.