Android崩溃

Android崩溃_第1张图片

ARPU: 一个时间段内运营商从每个用户所得到的收入;

DAU: 日活跃用户,MAU: 月活跃用户

Android崩溃_第2张图片

Android崩溃_第3张图片

Java Crash 应用程序层崩溃

Java的异常体系:
https://developer.android.com/reference/java/lang/Throwable.html
Throwable继承Object类。
Throwable有2个子类,Error和Exception。

Exception分为:
checked exception(可检查异常)、
unchecked exception(非检查异常,或运行时异常RuntimeException)。
checked exception:编译时,java编译器强制程序员必须进行捕获处理。比如IOException
RuntimeException:运行时产生的异常,比如NullPointerException、IndexOutOfBoundsException、
IllegalStateException等等.....

Android崩溃_第4张图片

java层异常处理(一)
Thread.UncaughtExceptionHandler是一个接口,它提供如下的方法,让我们自定义处理程序。
当一个线程因为没有捕捉的异常导致的突然终止时,该接口被唤醒。 
当一个线程因为不能捕捉的异常将要终止的时候,JVM会调用getUncaughtExceptionHandler方法查找扎个
线程对应的指定UncaughtExceptionHandler对象,并且回调这个对象的uncaughtException方法。如果这个
线程没有指定的UncaughtExceptionHandler对象,那么将ThreadGroup对象作为UncaughtExceptionHandler
对象,因为ThreadGroup类实现了Thread.UncaughtExceptionHandler接口;会调用顶层ThreadGroup的那个
默认的UncaughtExceptionHandler对象的uncaughtException方法。

java层异常处理(二)
异常处理是怎么样的呢?
1.当发生异常的时候,比如调用throw new Exception()没有捕获,
进入产生异常的线程(Thread类)的dispatchUncaughtException方法。
2.其中uncaughtExceptionHandler是UncaughtExceptionHandler的对象,
而group是ThreadGroup的对象。
3.如果我们通过setDefaultUncaughtExceptionHandler()
方法来设置指定的UncaughtExceptionHandler对象,就直接调用这个的
UncaughtExceptionHandler的uncaughtException方法,JVM退出。
4.如果我们没有通过setDefaultUncaughtExceptionHandler来设置指定的
UncaughtExceptionHandler对象,所以uncaughtExceptionHandler为空,
那么调用group的uncaughtException方法,因为ThreadGroup实现了

UncaughtExceptionHandler接口。

parent是ThreadGroup的对象,ThreadGroup中还可以有ThreadGroup对象。
程序会先找到顶层的ThreadGroup对象。直接进入else分支,如果设置了
默认UncaughtExceptionHandler对象,那么调用默认的
UncaughtExceptionHandler对象的uncaughtException方法,JVM退出。如果
没有设置默认的UncaughtExceptionHandler对象,那么就打印出异常信息,

最后虚拟机会退出。

Android崩溃_第5张图片

C层异常处理(一)
首先,需要理解几个概念:
1. 进程
Linux内核在启动过程中,创建第一个用户空间Init进程PID = 1,用于启动一些本地进程,比如Zygote进程。
创建一个名为Kthreadd的内核进程PID=2,用于创建内核空间其他进程。
一个进程有一个PID,还会有一个PPID(parent PID)来存储的父进程PID。
Zygote进程是一个专门用于创建Java进程的本地进程。
如果我们循着android应用进程的PPID不断向上追溯的话,总会发现其源头是init进程。

所以说,所有的进程也构成一个以init为根的树状结构。

2.Signal
信号是发送给进程或进程组的一个非常小的消息,通常只包含信号编号;
现在的系统可以附带siginfo信息,见sigaction的SA_SIGINFO标识。
信号主要有以下两个目的:
1.让进程知道出现某异步事件
2.出现异步事件,让进程能做出相应的处理(通过提供信号处理函数,由内核自动调用)


信号的种类:

1.可靠性方面:可靠信号与不可靠信号;
2.时间的关系上:实时信号与非实时信号。

不可靠信号:Linux信号机制基本上是从Unix系统中继承过来的。
早期Unix系统中的信号机制比较简单和原始,信号值小于SIGRTMIN(32)的信号都是不可靠信号。
可靠信号:信号值位于SIGRTMIN(32)和SIGRTMAX(64)之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。

非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。

Android崩溃_第6张图片

C层异常处理(二)
信号生命周期:
1.信号产生:内核更新目标进程数据结构,表示出现某异步事件
2.信号pending:信号产生但是未被传递出去,叫信号pending;
   主要是因为信号产生、信号传递是分为两个阶段的(信号在内核态返回用户态时传递,信号产生是在任意时间),所以之间存在延迟;
   同时信号阻塞会大大加长信号pending的时间;
3.信号传递:内核通过改变目标进程运行状态并执行信号的handler,来让目标进程对信号标识的异步事件做相应的处理
信号产生,主要有以下4种情况会产生signal:
1.硬件异常:当硬件检测到异常时;如SIGFPE(除0异常等),SIGSEGV(非法内存访问)
2.软件通知:当某事发生需要通知用户进程时;如信号SIGURG(网络连接中出现out-of-band数据,发送该信号),
   SIGPIPE(当往没有读者的管道中写数据时,发送该信号)
3.终端信号:当按下某些终端键时;如SIGINT(ctrl+c)
4.kill系统调用:当通过kill系统调用向其他进程发送信号时;如kill SIGUSR1 pid(kill命令调用kill系统调用)
 信号pending,主要有以下因素会影响信号pending的时间:
1.内核通常只传递当前进程的信号;当CPU从内核态切换到用户态时,内核会传递当前进程(占用该CPU的进程)的信号,而不会传递其它进程的信号。其它进程占用CPU后内核才会传递信号给该进程。
2.某信号可以被阻塞,直到该信号取消阻塞后,该信号才会被传递
3.当在执行某信号的处理handler时,内核会自动阻塞该信号直到该信号的处理完成;所以信号被处理时,该信号的再次出现不会打断信号处理,所以信号的处理handler不需要可重入。 
信号传递,当内核传递信号时,进程可以有如下action:
1.显式的忽略该信号
2.执行内核预定的默认动作,Terminate、Dump、Ignore、Stop、Continue

3.执行进程提供的自定义信号处理handler

Android崩溃_第7张图片

Android崩溃_第8张图片

结论:java层的崩溃,最后发送signal 9信号杀死继进程,是不能捕获、阻塞或忽略的。

这是Runtime崩溃与C层崩溃最直接的区别。

breakpad

Android崩溃_第9张图片

Android崩溃_第10张图片

Android崩溃_第11张图片


你可能感兴趣的:(android,java,Android崩溃)