Android 15 新功能和 API 详解:应用程序启动信息,ApplicationStartInfo

Android 15(API 级别 35)引入了 ApplicationStartInfo API,可以通过它更深入地了解应用的整个启动过程,包括启动状态、启动阶段所用的时间、在 Application 类被实例化时应用的启动方式等,使开发者能够优化应用启动过程的每一步。

介绍

在以前的 Android 版本中,在应用中确定应用是从冷状态、温状态还是热状态开始的过程很难确定。此外,我们也很难知道您的应用在不同发布阶段所用的时间:创建进程分支、调用 onCreate、绘制第一帧等。在实例化 Application 类时,您无法得知应用是从广播、content provider、任务(Job)、备份、启动完成(boot complete)、闹钟还是 Activity 启动的。

Android 15 上的 ApplicationStartInfo API 可提供所有这些功能以及更多其他功能。甚至可以选择将自己的时间戳添加到流程中,以便在一个位置收集时间数据。除了收集指标之外,您还可以使用 ApplicationStartInfo 直接优化应用启动;例如,当应用因广播而启动时,可以避免在 Application 类中实例化界面相关库的高成本。

ApplicationStartInfo 提供了有关应用进程如何启动的详细信息,包括:

  • 启动原因:

    应用为什么启动:用户操作、闹钟、广播、推送、启动器(Intent)等

  • 启动状态:

    启动过程中的当前状态:已启动、错误、绘制第一帧

  • 启动类型:

    冷启动、温启动、热启动

  • 时间戳:

    启动过程中关键事件的精确计时,例如:创建进程、Application.onCreate()、绘制第一帧等

  • Intent:

    启动应用的 Intent

获取 ApplicationStartInfo

ApplicationStartInfo 对象可以通过以下方式获取:

1. getHistoricalProcessStartReasons

可以在应用程序启动期间或之后调用。使用此方法,应用程序可以检索有关正在运行的应用程序的启动信息。

ActivityManager.getHistoricalProcessStartReasons 调用示例:

@RequiresApi(35)
private fun getAppStartInfo() {
    val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager

    // 记录列表,按从最近到最不近的顺序排序。
    val startInfos = activityManager.getHistoricalProcessStartReasons(0)
    startInfos.forEach { info ->
        Log.i("ApplicationStartInfo", """
            pid=${info.pid}
            realUid=${info.realUid}
            packageUid=${info.packageUid}
            definingUid=${info.definingUid}
            user=${info.packageUid}

            process=${info.processName}
            startupState=${info.startupState}
            // 触发进程启动的原因代码
            reason=${info.reason}
            startType=${info.startType}
            launchMode=${info.launchMode}
            wasForceStopped=${info.wasForceStopped()}

            intent=${info.intent.toString()}
        """.trimIndent())

        val sb = StringBuilder()
        // 整个启动过程中各种阶段的时间戳(以纳秒为单位)
        if (info.startupTimestamps.isNotEmpty()) {
            sb.append("timestamp: ")
            info.startupTimestamps.forEach { (key, value) ->
                sb.append("$key=$value ")
            }
        }
        Log.i("ApplicationInfo", sb.toString())
    }
}

上例中获取应用启动信息的输出结果:

pid=0
realUid=10203
packageUid=10203
definingUid=10203
user=10203

process=cn.itmob.compose.sample
startupState=2
reason=6
startType=1
launchMode=0
wasForceStopped=false

intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=cn.itmob.compose.sample/.MainActivity bnds=[824,1873][997,2068] }
timestamp: 0=1778473709200 3=1779065303200

2. addApplicationStartInfoCompletionListener

在启动完成时通过回调返回 ApplicationStartInfo 对象,或者在启动完成后请求立即返回。

ActivityManager.addApplicationStartInfoCompletionListener 调用示例:

package cn.itmob.compose.sample

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        if (Build.VERSION.SDK_INT >= 35) {
            addStartInfoListener()
        }
    }

    @RequiresApi(35)
    private val completionListener = Consumer<ApplicationStartInfo> { info ->
        Log.i("ApplicationStartInfo 1", """
            pid=${info.pid}
            realUid=${info.realUid}
            packageUid=${info.packageUid}
            definingUid=${info.definingUid}
            user=${info.packageUid}
            
            process=${info.processName}
            startupState=${info.startupState}
            // 触发进程启动的原因代码
            reason=${info.reason}
            startType=${info.startType}
            launchMode=${info.launchMode}
            wasForceStopped=${info.wasForceStopped()}
            
            intent=${info.intent.toString()}
        """.trimIndent())

        val sb = StringBuilder()
        // 整个启动过程中各种阶段的时间戳(以纳秒为单位)。
        if (info.startupTimestamps.isNotEmpty()) {
            sb.append("timestamp: ")
            info.startupTimestamps.forEach { (key, value) ->
                sb.append("$key=$value ")
            }
        }
        Log.i("ApplicationInfo", sb.toString())
    }

    @RequiresApi(35)
    private fun addStartInfoListener() {
        val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
        activityManager.addApplicationStartInfoCompletionListener(mainExecutor, completionListener)
    }
}

应用启动完成后的输出结果:

pid=0
realUid=10203
packageUid=10203
definingUid=10203
user=10203

process=cn.itmob.compose.sample
startupState=2
reason=6
startType=1
launchMode=0
wasForceStopped=false

intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=cn.itmob.compose.sample/.MainActivity bnds=[824,1873][997,2068] }
timestamp: 0=6370714763300 3=6371095338200

可以通过这些信息分析或优化应用的启动,也可以使用它们来触发特定操作。

总结

通过了解应用启动过程各个步骤以及每步所花费的时间,可以为用户提供更流畅、更快速、更高效的体验。

其他

Android 15 新功能:应用程序启动信息 API

New API: ApplicationStartInfo


Android 15 功能和变更列表

翻译:2024 年 9 月 3 日 Android 15 已发布至 AOSP

Android 15 新功能和 API 详解:Private Space/私密空间功能简介

Android 15 新功能和 API 详解:录屏检测,addScreenRecordingCallback

Android 15 新功能和 API 详解:支持 16 KB 页面大小

Android 15 新功能和 API 详解:更精确的 Intent 解析,UriRelativeFilterGroup 和 UriRelativeFilter


作者:ITmob
来源:ITmob.cn
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×