Android System crash DeadSystemException(Service/Activity/终极解决方案)

news2024/12/23 5:31:43

DeadSystemException

The core Android system has died and is going through a runtime restart. All running apps will be promptly killed.
Android 核心系统服务已经死亡,正在重启中。全部正在运行的app即将被kill杀死。

更多请阅读,DeadSystemException官方介绍

chatgpt给出的解决答案
Android中的DeadSystemException是一种非常严重的异常,表示系统已经崩溃。如果不进行处理,应用程序将会崩溃并退出。

处理方式:

  1. 捕获该异常:使用try-catch来捕获DeadSystemException异常,或者注册一个UncaughtExceptionHandler来处理未捕获的异常
  2. 根据产品需求进行业务逻辑处理:进行相应的处理,例如输出错误日志或者提示用户重新启动应用程序。

1.service create 发生该异常:

在这里插入图片描述
先来看下调用栈中抛出异常的地方:
/frameworks/base/core/java/android/app/ActivityThread.java 中handleCreateService():
在这里插入图片描述
在这里插入图片描述
从源码可知 :

  1. app 进程已经完成对service#oncreate()过程,接着与ams 通过binder通讯,发生了DeadObjectException 从而抛出了DeadSystemException。
  2. ActivityThread 中对service创建过程有异常处理机制try-catch ,会判断Instrumentation 是否拦截该异常。

为了进一步了解原因,接着查看bugly上该异常中捕获的日志,发现有几条有效日志:

//系统服务已经die死亡
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: com.android.systemui, PID: 19210
AndroidRuntime: DeadSystemException: The system died; earlier logs will point to the root cause
AppErrors: Process com.android.systemui has crashed too many times: killing!

//binder 通讯异常抛出日志
JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 104)

根据分析,推断系统服务已经死亡,app进程通过binder与之通讯,会抛出DeadSystemException。

根据FAILED BINDER TRANSACTION检索,找/frameworks/base/core/jni/android_util_Binder.cpp
signalExceptionForError():
在这里插入图片描述
从binder通讯源码中可知,当遇到异常返回status(failed_transansaction 和dead_object)时, 会抛出DeadObjectException异常。另外,单次读写超过200k的binder数据,就会抛出TransactionTooLargeException 异常;

原因推断:当app进程创建service 成功后,与ams 通讯过程中,binder 发生异常状态status failed_transansaction,从而抛出异常导致。

解决方案:
采用hook 方式,代理Instrumentation 捕获该异常:

 /**
     * 自定义 Instrumentation 子类,
     * 拦截对Activity和Service的系统异常拦截
     */
    private static class InstrumentationImpl extends Instrumentation{
        @Override
        public boolean onException(Object obj, Throwable e) {
             return isInterruptException(e);
        }
        public static void hookInstrumentation(){
            //基本上发生在7.0和7.1设备上
            if (Build.VERSION.SDK_INT==Build.VERSION_CODES.N_MR1||Build.VERSION.SDK_INT==Build.VERSION_CODES.N){
                try {
                    Instrumentation ins = new InstrumentationImpl();
                    Class cls = Class.forName("android.app.ActivityThread");
                    Method mthd = cls.getDeclaredMethod("currentActivityThread", (Class[]) null);
                    Object currentAT = mthd.invoke(null, (Object[]) null);
                    Field mInstrumentation = currentAT.getClass().getDeclaredField("mInstrumentation");
                    mInstrumentation.setAccessible(true);
                    mInstrumentation.set(currentAT, ins);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}
private static boolean isInterruptException(Throwable e){
    if (e.toString().contains("DeadSystemException")){
        //拦截DeadSystemException
        return true;
    }
     return false;
}

以上代码,在Application的oncreate()中调用。

还有其他hook 方式,ActivityThread#H 的handler callBack ,也可以通用实现以上效果;

捕获该异常后,需要启动的服务无法启动,Bugly 不会捕捉到该异常,但app进程很可能会被杀死。

2.activity destory 发生该异常

先查看调用栈:
在这里插入图片描述
查看下crash 所在的源码:
在这里插入图片描述
与前面的问题有些不同,当app 进程已经完成Activity销毁过程后,通知ams 过程中,发生系统进程,死亡异常则直接抛出。

解决方案
App 销毁Activity过程中没有异常捕捉机制,但该调用栈是在ActivityThread 中名为H 的handler中调用的,因此考虑hook 进行异常捕获。

再查看Handler的源码,发现可以为它设置callBack便可以拦截其handleMessage()调用。

在这里插入图片描述
编写代码如下所示:

private static class  CallBackImpl implements Handler.Callback{
    private  Handler activityThreadHandler;
    public CallBackImpl(Handler activityThreadHandler) {
        this.activityThreadHandler = activityThreadHandler;
    }
    @Override
    public boolean handleMessage(Message msg) {
        try {
            activityThreadHandler.handleMessage(msg); 
        }catch (Exception e){
            if (!isInterruptException(e)){
                //不被拦截的异常,继续抛出
                throw  e; 
            }   
        }
        return true;
    }
    public static void hook(){
        try {
            if (Build.VERSION.SDK_INT==Build.VERSION_CODES.N_MR1||Build.VERSION.SDK_INT==Build.VERSION_CODES.N){
            //获取到ActivityThread
            Class<?> ActivityThreadClass = Class.forName("android.app.ActivityThread");
            Field sCurrentActivityThreadField = ActivityThreadClass.getDeclaredField("sCurrentActivityThread");
            sCurrentActivityThreadField.setAccessible(true);
            Object ActivityThread = sCurrentActivityThreadField.get(null);
            //获取到ActivityThread中的handler
            Field mHField=ActivityThreadClass.getDeclaredField("mH");
            mHField.setAccessible(true);
            Handler mHandler=(Handler) mHField.get(ActivityThread);
            //给handler添加callback监听器,拦截
            Field mCallBackField = Handler.class.getDeclaredField("mCallback");
            mCallBackField.setAccessible(true);
            mCallBackField.set(mHandler, new CallBackImpl(mHandler));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

private static boolean isInterruptException(Throwable e){
    if (e.toString().contains("DeadSystemException")){
        //拦截DeadSystemException
        return true;
    }
     return false;
}

以上代码,在Application的oncreate()中调用

3.activity stop发生该异常

在这里插入图片描述
查看源码:
在这里插入图片描述
StopInfo 这个任务是在ActivityThread 执行Activity onstop状态时添加的:
在这里插入图片描述
handleStopActivity() 是在ActivityThread中H的handler中调用的。

解决方案
因StopInfo是runnable接口,无法通过Handler的handleMessage()函数进行拦截,因此考虑直接代理H 这个Handler , 通过dispatchMessage()分发,传递给H处理,进行异常捕捉。

private static class HandlerImpl extends Handler {
    private Handler proxy;
    public HandlerImpl(Handler proxy) {
        super(proxy.getLooper());
        this.proxy = proxy;
    }
    @Override
    public void dispatchMessage(@NonNull Message msg) {
        try {
            proxy.dispatchMessage(msg);
        } catch (Exception e) {
            if (!isInterruptException(e)) {
                //不被拦截的异常,继续抛出
                throw e;
            }
        }
    }
    public static void hook() {
        try {
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1 || Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
                //获取到ActivityThread
                Class<?> ActivityThreadClass = Class.forName("android.app.ActivityThread");
                Field sCurrentActivityThreadField = ActivityThreadClass.getDeclaredField("sCurrentActivityThread");
                sCurrentActivityThreadField.setAccessible(true);
                Object ActivityThread = sCurrentActivityThreadField.get(null);
                //获取到ActivityThread中的handler
                Field mHField = ActivityThreadClass.getDeclaredField("mH");
                mHField.setAccessible(true);
                Handler mHandler = (Handler) mHField.get(ActivityThread);
                mHField.set(ActivityThread, new HandlerImpl(mHandler));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
private static boolean isInterruptException(Throwable e) {
    if (e.toString().contains("DeadSystemException")) {
        //拦截DeadSystemException
        return true;
    }
    return false;
}

Hook H 这个Handler 可以解决Activity或者Service 生命周期中该异常的捕获。在Application的oncreate()中调用。

4. (终极解决方案,捕获任何地方发生该问题的调用栈)

实际上可能其他的线程或者其他的handler 中调用跨进程有关的api都可能会遇到该问题,单纯hook ActivityThread中Handler是无法解决的。
终极解决方案:通过主线程的异常处理器,捕获该异常,自定义Thread.UncaughtExceptionHandler。

/**
 * 终极解决方案
 */
private static class ExceptionHandlerImpl implements Thread.UncaughtExceptionHandler{
    private final Thread.UncaughtExceptionHandler mOldHandler;
    public ExceptionHandlerImpl(Thread.UncaughtExceptionHandler mOldHandler) {
        this.mOldHandler = mOldHandler;
    }

    @Override
    public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {
        if (isInterruptException( e)) {
            // 异常逻辑 1: 继续执行,进程不结束
            resumeMainThreadLoop();
            // restartApp() 或者直接中断该进程,进行重启重启该app 的逻辑2
            return;
        }
        if (mOldHandler != null) {
            mOldHandler.uncaughtException(t, e);
        }
    }
    private void restartApp(Context context){
        // 重新启动应用程序或者系统服务
        final Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingIntent);
        // 退出应用程序或者停止服务
        System.exit(0);
    }
    private void resumeMainThreadLoop() {
        try {
            Looper.loop();
        } catch (Exception e) {
            uncaughtException(Thread.currentThread(), e);
        }
    }
    public static void init(){
        // 小于或者等于7.1才开启
        boolean open = Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1;
        if (open) {
            Thread.UncaughtExceptionHandler mOldHandler = Thread.getDefaultUncaughtExceptionHandler();
            if (!(mOldHandler instanceof ExceptionHandlerImpl)) {
                Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandlerImpl(mOldHandler));
            }
        }
    }
}

以上代码在bugly或者异常捕获组件之后调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/500756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lecture 11:How versatile are self-supervised models

目录 Story 1: Cross-lingual Story 2: Cross-discipline Story 3: Pre-training with artificial data &#xff08;story1和story2的内容在前面课程中有讲过&#xff0c;这里笔记部分不再详述&#xff09; Story 1: Cross-lingual 多语言BERT具有跨语言的能力&#xff0…

Linux-Day01

Linux-Day01 课程内容 Linux简介Linux安装Linux常用命令 1. 前言 1.1 什么是Linux Linux是一套免费使用和自由传播的操作系统。说到操作系统&#xff0c;大家比较熟知的应该就是Windows和MacOS操作系统&#xff0c;我们今天所学习的Linux也是一款操作系统。 1.2 为什么要学…

12.IO流

1.字符流 1.1为什么会出现字符流【理解】 字符流的介绍 由于字节流操作中文不是特别的方便&#xff0c;所以Java就提供字符流 字符流 字节流 编码表 中文的字节存储方式 用字节流复制文本文件时&#xff0c;文本文件也会有中文&#xff0c;但是没有问题&#xff0c;原因是最…

消息队列中的事务消息

大家好&#xff0c;我是易安&#xff01;今天我们谈一谈消息队列中的事务消息这个话题。 一说起事务&#xff0c;你可能自然会联想到数据库。我们日常使用事务的场景&#xff0c;绝大部分都是在操作数据库的时候。像MySQL、Oracle这些主流的关系型数据库&#xff0c;也都提供了…

Java --- springboot2之异常处理

仅供参考 目录 一、异常处理 二、异常处理自动配置原理 三、异常处理流程 四、定制错误处理逻辑 4.1、自定义错误页 4.2、ControllerAdviceExceptionHandler处理全局异常 4.3、ResponseStatus自定义异常 4.4、Spring底层的异常&#xff0c;如 参数类型转换异常 4.5、自定义…

7种常见网络并发模型介绍

概述 对于网络服务器后端开发&#xff0c;为满足不同并发场景的需要&#xff0c;一般来说&#xff0c;不外乎几种常见的并发模型&#xff0c;除了一些教学场景常用的单线程、多进程&#xff08;线程&#xff09;的服务器实现外&#xff0c;生产用的服务器&#xff0c;一般都会…

Linux多路IO复用:epoll

1. epoll epoll是为克服select、poll每次监听都需要在用户、内核空间反复拷贝&#xff0c;以及需要用户程序自己遍历发现有变化的文件描述符的缺点的多路IO复用技术。 epoll原理 创建内核空间的红黑树&#xff1b; 将需要监听的文件描述符上树&#xff1b; 内核监听红黑树上…

实验室设备管理系统

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 应用背景 为方便实验室进行设备管理&#xff0c;某大学拟开发实验室设备管理系统 来管理所有实验室里的各种设备。系统可实现管理员登录&#xff0c;查看现有的所有设备&#xff0c; 增加设备等功能。 开发环境 Mac OS PyCha…

JAVA:Springboot 装配数据库Hikari和Druid连接池

1、JDBC Java数据库连接&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口&#xff0c;提供了诸如查询和更新数据库中数据的方法。 JDBC API主要位于JDK中的java.sql包中&#xff08;之后…

出现小红书点赞多粉丝少的情况,原因在哪里

刚开始运营自己账号的小伙伴们有时发现明明笔记点赞数量不少&#xff0c;但偏偏账号粉丝数量就是一直不怎么涨&#xff0c;像这样小红书点赞多粉丝少是怎么回事呢?今天就来说说&#xff0c;小红书该如何吸引用户关注。 一、小红书点赞多粉丝少是怎么回事 一般来说&#xff0c;…

从MIMIC学习组织自己的数据

从MIMIC学习组织自己的数据 相对于SEER数据库&#xff08;我们得到的是几乎可以直接进行分析的数据&#xff09;&#xff0c;MIMIC 数据库在数据采集后虽然经过了一定的处理&#xff0c;但是保留了数据库原始的样貌&#xff0c;所以我们除了对MIMIC数据进行分析外&#xff0c;…

推荐算法之DeepFM

论文&#xff1a;DeepFM: A Factorization-Machine based Neural Network for CTR Prediction Github&#xff1a;https://github.com/ChenglongChen/tensorflow-DeepFM https://github.com/shenweichen/DeepCTR IJCAI2017 本文将深度神经网络dnn和因式分解机Factorization-M…

程序中各种异常报错,对于JVM调优记录

一&#xff1a;GC overhead limit exceeded 数据量过大&#xff1a;当应用程序处理大量的数据时&#xff0c;会占用大量的内存和计算资源。如果内存资源不足&#xff0c;则可能会在垃圾回收过程中出现 GC overhead limit exceeded 错误 程序代码有问题&#xff1a;如果 应用程…

Vmware虚拟机问题解决方案

Vmware虚拟机问题解决方案 1. 运行虚拟机系统蓝屏 可能的原因有两个: 1). 虚拟机所在磁盘的空间不足 ; -------> 清理磁盘空间 。 2). 操作系统版本高, 需要适配新版本的Vmware ; ------> 卸载Vmware15版本, 安装Vmware16版本 。 2. 卸载Vmware步骤 1). 卸载已经安…

商用密码产品认证中的随机数(一)

1 商密认证中的随机数介绍 如果说密钥的安全是密码产品的基石&#xff0c;那随机数的安全就是密钥安全的基石。密码产品设计和商用密码产品认证中&#xff0c;随机数的合规性也是需要重点关注的环节。 随机数的合规性主要包括&#xff1a; 随机数的来源合规。如果是自行设计的…

一点通路由模拟实验8

首先先设置hostA和hostB和hostC的ip 其次设置路由接口的各个ip 路由A 像这样的&#xff0c;再设置路由B 唯一要记住的是&#xff0c;时钟只要设置一个就行 就是clock rate 6400&#xff0c;之后开启路由&#xff1a;ip routing 然后就是查看路由表了&#xff08;路由A&#…

Lecture 12(Preparation):Reinforcement Learning

目录 What is RL? (Three steps in ML) Policy Gradient Actor-Critic Reward Shaping No Reward: Learning from Demonstration It is challenging to label data in some tasks. 例如下围棋时&#xff0c;下一步下在哪个位置最好是不太好确定的&#xff0c;此时可以考虑…

无线传感器网络路由优化中的能量均衡LEACH改进算法(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 由于簇的规模和簇头选择对WSN总能耗影响较大&#xff1a;一方面&#xff0c;当簇的规模较小时&#xff0c;易导致WSN能量消耗不…

2021年NOC大赛编程马拉松赛道图形化中高组模拟卷,包含答案

目录 单选题: 判断题: 下载文档打印做题: 2021年NOC大赛编程马拉松赛道图形化中高组模拟卷 单选题: 1.雪球不小心误入了图灵学院旁边山林中的一个洞穴,一直都没有出来,禾木、桃子和小核桃打算进去找她,洞穴里漆黑一片,三人走着走着,不知怎么也走散了。如下图所示,…

加速开放计算产业化,OCTC五大原则瞄准需求痛点

回顾计算产业过去十余载的历程&#xff0c;开放计算始终是一个绕不开的核心焦点。 始于2011年Facebook发起的数据中心硬件开源项目--开放计算项目&#xff08;简称&#xff1a;OCP&#xff09;&#xff0c;开放计算犹如星星之火&#xff0c;不仅迅速形成燎原之势&#xff0c;更…