The article directories
Android plug-ins series of articles
- Dex file in “plug-in”
- Class loader analysis
- Get the class loader
- Parent delegation mechanism
I. Dex file in “plug-in”
At present, large Android projects are basically componentized + plug-in development, and the project architecture is componentized framework. Some Module modules that are frequently modified are set as “plug-in” modules and compiled into independent APK files. Deploy as “plug-ins” to be called by “host” modules;
When the application is running, click to start the interface in APK of a “plug-in”, first download the corresponding APK file of the plug-in, put it in the built-in storage area, and then load the APK file, mainly the Class bytecode data in the DEX file of the Class loader;
In this case, the App Module is the “host” Module and the Plugin Module is the “plug-in” Module, both of which are apps of the “Phone & Tablet Module” type.
The pluginactivity.class bytecode file can be found in the “classes.dex” file. After you find the module, you can load it into the application and jump to the interface.
Class loader analysis
Class loading is to load bytecode data into the Java VIRTUAL machine stack in the runtime data area of the Java virtual machine through the class loading engine.
ClassLoader loading involves parental delegation. The top ClassLoader in Android is BootClassLoader, followed by PathClassLoader. PathClassLoader is basically the same as DexClassLoader;
DexClassLoader inherits BaseDexClassLoader without any logic. It just calls the constructor of BaseDexClassLoader for initialization.
public class DexClassLoader extends BaseDexClassLoader { public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); }}Copy the code
Source address: / libcore/dalvik/SRC/main/Java/dalvik/system/DexClassLoader. Java
PathClassLoader also inherits BaseDexClassLoader, which defines the same constructor as DexClassLoader;
public class PathClassLoader extends BaseDexClassLoader { public PathClassLoader(String dexPath, ClassLoader parent) { super(dexPath, null, null, parent); } public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); }}Copy the code
Source address: / libcore/dalvik/SRC/main/Java/dalvik/system/PathClassLoader. Java
Therefore, the functions of PathClassLoader and DexClassLoader are basically the same. Both can be used to load Dex files.
PathClassLoader is officially used by Google. DexClassLoader is provided for developers. Use DexClassLoader as much as possible when using classloader.
Get the class loader
Call the following method in the Activity to get different levels of ClassLoader;
getClassLoader()
getClassLoader().getParent()
getClassLoader().getParent().getParent()
Copy the code
Code examples:
package kim.hsl.plugin; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, "getClassLoader() : " + getClassLoader()); Log.i(TAG, "getClassLoader().getParent() : " + getClassLoader().getParent()); Log.i(TAG, "getClassLoader().getParent().getParent() : " + getClassLoader().getParent().getParent()); }}Copy the code
Print result:
I/MainActivity: getClassLoader() : dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/kim.hsl.plugin-_uowA-lCCTOuGQrqkuXOeg==/base.apk"],nativeLibraryDirectories=[/data/app/kim.hsl.plugin-_uowA-l CCTOuGQrqkuXOeg==/lib/arm64, /system/lib64]]] I/MainActivity: getClassLoader().getParent() : java.lang.BootClassLoader@fc7ec45 I/MainActivity: getClassLoader().getParent().getParent() : nullCopy the code
Results analysis:
Call the getClassLoader() method directly in the Activity to get the PathClassLoader,
Call getClassLoader().getparent () to get the BootClassLoader;
In addition, there is no higher ClassLoader, getClassLoader().getparent ().getparent ();
The parent class of BaseDexClassLoader is ClassLoader. ClassLoader is an abstract class. BootClassLoader is not involved in inheritance.
In ClassLoader, there is a ClassLoader parent field, which is passed in by the constructor. GetClassLoader ().getparent () is not a ClassLoader. Instead, the specified parent class references the ClassLoader parent field,
public class BaseDexClassLoader extends ClassLoader {
}
Copy the code
Source reference: / libcore/dalvik/SRC/main/Java/dalvik/system/BaseDexClassLoader. Java
public abstract class ClassLoader { // The parent class loader for delegation // Note: VM hardcoded the offset of this field, thus all new fields // must be added *after* it. private final ClassLoader parent; private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; }}Copy the code
Source reference: / libcore/ojluni/SRC/main/Java/Java/lang/this Java
4. Parent delegation mechanism
Class loader level: from high to low: BootClassLoader -> PathClassLoader/DexClassLoader;
Parent delegate mechanism:
MyClassLoader (); Student (); parent (); The class asks its parent PathClassLoader if the Student object has been loaded, and if not;
The BootClassLoader continues to ask the parent class whether the Student object has been loaded. If it has been loaded, the BootClassLoader returns the class object. If it has not been loaded, the BootClassLoader starts to delegate the subclass to load.
BootClassLoader assigns the subclass PathClassLoader to load the Student object, and the PathClassLoader assigns MyClassLoader to load the Student object, MyClassLoader finds that it has no subclasses and starts class loading Student;
In the loadClass method of ClassLoader, the loadClass method is called first
// First, check if the class has already been loaded Class<? > c = findLoadedClass(name);Copy the code
If not, check whether the parent class is empty. If not, call the loadClass method of the parent class.
if (parent ! = null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); }Copy the code
The parent class also calls the loadClass method of the parent class. If the call reaches the top level and there is no parent class, the load starts.
ClassLoader ClassLoader
public abstract class ClassLoader { protected Class<? > loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class<? > c = findLoadedClass(name); if (c == null) { try { if (parent ! = null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. c = findClass(name); } } return c; }}Copy the code
Source reference: / libcore/ojluni/SRC/main/Java/Java/lang/this Java