前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >有赞 Android 崩溃保护的探索及实践

有赞 Android 崩溃保护的探索及实践

作者头像
有赞coder
发布于 2020-08-25 06:38:17
发布于 2020-08-25 06:38:17
1.3K00
代码可运行
举报
运行总次数:0
代码可运行

概述

Android 的 Crash 是件让人头疼的事,测试阶段好好的代码一上线就各种崩溃,即使是一个微不足道的 bug 也得发个 hotfix。很多时候我们更希望即使个别功能没法使用也不要崩溃,比如点击图片想看大图时,由于 onClick 回调中没做判空处理等导致 APP 崩溃了,这时我们更希望即使不能看大图也不要崩溃,这时你可以考虑使用 Bandage,当然 Bandage的强大之处远不止这些。

Bandage是什么

Bandage:绷带,通用的止血工具。 Bandage可以最大程度保证 APP 可用,任何 Java 异常都不会导致 APP 崩溃。 Bandage试图在 APP 即将崩溃时尽量去挽救,不至于情况更糟糕(医生,我觉得我还可以再抢救一下)。当然有些异常是一定要终止 APP 的,不然可能会给公司造成更大的损失,对于这种异常,可以通过黑白名单决定要不要终止 APP。

Bandage 是如何实现的

拦截 Activity 生命周期的异常

Activity 生命周期(比如 onCreateonResume等)抛出异常时,如果不 finish掉抛出异常的 Activity 的话会导致黑屏。

如何拦截?

简单来说是替换了 ActivityThread.mH.mCallback

Activity 生命周期所有方法都是在 mHhandleMessage方法中调用的,只要能拦截这个 handleMessage方法就能拦截所有生命周期的异常。然而我们没法通过反射替换掉这个 mH对象。因为 mH是 ActivityThread 中一个 H 类的实例,H 类又继承自 Handler,H 类又是 ActivityThread 中的一个私有类,但是 Handler会在调用 handleMessage前调用 mCallback.handleMessagemCallback是可以被替换掉的。

替换方式如下,可以参考 hookmH 方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//mhHandler是ActivityThread.mH,callbackField 是 mH 中的 mCallback 字段,可以通过反射得到
        callbackField.set(mhHandler, new Handler.Callback() {
            //拦截到生命周期相关的消息
            @Override
            public boolean handleMessage(Message msg) {
                switch (msg.what) {
                    case LAUNCH_ACTIVITY:
                        try {
                            //调用ActivityThread.mH.handleMessage
                            mhHandler.handleMessage(msg);
                            return true;
                        } catch (Throwable throwable) {
                            //捕获到生命周期的异常,可以直接关闭该Activity,参考下文的 finish Activity生命周期异常的Activity
                        }
                        //...省略部分相似逻辑
                }
                return false;
            }
        });

相关代码

  • Looper.loop()方法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void loop() {
        for (; ; ) {
            Message msg = queue.next(); // might block
            msg.target.dispatchMessage(msg);
        }
    }

Android 主线程所有的消息都是在这调用的,包括生命周期回调,view 绘制,自己 new Handler post 的消息等等。 msg.target就是相关联的 Handler,如果自己 new Handler 并 post 消息的话那么这个 target 就是你 new 的 Handler,也就是说哪个 Handler post 的 Message 就交给那个 Handler 处理。生命周期相关的 Message 是 mH post的,所以要交给 mH处理。

  • Handler.dispatchMessage方法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

可以看到会先判断 mCallback是否存在,存在的话就交给 mCallbackhandleMessage处理,如果 mCallbackhandleMessage返回 true 则不再调用 Handler 的 handleMessage方法。所以我们可以通过上述方式实现拦截 Activity 生命周期的异常。

finish 生命周期异常的 Activity

通过 ActivityManagerfinishActivity结束掉生命周期抛出异常的 Activity。

各版本 Android 的 ActivityManager 获取方式, finishActivity的参数, mToken(binder对象)的获取不一样,我们可以去每个版本的 Activity 的 finish 方法中查看,比如 API26 调用的是如下方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ActivityManager.getService().finishActivity(mToken, resultCode, resultData, finishTask)

mToken可以从 mH的 message 中获取。具体实现可以参考这 finish Activity

拦截主线程的其他异常

上文说过 Android 主线程所有的消息都是在 Looper.loop()方法中调用的,只要能 try catch 住这个 loop 方法就能实现拦截主线程的所有异常,我们可以在 uncaughtException方法中执行如下代码。实现方式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
while (true) {
    try {
        Looper.loop();
    } catch (Throwable e) {
    }
}
  • 为什么要加个 while 死循环?

如果不加 while 的话就只能捕获一次主线程的异常,下次主线程再抛出异常的话就没法在这捕获了。

  • 加了 while 不会 ANR 吗?

不会的,因为 while 内部又调用了 Looper.loop(),这时主线程就又开始消息循环了,主线程会不断的取走主线程中唯一的消息队列头部的消息执行掉,然后等待下一个消息的到来。所以主线程不会卡住,当然不会 ANR。每次主线程抛出异常时就会被我们的 try catch 捕获到,然后又进入了 while 循环。

拦截其他异常

通过 Thread.setDefaultUncaughtExceptionHandler 捕获其他异常。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
            }
        });

异常处理

有些异常是一定要终止 APP 的,不然可能会对公司造成更大的损失,而有些异常是可以直接忽略的。建议通过黑白名单控制拦截到的异常是直接忽略还是杀进程。可以在 APP 启动时,或者 crash 后下次重启时请求接口更新黑白名单。

什么样的异常可以不杀进程?

  • 如果忽略该异常不会对公司造成损失可以不杀进程
  • 如果忽略该异常只是造成某个 Activity 打不开,而没有其他副作用的话可以不杀进程
  • 如果忽略该异常只是部分 UI 不展示,而没有其他副作用的话可以不杀进程
  • 单纯的 UI 展示 Activity 的话可以不杀进程(比如只是展示商品详情等),涉及到金钱的 Activity 建议杀进程(比如当前 Activity 中有些开单计算,支付,退款等逻辑)
  • 对于一些顽疾,每个版本都出现,但又找不到问题所在,忽略后又没啥影响的异常可以不杀进程

总之,要不要杀进程由你决定,只要可以提升用户体验,并且不会对公司造成额外损失都可以不杀进程。

注意: ViewRootImpl抛出异常时可能会导致黑屏,这种情况建议直接终止 APP。

遍历出错堆栈,如果是 ViewRootImpl相关的异常建议直接杀进程,不然可能导致黑屏。

黑白名单如何配置?

只根据异常堆栈的话可能无法唯一确定一个问题,比如有两个 Activity,各有一个 Handler,都 post 了一个 Runnable,run 方法中一开始就都抛出了空指针异常,如果单纯根据异常堆栈的话我们无法确定到底是哪个 Activity 中的 Handler 抛出的异常。可以根据当前所在的 Activity 和异常堆栈来解决。如果还是无法确定问题出处的话,谨慎起见建议一律终止 APP。不过绝大多数情况下只根据异常堆栈就可以确定问题出处。

为了减少获取黑白名单的数据量,可以把当前所在 Activity 的类名称和异常堆栈拼接在一起,然后计算 md5 值,黑白名单中只包含该 md5 值即可,客户端捕获到异常时只需要进行同样的计算逻辑并判断md5值是否包含在黑白名单里。

Bandage 的不足之处

Bandage很多情况下只是忽略掉异常,让主线程再次进入消息循环,执行下一个消息, Bandage完全不清楚应该如何挽救。所以有时你会发现 Activity 根本打不开,又或者 Activity 中部分数据显示不完整,又或者 view 点击没反应,又或者其他奇奇怪怪的问题。但有些情况下直接忽略掉某些崩溃是没有任何影响的,或许直接忽略是最明智的选择。

Bandage可以最大程度保证 APP 可用,有人说这种拦截方式很暴力,但 Android 默认的异常杀进程逻辑不是更暴力吗,杀进程并不能解决问题,杀进程后再自动恢复 Activity 反而会导致更多的问题。

bugly 使用问题

bugly 也会通过设置 Thread.setDefaultUncaughtExceptionHandler 监听应用的异常,监听到后只是上报一下,然后又交给了原来的异常处理器处理, Bandage也会设置 DefaultUncaughtExceptionHandler,所以为了能让 bugly 主动上报异常,建议在 bugly 初始化前初始化 Bandage。另外 Activity 生命周期的异常会被 Bandage捕获,所以不会自动上传到 bugly,可以手动上传,同理 looper.loop() 由于被 Bandage捕获了,所以也不会自动上传到 bugly。特别注意: Bandage所捕获到的异常可能是由于上一个异常被忽略导致的,对于这种异常我们只需要修复之前的异常就可以了。

一点建议

开发阶段可以不启用 Bandage,以免发现不了 bug,如果开发阶段一定要启用 Bandage话可以在捕获到异常时开启个警告 Activity,或者所有 Activity 顶部置为绿色等,用于提示开发者已经出现了 bug,这时可以直接手动杀进程查 bug 了。

效果图

码链接

https://github.com/android-notes/Cockroach/tree/X

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 有赞coder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
区块链技术产生的比特币如何找回
主链侧链开发数字货币交易所白皮书区块链浏览器跨境支付场内场外宠物挖矿游戏基金会牌照 181-4069-6008 微信电话同号
用户2357564
2018/07/21
1.1K0
区块链技术产生的比特币如何找回
比特币是什么?比特币从何而来?
IFTNews:此文的目的是汇总比特币基本信息。最近我被问到很多关于密码空间的问题:你如何使用比特币?我如何购买比特币? WTF是我听过的比特币吗?加密吧? 如果你是个交易者,请忽略。如果你是投资者,或者只是想弄明白比特币的意义,那就继续阅读吧! 在考虑我关注比特币投资的基础知识时,我也认为在这里提到加密货币非常不稳定。市场规模很小,日间交易者全押。对于长期投资者来说,这种波动应该不重要。相反,它应该被拥抱。我们专注于每个月,每周甚至每一天都投入少量资金。因此,波动性是一件好事,它提供了以更低的价格更频
企鹅号小编
2018/01/24
2.1K0
比特币是什么?比特币从何而来?
比特币存储与资产安全
网贷谈嘉宾:比太钱包创始人文浩:今天和大家交流的内容是《比特币存储与资产安全》。目前,越来越多的人将比特币作为资产储藏,抵抗通胀膨胀。不论是企业还是个人,都越发关注比特币资产安全问题。 在过去几年我们遇到多次由于保存不当,导致比特币丢失的遗憾案例。所以了解比特币的基础知识与原理成为必要。只有如此,才能更好更安全的保护我们的资产。 第一个需要了解的基础概念:什么是比特币私钥? 对于比特币用户来讲,保管私钥是最为重要的事情。到底什么是私钥呢?简单来讲:私钥就是个随机数。 以掷骰子为例,每投掷一次,产生的数字
企鹅号小编
2018/01/19
2.2K0
比特币存储与资产安全
比特币冷钱包到底应该怎么做
引言 2015年的羊年新年假期, 中国最大的竞争币交易所之一的比特儿传出冷钱包被盗的新闻, 7170个比特币被黑客瞬间偷走, 损失超过1000万元人民币。大家不禁要问, 比特币都放进冷钱包了还会被偷走, 这比特币还能玩吗?这不靠谱啊! 比特儿交易所老总在之后的媒体采访中几次强调, “密码被破解”, 冷钱包和密码有很大关系吗?还是这位老总根本不知道何为冷钱包。引用Okcoin创始人徐明星的一句话来说明一下:“(比特币冷钱包的)关键要做到永不触网。” 下面笔者就一步一步的图文并用的给大家讲一讲最基本的冷钱包方案, 如何创建一个永不触网的冷钱包, 并且离线的创建一笔比特币交易。
程序新视界
2022/05/06
2.6K0
比特币冷钱包到底应该怎么做
浅谈比特币
最近比特币以及各种数字货币火的不行,区块链这个概念也三天两头霸占各种科技头条。以前虽然经常能听到「比特币」这个字眼,可完全没有足够的诱惑力吸引到我, 直到最近,因为曝光度实在太大,频繁出现在我的电脑和
用户1608022
2018/04/11
1.2K1
浅谈比特币
你的比特币安全吗?
比特币(BTC)是一种数字货币,能够快速给世界上的任何人。它依据特定算法、通过大量的计算而产生,因此比特币的发行不受任何政府、银行、组织及个人的操纵。 比特币的发展 BTC最初由Satoshi Nakamot(假名)设计,并获得MIT许可证。这种货币的优点包括低廉地海外汇款费用、比任何银行都快的交易速度、由于不受物理窃取数量约束而无法提交退款或者信用欺诈、没有通胀风险以及如果有能力你可以自己开采比特币。 比特币经历了一个巨大的成交量而从2013年的150亿美元增长57%至2014年的230亿美元。活跃的
FB客服
2018/02/06
1.1K0
你的比特币安全吗?
黑客又惹祸,致比特币下跌近2000美元
据BtcTrade国际站的数据,截止22日上午10:30,比特币今日价格现报125128.6CNY,较前一日有大幅下跌,同时也创下本周单日最大下跌幅度。而造成本轮下跌的原因,与最近一些早期比特币投资人出清手中持币有关。此外,有传闻称乌克兰交易所Liqui被黑客攻击,市场出现恐慌,各大交易平台均出现下跌情况。不仅如此,除比特币外的其他虚拟货币也纷纷受影响,均有所下跌。 黑客一直是数字货币世界挥之不去的噩梦。此前,韩国数字货币交易所Youbite宣布在19日下午4时左右,交易平台受到黑客入侵,造成的损失
企鹅号小编
2018/01/31
6010
黑客又惹祸,致比特币下跌近2000美元
比特币离你很近-比特币地址及生成
本文主要介绍了比特币地址及生成方法,包括随机生成64位16进制数初始私钥、在初始私钥基础上生成WIF非压缩私钥、在初始私钥基础上进行椭圆加密、在椭圆加密基础上生成公钥地址等步骤。同时,本文还提供了相应的代码示例,以帮助读者更好地理解比特币地址和生成过程。
企鹅号小编
2017/12/27
1.4K0
比特币离你很近-比特币地址及生成
区块链消费者们成为黑客攻击目标 比特币能否被找回存疑
文/泓和 2017年的区块链行业并不缺乏全新的技术术语,区块链消费者们也不免成为了黑客与罪犯们的攻击目标。不论是钱包黑客还是有欺诈性质的ICO,或者是软件代码漏洞,这些可能会使投资者损失数百万美元。 目前为止,这些罪犯们还没有被抓获,甚至不能被确认,而且这些资金可能基本无法被找回。 1. CoinDash ICO黑客 今年夏天,CoinDash推出了ICO,但其以太坊地址随后被泄露,最终不得不终止使用。在黑客更改地址之前,这家初创企业已经筹得730万美元。尽管该公司随后表示在发布公告之后再向以太
企鹅号小编
2018/01/12
7800
区块链消费者们成为黑客攻击目标 比特币能否被找回存疑
比特币入门教程
比特币(bitcoin)诞生于2008年的一篇论文。 一个署名为中本聪的人,提出了革命性的构想:让我们创造一种不受政府或其他任何人控制的货币!这个想法堪称疯狂:一串数字,背后没有任何资产支持,也没有任
wangxl
2018/03/09
8861
比特币入门教程
黑客攻击币安API完全调查:我们发现了比价值96比特币的SYS更有意思的信息
在 7 月 4 号的币安 API 被攻击本该是一件大事,当天,有 11 个名为 SYS 的 Token 在币安交易所内以 450 万人民币(96 个比特币)的价格被成交,相对其之前价格瞬间暴涨了 320 万倍。但这件事却因为当时最重磅的八卦「李笑来录音门」所被人忽视了。
区块链大本营
2018/08/03
8670
黑客攻击币安API完全调查:我们发现了比价值96比特币的SYS更有意思的信息
一个比特币交易流程是如何完成的 原
作为加密货币用户,你需要熟悉交易雏形——为了你对这种不断发展的创新有信心,以及作为理解新兴多签名交易和合约的基础,这两者都将在本系列的后期进行探讨。这不是纯技术文章,解释将集中在你需要了解的标准比特币交易——我们通常做的支出交易——并且我们将掩盖你可以安全忽略的内容。
笔阁
2018/11/09
3.5K0
比特币都有十年了,可能你至今还不知道怎样使用它才安全!
十年前,比特币刚刚出现时,中本聪(Satoshi Nakamoto)着重强调的是它作为数字化的“电子现金”的货币潜力。然而,一经面世,比特币便成为互联网地下世界的宠儿。匿名、加密等特征甚至还让它直接跟网络非法交易对等起来,尽管比特币并非完全匿名。
区块链大本营
2018/12/05
1.1K0
区块链学习笔记 | 比特币中用到的密码学原理
区块链这个名词,大家都不陌生,那么区块链的本质究竟是什么?有人说区块链是下一代的价值互联网;也有人说它是世界上最慢的数据库。的确,如果把它当数据库用的话是非常的慢,而且仅仅只能实现数据库中的一小部分功能。
Python进击者
2019/08/12
1.6K2
糖果没吃到,结果把比特币给弄丢了
本文来自「 路可比特 」作者:苏耀勇 本文由币乎(bihu.com)内容支持计划奖励 “币圈骗局”已是见多不怪的事情。常言道,哪里有诱惑,哪里就隐藏陷阱。近期路可君的一位朋友就差点掉进骗子设好的陷阱里,还好他机智过人,才得以确保自己数字财产的安全。以下是这位苏朋友所经历的整个过程: 2017年8月1日的比特币首次硬分叉,产生了比特币现金(BCH);在2017年10月25日比特币再次硬分叉,产生了比特币黄金(BTG)。这两个分叉币都在多个交易所上市交易,尤其是比特现金曾经一度有将比特币取而代之的想法。今天
企鹅号小编
2018/02/26
1.1K0
糖果没吃到,结果把比特币给弄丢了
带你了解“比特币黄金”和SegWit2x分叉
10月25日,比特币黄金从比特币中分离出来创造出一个基于ASIC挖矿的数字货币。几周之后,比特币公司中一个重要的集团想要根据 “纽约协议” 定义的SegWit2x方案来进行硬分叉,也许将要导致另一个新币的诞生。 如果这些都实现,在这篇文章发表后大约一个月内,比特币就会有三个不同的区块链和三种不同类型的币。一个区块链会符合现有的比特币协议;为了方便文章叙述,这个币会被称为“BTC”。第二个区块链会符合“比特币黄金协议”,这篇文章中,这个币会被称为“BTG”。第三个区块链会符合SegWit2x协议;这个币种将
区块链大本营
2018/05/10
8670
区块链比特币入门详解
比特币和区块链技术的发展非常迅速,即使那些没有听说过加密货币或了解其工作的人也在寻求投资和探索这个领域。区块链技术和加密货币今天已经成为人们开始执行标准交易的平行平台。现在,如果一个新系统正在慢慢取代现有系统,那么目前的系统肯定存在一些问题。我们将通过了解当前银行系统的问题引出当前的比特币和区块链的概念。
若与
2018/05/23
1.8K0
区块链比特币入门详解
黑客真的会毁了比特币吗?
不到一年时间里,从不到1万元涨至突破10万元,比特币以其快速的资产价格涨幅,由一个“圈子化”的数字资产,逐渐成为全世界市场所关注的焦点。 2017年年初,比特币仍处8000元左右价格,但当时已屡破历史新高,国内交易规模的扩大也引来监管层对大型交易平台启动的现场检查。但监管的关注未能阻止比特币继续上涨——今年6月初,比特币突破2万元大关。在期货合约酝酿、共同基金发起等利好推动下,比特币价格最终在合约上线CME前夕突破2万美元,折合人民币13万元以上。 在这快速暴涨的背后,虚拟货币的安全问题也成为人们关注的
企鹅号小编
2018/01/18
1.1K0
黑客真的会毁了比特币吗?
比特币核心技术解读
在上一篇文章《区块链基础知识与关键技术》里对区块链的基础知识和关键技术进行了梳理,而比特币是区块链最典型的应用,本文将对比特币核心技术进行解读,如有错漏,欢迎交流指正。
pseudoyu
2023/04/11
1.1K0
比特币核心技术解读
10大PHP比特币开源项目
如果你是一个Phper,如果你希望学习区块链,那么本文列出的 10个开源的Php比特币项目,将有助于你了解在自己的应用中 如何加入对比特币的支持。
用户1408045
2019/03/12
1.9K0
10大PHP比特币开源项目
相关推荐
区块链技术产生的比特币如何找回
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 概述
  • Bandage是什么
  • Bandage 是如何实现的
    • 拦截 Activity 生命周期的异常
    • finish 生命周期异常的 Activity
    • 拦截主线程的其他异常
    • 拦截其他异常
  • 异常处理
  • Bandage 的不足之处
  • bugly 使用问题
  • 一点建议
  • 效果图
  • 码链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档