Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 增加补丁失效功能,支持补丁修复内容发生异常时业务方可以及时监控并失效 #352

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/robust.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<catchReflectException>true</catchReflectException>
<!--<catchReflectException>false</catchReflectException>-->

<!--是否检测补丁异常,自动回滚补丁-->
<rollbackWhenException>true</rollbackWhenException>

<!--是否在补丁加上log,建议上线的时候这个开关的值为false,测试的时候为true-->
<!--<patchLog>true</patchLog>-->
<patchLog>false</patchLog>
Expand Down
45 changes: 45 additions & 0 deletions app/src/main/java/com/meituan/sample/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.util.ArrayMap;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.meituan.robust.PatchExecutor;
import com.meituan.robust.RollbackListener;
import com.meituan.robust.RollbackManager;

import java.util.Map;

/**
* For users of Robust you may only to use MainActivity or SecondActivity,other classes are used for test.<br>
* <br>
Expand All @@ -30,6 +37,8 @@ public class MainActivity extends AppCompatActivity {

TextView textView;
Button button;
private static final String TAG = "MainActivity";
private Map<String, Boolean> rollBacks;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -100,6 +109,42 @@ private void handlePermissionResult() {
}

private void runRobust() {
initRollbackListener();
new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new RobustCallBackSample()).start();
}

private void initRollbackListener() {
//TODO: 初始化时从本地取出,反序列化为map
rollBacks = new ArrayMap<>();

RollbackManager.getInstance().setRollbackListener(new RollbackListener() {
@Override
public void onRollback(String methodsId, String methodLongName, Throwable e) {
Log.e(TAG, "补丁$methodsId 发生异常,执行回滚!");
saveRollbackFlag(methodsId);
}

private void saveRollbackFlag(String methodsId) {
rollBacks.put(methodsId, true);
//TODO:存储标志位到本地
}

@Override
public boolean getRollback(String methodsId) {
boolean rollback = rollBacks.get(methodsId) != null ? rollBacks.get(methodsId) : false;
Log.d(TAG, "获取补丁$methodsId 的回滚状态为:$rollback");
return rollback;
}
});
}

/**
* 当有新补丁时清空rollbacks,标记所有位置为不回滚
*/
public void notifyPatchUpdated() {
if (rollBacks != null) {
rollBacks.clear();
}
//TODO:存储标志位到本地
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class ReadXML {
if (robust.switch.catchReflectException.text() != null && "" != robust.switch.catchReflectException.text())
Config.catchReflectException = Boolean.valueOf(robust.switch.catchReflectException.text()).booleanValue();

if (robust.switch.rollbackWhenException.text() != null && "" != robust.switch.rollbackWhenException.text())
Config.rollbackWhenException = Boolean.valueOf(robust.switch.rollbackWhenException.text()).booleanValue();

if (robust.switch.patchLog.text() != null && "" != robust.switch.patchLog.text())
Constants.isLogging = Boolean.valueOf(robust.switch.patchLog.text()).booleanValue();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

public final class Config {
public static boolean catchReflectException = false;
public static boolean rollbackWhenException = false;
public static boolean supportProGuard = true;
public static boolean isLogging = true;
public static boolean isManual = false;
Expand All @@ -44,6 +45,7 @@ public final class Config {

public static void init() {
catchReflectException = false;
rollbackWhenException = false;
isLogging = true;
isManual = false;
patchPackageName = Constants.PATCH_PACKAGENAME;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;

import static com.meituan.robust.autopatch.Config.catchReflectException;
import static com.meituan.robust.autopatch.Config.classPool;

/**
* Created by mivanzhang on 17/2/9.
*
* <p>
* create patch control classes,which dispatch patch methods
*/

Expand Down Expand Up @@ -44,7 +45,7 @@ private CtClass createControlClass(CtClass modifiedClass) throws Exception {
private
static String getAccessDispatchMethodBody(CtClass patchClass, String modifiedClassName) throws NotFoundException {
StringBuilder accessDispatchMethodBody = new StringBuilder();
if(Config.catchReflectException){
if (catchReflectException || Config.rollbackWhenException) {
accessDispatchMethodBody.append("try{");
}
if (Constants.isLogging) {
Expand Down Expand Up @@ -125,25 +126,28 @@ static String getAccessDispatchMethodBody(CtClass patchClass, String modifiedCla
}
}
for (int index = 0; index < parametertypes.length; index++) {
if (booleanPrimeType(parametertypes[index].getName())){
if (booleanPrimeType(parametertypes[index].getName())) {
accessDispatchMethodBody.append("((" + JavaUtils.getWrapperClass(parametertypes[index].getName()) + ") (fixObj(paramArrayOfObject[" + index + "]))");
accessDispatchMethodBody.append(")" + JavaUtils.wrapperToPrime(parametertypes[index].getName()));
if (index != parametertypes.length - 1) {
accessDispatchMethodBody.append(",");
}
} else {
accessDispatchMethodBody.append("((" + JavaUtils.getWrapperClass(parametertypes[index].getName()) + ") (paramArrayOfObject[" + index + "])");
accessDispatchMethodBody.append(")" + JavaUtils.wrapperToPrime(parametertypes[index].getName()));
if (index != parametertypes.length - 1) {
accessDispatchMethodBody.append(",");
}
accessDispatchMethodBody.append("((" + JavaUtils.getWrapperClass(parametertypes[index].getName()) + ") (paramArrayOfObject[" + index + "])");
accessDispatchMethodBody.append(")" + JavaUtils.wrapperToPrime(parametertypes[index].getName()));
if (index != parametertypes.length - 1) {
accessDispatchMethodBody.append(",");
}
}
}
accessDispatchMethodBody.append("));}\n");
}
}
if(Config.catchReflectException){
if (catchReflectException || Config.rollbackWhenException) {
accessDispatchMethodBody.append(" } catch (Throwable e) {");
if (Config.rollbackWhenException) {
accessDispatchMethodBody.append("com.meituan.robust.RollbackManager.getInstance().notifyOnException(methodsId, methodLongName, e); ");
}
accessDispatchMethodBody.append(" e.printStackTrace();}");
}
return accessDispatchMethodBody.toString();
Expand All @@ -152,6 +156,8 @@ static String getAccessDispatchMethodBody(CtClass patchClass, String modifiedCla
private static String getIsSupportMethodBody(CtClass patchClass, String modifiedClassName) throws NotFoundException {
StringBuilder isSupportBuilder = new StringBuilder();
StringBuilder methodsIdBuilder = new StringBuilder();
StringBuilder methodsLongNameBuilder = new StringBuilder();

if (Constants.isLogging) {
isSupportBuilder.append(" android.util.Log.d(\"robust\",\"arrivied in isSupport \"+methodName+\" paramArrayOfObject \" +paramArrayOfObject);");
}
Expand All @@ -167,13 +173,23 @@ private static String getIsSupportMethodBody(CtClass patchClass, String modified
if (methodNumber != null) {
// 一前一后的冒号作为匹配锚点,只有一边有的话可能会有多重匹配的bug
methodsIdBuilder.append(":" + methodNumber + ":");
methodsLongNameBuilder.append(methodLongName + ";");
}
}

String methodsIdStr = methodsIdBuilder.toString();
if (Constants.isLogging) {
isSupportBuilder.append(" android.util.Log.d(\"robust\",\"arrivied in isSupport \"+methodName+\" paramArrayOfObject \" +paramArrayOfObject+\" isSupport result is \"+\"" + methodsIdBuilder.toString() + "\".contains(\":\" + methodNo + \":\"));");
isSupportBuilder.append(" android.util.Log.d(\"robust\",\"arrivied in isSupport \"+methodName+\" paramArrayOfObject \" +paramArrayOfObject+\" isSupport result is \"+\"" + methodsIdStr + "\".contains(\":\" + methodNo + \":\"));");
}
isSupportBuilder.append("return \"" + methodsIdBuilder.toString() + "\".contains(\":\" + methodNo + \":\");");

isSupportBuilder.append("methodsId=\"" + methodsIdStr + "\";");
isSupportBuilder.append("methodLongName=\"" + methodsLongNameBuilder.toString() + "\";");

if (Config.rollbackWhenException) {
isSupportBuilder.append(" if (com.meituan.robust.RollbackManager.getInstance().getRollback(\"" + methodsIdStr + "\")) return false; ");
}

isSupportBuilder.append("return \"" + methodsIdStr + "\".contains(\":\" + methodNo + \":\");");
return isSupportBuilder.toString();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.meituan.robust;

/**
* @author feelschaotic
* @create 2019/7/30.
*/

public interface RollbackListener {
void onRollback(String methodsId, String methodLongName, Throwable e);

boolean getRollback(String methodsId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.meituan.robust;

public class RollbackManager {

private RollbackListener listener;


private static class RollbackManagerHolder {
private static final RollbackManager INSTANCE = new RollbackManager();
}

public static RollbackManager getInstance() {
return RollbackManagerHolder.INSTANCE;
}

private RollbackManager() {
}

public void setRollbackListener(RollbackListener listener) {
this.listener = listener;
}

public boolean getRollback(String methodsId) {
return listener != null && listener.getRollback(methodsId);
}

/**
* 当异常时重置标志位,表明这是一个旧补丁
*
* @return
*/
public void notifyOnException(String methodsId, String methodLongName, Throwable e) {
if (listener != null) {
listener.onRollback(methodsId, methodLongName, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public PatchTemplate() {

private static final Map<Object, Object> keyToValueRelation = new WeakHashMap<>();

private String methodsId;
private String methodLongName;

@Override
public Object accessDispatch(String methodName, Object[] paramArrayOfObject) {
return null;
Expand Down