3

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

 3 years ago
source link: http://yuanfentiank789.github.io/2016/08/12/crash/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、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));

}


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK