DeadSystemException:
The core Android system has died and is going through a runtime restart. All running apps will be promptly killed.
Android 核心系統(tǒng)服務已經(jīng)死亡,正在重啟中。全部正在運行的app即將被kill殺死。
更多請閱讀,DeadSystemException官方介紹
chatgpt給出的解決答案:
Android中的DeadSystemException是一種非常嚴重的異常,表示系統(tǒng)已經(jīng)崩潰。如果不進行處理,應用程序將會崩潰并退出。
處理方式:
- 捕獲該異常:使用try-catch來捕獲DeadSystemException異常,或者注冊一個UncaughtExceptionHandler來處理未捕獲的異常
- 根據(jù)產品需求進行業(yè)務邏輯處理:進行相應的處理,例如輸出錯誤日志或者提示用戶重新啟動應用程序。
1.service create 發(fā)生該異常:
先來看下調用棧中拋出異常的地方:/frameworks/base/core/java/android/app/ActivityThread.java
中handleCreateService():
從源碼可知 :
- app 進程已經(jīng)完成對service#oncreate()過程,接著與ams 通過binder通訊,發(fā)生了DeadObjectException 從而拋出了DeadSystemException。
- ActivityThread 中對service創(chuàng)建過程有異常處理機制try-catch ,會判斷Instrumentation 是否攔截該異常。
為了進一步了解原因,接著查看bugly上該異常中捕獲的日志,發(fā)現(xiàn)有幾條有效日志:
//系統(tǒng)服務已經(jīng)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)
根據(jù)分析,推斷系統(tǒng)服務已經(jīng)死亡,app進程通過binder與之通訊,會拋出DeadSystemException。
根據(jù)FAILED BINDER TRANSACTION
檢索,找/frameworks/base/core/jni/android_util_Binder.cpp
。
signalExceptionForError():
從binder通訊源碼中可知,當遇到異常返回status(failed_transansaction 和dead_object)時, 會拋出DeadObjectException異常。另外,單次讀寫超過200k的binder數(shù)據(jù),就會拋出TransactionTooLargeException 異常;
原因推斷:當app進程創(chuàng)建service 成功后,與ams 通訊過程中,binder 發(fā)生異常狀態(tài)status failed_transansaction,從而拋出異常導致。
解決方案:
采用hook 方式,代理Instrumentation 捕獲該異常:
/**
* 自定義 Instrumentation 子類,
* 攔截對Activity和Service的系統(tǒng)異常攔截
*/
private static class InstrumentationImpl extends Instrumentation{
@Override
public boolean onException(Object obj, Throwable e) {
return isInterruptException(e);
}
public static void hookInstrumentation(){
//基本上發(fā)生在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 ,也可以通用實現(xiàn)以上效果;
捕獲該異常后,需要啟動的服務無法啟動,Bugly 不會捕捉到該異常,但app進程很可能會被殺死。
2.activity destory 發(fā)生該異常:
先查看調用棧:
查看下crash 所在的源碼:
與前面的問題有些不同,當app 進程已經(jīng)完成Activity銷毀過程后,通知ams 過程中,發(fā)生系統(tǒng)進程,死亡異常則直接拋出。
解決方案:
App 銷毀Activity過程中沒有異常捕捉機制,但該調用棧是在ActivityThread 中名為H 的handler中調用的,因此考慮hook 進行異常捕獲。
再查看Handler的源碼,發(fā)現(xiàn)可以為它設置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)){
//不被攔截的異常,繼續(xù)拋出
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監(jiān)聽器,攔截
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發(fā)生該異常:
查看源碼:
StopInfo 這個任務是在ActivityThread 執(zhí)行Activity onstop狀態(tài)時添加的:
handleStopActivity() 是在ActivityThread中H的handler中調用的。
解決方案:
因StopInfo是runnable接口,無法通過Handler的handleMessage()函數(shù)進行攔截,因此考慮直接代理H 這個Handler , 通過dispatchMessage()分發(fā),傳遞給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)) {
//不被攔截的異常,繼續(xù)拋出
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. (終極解決方案,捕獲任何地方發(fā)生該問題的調用棧):
實際上可能其他的線程或者其他的handler 中調用跨進程有關的api都可能會遇到該問題,單純hook ActivityThread中Handler是無法解決的。
終極解決方案:通過主線程的異常處理器,捕獲該異常,自定義Thread.UncaughtExceptionHandler。文章來源:http://www.zghlxwxcb.cn/news/detail-686517.html
/**
* 終極解決方案
*/
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: 繼續(xù)執(zhí)行,進程不結束
resumeMainThreadLoop();
// restartApp() 或者直接中斷該進程,進行重啟重啟該app 的邏輯2
return;
}
if (mOldHandler != null) {
mOldHandler.uncaughtException(t, e);
}
}
private void restartApp(Context context){
// 重新啟動應用程序或者系統(tǒng)服務
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() {
if (Looper.myLooper() != Looper.getMainLooper()) {
return;
}
try {
Looper.loop();
} catch (Exception e) {
uncaughtException(Thread.currentThread(), e);
}
}
public static void init(){
//在bugly初始化或者自定義crash上報組件之后調用
Thread.UncaughtExceptionHandler mOldHandler = Thread.getDefaultUncaughtExceptionHandler();
if (!(mOldHandler instanceof ExceptionHandlerImpl)) {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandlerImpl(mOldHandler));
}
}
}
以上代碼在bugly或者異常捕獲組件之后調用。文章來源地址http://www.zghlxwxcb.cn/news/detail-686517.html
到了這里,關于Android System crash DeadSystemException(Service/Activity/終極解決方案)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!