https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=2649288031&idx=1&sn=91c94e16460a4685a9c0c8e1b9c362a6&chksm=8334c9ddb44340cb66e6ce512ca41592fb483c148419737dbe21f9bbc2bfc2f872d1e54d1641&scene=178&cur_album_id=1955379809983741955#rd
微信公眾號,WeMobileDev 2021年7月19日發布的 微信Android客戶端的ANR監控方案
該方案的所有代碼已經在Matrix(https://github.com/Tencent/matrix)中開源,這篇文章將詳細講解原始碼實作,

1.SignalAnrTracer onAlive方法里呼叫nativeInitSignalAnrDetective方法監聽SIGQUIT信號
public class SignalAnrTracer extends Tracer {
//region 引數
private static final String TAG = "SignalAnrTracer";
//檢測anr執行緒名字
//監控到SIGQUIT后,我們在20秒內(20秒是ANR dump的timeout時間)不斷輪詢自己是否有NOT_RESPONDING flag
//一旦發現有這個flag,那么馬上就可以認定發生了一次ANR,
private static final String CHECK_ANR_STATE_THREAD_NAME = "Check-ANR-State-Thread";
//檢測NOT_RESPONDING flag間隔時間
private static final int CHECK_ERROR_STATE_INTERVAL = 500;
//dump最長時間20s
private static final int ANR_DUMP_MAX_TIME = 20000;
//檢測error次數
private static final int CHECK_ERROR_STATE_COUNT =
ANR_DUMP_MAX_TIME / CHECK_ERROR_STATE_INTERVAL;
//前臺訊息,超時2s的時候,說明卡住了
private static final long FOREGROUND_MSG_THRESHOLD = -2000;
//后臺訊息,超時2s的時候,說明卡住了
private static final long BACKGROUND_MSG_THRESHOLD = -10000;
//是否hasInstance
public static boolean hasInstance = false;
//是否是前臺狀態
private static boolean currentForeground = false;
//anr trace 檔案路徑
private static String sAnrTraceFilePath = "";
// 這個Hook Trace的方案,不僅僅可以用來查ANR問題,任何時候我們都可以手動向自己發送一個SIGQUIT信號,
// 從而hook到當時的Trace,Trace的內容對于我們排查執行緒死鎖,執行緒例外,耗電等問題都非常有幫助,
//列印trace 檔案路徑 ,自己觸發的
private static String sPrintTraceFilePath = "";
//監聽
private static SignalAnrDetectedListener sSignalAnrDetectedListener;
//sApplication
private static Application sApplication;
//是否初始化了
private static boolean hasInit = false;
//anr發生時間,負值
private static long anrMessageWhen = 0L;
//anr發生時主執行緒處理的訊息
private static String anrMessageString = "";
//endregion
static {
//加載trace-canary lib
System.loadLibrary("trace-canary");
}
//region 建構式
public SignalAnrTracer(TraceConfig traceConfig) {
hasInstance = true;
sAnrTraceFilePath = traceConfig.anrTraceFilePath;
sPrintTraceFilePath = traceConfig.printTraceFilePath;
}
public SignalAnrTracer(Application application) {
hasInstance = true;
sApplication = application;
}
public SignalAnrTracer(Application application, String anrTraceFilePath, String printTraceFilePath) {
hasInstance = true;
sAnrTraceFilePath = anrTraceFilePath;
sPrintTraceFilePath = printTraceFilePath;
sApplication = application;
}
//endregion
/**
* AnrDumper.cc里 handleSignal
*/
@RequiresApi(api = Build.VERSION_CODES.M)
@Keep
private static void onANRDumped() {
//是否是前臺
currentForeground = AppForegroundUtil.isInterestingToUser();
//是否是主執行緒堵塞了,需要report
boolean needReport = isMainThreadBlocked();
//有兩種情況,主執行緒訊息已經堵住了,或者開啟一個執行緒檢測狀態 NOT_RESPONDING
//需要report
if (needReport) {
report(false);
} else {
// 監控到SIGQUIT后,我們在20秒內(20秒是ANR dump的timeout時間)不斷輪詢自己是否有NOT_RESPONDING flag
// ,一旦發現有這個flag,那么馬上就可以認定發生了一次ANR,
new Thread(new Runnable() {
@Override
public void run() {
//開啟了一個執行緒檢查
checkErrorStateCycle();
}
}, CHECK_ANR_STATE_THREAD_NAME).start();
}
}
@Keep
private static void onANRDumpTrace() {
try {
MatrixUtil.printFileByLine(TAG, sAnrTraceFilePath);
} catch (Throwable t) {
MatrixLog.e(TAG, "onANRDumpTrace error: %s", t.getMessage());
}
}
//endregion
@Keep
private static void onPrintTrace() {
try {
MatrixUtil.printFileByLine(TAG, sPrintTraceFilePath);
} catch (Throwable t) {
MatrixLog.e(TAG, "onPrintTrace error: %s", t.getMessage());
}
}
/**
* @param fromProcessErrorState false代表主執行緒阻塞了
*/
private static void report(boolean fromProcessErrorState) {
try {
String stackTrace = Utils.getMainThreadJavaStackTrace();
if (sSignalAnrDetectedListener != null) {
sSignalAnrDetectedListener.onAnrDetected(stackTrace, anrMessageString, anrMessageWhen, fromProcessErrorState);
return;
}
TracePlugin plugin = Matrix.with().getPluginByClass(TracePlugin.class);
if (null == plugin) {
return;
}
String scene = AppMethodBeat.getVisibleScene();
JSONObject jsonObject = new JSONObject();
jsonObject = DeviceUtil.getDeviceInfo(jsonObject, Matrix.with().getApplication());
jsonObject.put(SharePluginInfo.ISSUE_STACK_TYPE, Constants.Type.SIGNAL_ANR);
jsonObject.put(SharePluginInfo.ISSUE_SCENE, scene);
jsonObject.put(SharePluginInfo.ISSUE_THREAD_STACK, stackTrace);
jsonObject.put(SharePluginInfo.ISSUE_PROCESS_FOREGROUND, currentForeground);
Issue issue = new Issue();
issue.setTag(SharePluginInfo.TAG_PLUGIN_EVIL_METHOD);
issue.setContent(jsonObject);
plugin.onDetectIssue(issue);
MatrixLog.e(TAG, "happens real ANR : %s ", jsonObject.toString());
} catch (JSONException e) {
MatrixLog.e(TAG, "[JSONException error: %s", e);
}
}
//通過訊息時間,來判斷是否到超出閾值
@RequiresApi(api = Build.VERSION_CODES.M)
private static boolean isMainThreadBlocked() {
try {
MessageQueue mainQueue = Looper.getMainLooper().getQueue();
Field field = mainQueue.getClass().getDeclaredField("mMessages");
field.setAccessible(true);
final Message mMessage = (Message) field.get(mainQueue);
if (mMessage != null) {
anrMessageString = mMessage.toString();
long when = mMessage.getWhen();
if (when == 0) {
return false;
}
long time = when - SystemClock.uptimeMillis();
anrMessageWhen = time;
long timeThreshold = BACKGROUND_MSG_THRESHOLD;
if (currentForeground) {
timeThreshold = FOREGROUND_MSG_THRESHOLD;
}
return time < timeThreshold;
}
} catch (Exception e) {
return false;
}
return false;
}
private static void checkErrorStateCycle() {
int checkErrorStateCount = 0;
//開啟一個回圈檢測
while (checkErrorStateCount < CHECK_ERROR_STATE_COUNT) {
try {
checkErrorStateCount++;
boolean myAnr = checkErrorState();
if (myAnr) {
report(true);
break;
}
Thread.sleep(CHECK_ERROR_STATE_INTERVAL);
} catch (Throwable t) {
MatrixLog.e(TAG, "checkErrorStateCycle error, e : " + t.getMessage());
break;
}
}
}
//用來判斷anr發生了
// 在ANR彈窗前,會執行到makeAppNotRespondingLocked方法中,在這里會給發生ANR行程標記一個NOT_RESPONDING的flag,
// 而這個flag我們可以通過ActivityManager來獲取:
private static boolean checkErrorState() {
try {
Application application =
sApplication == null ? Matrix.with().getApplication() : sApplication;
ActivityManager am = (ActivityManager) application
.getSystemService(Context.ACTIVITY_SERVICE);
//從ActivityManager 獲取ProcessErrorStateInfo
List<ActivityManager.ProcessErrorStateInfo> procs = am.getProcessesInErrorState();
if (procs == null) return false;
for (ActivityManager.ProcessErrorStateInfo proc : procs) {
MatrixLog.i(TAG, "[checkErrorState] found Error State proccessName = %s, proc.condition = %d", proc.processName, proc.condition);
if (proc.uid != android.os.Process.myUid()
&& proc.condition == ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING) {
MatrixLog.i(TAG, "maybe received other apps ANR signal");
}
if (proc.pid != android.os.Process.myPid()) continue;
if (proc.condition != ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING) {
continue;
}
//只有是自己行程,并且是NOT_RESPONDING的時候,才回傳true
return true;
}
return false;
} catch (Throwable t) {
MatrixLog.e(TAG, "[checkErrorState] error : %s", t.getMessage());
}
return false;
}
//ok
public static void printTrace() {
if (!hasInstance) {
MatrixLog.e(TAG, "SignalAnrTracer has not been initialize");
return;
}
if (sPrintTraceFilePath.equals("")) {
MatrixLog.e(TAG, "PrintTraceFilePath has not been set");
return;
}
nativePrintTrace();
}
private static native void nativeInitSignalAnrDetective(String anrPrintTraceFilePath, String printTraceFilePath);
private static native void nativeFreeSignalAnrDetective();
private static native void nativePrintTrace();
@Override
protected void onAlive() {
super.onAlive();
if (!hasInit) {
//呼叫native方法啟動監聽
nativeInitSignalAnrDetective(sAnrTraceFilePath, sPrintTraceFilePath);
//主要用來判斷是否是前臺
AppForegroundUtil.INSTANCE.init();
hasInit = true;
}
}
@Override
protected void onDead() {
super.onDead();
//free anr檢測
nativeFreeSignalAnrDetective();
}
public void setSignalAnrDetectedListener(SignalAnrDetectedListener listener) {
sSignalAnrDetectedListener = listener;
}
public interface SignalAnrDetectedListener {
void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState);
}
}
2.MatrixTracer.cc
2.1 JNI_OnLoad初始化,雙向系結函式
2.2 nativeInitSignalAnrDetective,開啟檢測,真正檢測的地方在AnrDumper.cc
2.3 AnrDumper.cc 里handleSignal里呼叫MatrixTracer anrDumpCallback ,表示anr可能發生了,通知SignalAnrTracer檢測ui執行緒是否block或者狀態為NOT_RESPONDING,并呼叫hookAnrTraceWrite方法,開啟hook,為了找到write trace的點
2.4 my_connect,my_open是開始socket通信了,主要為了檢測socket通信之后的write方法
2.5 my_write是我們的write方法
#define PROP_VALUE_MAX 92 //用于求getApiLevel
#define PROP_SDK_NAME "ro.build.version.sdk" //用于求getApiLevel
#define HOOK_CONNECT_PATH "/dev/socket/tombstoned_java_trace" //socket檔案地址
#define HOOK_OPEN_PATH "/data/anr/traces.txt" //socket檔案地址
using namespace MatrixTracer;
static std::optional<AnrDumper> sAnrDumper; //AnrDumper,是自定義的SignalHandler
static bool isTraceWrite = false; //isTraceWrite my_connect my_open設定為true,my_write設定為false
static bool fromMyPrintTrace = false; //fromMyPrintTrace 是否是自己想打的
static bool isHooking = false; //是否hooking,unHookAnrTraceWrite設定為false
static std::string anrTracePathstring; //新的anrTracePathstring,系統用的
static std::string printTracePathstring; //新的printTracePathstring,我自己想列印的時候用的
static int signalCatcherTid; //signalCatcherTid的執行緒id
//一個結構體,用來保存java層 類,方法地址
static struct StacktraceJNI {
jclass AnrDetective; //SignalAnrTracer
jclass ThreadPriorityDetective;
jmethodID AnrDetector_onANRDumped; //SignalAnrTracer 里的
jmethodID AnrDetector_onANRDumpTrace; //SignalAnrTracer 里的
jmethodID AnrDetector_onPrintTrace; //SignalAnrTracer 里的
jmethodID ThreadPriorityDetective_onMainThreadPriorityModified;
jmethodID ThreadPriorityDetective_onMainThreadTimerSlackModified;
} gJ;
//region MainThreadPriorityModified相關的東西
int (*original_setpriority)(int __which, id_t __who, int __priority);
int my_setpriority(int __which, id_t __who, int __priority) {
if (__priority <= 0) {
return original_setpriority(__which, __who, __priority);
}
if (__who == 0 && getpid() == gettid()) {
JNIEnv *env = JniInvocation::getEnv();
env->CallStaticVoidMethod(gJ.ThreadPriorityDetective,
gJ.ThreadPriorityDetective_onMainThreadPriorityModified,
__priority);
} else if (__who == getpid()) {
JNIEnv *env = JniInvocation::getEnv();
env->CallStaticVoidMethod(gJ.ThreadPriorityDetective,
gJ.ThreadPriorityDetective_onMainThreadPriorityModified,
__priority);
}
return original_setpriority(__which, __who, __priority);
}
int (*original_prctl)(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
int my_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5) {
if (option == PR_SET_TIMERSLACK) {
if (gettid() == getpid() && arg2 > 50000) {
JNIEnv *env = JniInvocation::getEnv();
env->CallStaticVoidMethod(gJ.ThreadPriorityDetective,
gJ.ThreadPriorityDetective_onMainThreadTimerSlackModified,
arg2);
}
}
return original_prctl(option, arg2, arg3, arg4, arg5);
}
//endregion
/**
*
* @param content 內容
* @param filePath 檔案地址
*/
void writeAnr(const std::string &content, const std::string &filePath) {
//unhook write
unHookAnrTraceWrite();
std::stringstream stringStream(content);
std::string to;
std::ofstream outfile;
outfile.open(filePath);
outfile << content;
}
//region my_connect original_connect
int (*original_connect)(int __fd, const struct sockaddr *__addr, socklen_t __addr_length);
int my_connect(int __fd, const struct sockaddr *__addr, socklen_t __addr_length) {
if (__addr != nullptr) {
//hook connect方法,檢測sockaddr地址是否為HOOK_CONNECT_PATH,表明是signal檢測執行緒
if (strcmp(__addr->sa_data, HOOK_CONNECT_PATH) == 0) {
//設定signal檢測執行緒id
signalCatcherTid = gettid();
//標記開始列印
isTraceWrite = true;
}
}
return original_connect(__fd, __addr, __addr_length);
}
//endregion
//region my_open original_open
int (*original_open)(const char *pathname, int flags, mode_t mode);
int my_open(const char *pathname, int flags, mode_t mode) {
if (pathname != nullptr) {
//hook connect方法,檢測sockaddr地址是否為HOOK_OPEN_PATH,表明是signal檢測執行緒
if (strcmp(pathname, HOOK_OPEN_PATH) == 0) {
//設定signal檢測執行緒id
signalCatcherTid = gettid();
//標記開始列印
isTraceWrite = true;
}
}
return original_open(pathname, flags, mode);
}
//endregion
//region original_write my_write
ssize_t (*original_write)(int fd, const void *const __pass_object_size0 buf, size_t count);
ssize_t my_write(int fd, const void *const buf, size_t count) {
//如果標記為isTraceWrite為true,第一個signalCatcher執行緒,write呼叫即為列印trace的地方
if (isTraceWrite && gettid() == signalCatcherTid) {
isTraceWrite = false;
signalCatcherTid = 0;
if (buf != nullptr) {
std::string targetFilePath;
if (fromMyPrintTrace) {
targetFilePath = printTracePathstring;
} else {
targetFilePath = anrTracePathstring;
}
if (!targetFilePath.empty()) {
char *content = (char *) buf;
writeAnr(content, targetFilePath);
if (!fromMyPrintTrace) {
anrDumpTraceCallback();
} else {
printTraceCallback();
}
fromMyPrintTrace = false;
}
}
}
return original_write(fd, buf, count);
}
//endregion
//呼叫java的onANRDumped,AnrDumper.cc 里handleSignal里呼叫anrCallback然后呼叫這個anrDumpCallback回呼
bool anrDumpCallback() {
JNIEnv *env = JniInvocation::getEnv();
if (!env) return false;
env->CallStaticVoidMethod(gJ.AnrDetective, gJ.AnrDetector_onANRDumped);
return true;
}
//呼叫java的onANRDumpTrace,my_write里呼叫
bool anrDumpTraceCallback() {
JNIEnv *env = JniInvocation::getEnv();
if (!env) return false;
env->CallStaticVoidMethod(gJ.AnrDetective, gJ.AnrDetector_onANRDumpTrace);
return true;
}
//呼叫java的onPrintTrace,my_write里呼叫
bool printTraceCallback() {
JNIEnv *env = JniInvocation::getEnv();
if (!env) return false;
env->CallStaticVoidMethod(gJ.AnrDetective, gJ.AnrDetector_onPrintTrace);
return true;
}
//ok
int getApiLevel() {
char buf[PROP_VALUE_MAX];
int len = __system_property_get(PROP_SDK_NAME, buf);
if (len <= 0)
return 0;
return atoi(buf);
}
/**
* @param isSiUser true為自己的行程
* AnrDumper.cc 里handleSignal里呼叫anrCallback方法,或者呼叫siUserCallback,然后呼叫這個hookAnrTraceWrite回呼
*/
void hookAnrTraceWrite(bool isSiUser) {
int apiLevel = getApiLevel();
if (apiLevel < 19) {
return;
}
//isSiUser為true,表示自己行程發的時候是通過kill發的,此處不符合邏輯,回傳
if (!fromMyPrintTrace && isSiUser) {
return;
}
if (isHooking) {
return;
}
isHooking = true;
if (apiLevel >= 27) {
void *libcutils_info = xhook_elf_open("/system/lib64/libcutils.so");
if (!libcutils_info) {
libcutils_info = xhook_elf_open("/system/lib/libcutils.so");
}
xhook_hook_symbol(libcutils_info, "connect", (void *) my_connect,
(void **) (&original_connect));
} else {
void *libart_info = xhook_elf_open("libart.so");
xhook_hook_symbol(libart_info, "open", (void *) my_open, (void **) (&original_open));
}
if (apiLevel >= 30 || apiLevel == 25 || apiLevel == 24) {
void *libc_info = xhook_elf_open("libc.so");
xhook_hook_symbol(libc_info, "write", (void *) my_write, (void **) (&original_write));
} else if (apiLevel == 29) {
void *libbase_info = xhook_elf_open("/system/lib64/libbase.so");
if (!libbase_info) {
libbase_info = xhook_elf_open("/system/lib/libbase.so");
}
xhook_hook_symbol(libbase_info, "write", (void *) my_write, (void **) (&original_write));
xhook_elf_close(libbase_info);
} else {
void *libart_info = xhook_elf_open("libart.so");
xhook_hook_symbol(libart_info, "write", (void *) my_write, (void **) (&original_write));
}
}
//unhook
void unHookAnrTraceWrite() {
int apiLevel = getApiLevel();
if (apiLevel >= 27) {
void *libcutils_info = xhook_elf_open("/system/lib64/libcutils.so");
xhook_hook_symbol(libcutils_info, "connect", (void *) original_connect, nullptr);
} else {
void *libart_info = xhook_elf_open("libart.so");
xhook_hook_symbol(libart_info, "open", (void *) original_connect, nullptr);
}
if (apiLevel >= 30 || apiLevel == 25 || apiLevel == 24) {
void *libc_info = xhook_elf_open("libc.so");
xhook_hook_symbol(libc_info, "write", (void *) original_write, nullptr);
} else if (apiLevel == 29) {
void *libbase_info = xhook_elf_open("/system/lib64/libbase.so");
xhook_hook_symbol(libbase_info, "write", (void *) original_write, nullptr);
} else {
void *libart_info = xhook_elf_open("libart.so");
xhook_hook_symbol(libart_info, "write", (void *) original_write, nullptr);
}
isHooking = false;
}
//初始化,開啟檢測Signalanr檢測,真正檢測的地方在AnrDumper.cc
static void
nativeInitSignalAnrDetective(JNIEnv *env, jclass, jstring anrTracePath, jstring printTracePath) {
//anr發生時,列印path
const char *anrTracePathChar = env->GetStringUTFChars(anrTracePath, nullptr);
//手動發送SIGQUIT,列印的trace地址
const char *printTracePathChar = env->GetStringUTFChars(printTracePath, nullptr);
anrTracePathstring = std::string(anrTracePathChar);
printTracePathstring = std::string(printTracePathChar);
//開啟檢測,真正檢測的地方在AnrDumper.cc
sAnrDumper.emplace(anrTracePathChar, printTracePathChar, anrDumpCallback);
}
//Free Signal Anr Detective 重置,釋放
static void nativeFreeSignalAnrDetective(JNIEnv *env, jclass) {
//重置,釋放
sAnrDumper.reset();
}
//region MainThreadPriority相關 ,先不看
static void nativeInitMainThreadPriorityDetective(JNIEnv *env, jclass) {
xhook_register(".*\\.so$", "setpriority", (void *) my_setpriority,
(void **) (&original_setpriority));
xhook_register(".*\\.so$", "prctl", (void *) my_prctl, (void **) (&original_prctl));
xhook_refresh(true);
}
//endregion
//自己列印trace,發送自己的行程發送SIGQUIT
static void nativePrintTrace() {
fromMyPrintTrace = true;
kill(getpid(), SIGQUIT);
}
template<typename T, std::size_t sz>//todo
static inline constexpr std::size_t NELEM(const T(&)[sz]) { return sz; }//todo
//JNINativeMethod 陣列 anr相關的
static const JNINativeMethod ANR_METHODS[] = {
{"nativeInitSignalAnrDetective", "(Ljava/lang/String;Ljava/lang/String;)V", (void *) nativeInitSignalAnrDetective},
{"nativeFreeSignalAnrDetective", "()V", (void *) nativeFreeSignalAnrDetective},
{"nativePrintTrace", "()V", (void *) nativePrintTrace},
};
//MainThreadPriority相關的,先不看
static const JNINativeMethod THREAD_PRIORITY_METHODS[] = {
{"nativeInitMainThreadPriorityDetective", "()V", (void *) nativeInitMainThreadPriorityDetective},
};
//JNI_OnLoad 初始化jni環境
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
JniInvocation::init(vm);
JNIEnv *env;
//獲取env環境,如果env環境沒有獲取成功,回傳-1
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK)
return -1;
//獲取SignalAnrTracer變為jclass
jclass anrDetectiveCls = env->FindClass("com/tencent/matrix/trace/tracer/SignalAnrTracer");
if (!anrDetectiveCls)
return -1;
//保存SignalAnrTracer為jclass
gJ.AnrDetective = static_cast<jclass>(env->NewGlobalRef(anrDetectiveCls));
//保存方法
gJ.AnrDetector_onANRDumped =
env->GetStaticMethodID(anrDetectiveCls, "onANRDumped", "()V");
gJ.AnrDetector_onANRDumpTrace =
env->GetStaticMethodID(anrDetectiveCls, "onANRDumpTrace", "()V");
gJ.AnrDetector_onPrintTrace =
env->GetStaticMethodID(anrDetectiveCls, "onPrintTrace", "()V");
//注冊native方法,使得java可以呼叫native
if (env->RegisterNatives(
anrDetectiveCls, ANR_METHODS, static_cast<jint>(NELEM(ANR_METHODS))) != 0)
return -1;
//洗掉anrDetectiveCls
env->DeleteLocalRef(anrDetectiveCls);
jclass threadPriorityDetectiveCls = env->FindClass(
"com/tencent/matrix/trace/tracer/ThreadPriorityTracer");
if (!threadPriorityDetectiveCls)
return -1;
gJ.ThreadPriorityDetective = static_cast<jclass>(env->NewGlobalRef(threadPriorityDetectiveCls));
gJ.ThreadPriorityDetective_onMainThreadPriorityModified =
env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadPriorityModified",
"(I)V");
gJ.ThreadPriorityDetective_onMainThreadTimerSlackModified =
env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadTimerSlackModified",
"(J)V");
if (env->RegisterNatives(
threadPriorityDetectiveCls, THREAD_PRIORITY_METHODS,
static_cast<jint>(NELEM(THREAD_PRIORITY_METHODS))) != 0)
return -1;
env->DeleteLocalRef(threadPriorityDetectiveCls);
return JNI_VERSION_1_6;
} // namespace MatrixTracer
3.AnrDumper.h 定義AnrDumper,繼承SignalHandler
namespace MatrixTracer {
class AnrDumper : public SignalHandler {
public:
//定義回呼方法
using DumpCallbackFunction = std::function<bool()>;
AnrDumper(const char* anrTraceFile, const char* printTraceFile, DumpCallbackFunction&& callback);//&&參考,這個功能是C++的補充,常用在函式傳參(C中一般用指標)、臨時變數參考等,
virtual ~AnrDumper();
private:
//處理signal地方
Result handleSignal(int sig, const siginfo_t *info, void *uc) final;
const DumpCallbackFunction mCallback;
};
} // namespace MatrixTracer
#endif // LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_ANRDUMPER_H_
4.AnrDumper.cc handleSignal方法監聽 SIGQUIT信號,并根據其他行程還是自己行程來呼叫anrCallback 或者siUserCallback,
4.1 anr是system_server行程發來的SIGQUIT,anrCallback代表可能發生了anr,之后會呼叫anrDumpCallback,讓SignalAnrTracer檢測ui執行緒是否block或者狀態為NOT_RESPONDING
#define SIGNAL_CATCHER_THREAD_NAME "Signal Catcher"
#define SIGNAL_CATCHER_THREAD_SIGBLK 0x1000 //得到SignalCatcherThreadId,todo 沒看明白
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
namespace MatrixTracer {
static sigset_t old_sigSet;
const char *mAnrTraceFile;
const char *mPrintTraceFile;
//建立了Signal Handler之后,我們發現在同時有sigwait和signal handler的情況下,
// 信號沒有走到我們的signal handler而是依然被系統的Signal Catcher執行緒捕獲到了,這是什么原因呢?
//
//原來是Android默認把SIGQUIT設定成了BLOCKED,所以只會回應sigwait而不會進入到我們設定的handler方法中,
// 我們通過pthread_sigmask或者sigprocmask把SIGQUIT設定為UNBLOCK,那么再次收到SIGQUIT時,就一定會進入到我們的handler方法中,需要這樣設定:
AnrDumper::AnrDumper(const char *anrTraceFile, const char *printTraceFile,
AnrDumper::DumpCallbackFunction &&callback) : mCallback(callback) {
// must unblocked SIGQUIT, otherwise the signal handler can not capture SIGQUIT
// 必須unblock,否則signal handler無法接收到信號,而是由signal_cahcher執行緒中的sigwait接收信號,走一般的ANR流程
mAnrTraceFile = anrTraceFile;
mPrintTraceFile = printTraceFile;
sigset_t sigSet;
sigemptyset(&sigSet);
sigaddset(&sigSet, SIGQUIT);
pthread_sigmask(SIG_UNBLOCK, &sigSet, &old_sigSet);
}
//得到SignalCatcherThreadId,todo 沒看明白
static int getSignalCatcherThreadId() {
char taskDirPath[128];
DIR *taskDir;
long long sigblk;
int signalCatcherTid = -1;
int firstSignalCatcherTid = -1;
snprintf(taskDirPath, sizeof(taskDirPath), "/proc/%d/task", getpid());
if ((taskDir = opendir(taskDirPath)) == nullptr) {
return -1;
}
struct dirent *dent;
pid_t tid;
while ((dent = readdir(taskDir)) != nullptr) {
tid = atoi(dent->d_name);
if (tid <= 0) {
continue;
}
char threadName[1024];
char commFilePath[1024];
snprintf(commFilePath, sizeof(commFilePath), "/proc/%d/task/%d/comm", getpid(), tid);
Support::readFileAsString(commFilePath, threadName, sizeof(threadName));
if (strncmp(SIGNAL_CATCHER_THREAD_NAME, threadName,
sizeof(SIGNAL_CATCHER_THREAD_NAME) - 1) != 0) {
continue;
}
if (firstSignalCatcherTid == -1) {
firstSignalCatcherTid = tid;
}
sigblk = 0;
char taskPath[128];
snprintf(taskPath, sizeof(taskPath), "/proc/%d/status", tid);
ScopedFileDescriptor fd(open(taskPath, O_RDONLY, 0));
LineReader lr(fd.get());
const char *line;
size_t len;
while (lr.getNextLine(&line, &len)) {
if (1 == sscanf(line, "SigBlk: %" SCNx64, &sigblk)) {
break;
}
lr.popLine(len);
}
if (SIGNAL_CATCHER_THREAD_SIGBLK != sigblk) {
continue;
}
signalCatcherTid = tid;
break;
}
closedir(taskDir);
if (signalCatcherTid == -1) {
signalCatcherTid = firstSignalCatcherTid;
}
return signalCatcherTid;
}
//我們通過Signal Handler搶到了SIGQUIT后,原本的Signal Catcher執行緒中的sigwait就不再能收到SIGQUIT了,
// 原本的dump堆疊的邏輯就無法完成了,我們為了ANR的整個邏輯和流程跟原來完全一致,需要在Signal Handler里面重新向Signal Catcher執行緒發送一個SIGQUIT:
static void sendSigToSignalCatcher() {
//遍歷/proc/[pid]目錄,找到SignalCatcher執行緒的tid
int tid = getSignalCatcherThreadId();
syscall(SYS_tgkill, getpid(), tid, SIGQUIT);
}
//SIGQUIT發生了,其他行程發來的,anr是system_server行程發來的訊息,不是自己行程發來的
static void *anrCallback(void *arg) {
//anr可能發生了,通知SignalAnrTracer檢測ui執行緒是否block或者狀態為NOT_RESPONDING
anrDumpCallback();
if (strlen(mAnrTraceFile) > 0) {
//開始hook write socket
hookAnrTraceWrite(false);
}
//轉發SIGQUIT
sendSigToSignalCatcher();
return nullptr;
}
//SIGQUIT發生了,自己行程發來的,不是anr
static void *siUserCallback(void *arg) {
//這里沒有呼叫anrDumpCallback,因為是自己觸發的
if (strlen(mPrintTraceFile) > 0) {
//開始hook write socket
hookAnrTraceWrite(true);
}
//轉發SIGQUIT
sendSigToSignalCatcher();
return nullptr;
}
//另外,Signal Handler回呼的第二個引數siginfo_t,也包含了一些有用的資訊,該結構體的第三個欄位si_code表示該信號被
// 發送的方法,SI_USER表示信號是通過kill發送的,SI_QUEUE表示信號是通過sigqueue發送的,但在Android的ANR流程中,
// 高版本使用的是sigqueue發送的信號,某些低版本使用的是kill發送的信號,并不統一,
//
//而第五個欄位(極少數機型上是第四個欄位)si_pid表示的是發送該信號的行程的pid,這里適用幾乎所有Android版本和機型的
// 一個條件是:如果發送信號的行程是自己的行程,那么一定不是一個ANR,可以通過這個條件排除自己發送SIGQUIT,
// 而導致誤報的情況,
SignalHandler::Result AnrDumper::handleSignal(int sig, const siginfo_t *info, void *uc) {
// Only process SIGQUIT, which indicates an ANR.
if (sig != SIGQUIT) return NOT_HANDLED;
//Got An ANR
int fromPid1 = info->_si_pad[3];
int fromPid2 = info->_si_pad[4];
int myPid = getpid();
pthread_t thd;
if (fromPid1 != myPid && fromPid2 != myPid) {
//一個條件是:如果發送信號的行程是自己的行程,那么一定不是一個ANR,可以通過這個條件排除自己發送SIGQUIT,
pthread_create(&thd, nullptr, anrCallback, nullptr);
} else {
//自己的行程
pthread_create(&thd, nullptr, siUserCallback, nullptr);
}
pthread_detach(thd);
return HANDLED_NO_RETRIGGER;
}
//沒用到
static void *anr_trace_callback(void *args) {
anrDumpTraceCallback();
return nullptr;
}
//沒用到
static void *print_trace_callback(void *args) {
printTraceCallback();
return nullptr;
}
AnrDumper::~AnrDumper() {
pthread_sigmask(SIG_SETMASK, &old_sigSet, nullptr);
}
} // namespace MatrixTracer
5.我們的SignalHandler類
5.1 signalHandler方法主要是收到了信號
5.2 handleSignal處理信號
namespace MatrixTracer {
class SignalHandler {
public:
SignalHandler();
virtual ~SignalHandler();//解構式:
// 當一個類的物件離開作用域時,解構式將被呼叫(系統自動呼叫),解構式的名字和類名一樣,不過要在前面加上 ~ ,
// 對一個類來說,只能允許一個解構式,解構式不能有引數,并且也沒有回傳值,
// 解構式的作用是完成一個清理作業,如釋放從堆中分配的記憶體,
protected:
enum Result {
NOT_HANDLED = 0, HANDLED, HANDLED_NO_RETRIGGER
};//retrigger
virtual Result handleSignal(int sig, const siginfo_t *info, void *uc) = 0;
private:
static void signalHandler(int sig, siginfo_t *info, void *uc);
static bool installHandlersLocked();
//https://blog.csdn.net/lmb1612977696/article/details/80035487
SignalHandler(const SignalHandler &) = delete;//禁止生成該函式,默認拷貝建構式
SignalHandler &operator=(const SignalHandler &) = delete;//禁止生成該函式,默認賦值函式
};
} // namespace MatrixTracer
#endif // LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_SIGNALHANDLER_H_
6.SignalHandler.cc
6.1 installHandlersLocked 通過可以sigaction方法,建立一個Signal Handler,sa_sigaction方法地址設定為我們的signalHandler方法
6.2 signalHandler 信號處理的地方,轉發給各SignalHandler的handleSignal
//執行緒名字,todo,得到SignalCatcherThreadId,todo 沒看明白
#define SIGNAL_CATCHER_THREAD_NAME "Signal Catcher"
//退出執行緒標記,todo,得到SignalCatcherThreadId,todo 沒看明白
#define SIGNAL_CATCHER_THREAD_SIGBLK 0x1000
namespace MatrixTracer {
//信號
const int TARGET_SIG = SIGQUIT;//3
//使用sigaction方法注冊signal handler進行異步監聽,sOldHandlers是保存老的sigaction
struct sigaction sOldHandlers;//todo
bool sHandlerInstalled = false;
// The global signal handler stack. This is needed because there may exist
// multiple SignalHandler instances in a process. Each will have itself
// registered in this stack.
static std::vector<SignalHandler *> *sHandlerStack = nullptr;//todo
// C++11中新增了<mutex>,它是C++標準程式庫中的一個頭檔案,定義了C++11標準中的一些互斥訪問的類與方法等,其中std::mutex就是lock、unlock,std::lock_guard與std::mutex配合使用,把鎖放到lock_guard中時,mutex自動上鎖,lock_guard析構時,同時把mutex解鎖,mutex又稱互斥量,
static std::mutex sHandlerStackMutex;//todo
static bool sStackInstalled = false;
// InstallAlternateStackLocked will store the newly installed stack in new_stack
// and (if it exists) the previously installed stack in old_stack.
static stack_t sOldStack;//todo
static stack_t sNewStack;//todo
static void installAlternateStackLocked() {//todo
if (sStackInstalled)
return;
//重置
memset(&sOldStack, 0, sizeof(sOldStack));
memset(&sNewStack, 0, sizeof(sNewStack));
static constexpr unsigned kSigStackSize = std::max(16384, SIGSTKSZ);
//取到老的sOldStack
if (sigaltstack(nullptr, &sOldStack) == -1 || !sOldStack.ss_sp ||
sOldStack.ss_size < kSigStackSize) {
sNewStack.ss_sp = calloc(1, kSigStackSize);
sNewStack.ss_size = kSigStackSize;
//設定新的sNewStack
if (sigaltstack(&sNewStack, nullptr) == -1) {
free(sNewStack.ss_sp);
return;
}
}
sStackInstalled = true;
ALOGV("Alternative stack installed.");
}
// Runs before crashing: normal context.
// 我們通過可以sigaction方法,建立一個Signal Handler:ok
bool SignalHandler::installHandlersLocked() {
if (sHandlerInstalled) {
return false;
}
// Fail if unable to store all the old handlers.
//取到老的sOldHandlers
if (sigaction(TARGET_SIG, nullptr, &sOldHandlers) == -1) {
return false;
}
struct sigaction sa{};//sigaction結構體
sa.sa_sigaction = signalHandler;//方法地址,收到信號的地方
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTART;
//我們通過可以sigaction方法,建立一個Signal Handler
if (sigaction(TARGET_SIG, &sa, nullptr) == -1) {//sigaction方法,將sa設定為Signal Handler
ALOGV("Signal handler cannot be installed");
// At this point it is impractical to back out changes, and so failure to
// install a signal is intentionally ignored.
}
sHandlerInstalled = true;
ALOGV("Signal handler installed.");
return true;
}
//todo
static void installDefaultHandler(int sig) {
// Android L+ expose signal and sigaction symbols that override the system
// ones. There is a bug in these functions where a request to set the handler
// to SIG_DFL is ignored. In that case, an infinite loop is entered as the
// signal is repeatedly sent to breakpad's signal handler.
// To work around this, directly call the system's sigaction.
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_RESTART;
sigaction(sig, &sa, nullptr);
}
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
static void restoreHandlersLocked() {//todo
if (!sHandlerInstalled)
return;
//將老的sOldHandlers重新sigaction上
if (sigaction(TARGET_SIG, &sOldHandlers, nullptr) == -1) {
//todo
installDefaultHandler(TARGET_SIG);
}
sHandlerInstalled = false;
ALOGV("Signal handler restored.");
}
static void restoreAlternateStackLocked() {//todo
if (!sStackInstalled)
return;
stack_t current_stack;
if (sigaltstack(nullptr, ¤t_stack) == -1)
return;
// Only restore the old_stack if the current alternative stack is the one
// installed by the call to InstallAlternateStackLocked.
if (current_stack.ss_sp == sNewStack.ss_sp) {
if (sOldStack.ss_sp) {
if (sigaltstack(&sOldStack, nullptr) == -1)
return;
} else {
stack_t disable_stack;
disable_stack.ss_flags = SS_DISABLE;
if (sigaltstack(&disable_stack, nullptr) == -1)
return;
}
}
free(sNewStack.ss_sp);
sStackInstalled = false;
}
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
// 發生信號處理的地方,轉發給各sHandlerStack的handleSignal ok
void SignalHandler::signalHandler(int sig, siginfo_t *info, void *uc) {
ALOGV("Entered signal handler.");
// All the exception signals are blocked at this point.
std::unique_lock<std::mutex> lock(sHandlerStackMutex);
for (auto it = sHandlerStack->rbegin(); it != sHandlerStack->rend(); ++it) {
(*it)->handleSignal(sig, info, uc);
}
lock.unlock();
}
SignalHandler::SignalHandler() {
//上鎖,todo
std::lock_guard<std::mutex> lock(sHandlerStackMutex);
//建一個sHandlerStack
if (!sHandlerStack)
sHandlerStack = new std::vector<SignalHandler *>;
//todo
installAlternateStackLocked();
//todo
installHandlersLocked();
//將自己放進去
sHandlerStack->push_back(this);
}
SignalHandler::~SignalHandler() {
std::lock_guard<std::mutex> lock(sHandlerStackMutex);
auto it = std::find(sHandlerStack->begin(), sHandlerStack->end(), this);
sHandlerStack->erase(it);
if (sHandlerStack->empty()) {
delete sHandlerStack;
sHandlerStack = nullptr;
restoreAlternateStackLocked();
restoreHandlersLocked();
}
}
} // namespace MatrixTracer
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/292521.html
標籤:其他
