ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Analyzing App Startup and Shutdown details in Android 15

Tomáš Repčík
ProAndroidDev
Published in
5 min readOct 17, 2024

ApplicationStartInfo

val activityManager: ActivityManager =
context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val startInfos = activityManager.getHistoricalProcessStartReasons(maxNumberOfInstances)

Available data:

val startType = startInfo.startType
val startReason = startInfo.reason
val startUpState = startInfo.startupState
val launchMode = startInfo.launchMode
val startTimestamp = startInfo.startupTimestamps
val wasForceStopped = startInfo.wasForceStopped()
val startIntent = startInfo.intent

Add callback

val executor = context.mainExecutor
activityManager.addApplicationStartInfoCompletionListener(executor) {
// access the ApplicationStartInfo via `it`
}

Add your events

val currentTimeInNanos = System.nanoTime()
activityManager.addStartInfoTimestamp(25, timestamp)

ApplicationExitInfo

val exitInfos = activityManager.getHistoricalProcessExitReasons(packageName, 0, maxNum)

Available data:

Example usage

enum class StartReason {
START_REASON_ALARM,
START_REASON_BACKUP,
START_REASON_BOOT_COMPLETE,
START_REASON_BROADCAST,
START_REASON_CONTENT_PROVIDER,
START_REASON_JOB,
START_REASON_LAUNCHER,
START_REASON_LAUNCHER_RECENTS,
START_REASON_OTHER,
START_REASON_PUSH,
START_REASON_SERVICE,
START_REASON_START_ACTIVITY;

companion object {
fun fromValue(value: Int): StartReason = when (value) {
ApplicationStartInfo.START_REASON_ALARM -> START_REASON_ALARM
ApplicationStartInfo.START_REASON_BACKUP -> START_REASON_BACKUP
ApplicationStartInfo.START_REASON_BOOT_COMPLETE -> START_REASON_BOOT_COMPLETE
ApplicationStartInfo.START_REASON_BROADCAST -> START_REASON_BROADCAST
ApplicationStartInfo.START_REASON_CONTENT_PROVIDER -> START_REASON_CONTENT_PROVIDER
ApplicationStartInfo.START_REASON_JOB -> START_REASON_JOB
ApplicationStartInfo.START_REASON_LAUNCHER -> START_REASON_LAUNCHER
ApplicationStartInfo.START_REASON_LAUNCHER_RECENTS -> START_REASON_LAUNCHER_RECENTS
ApplicationStartInfo.START_REASON_OTHER -> START_REASON_OTHER
ApplicationStartInfo.START_REASON_PUSH -> START_REASON_PUSH
ApplicationStartInfo.START_REASON_SERVICE -> START_REASON_SERVICE
ApplicationStartInfo.START_REASON_START_ACTIVITY -> START_REASON_START_ACTIVITY
else -> throw IllegalArgumentException("Unknown start reason value: $value")
}
}
}
data class StartupTimestamps(
val applicationOnCreate: Long? = null,
val bindApplication: Long? = null,
val firstFrame: Long? = null,
val fork: Long? = null,
val fullyDrawn: Long? = null,
val initialRenderThreadFrame: Long? = null,
val launch: Long? = null,
val reservedRangeDeveloper: Long? = null,
val reservedRangeDeveloperStart: Long? = null,
val reservedRangeSystem: Long? = null,
val surfaceFlingerCompositionComplete: Long? = null
) {
companion object {
fun fromMap(timestampMap: Map<Int, Long>): StartupTimestamps = StartupTimestamps(
applicationOnCreate = timestampMap[ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE],
bindApplication = timestampMap[ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION],
firstFrame = timestampMap[ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME],
fork = timestampMap[ApplicationStartInfo.START_TIMESTAMP_FORK],
fullyDrawn = timestampMap[ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN],
initialRenderThreadFrame = timestampMap[ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME],
launch = timestampMap[ApplicationStartInfo.START_TIMESTAMP_LAUNCH],
reservedRangeDeveloper = timestampMap[ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER],
reservedRangeDeveloperStart = timestampMap[ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START],
reservedRangeSystem = timestampMap[ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_SYSTEM],
surfaceFlingerCompositionComplete = timestampMap[ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE]
)
}
}
enum class ExitReason {
REASON_ANR,
REASON_CRASH,
REASON_CRASH_NATIVE,
REASON_DEPENDENCY_DIED,
REASON_EXCESSIVE_RESOURCE_USAGE,
REASON_EXIT_SELF,
REASON_FREEZER,
REASON_INITIALIZATION_FAILURE,
REASON_LOW_MEMORY,
REASON_OTHER,
REASON_PACKAGE_STATE_CHANGE,
REASON_PACKAGE_UPDATED,
REASON_PERMISSION_CHANGE,
REASON_SIGNALED,
REASON_UNKNOWN,
REASON_USER_REQUESTED,
REASON_USER_STOPPED;

companion object {
fun fromValue(value: Int): ExitReason = when (value) {
ApplicationExitInfo.REASON_ANR -> REASON_ANR
ApplicationExitInfo.REASON_CRASH -> REASON_CRASH
ApplicationExitInfo.REASON_CRASH_NATIVE -> REASON_CRASH_NATIVE
ApplicationExitInfo.REASON_DEPENDENCY_DIED -> REASON_DEPENDENCY_DIED
ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE -> REASON_EXCESSIVE_RESOURCE_USAGE
ApplicationExitInfo.REASON_EXIT_SELF -> REASON_EXIT_SELF
ApplicationExitInfo.REASON_FREEZER -> REASON_FREEZER
ApplicationExitInfo.REASON_INITIALIZATION_FAILURE -> REASON_INITIALIZATION_FAILURE
ApplicationExitInfo.REASON_LOW_MEMORY -> REASON_LOW_MEMORY
ApplicationExitInfo.REASON_OTHER -> REASON_OTHER
ApplicationExitInfo.REASON_PACKAGE_STATE_CHANGE -> REASON_PACKAGE_STATE_CHANGE
ApplicationExitInfo.REASON_PACKAGE_UPDATED -> REASON_PACKAGE_UPDATED
ApplicationExitInfo.REASON_PERMISSION_CHANGE -> REASON_PERMISSION_CHANGE
ApplicationExitInfo.REASON_SIGNALED -> REASON_SIGNALED
ApplicationExitInfo.REASON_UNKNOWN -> REASON_UNKNOWN
ApplicationExitInfo.REASON_USER_REQUESTED -> REASON_USER_REQUESTED
ApplicationExitInfo.REASON_USER_STOPPED -> REASON_USER_STOPPED
else -> throw IllegalArgumentException("Unknown exit reason value: $value")
}
}
}

Android development

23 stories

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Tomáš Repčík

https://tomasrepcik.dev/ - Flutter app developer with experience in native app development and degree in biomedical engineering.

No responses yet

Write a response