Skip to content

Commit

Permalink
add anr trace fast callback, avoid to call getRunningAppProcesses, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
xuqingqing committed Jan 24, 2022
1 parent b27ef0a commit 16dff88
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 38 deletions.
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ task clean(type: Delete) {

ext {
minSdkVersion = 16
compileSdkVersion = 30
targetSdkVersion = 30
compileSdkVersion = 31
targetSdkVersion = 31
buildToolsVersion = '30.0.2'
javaVersion = JavaVersion.VERSION_1_6
javaVersion = JavaVersion.VERSION_1_8
ndkVersion = "21.3.6528147"
cmakeVersion = "3.10.2"
abiFilters = "armeabi-v7a,arm64-v8a,x86,x86_64"
useASAN = false

POM_GROUP_ID = "com.iqiyi.xcrash"
POM_ARTIFACT_ID = "xcrash-android-lib"
POM_VERSION_NAME = "3.0.0"
POM_VERSION_NAME = "3.1.0"

POM_NAME = "xCrash Android Lib"
POM_DESCRIPTION = "xCrash provides the Android app with the ability to capture java crash, native crash and ANR."
Expand Down
1 change: 1 addition & 0 deletions xcrash_lib/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
native <methods>;
void crashCallback(...);
void traceCallback(...);
void traceCallbackBeforeDump(...);
}
2 changes: 1 addition & 1 deletion xcrash_lib/src/main/cpp/common/xcc_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
#ifndef XCC_VERSION_H
#define XCC_VERSION_H 1

#define XCC_VERSION_STR "xCrash 3.0.0"
#define XCC_VERSION_STR "xCrash 3.1.0"

#endif
15 changes: 14 additions & 1 deletion xcrash_lib/src/main/cpp/xcrash/xc_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-statement-expression"


#define XC_TRACE_FAST_CALLBACK_METHOD_NAME "traceCallbackBeforeDump"
#define XC_TRACE_FAST_CALLBACK_METHOD_SIGNATURE "()V"

#define XC_TRACE_CALLBACK_METHOD_NAME "traceCallback"
#define XC_TRACE_CALLBACK_METHOD_SIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V"

Expand Down Expand Up @@ -78,6 +82,7 @@ static int xc_trace_dump_fds;
static int xc_trace_dump_network_info;

//callback
static jmethodID xc_trace_fast_cb_method = NULL;
static jmethodID xc_trace_cb_method = NULL;
static int xc_trace_notifier = -1;

Expand Down Expand Up @@ -314,6 +319,10 @@ static void *xc_trace_dumper(void *arg)
//check if process already crashed
if(xc_common_native_crashed || xc_common_java_crashed) break;

if(NULL == xc_trace_fast_cb_method) continue;
(*env)->CallStaticVoidMethod(env, xc_common_cb_class, xc_trace_fast_cb_method);
XC_JNI_IGNORE_PENDING_EXCEPTION();

//trace time
if(0 != gettimeofday(&tv, NULL)) break;
trace_time = (uint64_t)(tv.tv_sec) * 1000 * 1000 + (uint64_t)tv.tv_usec;
Expand Down Expand Up @@ -417,12 +426,16 @@ static void xc_trace_handler(int sig, siginfo_t *si, void *uc)
static void xc_trace_init_callback(JNIEnv *env)
{
if(NULL == xc_common_cb_class) return;


xc_trace_fast_cb_method = (*env)->GetStaticMethodID(env, xc_common_cb_class, XC_TRACE_FAST_CALLBACK_METHOD_NAME, XC_TRACE_FAST_CALLBACK_METHOD_SIGNATURE);
XC_JNI_CHECK_NULL_AND_PENDING_EXCEPTION(xc_trace_fast_cb_method, err);

xc_trace_cb_method = (*env)->GetStaticMethodID(env, xc_common_cb_class, XC_TRACE_CALLBACK_METHOD_NAME, XC_TRACE_CALLBACK_METHOD_SIGNATURE);
XC_JNI_CHECK_NULL_AND_PENDING_EXCEPTION(xc_trace_cb_method, err);
return;

err:
xc_trace_fast_cb_method = NULL;
xc_trace_cb_method = NULL;
}

Expand Down
11 changes: 10 additions & 1 deletion xcrash_lib/src/main/java/xcrash/AnrHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class AnrHandler {
private boolean dumpFds;
private boolean dumpNetworkInfo;
private ICrashCallback callback;
private ICrashCallback anrFastCallback;
private long lastTime = 0;
private FileObserver fileObserver = null;

Expand All @@ -75,7 +76,7 @@ static AnrHandler getInstance() {
@SuppressWarnings("deprecation")
void initialize(Context ctx, int pid, String processName, String appId, String appVersion, String logDir,
boolean checkProcessState, int logcatSystemLines, int logcatEventsLines, int logcatMainLines,
boolean dumpFds, boolean dumpNetworkInfo, ICrashCallback callback) {
boolean dumpFds, boolean dumpNetworkInfo, ICrashCallback callback, ICrashCallback anrFastCallback) {

//check API level
if (Build.VERSION.SDK_INT >= 21) {
Expand All @@ -95,6 +96,7 @@ void initialize(Context ctx, int pid, String processName, String appId, String a
this.dumpFds = dumpFds;
this.dumpNetworkInfo = dumpNetworkInfo;
this.callback = callback;
this.anrFastCallback = anrFastCallback;

fileObserver = new FileObserver("/data/anr/", CLOSE_WRITE) {
public void onEvent(int event, String path) {
Expand Down Expand Up @@ -139,6 +141,13 @@ private void handleAnr(String filepath) {
return;
}

if(anrFastCallback != null) {
try {
anrFastCallback.onCrash(null, null);
} catch (Exception ignored) {
}
}

//check process error state
if (this.checkProcessState) {
if (!Util.checkProcessAnrState(this.ctx, anrTimeoutMs)) {
Expand Down
27 changes: 24 additions & 3 deletions xcrash_lib/src/main/java/xcrash/NativeHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,25 @@
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.util.Map;

@SuppressLint("StaticFieldLeak")
class NativeHandler {

private static final String TAG = "xcrash";
private static final NativeHandler instance = new NativeHandler();
private long anrTimeoutMs = 15 * 1000;
private long anrTimeoutMs = 25 * 1000;

private Context ctx;
private boolean crashRethrow;
private ICrashCallback crashCallback;
private boolean anrEnable;
private boolean anrCheckProcessState;
private ICrashCallback anrCallback;
private ICrashCallback anrFastCallback;

private boolean initNativeLibOk = false;

Expand Down Expand Up @@ -78,7 +81,8 @@ int initialize(Context ctx,
int anrLogcatMainLines,
boolean anrDumpFds,
boolean anrDumpNetworkInfo,
ICrashCallback anrCallback) {
ICrashCallback anrCallback,
ICrashCallback anrFastCallback) {
//load lib
if (libLoader == null) {
try {
Expand All @@ -102,7 +106,8 @@ int initialize(Context ctx,
this.anrEnable = anrEnable;
this.anrCheckProcessState = anrCheckProcessState;
this.anrCallback = anrCallback;
this.anrTimeoutMs = anrRethrow ? 15 * 1000 : 30 * 1000; //setting rethrow to "false" is NOT recommended
this.anrFastCallback = anrFastCallback;
this.anrTimeoutMs = anrRethrow ? 25 * 1000 : 45 * 1000; //setting rethrow to "false" is NOT recommended

//init native lib
try {
Expand Down Expand Up @@ -214,9 +219,25 @@ private static void crashCallback(String logPath, String emergency, boolean dump
}
}

// do NOT obfuscate this method
@SuppressWarnings("unused")
private static void traceCallbackBeforeDump() {
Log.i(TAG, "trace fast callback time: " + System.currentTimeMillis());
ICrashCallback anrFastCallback = NativeHandler.getInstance().anrFastCallback;
if (anrFastCallback != null) {
try {
anrFastCallback.onCrash(null, null);
} catch (Exception e) {
XCrash.getLogger().w(Util.TAG, "NativeHandler ANR callback.onCrash failed", e);
}
}
}

// do NOT obfuscate this method
@SuppressWarnings("unused")
private static void traceCallback(String logPath, String emergency) {
Log.i(TAG, "trace slow callback time: " + System.currentTimeMillis());

if (TextUtils.isEmpty(logPath)) {
return;
}
Expand Down
154 changes: 134 additions & 20 deletions xcrash_lib/src/main/java/xcrash/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.os.Debug;
import android.system.Os;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
Expand Down Expand Up @@ -76,20 +77,20 @@ private Util() {
static String getProcessName(Context ctx, int pid) {

//get from ActivityManager
try {
ActivityManager manager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
if (manager != null) {
List<ActivityManager.RunningAppProcessInfo> processInfoList = manager.getRunningAppProcesses();
if (processInfoList != null) {
for (ActivityManager.RunningAppProcessInfo processInfo : processInfoList) {
if (processInfo.pid == pid && !TextUtils.isEmpty(processInfo.processName)) {
return processInfo.processName; //OK
}
}
}
}
} catch (Exception ignored) {
}
// try {
// ActivityManager manager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
// if (manager != null) {
// List<ActivityManager.RunningAppProcessInfo> processInfoList = manager.getRunningAppProcesses();
// if (processInfoList != null) {
// for (ActivityManager.RunningAppProcessInfo processInfo : processInfoList) {
// if (processInfo.pid == pid && !TextUtils.isEmpty(processInfo.processName)) {
// return processInfo.processName; //OK
// }
// }
// }
// }
// } catch (Exception ignored) {
// }

//get from /proc/PID/cmdline
BufferedReader br = null;
Expand Down Expand Up @@ -298,11 +299,15 @@ static boolean checkProcessAnrState(Context ctx, long timeoutMs) {
for (int i = 0; i < poll; i++) {
List<ActivityManager.ProcessErrorStateInfo> processErrorList = am.getProcessesInErrorState();
if (processErrorList != null) {
XCrash.getLogger().e(Util.TAG, "processErrorList is NOT null !!!!" + ", i = " + i);
for (ActivityManager.ProcessErrorStateInfo errorStateInfo : processErrorList) {
XCrash.getLogger().e(Util.TAG, "errorStateInfo.pid = " + errorStateInfo.pid + ", my pid = " + pid + ", errorStateInfo.condition = " + errorStateInfo.condition);
if (errorStateInfo.pid == pid && errorStateInfo.condition == ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING) {
return true;
}
}
} else {
XCrash.getLogger().e(Util.TAG, "processErrorList is null !!!!" + " poll = " + poll + ", i = " + i);
}

try {
Expand Down Expand Up @@ -515,14 +520,9 @@ public static String getSystemProperty(String key, String defaultValue) {
return defaultValue;
}

public static boolean isMIUI() {
String property = getSystemProperty("ro.miui.ui.version.name", "");
return !TextUtils.isEmpty(property);
}

public static String getMobileModel() {
String mobileModel = null;
if (isMIUI()) {
if (Rom.isMiui()) {
String deviceName = "";

try {
Expand Down Expand Up @@ -553,4 +553,118 @@ public static String getMobileModel() {

return mobileModel;
}


public static class Rom {
private static final String TAG = "Rom";

public static final String ROM_MIUI = "MIUI";
public static final String ROM_EMUI = "EMUI";
public static final String ROM_FLYME = "FLYME";
public static final String ROM_OPPO = "OPPO";
public static final String ROM_SMARTISAN = "SMARTISAN";
public static final String ROM_VIVO = "VIVO";
public static final String ROM_QIKU = "QIKU";

private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";
private static final String KEY_VERSION_EMUI = "ro.build.version.emui";
private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";
private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";
private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";

private static String sName;
private static String sVersion;

public static boolean isEmui() {
return check(ROM_EMUI);
}

public static boolean isMiui() {
return check(ROM_MIUI);
}

public static boolean isVivo() {
return check(ROM_VIVO);
}

public static boolean isOppo() {
return check(ROM_OPPO);
}

public static boolean isFlyme() {
return check(ROM_FLYME);
}

public static boolean is360() {
return check(ROM_QIKU) || check("360");
}

public static boolean isSmartisan() {
return check(ROM_SMARTISAN);
}

public static String getName() {
if (sName == null) {
check("");
}
return sName;
}

public static String getVersion() {
if (sVersion == null) {
check("");
}
return sVersion;
}

public static boolean check(String rom) {
if (sName != null) {
return sName.equals(rom);
}

if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {
sName = ROM_MIUI;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {
sName = ROM_EMUI;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {
sName = ROM_OPPO;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {
sName = ROM_VIVO;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {
sName = ROM_SMARTISAN;
} else {
sVersion = Build.DISPLAY;
if (sVersion.toUpperCase().contains(ROM_FLYME)) {
sName = ROM_FLYME;
} else {
sVersion = Build.UNKNOWN;
sName = Build.MANUFACTURER.toUpperCase();
}
}
return sName.equals(rom);
}

public static String getProp(String name) {
String line = null;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + name);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
Log.e(TAG, "Unable to read prop " + name, ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return line;
}
}
}
2 changes: 1 addition & 1 deletion xcrash_lib/src/main/java/xcrash/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ class Version {
private Version() {
}

static final String version = "3.0.0";
static final String version = "3.1.0";
static final String fullVersion = "xCrash " + version;
}
Loading

0 comments on commit 16dff88

Please sign in to comment.