SystemUi SYSTEM ALERT类型窗口无法在子用户下显示
SystemUI 在子用户下窗口不显示的问题分析
问题现象
- 在子用户下,SystemUI 通过 WindowManager.addView 创建的窗口不显示
- 窗口类型为 TYPE_SYSTEM_ALERT 或 TYPE_APPLICATION_OVERLAY
根本原因
- SystemUI 使用 sharedUserId=”android.uid.systemui”,对应 UID 10140
- 该 UID 被解析为系统用户(userId=0),导致窗口归属到系统用户
- 多用户可见性判断依赖 mShowUserId,与当前用户不匹配时被过滤
UID 计算
1 | // UserHandle.getUserId() 实现 |
- SystemUI UID: 10140
- 计算出的用户ID: 0(系统用户)
- 实际运行用户: 子用户(如用户1)
窗口可见性判断
1 | // WindowState.showToCurrentUser() |
- mShowUserId 来自创建窗口时的 userId,对 SystemUI 为 0
- 在子用户下,isUserVisible(0) 可能为 false,导致窗口被隐藏
窗口类型行为
1 | // TYPE_SYSTEM_ALERT 默认行为 |
- TYPE_SYSTEM_ALERT 默认仅对创建用户可见
- 需要 SYSTEM_FLAG_SHOW_FOR_ALL_USERS 才能跨用户显示
1 | // TYPE_APPLICATION_OVERLAY 默认行为 |
- TYPE_APPLICATION_OVERLAY 同样默认仅对创建用户可见
showForAllUsers 逻辑
1 | boolean showForAllUsers() { |
- 未设置 SYSTEM_FLAG_SHOW_FOR_ALL_USERS 时,默认仅对创建用户可见
- 需要 mOwnerCanAddInternalSystemWindow 权限
解决方案
- 方案1:设置 SYSTEM_FLAG_SHOW_FOR_ALL_USERS
1 | WindowManager.LayoutParams params = new WindowManager.LayoutParams(); |
- 方案2:使用默认跨用户的窗口类型
1 | // 使用默认对所有用户可见的窗口类型 |
- 方案3:在 SystemUI 中统一处理
1 | // 在 SystemUI 的窗口创建工具类中 |
验证
- 在子用户下创建窗口并检查可见性
- 确认 mShowUserId 与当前用户匹配
- 验证 showForAllUsers() 返回 true
总结
- 根因是 sharedUserId 使 SystemUI 的 UID 被解析为系统用户,窗口归属到系统用户
- 多用户可见性判断依赖 mShowUserId,与当前用户不匹配时被过滤
- 通过设置 SYSTEM_FLAG_SHOW_FOR_ALL_USERS 或使用默认跨用户的窗口类型可解决
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 BravestSnail's Blog!