1, What is hot repair
Hot fix is simply "patching". For example, when your company launches an app, users respond that there are major bug s and need to be repaired urgently. If according to
The usual practice is to fix the bug, test, repackage and release. The problem brought by this is high cost and low efficiency. So, heat
Generally, the Bug free code is downloaded from the Internet through a preset interface to replace the Bug free code. It'll save you a lot of trouble
The customer experience is good.
2, Principle of thermal repair
1.Android class loading mechanism
There are two types of class loaders for Android, PathClassLoader and DexClassLoader, both of which inherit from BaseDexClassLoader
The PathClassLoader code is located in libcore\dalvik\src\main\java\dalvik\system\PathClassLoader.java
The DexClassLoader code is located in libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java
The BaseDexClassLoader code is located in libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java
PathClassLoader
Used to load system classes and application classes
DexClassLoader
It is used to load jar, apk and DEX files. Loading jar and apk is also the final extraction of DEX files for loading
2. Thermal repair mechanism
Take a look at the PathClassLoader code
public class PathClassLoader extends BaseDexClassLoader { public PathClassLoader(String dexPath, ClassLoader parent) { super(dexPath, null, null, parent); } public PathClassLoader(String dexPath, String libraryPath, ClassLoader parent) { super(dexPath, null, libraryPath, parent); } }
DexClassLoader code
public class DexClassLoader extends BaseDexClassLoader { public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) { super(dexPath, new File(optimizedDirectory), libraryPath, parent); } }
Two classloaders are just two or three lines of code, just calling the constructor of the parent class
public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) { super(parent); this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { List<Throwable> suppressedExceptions = new ArrayList<Throwable>(); Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; }
Create an instance of the DexPathList class in the BaseDexClassLoader constructor, and the DexPathList constructor will create a dexElements array
public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory) { ... this.definingContext = definingContext; ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>(); //Create an array this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions); ... }
Then BaseDexClassLoader rewrites the findClass method, calls pathList.findClass, and jumps to the DexPathList class
/* package */final class DexPathList { ... public Class findClass(String name, List<Throwable> suppressed) { //Traverse the array for (Element element : dexElements) { //Initialize DexFile DexFile dex = element.dexFile; if (dex != null) { //Call the loadClassBinaryName method of the DexFile Class to return the Class instance Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed); if (clazz != null) { return clazz; } } } return null; } ... }
It will traverse the array and initialize DexFile. If DexFile is not empty, call the loadClassBinaryName method of DexFile Class to return the Class instance
To sum up, ClassLoader will traverse the array and then load the dex file in the array
After loading the correct class, ClassLoader will not load the class with Bug. We can put the correct class in the Dex file and put the Dex file in front of the dexElements array
Here is a problem. Please refer to the introduction of Android App hot patch dynamic repair technology of QQ space team
To sum up: if the classes (direct reference relationship) of the referent and the referenced are in the same Dex, the referenced class will be marked with class when the virtual machine is started_ Isprevified flag, so that the referenced class cannot be hot repaired
Then we must prevent the referenced class from being labeled class_ Isprevified flag. The method of QQ space is to insert a piece of code into all constructors that refer to this class, and the code refers to other classes
3, Examples of thermal repair
I use the open source hot repair framework of Alibaba and fix hot repair framework address
In fact, its principle is to load class files dynamically, and then call reflection to complete the repair.
AndFix is the abbreviation of "Android hot fix". It supports Android 2.3 to 6.0, and supports devices with arm and X86 system architecture. Perfect support for Dalvik and ART Runtime. The patch file for AndFix is a file ending in. apatch.
This is a Demo written in eclipse
1. Extract AndFix into the form of library dependency
2. Create a new AndFixDemo project and rely on the library of AndFix
2.1
Create a new MyApplication inheritance Application
public class MyApplication extends Application {
private static final String TAG = "MyApplication"; /** * apatch file */ private static final String APATCH_PATH = "/Dennis.apatch"; private PatchManager mPatchManager; @Override public void onCreate() { super.onCreate(); // initialization mPatchManager = new PatchManager(this); mPatchManager.init("1.0"); // Version number // Load apatch mPatchManager.loadPatch(); //Directory of apatch files String patchFileString = Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH; File apatchPath = new File(patchFileString); if (apatchPath.exists()) { Log.i(TAG, "Patch file exists"); try { //Add apatch file mPatchManager.addPatch(patchFileString); } catch (IOException e) { Log.i(TAG, "Patching error"); e.printStackTrace(); } } else { Log.i(TAG, "Patch file does not exist"); } } }
In fact, the apatch file must be downloaded through the network interface. I put it in the root directory of the SD card for the convenience of demonstration
2.2
Use a button to pop up toast in MainActivity. The code with Bug is above and the revised code is below
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-whdo4cyt-1635561199273)( https://upload-images.jianshu.io/upload_images/27187314-0b364261fbd61bad.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/1240)]
Package into Bug.apk and NoBug.apk respectively**
2.3
Then you need to use a patch generation tool apkpatch
decompression
_MACOSX is for OSX system
. bat is for window system
I use. bat
Put the previously generated Bug.apk, NoBug.apk, and the keystore file used for packaging into the apkpatch-1.0.3 directory
Open cmd, enter apkpatch-1.0.3 directory, and enter the following command
apkpatch.bat -f NoBug.apk -t Bug.apk -o Dennis -k keystore -p 111111 -a 111111 -e 111111
The meaning of each parameter is as follows
-f new version of apk
-t old version of apk
-o folder for outputting apatch files, which can be named at will
-k packaged keystore file name
-Password for p keystore
-a keystore user alias
-e keystore password for user alias
If add modified... Appears, it means success. Go to apkpatch-1.0.3 directory and add Dennis directory
I changed this file to Dennis.apatch
2.4
Install Bug.apk on the mobile phone and run it
Then put Dennis.apatch in the root directory of the SD card, exit the app, enter again, and press the button
Finally, the Demo and apk and apatch files are attached Open link
This article is transferred from https://blog.csdn.net/qq_31530015/article/details/51785228 , in case of infringement, please contact to delete.
Relevant video recommendations:
Android performance optimization learning [2]: APP startup speed optimization
[Android advanced system learning]: bytecode stake insertion technology to realize automation, time-consuming recording bilibili bili
Android performance optimization learning [2]: APP startup speed optimization
[Android interview topic]: the interview was asked about interprocess communication, but you don't even know what Binder is? Beep beep bilibili bili
BAT interview skills - what do you know about network programming for Android interview? Beep beep bilibili bili