Skip to content

Commit

Permalink
Fix ANR
Browse files Browse the repository at this point in the history
  • Loading branch information
Nep-Timeline committed Sep 11, 2024
1 parent 828143b commit c26298e
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package nep.timeline.cirno.hooks.android.anr;

import android.content.pm.ApplicationInfo;
import android.os.Build;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import nep.timeline.cirno.framework.AbstractMethodHook;
import nep.timeline.cirno.framework.MethodHook;
import nep.timeline.cirno.utils.AnrHelper;

public class ANRErrorStateHook extends MethodHook {
public ANRErrorStateHook(ClassLoader classLoader) {
super(classLoader);
}

@Override
public String getTargetClass() {
return "com.android.server.am.ProcessErrorStateRecord";
}

@Override
public String getTargetMethod() {
return "appNotResponding";
}

@Override
public Object[] getTargetParam() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU)
return new Object[] { String.class, ApplicationInfo.class, String.class, "com.android.server.wm.WindowProcessController", boolean.class, "com.android.internal.os.TimeoutRecord", ExecutorService.class, boolean.class, boolean.class, Future.class };
return new Object[] { String.class, ApplicationInfo.class, String.class, "com.android.server.wm.WindowProcessController", boolean.class, String.class, boolean.class };
}

@Override
public XC_MethodHook getTargetHook() {
return new AbstractMethodHook() {
@Override
protected void beforeMethod(MethodHookParam param) {
Object app = XposedHelpers.getObjectField(param.thisObject, "mApp");
if (app == null)
return;
AnrHelper.processingAnr(param, app);
}
};
}

@Override
public int getMinVersion() {
return Build.VERSION_CODES.S;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package nep.timeline.cirno.hooks.android.anr;

import java.lang.reflect.Method;

import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import nep.timeline.cirno.framework.AbstractMethodHook;
import nep.timeline.cirno.utils.AnrHelper;

public class ANRHelperHooks {
public final Integer findIndex(Class<?>[] parameterTypes, String clazz) {
for (int i = 0; i < parameterTypes.length; i++)
if (clazz.equals(parameterTypes[i].getName()))
return i;
return null;
}

public ANRHelperHooks(ClassLoader classLoader) {
try {
Class<?> targetClass = XposedHelpers.findClassIfExists("com.android.server.am.AnrHelper", classLoader);

if (targetClass == null)
return;

for (Method method : targetClass.getDeclaredMethods()) {
if ((method.getName().equals("appNotResponding") || method.getName().equals("deferAppNotResponding")) && method.getReturnType().equals(void.class)) {
Integer index = findIndex(method.getParameterTypes(), "com.android.server.am.ProcessRecord");
if (index == null) { // Not found
Integer MIUIRecordIndex = findIndex(method.getParameterTypes(), "com.android.server.am.AnrHelper$AnrRecord");
if (MIUIRecordIndex != null) {
XposedBridge.hookMethod(method, new AbstractMethodHook() {
@Override
protected void beforeMethod(MethodHookParam param) {
Object anrRecord = param.args[MIUIRecordIndex];
if (anrRecord == null)
return;
Object app = XposedHelpers.getObjectField(anrRecord, "mApp");
if (app == null)
return;
AnrHelper.processingAnr(param, app);
}
});
}
} else {
XposedBridge.hookMethod(method, new AbstractMethodHook() {
@Override
protected void beforeMethod(MethodHookParam param) {
Object record = param.args[index];
if (record == null)
return;
AnrHelper.processingAnr(param, record);
}
});
}
}
}
} catch (Throwable ignored) {

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package nep.timeline.cirno.hooks.android.anr;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import nep.timeline.cirno.framework.AbstractMethodHook;
import nep.timeline.cirno.framework.MethodHook;
import nep.timeline.cirno.utils.AnrHelper;

public class ANRHook extends MethodHook {
public ANRHook(ClassLoader classLoader) {
super(classLoader);
}

@Override
public String getTargetClass() {
return "com.android.server.am.AnrHelper$AnrRecord";
}

@Override
public String getTargetMethod() {
return "appNotResponding";
}

@Override
public Object[] getTargetParam() {
return new Object[] { boolean.class };
}

@Override
public XC_MethodHook getTargetHook() {
return new AbstractMethodHook() {
@Override
protected void beforeMethod(MethodHookParam param) {
Object app = XposedHelpers.getObjectField(param.thisObject, "mApp");
if (app == null)
return;
AnrHelper.processingAnr(param, app);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ protected void beforeMethod(MethodHookParam param) {
Object settings;

int userId;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
userId = XposedHelpers.getIntField(param.thisObject, "mCurrentUserId");
settings = XposedHelpers.callStaticMethod(XposedHelpers.findClassIfExists("com.android.server.inputmethod.InputMethodSettingsRepository", classLoader), "get", userId);
}
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/nep/timeline/cirno/master/AndroidHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import nep.timeline.cirno.hooks.android.activity.ActivityManagerServiceHook;
import nep.timeline.cirno.hooks.android.activity.ActivityStatsHook;
import nep.timeline.cirno.hooks.android.alarms.AlarmManagerService;
import nep.timeline.cirno.hooks.android.anr.ANRErrorStateHook;
import nep.timeline.cirno.hooks.android.anr.ANRHelperHooks;
import nep.timeline.cirno.hooks.android.anr.ANRHook;
import nep.timeline.cirno.hooks.android.audio.AudioStateHook;
import nep.timeline.cirno.hooks.android.audio.PlayerBanHook;
import nep.timeline.cirno.hooks.android.audio.SendMediaButtonHook;
Expand All @@ -31,6 +34,10 @@ public static void start(ClassLoader classLoader) {
FileObserver fileObserver = new ConfigFileObserver();
fileObserver.startWatching();

// ANR
new ANRHook(classLoader);
new ANRErrorStateHook(classLoader);
new ANRHelperHooks(classLoader);
// Signal
new SendSignalHook(classLoader);
new SendSignalQuietHook(classLoader);
Expand Down
21 changes: 21 additions & 0 deletions app/src/main/java/nep/timeline/cirno/utils/AnrHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package nep.timeline.cirno.utils;

import de.robv.android.xposed.XC_MethodHook;
import nep.timeline.cirno.entity.AppRecord;
import nep.timeline.cirno.services.ProcessService;
import nep.timeline.cirno.virtuals.ProcessRecord;

public class AnrHelper {
public static void processingAnr(XC_MethodHook.MethodHookParam param, Object app) {
if (app == null)
return;
ProcessRecord processRecord = ProcessService.getProcessRecord(app);
if (processRecord == null)
return;
AppRecord appRecord = processRecord.getAppRecord();
if (appRecord == null)
return;
if (!appRecord.isSystem())
param.setResult(null);
}
}

0 comments on commit c26298e

Please sign in to comment.