ApplicationExitInfo
Android 11 (API Level 30) introduces a class named ApplicationExitInfo
that contains the information of an application process's death.
This class is mostly useful for debugging crashes caused by Application Not Responding (ANR) (unresponsive) or native code crash. However, it can also be used to gain insight of why our application exits.
Basic Usage​
To use ApplicationExitInfo
class, simply use getHistoricalProcessExitReasons()
method inside ActivityManager
class:
import android.app.ActivityManager
import android.app.ApplicationExitInfo
import android.content.Context
import android.os.Build
import android.util.Log
import java.io.File
val activityManager = context.getSystemService(ActivityManager::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val applicationExitInfos = activityManager.getHistoricalProcessExitReasons(
context.packageName,
0,
0,
)
applicationExitInfos.forEach {
Log.i("TAG", it.toString())
if (it.reason == ApplicationExitInfo.REASON_ANR || it.reason == ApplicationExitInfo.REASON_CRASH_NATIVE) {
// Copy trace stack to a temporary file
it.traceInputStream?.use { input ->
val file = File.createTempFile("tracestack", ".txt")
file.outputStream().use { output ->
input.copyTo(output)
}
}
}
}
}
Notice that for process deaths that caused by REASON_ANR
and REASON_CRASH_NATIVE
, we can try retrieving the stacktrace by using getTraceInputStream()
method.
ApplicationExitInfo
also has getReason()
method that contains the reason code of the application process' death. Taken from the documentation, the possible reason codes are as follows:
Reason Code | Description |
---|---|
REASON_ANR | Application process was killed due to being unresponsive (ANR). |
REASON_CRASH | Application process died because of an unhandled exception in Java code. |
REASON_CRASH_NATIVE | Application process died because of a native code crash. |
REASON_DEPENDENCY_DIED | Application process was killed because its dependency was going away, for example, a stable content provider connection's client will be killed if the provider is killed. |
REASON_EXCESSIVE_RESOURCE_USAGE | Application process was killed by the system due to excessive resource usage. |
REASON_EXIT_SELF | Application process exit normally by itself, for example, via System.exit(int) ; getStatus() will specify the exit code. |
REASON_FREEZER | Application process was killed by App Freezer, for example, because it receives sync binder transactions while being frozen. |
REASON_INITIALIZATION_FAILURE | Application process was killed because of initialization failure, for example, it took too long to attach to the system during the start, or there was an error during initialization. |
REASON_LOW_MEMORY | Application process was killed by the system low memory killer, meaning the system was under memory pressure at the time of kill. |
REASON_OTHER | Application process was killed by the system for various other reasons which are not by problems in apps and not actionable by apps, for example, the system just finished updates; getDescription() will specify the cause given by the system. |
REASON_PACKAGE_STATE_CHANGE (🚨 New in Android 14) | Application process was killed because the app was disabled, or any of its component states have changed without PackageManager.DONT_KILL_APP . |
REASON_PACKAGE_UPDATED (🚨 New in Android 14) | Application process was killed because it was updated. |
REASON_PERMISSION_CHANGE | Application process was killed due to a runtime permission change. |
REASON_SIGNALED | Application process died due to the result of an OS signal; for example, OsConstants.SIGKILL ; getStatus() will specify the signal number. |
REASON_UNKNOWN | Application process died due to unknown reason. |
REASON_USER_REQUESTED | Application process was killed because of the user request, for example, user clicked the "Force stop" button of the application in the Settings, or removed the application away from Recents. |
REASON_USER_STOPPED | Application process was killed, because the user it is running as on devices with mutlple users, was stopped. |