xCrash 和 Android 系统处理 Native Crash 流程(即 debuggerd 守护进程)基本一致。

Android Native Crash 处理流程

初始化

初始化参数信息:

xc_jni#xc_jni_init

static jint xc_jni_init(JNIEnv       *env,
                        jobject       thiz,
                        jint          api_level,
                        jstring       os_version,
												..) {
	// 保存配置参数,获取进程名,创建日志文件夹,
	// 预先打开两个文件描述符,防止文件描述符达到上限,无法创建
	xc_common_init(api, version...) 
	if(crash_enable) {
		...
		// 使用calloc,为需要dump的线程(支持正则配置)数组分配内存
		// 例如 "^xcrash\\\\.sample$", "^Signal Catcher$", "^Jit thread pool$"
		if(NULL != (c_crash_dump_all_threads_whitelist = calloc(len, sizeof(char *)))) {
			...
		}

		//crash init
    r_crash = xc_crash_init(env,
                            crash_rethrow ? 1 : 0,
                            (unsigned int)crash_logcat_system_lines,
                            (unsigned int)crash_logcat_events_lines,
                            (unsigned int)crash_logcat_main_lines,
                            crash_dump_elf_hash ? 1 : 0,
                            crash_dump_map ? 1 : 0,
                            crash_dump_fds ? 1 : 0,
                            crash_dump_network_info ? 1 : 0,
                            crash_dump_all_threads ? 1 : 0,
                            (unsigned int)crash_dump_all_threads_count_max,
                            c_crash_dump_all_threads_whitelist,
                            c_crash_dump_all_threads_whitelist_len);
	...
		
	}
	return (0 == r_crash && 0 == r_trace) ? 0 : XCC_ERRNO_JNI;
}

注册信号捕获

xc_crash#xc_crash_init

int xc_crash_init(JNIEnv *env,
                  int rethrow,
                  unsigned int logcat_system_lines,
                  unsigned int logcat_events_lines,
                  unsigned int logcat_main_lines,
                  int dump_elf_hash,
                  int dump_map,
                  int dump_fds,
                  int dump_network_info,
                  int dump_all_threads,
                  unsigned int dump_all_threads_count_max,
                  const char **dump_all_threads_whitelist,
                  size_t dump_all_threads_whitelist_len)
{
    xc_crash_prepared_fd = XCC_UTIL_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
    xc_crash_rethrow = rethrow;
    if(NULL == (xc_crash_emergency = calloc(XC_CRASH_EMERGENCY_BUF_LEN, 1))) return XCC_ERRNO_NOMEM;
    // 获取 nativeLibraryDir 下的 libxcrash_dumper.so
    if(NULL == (xc_crash_dumper_pathname = xc_util_strdupcat(xc_common_app_lib_dir, "/"XCC_UTIL_XCRASH_DUMPER_FILENAME))) return XCC_ERRNO_NOMEM;
    XCD_LOG_DEBUG("xc_common_app_lib_dir: %s", xc_common_app_lib_dir);
    XCD_LOG_DEBUG("xc_crash_dumper_pathname: %s", xc_crash_dumper_pathname);

    XCD_LOG_DEBUG("xc_common_api_level: %d", xc_common_api_level);
    //init the local unwinder for fallback mode
    xcc_unwind_init(xc_common_api_level);

    //init for JNI callback
    xc_crash_init_callback(env);

    //struct info passed to the dumper process
    memset(&xc_crash_spot, 0, sizeof(xcc_spot_t));
    xc_crash_spot.api_level = xc_common_api_level;
    xc_crash_spot.crash_pid = xc_common_process_id;
    xc_crash_spot.start_time = xc_common_start_time;
    xc_crash_spot.time_zone = xc_common_time_zone;
    xc_crash_spot.logcat_system_lines = logcat_system_lines;
    xc_crash_spot.logcat_events_lines = logcat_events_lines;
    xc_crash_spot.logcat_main_lines = logcat_main_lines;
    xc_crash_spot.dump_elf_hash = dump_elf_hash;
    xc_crash_spot.dump_map = dump_map;
    xc_crash_spot.dump_fds = dump_fds;
    xc_crash_spot.dump_network_info = dump_network_info;
    xc_crash_spot.dump_all_threads = dump_all_threads;
    xc_crash_spot.dump_all_threads_count_max = dump_all_threads_count_max;
    xc_crash_spot.os_version_len = strlen(xc_common_os_version);
    xc_crash_spot.kernel_version_len = strlen(xc_common_kernel_version);
    xc_crash_spot.abi_list_len = strlen(xc_common_abi_list);
    xc_crash_spot.manufacturer_len = strlen(xc_common_manufacturer);
    xc_crash_spot.brand_len = strlen(xc_common_brand);
    xc_crash_spot.model_len = strlen(xc_common_model);
    xc_crash_spot.build_fingerprint_len = strlen(xc_common_build_fingerprint);
    xc_crash_spot.app_id_len = strlen(xc_common_app_id);
    xc_crash_spot.app_version_len = strlen(xc_common_app_version);
    xc_crash_init_dump_all_threads_whitelist(dump_all_threads_whitelist, dump_all_threads_whitelist_len);

    //for clone and fork
#ifndef __i386__
    if(NULL == (xc_crash_child_stack = calloc(XC_CRASH_CHILD_STACK_LEN, 1))) return XCC_ERRNO_NOMEM;
    xc_crash_child_stack = (void *)(((uint8_t *)xc_crash_child_stack) + XC_CRASH_CHILD_STACK_LEN);
#else
    if(0 != pipe2(xc_crash_child_notifier, O_CLOEXEC)) return XCC_ERRNO_SYS;
#endif
    
    //register signal handler
    return xcc_signal_crash_register(xc_crash_signal_handler);
}