在Android Native层实现Try/Catch异常处理机制


在Java层,我们可以使用try/catch语句来捕获和处理异常。然而,在Android的Native层(C/C++代码),我们并没有内置的异常处理机制。这篇文章将介绍如何在Android Native层实现类似于try/catch的异常处理机制。

一、技术原理

在Native层实现异常处理的关键在于信号处理(Signal Handling)和非局部跳转(Non-Local Jumps)。当程序发生错误(如访问非法内存、除以零等)时,操作系统会向进程发送一个信号。我们可以设置一个信号处理函数(Signal Handler),在收到信号时执行特定的代码。

非局部跳转提供了一种在程序中跳转到另一个位置的方法,而不是按照正常的控制流程执行。在C语言中,我们可以使用setjmplongjmp函数来实现非局部跳转。setjmp函数保存当前的执行上下文(包括堆栈和寄存器状态等),并返回0。longjmp函数恢复由setjmp保存的上下文,并使setjmp返回一个非零值。我们可以利用这个特性,在信号处理函数中调用longjmp,跳转到setjmp所在的位置,实现异常的捕获和处理。

二、代码实现

2.1 定义结构体保存线程的异常处理信息

首先,我们定义一个结构体native_code_handler_struct,用于保存线程的异常处理信息。这个结构体包括一个sigjmp_buf类型的变量ctx,用于保存setjmp的上下文;一个标志位ctx_is_set,表示上下文是否已经被设置;以及其他与异常处理相关的信息。

/* Thread-specific crash handler structure. */
typedef struct native_code_handler_struct {
   
  /* Restore point context. */
  sigjmp_buf ctx;
  int ctx_is_set;
  int reenter;

  /* Alternate stack. */
  char *stack_buffer;
  size_t stack_buffer_size;
  stack_t stack_old;

  /* Signal code and info. */
  int code;
  siginfo_t si;
  ucontext_t uc;

  /* Custom assertion failures. */
  const char *expression;
  const char *file;
  int line;

  /* Alarm was fired. */
  int alarm;
} native_code_handler_struct;

native_code_handler_struct* native_code_handler_g;

static native_code_handler_struct* getCrashHandler() {
   
    return native_code_handler_g;
}

2.2 实现try/catch语义

然后,我们定义了一系列的函数和宏,用于实现try/catch语义。COFFEE_TRY宏检查当前是否已经在一个try块中(通过inside函数),如果不在,则设置信号处理函数(通过setupSignalHandler函数)并保存执行上下文(通过sigsetjmp函数)。COFFEE_CATCH宏和COFFEE_END宏则用于标识catch块和try/catch块的结束。

/** Internal functions & definitions, not to be used directly. **/
#include <setjmp.h>
extern int inside(void);
extern int setupSignalHandler(int);
extern sigjmp_buf* get_ctx(void);
extern void cleanup(void);
#define COFFEE_TRY()                                \
  if (inside() || \
      (setupSignalHandler() == 0 \
       && sigsetjmp(*get_ctx(), 1) == 0))
#define COFFEE_CATCH() else
#define COFFEE_END() cleanup()
/** End of internal functions & definitions. **/

2.3 检查当前线程的异常处理信息

inside函数检查当前线程的异常处理信息,如果已经在一个try块中,则增加reenter计数并返回1;否则返回0。

 * Returns 1 if we are already inside a coffeecatch block, 0 otherwise.
 */
int inside() {
   
    native_code_handler_struct *const t = getCrashHandler();
    if (t != NULL && t->reenter > 0) {
   
        t->reenter++;
        return 1;
    }
    return 0;
}

2.4 设置信号处理函数

setupSignalHandler函数设置信号处理函数,并将reenter计数加1,表示进入了一个新的try块。

/**
 * Calls handler_setup(1) to setup a crash handler, mark the
 * context as valid, and return 0 upon success.
 */
int setupSignalHandler(int id) {
   
    if (handler_setup(1, id) == 0) {
   
        native_code_handler_struct *const t = getCrashHandler();
        assert(t != NULL);
        t->reenter++;
        t->ctx_is_set = 1;
        LOGD("setup reenter:%d", t->reenter);
        return 0;
    } else {
   
        return -1;
    }
}

handler_setup设置崩溃处理器,包括全局和线程相关的资源。首先调用handler_setup_global(id)初始化全局资源,然后为当前线程初始化本地资源。

/**
 * Acquire the crash handler for the current thread.
 * The handler_cleanup() must be called to release allocated
 * resources.
 **/
static int handler_setup(int setup_thread, int id) {
   
    int code;
    
    DEBUG(print("setup for a new handler\n"));
    
    /* Initialize globals. */
    if (pthread_mutex_lock(&native_code_g.mutex) != 0) {
   
        return -1;
    }
    
    code = handler_setup_global(id);
    
    if (pthread_mutex_unlock(&native_code_g.mutex) != 0) {
   
        return -1;
    }
    
    /* Global initialization failed. */
    if (code != 0) {
   
        return 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆业聪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值