First, preface
Android in the Heat repair framework is more, each company has a corresponding program and framework, such as Ali's Andfix framework, about this framework in the previous article has been explained in detail, do not know the students can click here: Andfix Heat Repair Framework principle analysis. This article continues to look at another hot fix framework, the robust framework developed by the American team. There is already a detailed explanation of the framework on the Internet, and there are specific uses. However, he does not open source, so this article briefly introduced his principle, a case to demonstrate the role of the framework, but the point is that we code their own framework to implement the mechanism, so that its "closed source" into "open".
second, the principle of analysis
About the hot repair technology point, in fact, although each has a corresponding framework, but the core points are inseparable from the dynamic loading mechanism. With the dynamic loading mechanism, and then the specific fix solution problem, for the robust repair program is relatively simple. Here's a brief look at his general principles:
The robust plugin automatically inserts a piece of code into each function of each product code during the compile and package phase , and the insertion process is completely transparent to the business development. such as State.java's GetIndex function:
public long getIndex () {
return 100;
}
It is processed into the following implementation:
public static ChangeQuickRedirect changeQuickRedirect;
public long getIndex () {
if (changeQuickRedirect! = null) {
// PatchProxy encapsulates the logic to get the current className and methodName, and finally calls the corresponding function of changeQuickRedirect inside it
if (PatchProxy.isSupport (new Object [0], this, changeQuickRedirect, false)) {
return ((Long) PatchProxy.accessDispatch (new Object [0], this, changeQuickRedirect, false)). longValue ();
}
}
return 100L;
}
It can be seen that Robust adds a static member of type ChangeQuickRedirect to each class, and the logic related to the use of changeQuickRedirect is inserted before each method. When changeQuickRedirect is not null, accessDispatch may be executed to replace the old one. Logic to achieve the purpose of fix. If you need to change the return value of the getIndex function to return 106, then the corresponding generated patch mainly contains two classes: PatchesInfoImpl.java and StatePatch.java.
PatchesInfoImpl.java:
public class PatchesInfoImpl implements PatchesInfo {
public List <PatchedClassInfo> getPatchedClassesInfo () {
List <PatchedClassInfo> patchedClassesInfos = new ArrayList <PatchedClassInfo> ();
PatchedClassInfo patchedClass = new PatchedClassInfo ("com.meituan.sample.d", StatePatch.class.getCanonicalName ());
patchedClassesInfos.add (patchedClass);
return patchedClassesInfos;
}
}
StatePatch.java:
public class StatePatch implements ChangeQuickRedirect {
@Override
public Object accessDispatch (String methodSignature, Object [] paramArrayOfObject) {
String [] signature = methodSignature.split (":");
if (TextUtils.equals (signature [1], "a")) {// long getIndex ()-> a
return 106;
}
return null;
}
@Override
public boolean isSupport (String methodSignature, Object [] paramArrayOfObject) {
String [] signature = methodSignature.split (":");
if (TextUtils.equals (signature [1], "a")) {// long getIndex ()-> a
return true;
}
return false;
}
}
After the client gets the patch.dex containing PatchesInfoImpl.java and StatePatch.java, it uses DexClassLoader to load patch.dex, and reflection gets the PatchesInfoImpl.java class. After getting it, create an object of this class. Then through the getPatchedClassesInfo function of this object, know that the class that needs to be patch is com.meituan.sample.d (com.meituan.sample.State obfuscated name), and then reflect to get com.meituan.sample.d in the current operating environment class, assign the changeQuickRedirect field to the object that comes out of the class new from StatePatch.java in patch.dex. This is the main process of patching. Through principle analysis, in fact, Robust is only using DexClassLoader normally, so it can be said that this framework has no compatibility issues.
Let's take a picture directly to see the principle structure of others (click to download and view the high-resolution image):
Let's take a look at the schematic diagram released by the Meituan team:
The principle is really simple: use the DexClassLoader to load the repair package directly, and then use the loadClass method to load the repair class, and a new object is created. You can use reflection to set the new repair object to the changeQuickRedirect static variable of the specified class. In fact, this kind of repair is similar to the static proxy of the design pattern in Java.
3. Case Practice
Knowing the general principle, let ’s use a simple case to run it and see the effect. Here we need to create three new projects and directly copy the project that developed the plug-in. The structure of the three project diagrams is as follows:
This article still uses this structure diagram as follows:
Here we mainly look at the three projects RobustHost, RobustPatch, RobustPatchImpl, RobustInsertCodeTools is a Java project for the dynamic code insertion tool that will be introduced later.
First, the repair package interface project RobustPatch
This project is relatively simple. Most of them are interface definitions. There are three main classes and interfaces:
1. ChangeQuickRedirect interface
This interface is mainly an interface that each repair class in the following repair package must implement. There are two internal methods: one is to determine whether the current method supports repair, and the other is the specific repair logic.
The parameters of both methods are the same:
The first parameter is the signature of the method. The format of this signature is very simple: the full name of the class to which the method belongs: method name: whether the method is of static type, pay attention to the connection using a colon in the middle.
The second parameter is the parameter information of the method, and when analyzing the logic of dynamically inserting code behind this parameter, you will find that the operation is very troublesome, and you only get this parameter.
2. PatchesInfo interface
This interface is relatively simple, there is only one method, the user stores the specific information of all the classes to be repaired in a repair package, because there may be multiple classes to be repaired in a repair package. This interface is also needed for dynamic loading in the host project behind. Through this interface to get the specified repair class and old class information.
3. PatchedClassInfo class
This class is relatively simple. It mainly stores two fields: one is the repaired class information, and the other is the need to repair the old class information, so that this class will be used by the above interface.
Second, the repair package project
Here we have finished the repair package interface project. Let's continue to look at the repair package project:
The repair package project is relatively simple, just add the repair class directly. As you can see here, we need to repair a MoneyBean class in the host project. This class must implement the ChangeQuickRedirect interface in the repair package interface project above, and then you need to save the repair class The information and the old class information to be repaired are saved and returned in PatchesInfoImpl, and this class implements the PatchesInfo interface in the repair package interface project.
1. MoneyBeanStatePatch repair class
This class sees, implements the repair interface ChangeQuickRedirect, and then implements two specific methods.
1》 In the isSupport method, the method name is obtained from the method's signature information, and then the method that supports repair is determined. What you see here is that the two methods getMoneyValue and desc in the class to be repaired need to be repaired.
2》 In the accessDispatch method, the specific repair plan was mainly implemented. At the beginning, the method signature information was first obtained to obtain the method name, and then in determining which methods need to be repaired, the return value of the getMoneyValue method was repaired to 10000, and the desc The return value of the method was fixed as "Patch Desc".
Third, the host project RobustHost
The biggest job of the host project is to load the repair package, this need not be explained, just put it in the Application. There is nothing to say about the loading logic. Here we have a MoneyBean class:
Each method of this class is preceded by a code segment with a repair function. For example, if there is a problem with the return value of this class of methods in the online package, you can use the hot repair function at this time. Package and release the second repair package project.
Let's take a look again here is a PatchProxy class:
This class actually wraps the repair class. There is an important logic inside to get the information of the current execution method, including the class name and method name. Here is mainly obtained through the method stack information:
Then is the logic of loading the repair package in the host project:
Use DexClassLoader to load the repair package file, not much explanation. With the loader, the subsequent loading logic begins. First of all, we have to get PatchesInfoImpl class information, because this class saves repair class information. Here is a new object. Then call its method to get the belief information of the repair class, traverse the repair class information list in turn, get the repair class and the old class information to be repaired, still use reflection new to create a new object, and then set the repair class object to the static of the old class to be repaired The variable changeQuickRedirect can be used.
4. Operation effect
Well, here we have analyzed the projects involved in the Robust thermal repair framework, mainly three projects. The results of the direct operation are started below. However, we still have to come up with a repair package first, this is relatively simple, just run the repair package RobustPatchImpl project and get the apk file. The dex file is loaded in this article, so we get the classes.dex file in this apk , And then change to patch.dex and put it in the sd card directory of the device. During operation, an error may be reported:
Regarding this error, I won't explain it too much, because we have added the code of the repair package interface project to the repair package dex. Specific error causes and solutions must be found here: Android plug-in development principles. I remember it must be.
Assuming here that we have solved all the problems, run the following to see the effect:
Let's take a look at the effect before repairing:
From here, we can see that the repair method was successful.
V. Analysis of the practical cases of Meituan
However, we haven't finished our work, because the framework of Meituan is not open source, so the above case is not convincing. So in order to verify that our implementation logic is not wrong, we need to decompile the Meituan app to see what his hot repair logic looks like. Just use the Jadx tool to open the Meituan app directly:
After we open the app, we can directly search the PatchProxy class globally. Remember to check Class, otherwise there will be too much content. Then found the definition of this class:
Seeing the implementation of this class, in fact, I want to tell everyone here that the PatchProxy class in my case project is to export this class, because I am too lazy to write code. This category is not confusing.
Let's continue to look at his logic of loading code, here is a little trick: when viewing the dynamic loading logic in an application, you can search for information globally: DexClassLoader, the following results:
In fact, it is the PatchExecutor class of the US group. Click here to view directly:
See the core loading logic here, not many solutions Explanation, the code logic is very simple, roughly the same as what we have achieved. Finally, let's take a look at whether each method in the app's class has a repair code segment inserted:
Just open a class, every method in the class has this repair code before. Haha, here we are very sure, our case realization and the implementation logic of Meituan's repair framework are roughly the same.
Six, automatically insert the repair code
In fact, it is not the end here, because this article is not the intention of the Robust framework, because after reading the above principles, you find that it is not very difficult to repair the principles. And my intention is how to make every method in every class insert a piece of repair code.
Because from the above we can see that the biggest difficulty of this framework is that there must be a repair code segment before each method of each class. If not, the repair function is lost. But the question is, how can a huge project such as Meituan ensure that every developer needs to manually add this repair code when writing a method? This is impossible to constrain success. So this needs to be automated. In fact, when Meituan officially explained this framework, it mentioned the basis: "Insert code is automatically performed at compile time, and is transparent to developers." So this sentence is the most tempting to me, because I studied this framework. Therefore, due to space limitations, it cannot be explained in one article. As you can see from here, the core point of the Robust framework is not this article, but in the next article, I will take you to manually write how to automatically insert the repair code during the compilation period, without the need for developers to worry. After that article is introduced, the advantages and disadvantages of Meituan's thermal repair framework Robust will be introduced in detail.
Hereby explain
About the Robust hot repair framework of Meituan, the next article introduces the function of automatic code insertion, and will summarize the advantages and disadvantages of this framework. Again, the main point of this framework is to automatically insert code modules. Perhaps this is one reason why Meituan did not open source, of course, there are other reasons. The practical case in this article is a general realization of the Robust framework principle, but there are still many details that need to be optimized. I can also see from my three project codes that the writing is rough. Many situations are not taken into account. So if you want to perfect and optimize yourself, you can do it yourself.
Project: https://github.com/fourbrother/Robust
7. Summary
This article mainly introduces the Robust principle of Meituan ’s thermal repair framework. Because he does not have open source, we have analyzed the principles given by the official and roughly implemented a simple case. In order to verify that our case is similar to the framework logic of the Meituan app, how We decompiled the Meituan app, and after checking, we determined that the implementation logic is roughly the same as Robust's implementation, and there are no specific details. But when we realize the case, we will find that this framework has a big constraint, that is, each method of each class must be added with a piece of repair code. If this method is not added, the repair function will be lost. Of course, this code is impossible to constrain each developer to manually add during the development process. The official explanation is: it is automatically added during the project compilation stage, and is transparent to developers. So this is the focus of my analysis of this framework this time, and also the focus of the next article, how to write tools to automatically insert repair code. I feel quite guilty here. I originally wanted to explain all of this article together, but I didn't expect that the article would be much more than what was written. However, this does not affect the key articles behind you. I hope you will remain highly enthusiastic after reading this article and look forward to the next article. I am writing articles for everyone on weekends, and I hope everyone can share a lot. It is better to have a reward.
More content: click here
Pay attention to the public number, the latest technology dry goods real-time push
Sweep and add editor
Please indicate when adding: "coding beautiful" otherwise it will not be passed!
Android hot fix framework Robust principle analysis + and change the framework code from "closed source" to "open source" (Part 1)