activity 启动行为由相应应用的 AndroidManifest.xml
文件中的启动模式、intent 标志以及调用方提供的 ActivityOptions 定义。使用 ActivityOption#setLaunchDisplayId(int)
可将特定屏幕指定为 activity 启动的目标。
- 默认情况下,activity 与调用方在同一个屏幕上启动。例如,如果未指定其他标志或选项,通过启动器启动的新 Activity 实例应该放置与启动器相同的屏幕上。请务必在启动时使用正确的上下文(activity 与应用)。
- 如果在与特定屏幕无关的来源执行启动(例如通过 shell 或应用上下文),那么 activity 会位于用户上次与设备互动或上一个 activity 启动时的顶部屏幕上。
- 用于启动 activity 的 intent 可解析为系统中已有的 activity 实例。在这种情况下,如果未提供其他标志,activity 会显示在上次使用它时所在的屏幕上。如果使用
ActivityOptions#setTargetDisplayId()
指定目标屏幕,activity 会移动到该屏幕(如果安全限制及其他限制允许的话)。
安全限制
在 Android 10 中,为了防止恶意应用通过从其创建的虚拟屏幕的表面读取用户敏感信息来盗用相关信息,应用只能在其创建的虚拟屏幕上启动其自己的 Activity。但是:
- 具有
INTERNAL_SYSTEM_WINDOW
权限的系统组件可以在任何屏幕上启动。 - 具有
ACTIVITY_EMBEDDING
权限的调用方可以从具有ActivityInfo.FLAG_ALLOW_EMBEDDED
标志的其他应用启动 activity。 - 对于专有屏幕,只有其所有者或已在此类屏幕上的 activity 能够在此类屏幕上启动 activity。
向屏幕添加窗口会受到类似限制。
Android 10 包含 ActivityManager#isActivityStartAllowedOnDisplay(Context context, int
displayId, Intent intent)
方法,用于先检查应用的安全限制,然后再尝试在屏幕上启动。在 Android 9(及更低版本)中,如果启动受到限制,系统会抛出 SecurityException
。
大多数安全限制都在 ActivityStackSupervisor#isCallerAllowedToLaunchOnDisplay()
方法中实现。