天天看点

@@Android 稳定性研究Android有两类CrashJava crashNative crash编码的一些想法

稳定就是不出错,不崩溃

Android有两类Crash

· JavaCrash

· NativeCrash

Java crash

   一般都是java曾代码触发,一般的crash工具也能捕获到,系统也有api提供。在开发过程中,通过logcat就可以看打印出来的堆栈信息。简单的话,这样就可以解决了。稍微复杂点,就需要查看更多的log,很多时候某一个crash并不是起因,那就需要再往上继续查。这种情况就复杂了,如果log完整,还是可以找到crash的原因。如果只是知道Error,但并不知为何挂,就需要在大概的多加log打印信息。从Framework层来讲,像intel,mtk的framework还是稳定的。而其他的平台比如全智、RK增加功能的方式比较粗暴。解决具体问题时,比如window token null,就检查下添加时机如何。

1 首先看崩溃的类型,是否是比较特定的那几种

   拿BadTokenException举个例子:你大致就能确定一个activity正在被销毁或被销毁后dialog再去展示,造成的。这种很容易让人联想到一些不确定时长的异步操作(比如请求网络)之后才能显示的。然后,对应程序逻辑代码加上log很容易找。

2 检测是否有异常处理

   有一些错误类型是不太正常的,比如执行到一个方法内发生了异常,但他对异常的一些处理导致了这段代码虽然异常,但仍然执行过去了,程序没有crash,但导致之后传递的结果或者调用产生了问题。

3 查看用户操作轨迹

   这次崩溃是否由某些所特定的连锁操作做成的。

4 检查崩溃的机型,rom信息

   看是否是厂商给开发者留的坑而被我们忽略了,还有一些是个人制作的rom留下了一些比较难以预料的这种坑。

5 混淆之后记得保持mapping。

6 OPENGL要注意

   这些东西有可能跟webview之类也有关,在activity切换时,要注意其生命周期,还有内存。

7 异步操作得留意

   有多线程的时候,要注意那种不定时的异步操作,可能会溢出

8 部门之间的沟通坑

   还有种情况,在多部门联合开发时,往往服务端悄悄改了个东西,没通知到位,甚至根本就是悄悄改了点。这时候出现了一些格式错误什么的。这时候就出bug的都是客户端,最好这里把所有跟服务器相关的数据都要严格处理。做严格的单元测试。过滤不要用try catch,可以通过正则表达式过滤掉。这样,执行效率更高,代码更坚决,编码更严谨,这得要求所有初中级程序员做,有良好的编码习惯是需要的。

9 crash后的恢复要确保

   还有就是出现crash后,要注意是否有必要别让app不断重启。这样体验比较查。会反复重启。App Crash之后系统会重新启动Task栈顶的Activity.在杀死app对应的process之前,要结束掉task栈中所有的activity就可以。这里最好是自己记录开启关闭的activity。用单例的方式在unCaughtException时,将所有的activity finish掉。再System.exit。

10 crash后的恢复要确保2

   还有个就是如果嫌弃android系统自带的AppErrorDialog,比较丑,可以通过hook的方法,拦截后killprocess。这个要看需求了。

11 日志要记录

   通过UncaughtExceptionHandler记录dump异常日志

实现方式:用New CrashHandler 实现UncaughtExceptionHandler,在Application中,用单例init,就可以将异常日志记录起来。然后再上传到服务器就解决了。不过这种方法只适用java crash捕获。

12 hot patch要小心

   还有一种是hot patch导致的crash。Hot patch支持java、so、res文件的替换,但不支持AndroidManifest.xml,所以基本上绝大部分新需求和bug修复都可以用hot patch。

如果hot patch出问题,一查拉取的hotpatch的版本对不对。二看hotpatch包的size是不是太大,最好别超过100K,否则会超时。看看有没有没必要的类被hotpatch。再比如父类少动;有些变量用局部变量代替,有些常量可以hardcode;一些操作上用单例的manager,减少新变量。

   要配置灰度。配置crash止血。Hotpatch回滚。Crash率过高,就回滚。修复之后,重新测试并灰度。

13 第三方log记录工具

   第三方sdk可以考虑腾讯bugly、友盟bugtags等。考虑到兼容性,还有系统自带的DropBoxManager可以考虑.还有种方法,就是利用AMS,AMS里头是有crashListener的。

日志上传的话,可以考虑ACRA(applicationcrash reporting on Android),可以自动上传崩溃日志到自己的服务器上。这个号称有53K的App使用,70%chances that acra is running on anyphone。billion devices。可以考虑试试。

14 hook出一个新界面

   可以通过hook一个AMS还是什么,我忘了,干掉系统老的errorDLG,展示一个更友好的自定义界面,大幅提高用户的体验。网上找了个github,可以看一下https://github.com/Sunzxyong/Recovery 

Native crash

NativeCrash的特点

· 出错时界面不会弹出提示框提醒程序崩溃(Android 5.0以下)

· 出错时会弹出提示框提醒程序崩溃(Android 5.0以上)

· 程序会直接闪退到系统桌面

· 这类错误一般是由C++层代码错误引起的

· 绝大部分Crash工具不能够捕获

简介

   Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64(从2014年起),每一种都关联着一个相应的ABI(应用程序二进制接口(Application Binary Interface)。

   ABI定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。在Android系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。

   尽可能的提供专为每个ABI优化过的.so文件,不要混合着使用!!!为每个ABI目录提供对应的.so文件!!!这就要注意NDK这些so编译所用的platform.这要注意兼容运行的时候,比如64平台上运行32位的so.那针对64位优化的性能就会丢失了.

   在NDK实现中,如果C实现里头,有error,会产生一个SEGSEGV信号,然后报错,这可以通过logcat也可以打出堆栈信息。

在堆栈信息里头,有进程信息,错误信号,寄存器快照,堆栈信息。堆栈信息里头也是一样的嵌套调用。

从网上找了张图如图

@@Android 稳定性研究Android有两类CrashJava crashNative crash编码的一些想法

测试工具

   可以考虑用Google breakpad来测试。这个就不说明了,我也没试过,这里有个链接http://r12f.com/posts/google-breakpad-1-introduction-with-windows/

库缺失导致出错

   第三方SDK会将编译好的SO库release出来,但是处于一些原因,有些sdk就不会提供全面的sdk,一些大厂会提供所有目录对应的so库文件。在不全的时候,可以考虑删掉试试,虽说有些库是向下兼容的,不过最好是补齐对应的库。这就要注意NDK这些so编译所用的platform.这要注意兼容运行的时候,比如64平台上运行32位的so.那针对64位优化的性能就会丢失了.

分析工具

Native需要用到addr2line和gdb,这有32bit和64bit两个版本

32bit:

arm-eabi-addr2line

arm-eabi-gdb

64bit:

aarch64-linux-android-addr2line

aarch64-linux-android-gdb

步骤

1. 先看abi是什么,然后选用正确的工具。

2. 再看错误的地址是什么。粗略判断下是不是空指针。

3. 分析堆信息确认具体错误位置。(这里说明一下,系统级apk如果其中含有solib,是不会将其解压到某一个目录的,所以最终还是显示xxxx.apk,但实际指的是xxx.apk中的一个so)

4. 然后就可以用addr2line+各层调用栈的地址。根据命令行显示,就可以得到大概出错的位置了。

5. 如果分析代码之后。发现还是不知道为什么挂了,就要进一步分析corefile,查看错误当时具体汇编代码在干什么,当时保存的寄存器以及内存现场时怎么样的。

6. 可以用Gdb调用corefile

7. 如果出现了nativecrash问题,一般都会在手机中生成corefile来dump当时的内存信息。基本上接下来就要看汇编了。

!!!调试基本上没什么技巧,一般都是循序渐渐地按照步骤来查找问题。Native crash要多用用GDB.

编码的一些想法

1. 要设定crash rate,不能超过0.5%,也有一些是更低的0.2%

2. 根据crash的严重程度,影响范围,把bug都列出来,然后一个个解决

3. Google找找

4. 用一些第三方的crash收集平台。开发时,严格在关键地方多打些log

5. 然后就是多问问人

6. 版本折半回退法

7. 据说还有个appsee可以试试

8. 可以用一些静态分析工具,提前发现隐患。Lint,find bugs都行,codereview要做好,解耦充分。异常处理要规范。单元测试要做好做彻底。

继续阅读