网络技术

找论坛
zst_banyue
Lv5 太平洋舰队上尉
太平洋舰队上尉 贡献966,距离下一级还需134贡献
楼主
2018-03-13 15:26 0 0 只看楼主
电梯直达 
[p=26, null, left]本着探究下iOS Crash捕获的目的,学习了下Crash捕获相关的Mach异常和signal信号处理,记录下相关内容,并提供对应的测试示例代码。Mach为XNU的微内核,Mach异常为最底层的内核级异常,在iOS系统中,底层Crash先触发Mach异常,然后再转换为对应的signal信号。[/p] [p=26, null, left]作者:阿里云-移动云-大前端团队
[/p][p=26, null, left]原文:http://click.aliyun.com/m/43672/
[/p][p=26, null, left]1. iOS Mach异常[/p][p=26, null, left]1.1 XNU[/p][p=26, null, left]Darwin是Mac OS和iOS的操作系统,而XNU是Darwin操作系统的内核部分。XNU是混合内核,兼具宏内核和微内核的特性,而Mach即为其微内核。[/p][p=26, null, left]评论[/p][p=26, null, left]Darwin操作系统和MacOS、iOS系统版本号的对应如上图所示,Mac可执行下述命令查看Darwin版本号。[/p][p=26, null, center]评论[/p][p=26, null, left]1.2 Mach[/p][p=26, null, left]Mach:[m?k],操作系统微内核,是许多新操作系统的设计基础。[/p][p=26, null, left]Mach微内核中有几个基础概念:[/p]

  • Tasks,拥有一组系统资源的对象,允许"thread"在其中执行。
  • Threads,执行的基本单位,拥有task的上下文,并共享其资源。
  • Ports,task之间通讯的一组受保护的消息队列;task可对任何port发送/接收数据。
  • Message,有类型的数据对象集合,只可以发送到port。
[p=26, null, left]1.3 模拟Mach Message发送[/p]

  • Mach提供少量API,苹果文档介绍较少。
[p=26, null, center]评论[/p][p=26, null, left]下述代码模拟向Mach Port发送Message,接收Message后做处理:[/p]

  • 首先调用createPortAndAddListener创建Mach Port;
  • 调用sendMachPortMessage:向已创建的Mach Port发送消息;
  • 执行结果示例:
[p=26, null, center]评论[/p]

  • 示例代码:
[p=26, null, center]评论[/p][p=26, null, center]评论[/p][p=26, null, left]1.4 捕获Mach异常[/p]

  • task_set_exception_ports(),设置内核接收Mach异常消息的Port,替换为自定义的Port后,即可捕获程序执行过程中产生的异常消息。
  • 执行结果示例:
[p=26, null, center]评论[/p]

  • 示例代码:
[p=26, null, center]评论[/p][p=26, null, left]1.5 Runloop[/p][p=26, null, left]Mach Port的应用不止于内核级别,在Cocoa Foundation和Core Foundation层同样有其应用,比如说:Runloop。[/p][p=26, null, left]评论[/p][p=26, null, left]Runloop sources分两类:[/p]

  • Input sources ? Port-Based sources ? Custom Input sources
  • Timer sources
[p=26, null, left]其中Port-Based sources即基于Mach Port,在Runloop中完成消息传递。[/p][p=26, null, left]上述的Mach API为内核层透出接口,Cocoa Foundation和Core Foundation层分别封装了Mach Port的接口供调用,参考:Apple - Runloop Programming Guard,有详细的示例代码。[/p][p=26, null, left]2. signal信号[/p][p=26, null, left]signal是一种软中断信号,提供异步事件处理机制。signal是进程间相互传递信息的一种粗糙方法,使用场景:[/p]

  • 进程终止相关;
  • 终端交互;
  • 编程错误或硬件错误相关,系统遇到不可恢复的错误时触发崩溃机制让程序退出,比如:除0、内存写入错误等。
[p=26, null, left]这里我们主要考虑系统遇到不可恢复的错误时即Crash时,信号相关的应用。signal信号处理是UNIX操作系统机制,所以Android平台理论上也是使用的,可以基于signal来捕获Android Native Crash。[/p][p=26, null, left]2.1 signal注册和处理[/p]

  • signal() ? #import <sys/signal.h>; ? 注册signal handler; ? 调用成功时,会移除signo信号当前的操作,以handler指定的新信号处理程序替代; ? 信号处理函数返回void,因为没有地方给该函数返回。
  • 注册自定义信号处理函数,构造Crash后,发出信号并执行自定义信号处理逻辑。 ? 【附】:Xcode Debug运行时,添加断点,在Crash触发前,执行pro hand -p true -s false SIGABRT命令。
[p=26, null, center]评论[/p]

  • 示例代码:
[p=26, null, center]评论[/p][p=26, null, left]2.2 LLDB Debugger[/p][p=26, null, left]Xcode Debug模式运行App时,App进程signal被LLDB Debugger调试器捕获;需要使用LLDB调试命令,将指定signal处理抛到用户层处理,方便调试。[/p]

  • 查看全部信号传递配置:
[p=26, null, center]评论[/p]

  • 修改指定信号传递配置:
[p=26, null, center]评论[/p][p=26, null, left]2.3 可重入[/p][p=26, null, left]向内核发送信号时,进程可能执行到代码的任意位置,例:进程在执行重要操作,中断后可能产生不一致状态,或进程正在处理另一信号。因此要确保信号处理程序只执行可重入操作:[/p]

  • 写中断处理程序时,假定中断进程可能处于不可重入函数中。
  • 慎重修改全局数据。
[p=26, null, left]2.4 高级信号处理[/p][p=26, null, left]signal()函数非常基础,只提供了最低限度的信号管理的标准。而sigaction()系统调用,提供更强大的信号管理能力。当信号处理程序运行时,可以用来阻塞特定信号的接收,也可以用来获取信号发送时各种操作系统和进程状态的信息。[/p]

  • 示例代码:
[p=26, null, center]评论[/p][p=26, null, left]3. 参考[/p]

您需要登录后才可以发帖 登录 | 立即注册

其他登录方式:

常用表情
太平洋电脑网论坛帖子仅代表作者本人意见,不代表网站立场。请勿轻信特价、汇款、中奖等信息,
请勿轻易透露个人资料,因此产生的一切后果,PConline不承担任何责任
回复 发新帖 找论坛 反馈 回顶部