ndroid平台ative代码的崩溃捕获机制及实现腾讯云开发者社区

在Android平台,native crash一直是crash里的大头。native crash具有上下文不全、出错信息模糊、难以捕捉等特点,比java crash更难修复。所以一个合格的异常捕获组件也要能达到以下目的:

其实3个方案在Android平台的实现原理都是基本一致的,综合考虑,可以基于coffeecatch改进。

函数运行在用户态,当遇到系统调用、中断或是异常的情况时,程序会进入内核态。信号涉及到了这两种状态之间的转换。

接收信号的任务是由内核代理的,当内核接收到信号后,会将其放到对应进程的信号队列中,同时向进程发送一个中断,使其陷入内核态。注意,此时信号还只是在队列中,对进程来说暂时是不知道有信号到来的。

进程陷入内核态后,有两种场景会对信号进行检测:

当发现有新信号时,便会进入下一步,信号的处理。

信号处理函数是运行在用户态的,调用处理函数前,内核会将当前内核栈的内容备份拷贝到用户栈上,并且修改指令寄存器(eip)将其指向信号处理函数。

接下来进程返回到用户态中,执行相应的信号处理函数。

信号处理函数执行完成后,还需要返回内核态,检查是否还有其它信号未处理。如果所有信号都处理完成,就会将内核栈恢复(从用户栈的备份拷贝回来),同时恢复指令寄存器(eip)将其指向中断前的运行位置,最后回到用户态继续执行进程。

至此,一个完整的信号处理流程便结束了,如果同时有多个信号到达,上面的处理流程会在第2步和第3步骤间重复进行。

第一步就是要用信号处理函数捕获到native crash(SIGSEGV, SIGBUS等)。在posix系统,可以用sigaction():

首先我们要了解async-signal-safe和可重入函数概念:

回想下在“信号机制”一节中的图示,进程捕捉到信号并对其进行处理时,进程正在执行的正常指令序列就被信号处理程序临时中断,它首先执行该信号处理程序中的指令(类似发生硬件中断)。但在信号处理程序中,不能判断捕捉到信号时进程执行到何处。如果进程正在执行malloc,在其堆中分配另外的存储空间,而此时由于捕捉到信号而插入执行该信号处理程序,其中又调用malloc,这时会发生什么?这可能会对进程造成破坏,因为malloc通常为它所分配的存储区维护一个链表,而插入执行信号处理程序时,进程可能正在更改此链表。(参考《UNIX环境高级编程》)

Single UNIX Specification说明了在信号处理程序中保证调用安全的函数。这些函数是可重入的并被称为是异步信号安全(async-signal-safe)。除了可重入以外,在信号处理操作期间,它会阻塞任何会引起不一致的信号发送。下面是这些异步信号安全函数:

但即使我们自己在信号处理程序中不使用不可重入的函数,也无法保证保存的旧的信号处理程序中不会有非异步信号安全的函数。所以要使用alarm保证信号处理程序不会陷入死锁或者死循环的状态。

考虑到信号处理程序中的诸多限制,一般会clone一个新的进程,在其中完成解析堆栈等任务。

下面是Google Breakpad的流程图,在新的进程中DoDump,使用ptrace解析crash进程的堆栈,同时信号处理程序等待子进程完成任务后,再调用旧的信号处理函数。父子进程使用管道通信。

在我的实验中,在子进程或者信号处理函数中,经常无法回调给java层。于是我选择了在初始化的时候就建立了子线程并一直等待,等到捕捉到crash信号时,唤醒这条线程dump出crash堆栈,并把crash堆栈回调给java。

信号处理函数的入参中有丰富的错误信息,下面我们来一一分析。

发生native crash之后,logcat中会打出如下一句信息:

signal 11 (SIGSEGV), code 0 (SI_USER), fault addr 0x0

根据code去查表,其实就可以知道发生native crash的大致原因:

代码的一部分如下,其实就是根据不同的code,输出不同信息,这些都是固定的。

pc值是程序加载到内存中的绝对地址,我们需要拿到奔溃代码相对于共享库的相对偏移地址,才能使用addr2line分析出是哪一行代码。通过dladdr()可以获得共享库加载到内存的起始地址,和pc值相减就可以获得相对偏移地址,并且可以获得共享库的名字。

作为有追求的我们,肯定不满足于仅仅通过一个函数就获得答案。我们尝试下如何手工分析出相对地址。首先要了解下进程的地址空间布局。

任何一个程序通常都包括代码段和数据段,这些代码和数据本身都是静态的。程序要想运行,首先要由操作系统负责为其创建进程,并在进程的虚拟地址空间中为其代码段和数据段建立映射。光有代码段和数据段是不够的,进程在运行过程中还要有其动态环境,其中最重要的就是堆栈。

上图中Random stack offset和Random mmap offset等随机值意在防止恶意程序。Linux通过对栈、内存映射段、堆的起始地址加上随机偏移量来打乱布局,以免恶意程序通过计算访问栈、库函数等地址。

栈(stack),作为进程的临时数据区,增长方向是从高地址到低地址。

在Linux系统中,/proc/self/maps保存了各个程序段在内存中的加载地址范围,grep出共享库的名字,就可以知道共享库的加载基值是多少。

得到相对偏移地址之后,使用readelf查看共享库的符号表,就可以知道是哪个函数crash了。

在前一步,我们获取了奔溃时的pc值和各个寄存器的内容,通过SP和FP所限定的stack frame,就可以得到母函数的SP和FP,从而得到母函数的stack frame(PC,LR,SP,FP会在函数调用的第一时间压栈),以此追溯,即可得到所有函数的调用顺序。

libunwind是一个独立的开源库,高版本的安卓源码中也使用了libunwind作为解堆栈的工具,并针对安卓做了一些适配。下面是使用libunwind解堆栈的主循环,每次循环解一层堆栈。

可以通过libcorkscrew中的get_backtrace_symbols函数获得函数符号。

更通用的方法是通过dladdr获得函数名字。

传入每一层堆栈的相对偏移地址,就可以从dli_fname中获得函数名字。

如何获得native crash所对应的java层堆栈,这个问题曾经困扰了我一段时间。这里有一个前提:我们认为crash线程就是捕获到信号的线程,虽然这在SIGABRT下不一定可靠。有了这个认知,接下来就好办了。在信号处理函数中获得当前线程的名字,然后把crash线程的名字传给java层,在java里dump出这个线程的堆栈,就是crash所对应的java层堆栈了。

在c中获得线程名字:

然后传给java层:

经过诸多探索,终于得到了完美的堆栈:

在native层构造了一个Error传给java,所以在java层可以很轻松地根据堆栈进行业务上的处理。

另外初始化时就建立等待回调线程的方式,提供了稳定的给java层的回调。在回调中我们打印了app的状态信息,包括activity的堆栈、app是否在前台等,以及打印crash前的logcat日志和把应用日志flush进文件。针对某些具体的native crash还做了业务上的处理,例如遇到热补丁框架相关的crash时就回滚补丁。

在用户环境中的很多native crash单靠堆栈是解决不了的,logcat是非常重要的补充。好几例webview crash都是通过发生crash时的logcat定位的。比如我们曾经遇到过的一个的webview crash:

单凭堆栈根本看不出来是什么问题,但是在logcat中却看到这样一个warning log:

查代码发现是我们在WebViewClient的shouldInterceptRequest接口中的业务代码发生了NullPointerException, 传进去WebView内部变成了natvie crash,问题解决。

THE END
0.熬夜的理由千千万,早睡的理由只有这一条…哪个不是对熬夜的危害倒背如流? 可不管爸妈朋友圈里的养生爆文 把熬夜写得多么「十恶不赦」 我们还是对熬夜修仙有着迷之执念 当代年轻人为什么会沉迷熬夜无法自拔呢? 正如歌词所说: 「夜太美,尽管再危险,总有人黑着眼眶熬着夜」 除了那些由于失眠迫不得以睁眼到天明的小可怜外 https://www.meipian.cn/2ie8z1fx
1.怎么解锁自己的朋友圈权限怎么解锁自己的朋友圈本文共计6个字怎么解锁自己的朋友圈权限 怎么解锁自己的朋友圈 导读: 對喜歡規避責任的人來說,困難則成了最好的擋箭牌。 假如每個人成天都認為環境不好,當然就會把自己的過失諉諸「缺陷」或種種其他原因。 具有成熟心靈的人,他們不會陷於自己的困難當中,而是勇敢地去面對它、接受它,然後想辦法加以克服、解決。他們不會去乞憐,https://www.52yuer.cn/qiaomen/zhichang/16829472759607702.html
2.花样文字app下载安装花样文字解锁版下载v2.9.4《花样文字 解锁版》一款有趣的字体转换软件,可以在朋友圈、小红书、Ins、抖音等各种社交软件上打出花样字体、特殊符号,自带朋友圈热门文案,常用花式短语,颜文字,小辫子 Emoji 等,让在你聊天交友,网站冲浪时把文字玩出花,那还等什么,感兴趣的下载去体验吧。 软件简介 丰富海量的表情输入,各种特殊符号完美演绎,https://shouyou.3dmgame.com/android/263374.html
3.ppt被锁定不能编辑怎么办ppt被锁定不能编辑解决方法【教程2. iSunshare PowerPoint Unprotect Genius:这是另一款流行的PPT解锁工具,可以帮助您解锁被锁定的PPT文件。 四、联系PPT文件的创建者 如果您无法解锁PPT文件或找不到合适的解锁工具,您可以尝试联系PPT文件的创建者。他们可能知道PPT文件的保护密码或其他解锁方法。通过与他们沟通,您可能能够解决PPT锁定不能编辑的问题https://g.pconline.com.cn/x/1655/16554889.html
4.最全最好用的app推荐——总能找到你需要的那一款1、专为手机控设计,设定自己不能玩手机的时间,手机会被锁定,能一定程度控制玩手机的欲望 2、界面简单,容易操作,强行玩手机会被迫发朋友圈等社交圈开锁 〈三〉时间管理 推荐一:爱今天 图片发自简书App 推荐理由: 1、超喜欢的时间管理app,可以规划自己的小目标,并且设定完成这个目标的总时间,平均每天完成的时间,比https://www.jianshu.com/p/835ccf6d0d37
5.原创10个日签文案,适合发朋友圈(附日签海报)文案不该有套路,我们更不该被套路锁死思维。 1、 有人想赚钱, 有人想做自己喜欢的事, 而我属于既想赚钱又想做自己喜欢的事的人, 但无论选择何种生活, 开心才是最重要的。 ——人生苦短,及时行乐 2、 我们总会试图留住一切美好, 但我们是否想过, http://www.360doc.com/content/20/0311/14/66265126_898407248.shtml
6.微信新增删除声音锁功能扩展文字输入区域据相关爆料,微信发布了 iOS 微信 8.0.30 正式版,Android和iOS都可以升级至微信的最新版本,新版本升级主要为三方面,分别为微信朋友圈扩展文字输入区域、长按订阅号可以取消关注、新增删除声音锁功能。 据悉,微信朋友圈扩展文字输入区域主要是大家在编辑朋友圈文案时,文本区域会随着文字的数量而逐渐增大,更方面大家编辑与http://www.mnw.cn/news/digi/2707440.html
7.精JAVA基础进阶知识汇总HELLOXFjava进阶里氏替换原则:继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层https://blog.csdn.net/LANXIAMAO/article/details/130040533
8.几个实用的微信隐藏小技巧,你知道吗?|TaoKeShow复制括号内的文字代码( ॣ ॣ ॣ ),然后发送给需要检测的好友,这个文字代码对方是接收不到的,不会有任何提示。所以可以在对方不知情的情况下检测对方是否删除拉黑你。 二、微信发送长视频到朋友圈 微信朋友圈限制只能发十秒钟的视频,但是我们可以通过收藏笔记的方法发送长视频到朋友圈(不能超过五分钟)。首先https://www.taokeshow.com/3769.html
9.中国教育报“青年说”2022年度十佳从表达的分类讲,一是私人表达,比如写日记、在朋友圈发布感想等等,这些属于自言自语,没想让别人阅读,不产生溢出效应;二是公共表达,即在公共平台撰写评论或其他文本,将自己的生活、知识或理念或观点进行发表,这是一种分享或对话行为,具有明显的溢出效应。http://www.jyb.cn/rmtzcg/xwy/wzxw/202212/t20221230_2110987567.html
10.快科技资讯2022年04月28日Blog版资讯中心就拿平行视界功能来说,用户可以将一个应用的不同功能页面分屏显示,实现诸如微信视频通话的同时刷朋友圈等类似体验,简化了操作步骤,提高效率。 华为浏览器针对折叠屏进行了深度适配,其全新推出的网页自适应功能能够规避在大屏上,内容被强行拉伸的扰人体验;多任务分屏功能也让用户可以便浏览资讯,边记录下想法和灵感。 https://news.mydrivers.com/blog/20220428.htm
11.JAVA实习面试题大全必看java实习生面试题②禁止指令重排序,被修饰的变量不会被缓存在寄存器中或者对其他处理器不可见的地方,因此在读取volatile修饰的变量时总是会返回最新写入的值。③不会执行加锁操作,不会导致线程阻塞,主要适用于一个变量被多个线程共享,多个线程均可对这个变量执行赋值或读取的操作。④volatile可以严格保证变量的单次读写操作的原子性,https://blog.csdn.net/weixin_43833597/article/details/105261758
12.微信已发说说怎么锁微信朋友圈可直接发布图片动态。图片可以选择拍照或者从相册中选取,一次最多可以分享九张图片。但图片发布出来后会有压缩,不同平台的压缩比率不同。通常来说,iOS下发布的图片清晰度高于其他平台。发布图片的同时可以配上文字说明。 怎么样判断对方微信朋友圈是锁或是删完了说说 https://www.51dongshi.com/gefzdsgecdv.html
13.微信使用常见问题25问或者不看某些人发到朋友圈的内容? 回答: 请到微信的【我】-【设置】-【隐私】。 (偷偷说:如果设置不让好友看自己朋友圈,有个小缺点,当好友来查看你相册的是时候,如果一张都看不到,对方就明白发生了什么。) 问题17 能不能每次发朋友圈消息时,临时设置让这一条不被某些人看? 回答: 上面第16条讲的是一次https://www.360doc.cn/article/1003261_737340831.html
14.懂视锁定一行不动 一行锁定 竖排文字从左 ppt竖排文本 从左往右 从右到 怎么从左到右 从右至左 从左至右 ppt竖排文字怎么设置从左到右 竖排从左 竖排文字从左到右 文字从右 直播领红包怎么领 百度知道直播怎么 直播如何领红包 直播领红包怎么 知道怎么领取直播 直播红包怎么领 设置图片自动播放 图片播放 图片怎么https://m.51dongshi.com/tagall679/
15.GitHubAllocAndInit/TimLiuGSAlert.swfit - 苹果在iOS8推出了全新的UIAlertController,旧的UIAlertView和UIActionSheet渐渐被废弃,但如果你仍然支持iOS7系统,你将不得不写两套代码。GSAlert解决了这个问题. SweetAlert-iOS - SweetAlert-iOS 带动画效果弹窗对话框封装类. CCActionSheet - CCActionSheet:仿照微信朋友圈自定义actionsheet,一行代码即可https://github.com/AllocAndInit/TimLiu-iOS
16.iOS第三方库插件知名博客总结纯情的小公鸡CCActionSheet- CCActionSheet:仿照微信朋友圈自定义actionsheet,一行代码即可使用。 TKSwarmAlert.swift- TKSwarmAlert.swift:模仿 Swarm app 的 Alert 提醒框动画工具。 CustomPopOverView- 自定义弹出视图,内容支持传一组菜单标题,也支持自定义view,或者自定义viewController,支持任意按钮触发,会显示在按钮底部,也支持切https://www.cnblogs.com/YangFuShun/p/8430828.html