Android上如何在发生崩溃时抓取日志

Posted by JackPeng on August 12, 2016

一、java层未处理异常

未处理异常定义:没有被try…catch 住的异常(这里说的异常包括Exception和Error) Java层默认未处理异常的Handler,都是调用Thread.setDefaultUncaughtExceptionHandler,注册一个UncaughtExceptionHandler来实现的。可以抓到所有线程的未处理异常

final Thread.UncaughtExceptionHandler oldHandler = Thread.getDefaultUncaughtExceptionHandler();
	Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		
		@Override
		public void uncaughtException(Thread thread, Throwable throwable) {
			// 编写崩溃前的处理逻辑
			// ...
			// 此回调既可以收到Exception, 也可以收到Error


                            /*调用默认处理,杀死进程*/
			oldHandler.uncaughtException(thread, throwable);
		}
	});

当然也可以注册针对指定线程的未处理异常的Handler,如:

Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
				
				@Override
				public void uncaughtException(Thread thread, Throwable throwable) {
					// 编写崩溃前的处理逻辑
					// ...
					// 此回调既可以收到Exception, 也可以收到Error
					if( /*这是一个致命错误*/ ) {
						//调用默认处理,杀死进程
						Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, throwable);
					} else {
						// 什么也不处理的话, 当前线程被终止,但是整个进程可以继续运行
					}
				}
			});

另外发现,有一种捕获不到的exception,可以尝试adb log捕获所有信息,然后删选有用信息

二、native层异常

native异常是通过信号来通知的。所以要想抓到native异常,需要注册信号回调。

注册方法:

static struct sigaction g_oldCSSigAction[8] = {0};
void CrashSaver_handleSignal(int sig, siginfo_t* info, void* context);

// 注册信号函数
void CrashSaver_install()
{
// 保存信号的默认行为对象
memset(g_oldCSSigAction, 0, sizeof(g_oldCSSigAction));
sigaction(SIGTRAP, NULL, &g_oldCSSigAction[0]);
sigaction(SIGABRT, NULL, &g_oldCSSigAction[1]);
sigaction(SIGILL, NULL, &g_oldCSSigAction[2]);
sigaction(SIGSEGV, NULL, &g_oldCSSigAction[3]);
sigaction(SIGFPE, NULL, &g_oldCSSigAction[4]);
sigaction(SIGBUS, NULL, &g_oldCSSigAction[5]);
sigaction(SIGPIPE, NULL, &g_oldCSSigAction[6]);
sigaction(SIGSYS, NULL, &g_oldCSSigAction[7]);

// 创建 信号行为对象
struct sigaction newSigAction;       
sigemptyset(&newSigAction.sa_mask);
newSigAction.sa_flags = SA_SIGINFO;
/*设置信号处理函数*/
newSigAction.sa_sigaction = CrashSaver_handleSignal;

// 注册信号新的行为对象
sigaction(SIGTRAP, &newSigAction, NULL);
sigaction(SIGABRT, &newSigAction, NULL);
sigaction(SIGILL, &newSigAction, NULL);
sigaction(SIGSEGV, &newSigAction, NULL);
sigaction(SIGFPE, &newSigAction, NULL);
sigaction(SIGBUS, &newSigAction, NULL);
sigaction(SIGPIPE, &newSigAction, NULL);
sigaction(SIGSYS, &newSigAction, NULL);

}

编写回调处理函数:

void CrashSaver_handleSignal(int sig, siginfo_t* info, void* context)
{
// sig  触发的信号ID   如 SIGABRT、SIGSEGV等
// info  对此信号的描述信息
// context 信号发生的上下文。比如各种寄存器信息。此结构和具体的CPU平台有关

// 此处增加处理逻辑

CrashSaver_uninstall(); /*反注册*/
raise(signum); /*调用系统默认信号处理*/
}

反注册函数:

void CrashSaver_uninstall()
{
sigaction(SIGTRAP, &g_oldCSSigAction[0], NULL);
sigaction(SIGABRT, &g_oldCSSigAction[1], NULL);
sigaction(SIGILL , &g_oldCSSigAction[2], NULL);
sigaction(SIGSEGV, &g_oldCSSigAction[3], NULL);
sigaction(SIGFPE, &g_oldCSSigAction[4], NULL);
sigaction(SIGBUS, &g_oldCSSigAction[5], NULL);
sigaction(SIGPIPE, &g_oldCSSigAction[6], NULL);
sigaction(SIGSYS, &g_oldCSSigAction[7], NULL);
memset(g_oldCSSigAction, 0, sizeof(g_oldCSSigAction));

}