如何定位软件ANR 定位软件到

android 开发过程中有时会遇见项目无响应异常,这类异常异常并不像Crash那样打印log信息,因此无法被捕获。所以来看一下这个ANR异常的出现原因及其定位。关键字:
主线程阻塞:网络访问等的线程阻塞,CPU满负荷, I/O阻塞,内存不够用等都会造成代码长时间执行,后面统称为 主线程阻塞。1 首先什么是ANR?
在一般的理解中ANR就是将主线程阻塞,当主线程阻塞超过相应阀值则会触发ANR异常。OK我们来写一个栗子测试一下。
运行之后发现并没有出现ANR异常,程序乖乖的延时5秒后再执行后面的代码。将延时修改为15秒之后结果还是这样。其实在onCreate方法中来执行延时函数是不会触发无响应异常的。这里就需要来看一下ANR的介绍了。
简单来说:ANR就是当前的事件没有得到及时有效的处理。
也就是说,ANR的触发是跟事件处理有关系的,例如当系统接收到点击事件之后就会将其传递给相应的应用,正常情况下事件会传递到处理这个点击事件的view来做具体逻辑处理。但是如果这个时候主线程是阻塞状态的,而系统又不允许其他线程去处理UI相关的事件,这时事件就会被阻塞住而无法及时处理。当阻塞时间超过一定阀值就会触发这个异常。
我们把界面改成两个按钮,并在第一个按钮的点击事件里来进行延时阻塞线程。
运行起来之后先只点击第一个进行延时然后不做任何操作。看到程序可以正常的运行完而没有异常。但是当点击完第一个按钮来阻塞住UI线程之后点击第二个按钮,则会出现ANR异常。并且catch里并没有捕获这个异常。结论:主线程在无事件处理时本身就会处于阻塞状态,当有点击事件传递给主线程或者其他线程使用Handler向MessageQueue中存放消息,导致loop被唤醒时,主线程就会被唤醒执行相应事件,但是这时如果主线程还是被阻塞住,就会导致事件无法处理。当时间超过阀值(activity貌似是5s)时,就会触发ANR异常。2 怎么定位ANR异常2.1
在发生anr时log日志只会打印I/art: Thread[2,tid=25238,WaitingInMainSignalCatcherLoop,Thread*=0xafa0e400,peer=0x12c2a080,"Signal Catcher"]: reacting to signal 3
I/art: Wrote stack traces to '/data/anr/traces.txt'
这两个I类的log信息,所以定位ANR异常不能只看异常日志首先打开studio 点击Tools --& Android --& Android Device Monltor 打开DDMS界面然后选中要调试的进程之后刷新线程刷新完成之后就会出现当前运行的线程,第一个name为main 则为主线程我们主要就是看这个线程选中这个线程底部有Refresh按钮,之后在程序阻塞时刷新该线程就可以显示其阻塞位置。在现有例子下,我们点击第一个按钮,先让线程阻塞,然后点击Refresh。这里可以就可以看到主程序阻塞的位置了。在TestActivity中的onClick方法中,在执行第41行代码时阻塞。至此,ANR异常解析及定位大功告成。最后在CPU使用率过高及内存不够时都可能造成ANR异常,具体可参看。
Android中ANR的监测与定位
1. ANR监测原理
判断ANR的方法其实很简单,我们在子线程里向主线程发消息,如果过了固定时间后,消息仍未处理,则说明已发生ANR了。
看懂了直接看2,没看懂继续看。
Android ANR(应用无响应)解决分析
http://blog.csdn.net/tjy1985/article/details/6777346
http://blog.csdn.net/tjy1985/article/...
App出现ANR时一些主要错误类型
App出现ANR时一些主要错误类型ANR:Application Not Responding,即应用无响应ANR一般有三种类型:
1:KeyDispatchTimeout(5 seconds) –主...
ANR在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应
用程序无响应(ANR:ApplicationNotResponding)对话框。用户可以...
自http://swverification.blog.sohu.com/.html
对于android上的bug定位的文档很少,因为应用程序千差万别的,出现的问题...
http://blog.csdn.net/dadoneo/article/details/8270107
ANR出现情况及通过log分析追踪问题
一:什么是ANR
ANR:Applicati...
1. android重启,应用异常问题
1.1 Android进程终止和重启问题分类
App Force Close 问题
原因是:虚拟机捕获了一些unchecked异常,如...
解决bug中的总结:Fragment Transactions 和Activity状态丢失
Fragment transactions用于在一个Activity上添加、移除或者替换frag...
Android App开发之ANR异常的原因分析及处理总结ANR的全称是application not responding,根据它的意思我们就能看出来是应用程序未响应,就像是我们在电脑上碰到的程序未...
ANRs (“Application Not Responding”),意思是”应用没有响应“。
在如下情况下,Android会报出ANR错误:
– 主线程 (“事件处理线程” / “U...
没有更多推荐了,ANR全称是Application Not Responding,意思是应用程序无响应。相信从事Android开发的肯定遇到过。ANR的直观体验是用户在操作App的过程中,感觉界面卡顿,当界面卡顿超过一定时间(一般5秒),就会出现ANR对话框。ANR对于一个应用来说是不能承受之痛,其影响并不比应用发生Crash小。
ANR产生的原因
只有当应用程序的UI线程响应超时才会引起ANR,超时产生原因一般有两种。
当前的事件没有机会得到处理,例如UI线程正在响应另一个事件,当前事件由于某种原因被阻塞了。
当前的事件正在处理,但是由于耗时太长没能及时完成。
根据ANR产生的原因不同,超时事件也不尽相同,从本质上将,产生ANR的原因有三种,大致可以对应到Android中四大组件中的三个(Activity/View,BroadcastReceiver和Service)。
KeyDispatchTimeout
最常见的一种类型,原因就是View的点击事件或者触摸事件在特定的时间(5s)内无法得到响应。
BroadcastTimeout
原因是BroadcastReceiver的onReceive()函数运行在主线程中,在特定的时间(10s)内无法完成处理。
ServiceTimeout
比较少出现的一种类型,原因是Service的各个生命周期函数在特定时间(20s)内无法完成处理。
典型的ANR问题场景
应用程序UI线程存在耗时操作。例如在UI线程中进行联网请求,数据库操作或者文件操作等。
应用程序的UI线程等待子线程释放某个锁,从而无法处理用户的输入。
耗时的动画需要大量的计算工作,可能导致CPU负载过重。
ANR的定位和分析
当发生ANR时,可以通过结合Logcat日志和生成的位于手机内部存储的/data/anr/traces.tex文件进行分析和定位。
Cmd line: com.anly.githubapp
// 最新的ANR发生的进程(包名)
DALVIK THREADS (41):
"main" prio=5 tid=1 Sleeping
| group="main" sCount=1 dsCount=0 obj=0x73467fa8 self=0x7fbf66c95000
| sysTid=2976 nice=0 cgrp=default sched=0/0 handle=0x7fbf6a8953e0
| state=S schedstat=( 0 0 0 ) utm=60 stm=37 core=1 HZ=100
| stack=0x7ffff4ffd000-0x7ffff4fff000 stackSize=8MB
| held mutexes=
at java.lang.Thread.sleep!(Native method)
- sleeping on &0x35fc9e33& (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:1031)
- locked &0x35fc9e33& (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:985) // 主线程中sleep过长时间, 阻塞导致无响应.
at com.tencent.bugly.crashreport.crash.c.l(BUGLY:258)
- locked &@addr=0x12dadc70& (a com.tencent.bugly.crashreport.crash.c)
at com.tencent.bugly.crashreport.CrashReport.testANRCrash(BUGLY:166)
// 产生ANR的那个函数调用
- locked &@addr=0x12d1e840& (a java.lang.Class&com.tencent.bugly.crashreport.CrashReport&)
at com.anly.githubapp.common.wrapper.CrashHelper.testAnr(CrashHelper.java:23)
at com.anly.githubapp.ui.module.main.MineFragment.onClick(MineFragment.java:80) // ANR的起点
at com.anly.githubapp.ui.module.main.MineFragment_ViewBinding$2.doClick(MineFragment_ViewBinding.java:47)
at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
at android.view.View.performClick(View.java:4780)
at android.view.View$PerformClick.run(View.java:19866)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke!(Native method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
现在找到了ANR产生的原因和位置了,就可以对产生ANR的代码进行修复。这么一个一个的找肯定不现实,那我们就来说说如何避免和检测ANR。
ANR的避免和检测
为了避免在开发中引入可能导致应用发生ANR的问题,除了切记不要在主线程中作耗时操作,我们也可以借助于一些工具来进行检测,从而更有效的避免ANR的引入。
StrictMode
严格模式StrictMode是Android SDK提供的一个用来检测代码中是否存在违规操作的工具类,StrictMode主要检测两大类问题。
线程策略 ThreadPolicy
detectCustomSlowCalls:检测自定义耗时操作
detectDiskReads:检测是否存在磁盘读取操作
detectDiskWrites:检测是否存在磁盘写入操作
detectNetWork:检测是否存在网络操作
虚拟机策略VmPolicy
detectActivityLeaks:检测是否存在Activity泄露
detectLeakedClosableObjects:检测是否存在未关闭的Closeable对象泄露
detectLeakedSqlLiteObjects:检测是否存在Sqlite对象泄露
setClassInstanceLimit:检测类实例个数是否超过限制
可以看到,ThreadPolicy可以用来检测可能催在的主线程耗时操作,需要注意的是我们只能在Debug版本中使用它,发布到市场上的版本要关闭掉。StrictMode的使用很简单,我们只需要在应用初始化的地方例如Application或者MainActivity类的onCreate方法中执行如下代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
// 开启线程模式
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDialog() ////打印logcat,当然也可以定位到dropbox,通过文件保存相应的log
// 开启虚拟机模式
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
上面的初始化代码调用penaltyLog表示在Logcat中打印日志,调用detectAll方法表示启动所有的检测策略,我们也可以根据应用的具体要求只开启某些策略,语句如下:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.detectActivityLeaks()
.penaltyLog()
BlockCanary
BlockCanary是一个非侵入式式的性能监控函数库,它的用法和leakCanary类似,只不过后者监控应用的内存泄露,而BlockCanary主要用来监控应用主线程的卡顿。它的基本原理是利用主线程的消息队列处理机制,通过对比消息分发开始和结束的时间点来判断是否超过设定的时间,如果是,则判断为主线程卡顿。它的集成很简单,首先在build.gradle中添加依赖
一般选取以下其中一个 case 引入即可
dependencies {
compile 'com.github.markzhai:blockcanary-android:1.5.0'
// 仅在debug包启用BlockCanary进行卡顿监控和提示的话,可以这么用
debugCompile 'com.github.markzhai:blockcanary-android:1.5.0'
releaseCompile 'com.github.markzhai:blockcanary-no-op:1.5.0'
然后在Application类中进行配置和初始化即可
public class AnrDemoApplication extends Application {
public void onCreate() {
super.onCreate();
BlockCanary.install(this, new AppBlockCanaryContext()).start();
实现自己监控的上下文
public class AppBlockCanaryContext extends BlockCanaryContext {
* Implement in your project.
* Qualifier which can specify this installation, like version + flavor.
public String provideQualifier() {
return "unknown";
* Implement in your project.
public String provideUid() {
return "uid";
* Network type
* {@link String} like 2G, 3G, 4G, wifi, etc.
public String provideNetworkType() {
return "unknown";
* Config monitor duration, after this time BlockCanary will stop, use
* with {@code BlockCanary}'s isMonitorDurationEnd
* monitor last duration (in hour)
public int provideMonitorDuration() {
return -1;
* Config block threshold (in millis), dispatch over this duration is regarded as a BLOCK. You may set it
* from performance of device.
* threshold in mills
public int provideBlockThreshold() {
return 1000;
* Thread stack dump interval, use when block happens, BlockCanary will dump on main thread
* stack according to current sample cycle.
* Because the implementation mechanism of Looper, real dump interval would be longer than
* the period specified here (especially when cpu is busier).
* dump interval (in millis)
public int provideDumpInterval() {
return provideBlockThreshold();
* Path to save log, like "/blockcanary/", will save to sdcard if can.
* path of log files
public String providePath() {
return "/blockcanary/";
* If need notification to notice block.
* true if need, else if not need.
public boolean displayNotification() {
return true;
* Implement in your project, bundle files into a zip file.
files before compress
* dest files compressed
* true if compression is successful
public boolean zip(File[] src, File dest) {
return false;
* Implement in your project, bundled log files.
* zippedFile zipped file
public void upload(File zippedFile) {
throw new UnsupportedOperationException();
* Packages that developer concern, by default it uses process name,
* put high priority one in pre-order.
* null if simply concern only package with process name.
public List&String& concernPackages() {
return null;
* Filter stack without any in concern package, used with @{code concernPackages}.
* true if filter, false it not.
public boolean filterNonConcernStack() {
return false;
* Provide white list, entry in white list will not be shown in ui list.
* return null if you don't need white-list filter.
public List&String& provideWhiteList() {
LinkedList&String& whiteList = new LinkedList&&();
whiteList.add("org.chromium");
return whiteL
* Whether to delete files whose stack is in white list, used with white-list.
* true if delete, false it not.
public boolean deleteFilesInWhiteList() {
return true;
* Block interceptor, developer may provide their own actions.
public void onBlock(Context context, BlockInfo blockInfo) {
在AndroidManifest.xml文件中声明Application,一定不要忘记
现在就已经将BlockCanary集成到应用里面了,接下来,编译安装到手机上,点击测试按钮,将产生一个ANR,效果如图:
【Android】定位与解决anr错误记录
cocos2d-x游戏项目android工程接入sdk,支付成功后,java代码回调lua方法,产生了anr。
如何定位anr?
在data/anr/traces.txt文件中记录和...
Android ANR的产生与分析
ANR即Application Not Responding应用无响应,一般在ANR的时候会弹出一个应用无响应对话框。也许有些开发者在使用某些手机开发中不在弹出应用无响应弹出框,特别是国产手机Andr...
通过Android trace文件分析死锁ANR
对于从事Android开发的人来说,遇到ANR(Application Not Responding)是比较常见的问题。一般情况下,如果有ANR发生,系统都会在/data/anr/目录下生成trace...
Android ANR分析与总结
一、什么是ANR?
Android Not Response : 通常是UI线程做耗时操作会导致ANR。
界面操作按钮的点击等待响应时间超过5秒
HandleMes...
你还可以去data/anr的目录下把trace.txt这个文件拷贝出来,在该文件中会写了产生anr的函数堆栈可以帮助分析
Log 在android中的地位非常重要,要是作为一个android程序员不能过分析log这关,算是android没有入门吧 。 下面我们就来说说如何处理log文件 。
什么时候会有Log文...
一:什么是ANR
ANR:Application Not Responding,即应用无响应
二:ANR的类型
ANR一般有三种类型:
1:KeyDispatchTimeout(5 secon...
Trace文件怎么获取?traces.txt只保留最后一次ANR的信息,Android系统有个DropBox功能功能,它能记录系统出现的crash错误.因此保留有发生过的ANR的信息.(log路径:/...
http://blog.csdn.net/dadoneo/article/details/8270107
ANR出现情况及通过log分析追踪问题
一:什么是ANR
ANR:Applicati...
ANR(Application Not Responding):应用程序无响应,是Android中AMS与WMS监测应用响应超时的表现;
我们应用开发中常见的ANR主要有如下几类:
按键触摸...
ANR产生的原因
只有当应用程序的UI线程响应超时时才会引起ANR,超时产生原因一般有两种:
--当前的事件没有机会得到处理,例如UI线程正在响应另一个事件,当前事件由于某种原因被阻塞了。
--当前的事件正在处理,...
没有更多推荐了,Android &&&&最新内容
Android &&&&相关内容在Android开发中,程序Crash分三种情况:未捕获的异常、ANR(Application Not Responding)和闪退(NDK引发错误)。其中未捕获的异常根据logcat打印的堆栈信息很容易定位错误。ANR错误也好查,Android规定,应用与用户进行交互时,如果5秒内没有响应用户的操作,则会引发ANR错误,并弹出一个系统提示框,让用户选择继续等待或立即关闭程序。并会在/data/anr目录下生成一个traces.txt文件,记录系统产生anr异常的堆栈和线程信息。如果是闪退,这问题比较难查,通常是项目中用到了NDK引发某类致命的错误导致闪退。因为NDK是使用C/C++来进行开发,熟悉C/C++的程序员都知道,指针和内存管理是最重要也是最容易出问题的地方,稍有不慎就会遇到诸如内存地址访问错误、使用野针对、内存泄露、堆栈溢出、初始化错误、类型转换错误、数字除0等常见的问题,导致最后都是同一个结果:程序崩溃。不会像在Java层产生的异常时弹出“xxx程序无响应,是否立即关闭”之类的提示框。当发生NDK错误后,logcat打印出来的那堆日志根据看不懂,更别想从日志当中定位错误的根源,让我时常有点抓狂,火冒三丈,喝多少加多宝都不管用。当时尝试过在各个jni函数中打印日志来跟踪问题,那效率实在是太低了,而且还定位不到问题。还好老天有眼,让我找到了NDK提供的几款调试工具,能够精确的定位到产生错误的根源。
NDK安装包中提供了三个调试工具:addr2line、objdump和ndk-stack,其中ndk-stack放在$NDK_HOME目录下,与ndk-build同级目录。addr2line和objdump在ndk的交叉编译器工具链目录下,下面是我本机NDK交叉编译器工具链的目录结构:
从上图的目录结构中可以看出来,NDK针对不同的CPU架构实现了多套相同的工具。所以在选择addr2line和objdump工具的时候,要根据你目标机器的CPU架构来选择。如果是arm架构,选择arm-linux-androidabi-4.6/4.8(一般选择高版本)。x86架构,选择x86-4.6/4.8。mipsel架构,选择mipsel-linux-android-4.6/4.8。如果不知道目标机器的CPU架构,把手机连上电脑,用adb shell cat /proc/cpuinfo可以查看手机的CPU信息。下图是我本机的arm架构工具链目录结构:
下面通过NDK自带的例子hello-jni项目来演示一下如何精确的定位错误
#include &string.h&
#include &jni.h&
// hell-jni.c
#ifdef __cplusplus
extern "C" {
void willCrash()
int i = 10;
int y = i / 0;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
willCrash();
return JNI_VERSION_1_4;
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
// 此处省略实现逻辑。。。
#ifdef __cplusplus
#endif第7行定义了一个willCrash函数,函数中有一个除0的非法操作,会造成程序崩溃。第13行JNI_OnLoad函数中调用了willCrash,这个函数会在Java加载完.so文件之后回调,也就是说程序一启动就会崩溃。下面是运行程序后打印的log:
01-01 17:59:38.246: D/dalvikvm(20794): Late-enabling CheckJNI
01-01 17:59:38.246: I/ActivityManager(1185):
Start proc com.example.hellojni for activity com.example.hellojni/.HelloJni: pid=20794 uid=10351 gids={5, 1015}
01-01 17:59:38.296: I/dalvikvm(20794): Enabling JNI app bug workarounds for target SDK version 3...
01-01 17:59:38.366: D/dalvikvm(20794): Trying to load lib /data/app-lib/com.example.hellojni-1/libhello-jni.so 0x422a4f58
01-01 17:59:38.366: D/dalvikvm(20794): Added shared lib /data/app-lib/com.example.hellojni-1/libhello-jni.so 0x422a4f58
01-01 17:59:38.366: A/libc(20794): Fatal signal 8 (SIGFPE) at 0x0000513a (code=-6), thread 20794 (xample.hellojni)
01-01 17:59:38.476: I/DEBUG(253): pid: 20794, tid: 20794, name: xample.hellojni
&&& com.example.hellojni &&&
01-01 17:59:38.476: I/DEBUG(253): signal 8 (SIGFPE), code -6 (SI_TKILL), fault addr 0000513a
01-01 17:59:38.586: I/DEBUG(253):
r1 0000513a
01-01 17:59:38.586: I/DEBUG(253):
r5 0000000d
r6 0000513a
r7 0000010c
01-01 17:59:38.586: I/DEBUG(253):
r8 75226d08
sl 417c5c38
fp bedbf134
01-01 17:59:38.586: I/DEBUG(253):
sp bedbf0f0
pc 4013d10c
cpsr 000f0010
// 省略部份日志 。。。。。。
01-01 17:59:38.596: I/DEBUG(253): backtrace:
01-01 17:59:38.596: I/DEBUG(253):
pc 0002210c
/system/lib/libc.so (tgkill+12)
01-01 17:59:38.596: I/DEBUG(253):
/system/lib/libc.so (pthread_kill+48)
01-01 17:59:38.596: I/DEBUG(253):
/system/lib/libc.so (raise+10)
01-01 17:59:38.596: I/DEBUG(253):
pc 00000e80
/data/app-lib/com.example.hellojni-1/libhello-jni.so (__aeabi_idiv0+8)
01-01 17:59:38.596: I/DEBUG(253):
pc 00000cf4
/data/app-lib/com.example.hellojni-1/libhello-jni.so (willCrash+32)
01-01 17:59:38.596: I/DEBUG(253):
pc 00000d1c
/data/app-lib/com.example.hellojni-1/libhello-jni.so (JNI_OnLoad+20)
01-01 17:59:38.596: I/DEBUG(253):
pc 00052eb1
/system/lib/libdvm.so (dvmLoadNativeCode(char const*, Object*, char**)+468)
01-01 17:59:38.596: I/DEBUG(253):
pc 0006a62d
/system/lib/libdvm.so
01-01 17:59:38.596: I/DEBUG(253):
// 省略部份日志 。。。。。。
01-01 17:59:38.596: I/DEBUG(253): stack:
01-01 17:59:38.596: I/DEBUG(253):
/system/lib/libsechook.so
01-01 17:59:38.596: I/DEBUG(253):
01-01 17:59:38.596: I/DEBUG(253):
/system/lib/libsechook.so
01-01 17:59:38.596: I/DEBUG(253):
/system/lib/libc.so (dlfree+50)
01-01 17:59:38.596: I/DEBUG(253):
/system/lib/libc.so
01-01 17:59:38.596: I/DEBUG(253):
// 省略部份日志 。。。。。。
01-01 17:59:38.736: W/ActivityManager(1185):
Force finishing activity com.example.hellojni/.HelloJni日志分析:
第3行开始启动应用,第5行尝试加载应用数据目录下的so,第6行在加载so文件的时候产生了一个致命的错误,第7行的Fatal signal 8提示这是一个致命的错误,这个信号是由linux内核发出来的,信号8的意思是浮点数运算异常,应该是在willCrash函数中做除0操作所产生的。下面重点看第15行backtrace的日志,backtrace日志可以看作是JNI调用的堆栈信息,以“#两位数字 pc”开头的都是backtrace日志。注意看第20行和21行,是我们自己编译的so文件和定义的两个函数,在这里引发了异常,导致程序崩溃。
01-01 17:59:38.596: I/DEBUG(253):
pc 00000cf4
/data/app-lib/com.example.hellojni-1/libhello-jni.so (willCrash+32)
01-01 17:59:38.596: I/DEBUG(253):
pc 00000d1c
/data/app-lib/com.example.hellojni-1/libhello-jni.so (JNI_OnLoad+20)开始有些眉目了,但具体崩在这两个函数的哪个位置,我们是不确定的,如果函数代码比较少还好查,如果比较复杂的话,查起来也费劲。这时候就需要靠NDK为我们提供的工具来精确定位了。在这之前,我们先记录下让程序崩溃的汇编指令地址,willCrash:00000cf4,JNI_OnLoad:00000d1c
方式1:使用arm-linux-androideabi-addr2line
定位出错位置
以arm架构的CPU为例,执行如下命令:
/Users/yangxin/Documents/devToos/java/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line -e /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a/libhello-jni.so 000d1c
-e:指定so文件路径
0d1c:出错的汇编指令地址
结果如下:
是不是惊喜的看到我们想要的结果了,分别在hello-jni.c的10和15行的出的错,再回去看看hello-jni.c的源码,15行的Jni_OnLoad函内调用了willCrash函数,第10行做了除0的操作引发的crash。
方式2:使用arm-linux-androideabi-objdump
定位出错的函数信息
在第一种方式中,通过addr2lin已经获取到了代码出错的位置,但是不知道函数的上下文信息,显得有点不是那么的“完美”,对于追求极致的我来说,这显然是不够的,下面我们来看一下怎么来定位函数的信息。
首先使用如下命令导出so的函数表信息:
/Users/yangxin/Documents/devToos/java/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump -S -D /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a/libhello-jni.so & Users/yangxin/Desktop/dump.log在生成的asm文件中,找出我们开始定位到的那两个出错的汇编指令地址(在文件中搜索cf4或willCrash可以找到),如下图所示:
通过这种方式,也可以查出这两个出错的指针地址分别位于哪个函数中。
方式3:ndk-stack
如果你觉得上面的方法太麻烦的话,ndk-stack可以帮你减轻操作步聚,直接定位到代码出错的位置。
实时分析日志:
使用adb获取logcat的日志,并通过管道输出给ndk-stack分析,并指定包含符号表的so文件位置。如果程序包含多种CPU架构,需要根据手机的CPU类型,来选择不同的CPU架构目录。以armv7架构为例,执行如下命令:
adb logcat | ndk-stack -sym /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a当程序发生crash时,会输出如下信息:pid: 22654, tid: 22654, name: xample.hellojni
&&& com.example.hellojni &&&
signal 8 (SIGFPE), code -6 (SI_TKILL), fault addr 0000587e
Stack frame #00
pc 0002210c
/system/lib/libc.so (tgkill+12)
Stack frame #01
/system/lib/libc.so (pthread_kill+48)
Stack frame #02
/system/lib/libc.so (raise+10)
Stack frame #03
pc 00000e80
/data/app-lib/com.example.hellojni-1/libhello-jni.so (__aeabi_idiv0+8): Routine __aeabi_idiv0 at /s/ndk-toolchain/src/build/../gcc/gcc-4.6/libgcc/../gcc/config/arm/lib1funcs.asm:1270
Stack frame #04
pc 00000cf4
/data/app-lib/com.example.hellojni-1/libhello-jni.so (willCrash+32): Routine willCrash at /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/jni/hello-jni.c:10
Stack frame #05
pc 00000d1c
/data/app-lib/com.example.hellojni-1/libhello-jni.so (JNI_OnLoad+20): Routine JNI_OnLoad at /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/jni/hello-jni.c:15
Stack frame #06
pc 00052eb1
/system/lib/libdvm.so (dvmLoadNativeCode(char const*, Object*, char**)+468)
Stack frame #07
pc 0006a62d
/system/lib/libdvm.so第7行和第8行分别打印出了在源文件中出错的位置,和addr2line得到的结果一样。
先获取日志再分析:
这种方式和上面的方法差不多,只是获取log的来源不一样。适用于应用或游戏给测试部们测试的时候,测试人员发现crash,用adb logcat保存日志文件,然后发给程序员通过ndk-stack命令分析。操作流程如下:
adb logcat & crash.log
ndk-stack -sym /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a -dump crash.log得到的结果和上面的方式是一样的。
Android Native 崩溃日志收集
android和iOS平台的崩溃捕获和收集
通过崩溃捕获和收集,可以收集到已发布应用(游戏)的异常,以便开发人员发现和修改bug,对于提高软件质量有着极大的帮助。本文介绍了iOS和android平台...
使用objdump进行Android crash 日志 分析
转载请注明出处:http://blog.csdn.net/xyang81/article/details/
在Android开发中,程序Crash分三种情况:未捕获的异常、...
android ndk开发 定位native层c/c++语言的错误行号,崩溃行号。
mac系统 android studio ndk 开发时候,android层的崩溃或者报错,as是可以定位到具体哪行的,但是,我们在ndk编译c语言时候,c如果有逻辑出错,崩溃,as运行日志是打印不出...
解决JNI调用在Android5.0+闪退问题
日志信息如下:
08-14 15:48:41.127: A/art(5526): art/runtime/check_jni.cc:70] JNI DETECTED ERROR IN APPLICAT...
解析Android崩溃日志(Android ndk-stack tool)
Android崩溃后日志会输出堆栈跟踪信息,例如:
BackTrace 工具:Android ndk-stack tool
ndk-stack是NDK自带的小工具,存放在NDK根目...
Android崩溃日志获取与解析
今天来写点Android崩溃的东西,在我们写代码的过程中,代码写的再好再严谨,也总是会有一些程序的崩溃,对于release出去的APP,我们肯定是希望我们能够拿到崩溃的日志,便于bug的发现以及修复,...
使用android studio进行ndk开发时如何定位crash错误
使用android studio进行ndk开发时如何定位crash崩溃错误
在ndk开发时, jni层的代码一旦出现问题, 就会打印如下信息, 然后直接闪退, 这时候让人非常抓狂, 只能过在各个jn...
Android NDK Crash 日志抓取及定位
Android NDK Crash 日志抓取及定位
有人说,如何在Android Studio 可以配置日志模式,过滤NDK的crash,那么就让我们来简单看看下如何配置的。
一、Androi...
Android Crash之Native Crash分析
前言上一篇给大家介绍了Android Crash中的Java Crash分析,我们可以知道Java Crash一般会弹出提示框告诉我们程序崩溃了,通常使用Crash工具都能够捕获到;本篇博客来谈谈如何...
如何定位Android NDK开发中遇到的错误
应部分同学要求,把之前的几篇文章合成这个一篇
正式开始这个话题之前,先简单介绍一下什么是NDK和JNI,部分内容来自网络
Android NDK是什么,为什么我们要用NDK?
Android ...
没有更多推荐了,

我要回帖

更多关于 手机号码定位 的文章

 

随机推荐