Plugging - Class Loading

Posted by sdat1333 on Thu, 09 Jan 2020 04:55:06 +0100

Recent learning plug-in, see all kinds of brain pain, now write some notes with your own hands for future review, there are incorrect understanding, please point out

Loading classes is accomplished through the class loader ClassLoader, which has several classloaders, as follows

pathClassLoader can be understood as loading activities written by itself, such as TestActivity extends Activity, which is then printed out directly in onCreat in TestActivity as getClassLoader

pathClassLoader

DexClassLoader can be understood as loading system classes, such as those under android.app.activity

First hand-drawn process of loading a class, a little confused, let's take a look, draw according to your own understanding

The main thing here is the parental delegation mechanism. The benefit is security, which prevents duplicate loading. When loading a class first, call the loadClass method. In the loadClass method, call the findloadedclass() method first. Find it from the loaded class, return it directly, and call the loadClass method of parent if it is not found. Parent is not a parent class here, it means the parent class. In the upper class, the findloadedclass() method is called first.The findloadedclass () is still findloadedclass (), and through recursion, always finds the top BootClassLoader, which loads its findclass without findloadedclass, passes through the object pathList.findclass of DexPathList in the findclass of BaseDexClassLoader, and then enters the DexPathList, and findclass method passes through the object dexElements of Element[], and loops for fiNdclass, one dex file for each element you get

Attach the code to load the plug-in below

public class LoadPluginUtils {
    private final static String apkPath = "/sdcard/test-debug.apk";
    public static void start(Context context){
        try {
            Class<?> dexpathClass = Class.forName("dalvik.system.DexPathList");
            Field dexElements = dexpathClass.getDeclaredField("dexElements");
            dexElements.setAccessible(true);

            Class<?> basedexClass = Class.forName("dalvik.system.BaseDexClassLoader");
            Field pathList = basedexClass.getDeclaredField("pathList");
            pathList.setAccessible(true);

            /**
             * Get the element array in the plug-in
             * The first parameter is the path, the path where the plug-in is placed
             * The second parameter is the upper-level classLoader, where context.getClassLoader() is the BootClassloader
             */
            PathClassLoader pathClassLoader = new PathClassLoader(apkPath, context.getClassLoader());
            //Gets the properties of the pathList in the pathClassLoader object
            Object pluginPathList = pathList.get(pathClassLoader);
            //Gets the properties of dexElements in the pluginPathList object
            Object[] pluginElement = (Object[]) dexElements.get(pluginPathList);

            //Get the element array in the host
            PathClassLoader classLoader = (PathClassLoader) context.getClassLoader();
            Object hostPathList = pathList.get(classLoader);
            Object[] hostElement = (Object[]) dexElements.get(hostPathList);

            //Then combine the two element s into one
            Object[] arr = (Object[]) Array.newInstance(hostElement.getClass().getComponentType(), hostElement.length + pluginElement.length);
            System.arraycopy(hostElement,0,arr,0,hostElement.length);
            System.arraycopy(pluginElement,0,arr,hostElement.length,pluginElement.length);

            //The merged array is then assigned to the host dexElements property
            dexElements.set(hostPathList,arr);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Advanced items are loaded in the application.

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        LoadPluginUtils.start(this);
    }
}

Then at the place where it was called

Class<?> aClass = Class.forName("com.example.test.Test");
Method print = aClass.getMethod("print");
print.invoke(null);

Remember to put the plugin in sdcard

Topics: Mobile Android