其他
一不小心把native crash监控玩坏了
本文作者
作者:Pika
链接:
https://juejin.cn/post/7248513044917682231
本文由作者授权发布。
之前写了几篇关于Linux信号的文章,有很多小读者找到我后台留言,说对他们帮助很大。同时也有小伙伴用了我之前写的一个框架,Signal把公司的Crash上报机制给“玩坏”了。
https://github.com/TestPlanB/Signal
下面我们来看一下具体的经过,已经“始作俑者”的我究竟干了什么。
int sigaction(int __signal, const struct sigaction* __new_action, struct sigaction* __old_action);
struct sigaction sigc;
sigc.sa_sigaction = sig_func;
sigfillset(&sigc.sa_mask);
sigc.sa_flags = SA_SIGINFO | SA_ONSTACK |SA_RESTART;
struct sigaction normal_sig;
normal_sig.sa_sigaction = normal_func;
sigfillset(&normal_sig.sa_mask);
normal_sig.sa_flags = SA_SIGINFO | SA_ONSTACK |SA_RESTART;
我们注册两个sigaction
sigaction(SIGSEGV, &sigc, NULL);
sigaction(SIGSEGV, &normal_sig, NULL);
可以看到,信号处理的这条“链”,它是可以被人为破坏掉的,因为旧的信号处理器可以不被保留,就算被保留了,也可以不调用。
extern "C" int sigaction(int signal, const struct sigaction* new_action,
struct sigaction* old_action) {
InitializeSignalChain();
return __sigaction(signal, new_action, old_action, linked_sigaction);
}
SignalChain机制
__attribute__((constructor)) static void InitializeSignalChain() {
static std::once_flag once;
std::call_once(once, []() {
lookup_libc_symbol(&linked_sigaction, sigaction, "sigaction");
lookup_libc_symbol(&linked_sigprocmask, sigprocmask, "sigprocmask");
#if defined(__BIONIC__)
lookup_libc_symbol(&linked_sigaction64, sigaction64, "sigaction64");
lookup_libc_symbol(&linked_sigprocmask64, sigprocmask64, "sigprocmask64");
#endif
});
}
void FaultManager::Init(bool use_sig_chain) {
CHECK(!initialized_);
if (use_sig_chain) {
sigset_t mask;
sigfillset(&mask);
sigdelset(&mask, SIGABRT);
sigdelset(&mask, SIGBUS);
sigdelset(&mask, SIGFPE);
sigdelset(&mask, SIGILL);
sigdelset(&mask, SIGSEGV);
SigchainAction sa = {
.sc_sigaction = art_sigsegv_handler,
.sc_mask = mask,
.sc_flags = 0UL,
};
AddSpecialSignalHandlerFn(SIGSEGV, &sa);
static bool art_sigsegv_handler(int sig, siginfo_t* info, void* context) {
return fault_manager.HandleSigsegvFault(sig, info, context);
}
extern "C" void AddSpecialSignalHandlerFn(int signal, SigchainAction* sa) {
InitializeSignalChain();
if (signal <= 0 || signal >= _NSIG) {
fatal("Invalid signal %d", signal);
}
chains其实是一个数组,最先加入的元素,也就是Chain头,就是一开始通过FaultManager Init方法加入的处理器
chains[signal].AddSpecialHandler(sa);
chains[signal].Claim(signal);
}
直接调用libc sigaction
获取libc.so句柄
void *libc = dlopen("libc.so", RTLD_LOCAL);
if (__predict_true(NULL != libc)) {
// sigaction64() / sigaction()
libc_sigaction64 = (libc_sigaction64_t)dlsym(libc, "sigaction64");
if (NULL == libc_sigaction64)
libc_sigaction = (libc_sigaction_t)dlsym(libc, "sigaction");
dlclose(libc);
}
struct sigaction sigc;
sigc.sa_sigaction = sig_func;
// 信号处理时,先阻塞所有的其他信号,避免干扰正常的信号处理程序
sigfillset(&sigc.sa_mask);
sigc.sa_flags = SA_SIGINFO | SA_ONSTACK |SA_RESTART;
struct sigaction *ac = calloc(1,sizeof (struct sigaction));
prev_action = ac;
libc_sigaction64(SIGSEGV, &sigc, prev_action);
typedef int (*libc_sigaction64_t)(int, const struct sigaction64 *, struct sigaction64 *);
typedef int (*libc_sigaction_t)(int, const struct sigaction *, struct sigaction *);
static libc_sigaction64_t libc_sigaction64 = NULL;
static libc_sigaction_t libc_sigaction = NULL;
struct sigaction * prev_action;
static void sig_func(int sig_num, struct siginfo *info, void *ptr) {
__android_log_print(ANDROID_LOG_ERROR, "hello", "sig fun ");
prev_action ->sa_sigaction(sig_num,info,ptr);
}
static void normal_func(int sig_num, struct siginfo *info, void *ptr) {
__android_log_print(ANDROID_LOG_ERROR, "hello", "normal_func ");
}
JNIEXPORT void JNICALL
Java_com_pika_mooner_MainActivity_test(JNIEnv *env, jobject thiz) {
void *libc = dlopen("libc.so", RTLD_LOCAL);
if (__predict_true(NULL != libc)) {
// sigaction64() / sigaction()
需要区分64位就调用sigaction64 32就调用sigaction
libc_sigaction64 = (libc_sigaction64_t)dlsym(libc, "sigaction64");
libc_sigaction = (libc_sigaction_t)dlsym(libc, "sigaction");
dlclose(libc);
}
struct sigaction sigc;
sigc.sa_sigaction = sig_func;
// 信号处理时,先阻塞所有的其他信号,避免干扰正常的信号处理程序
sigfillset(&sigc.sa_mask);
sigc.sa_flags = SA_SIGINFO | SA_ONSTACK |SA_RESTART;
struct sigaction *ac = calloc(1,sizeof (struct sigaction));
prev_action = ac;
这里简单直接调用libc_sigaction64
libc_sigaction64(SIGSEGV, &sigc, prev_action);
struct sigaction normal_sig;
normal_sig.sa_sigaction = normal_func;
// 信号处理时,先阻塞所有的其他信号,避免干扰正常的信号处理程序
sigfillset(&normal_sig.sa_mask);
normal_sig.sa_flags = SA_SIGINFO | SA_ONSTACK |SA_RESTART;
sigaction(SIGSEGV, &normal_sig, NULL);
}
之后我们采取这种方式进行APM改造,就能最先获取信号并处理了!
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!