[MODE: RESEARCH]

Android 窗口多用户显示机制总结

核心概念

1. 用户隔离

  • 每个用户有独立的应用和数据
  • 窗口默认仅对创建用户可见
  • 系统级窗口可跨用户显示

2. UID 与用户 ID

1
2
3
4
// UID 结构:userId * PER_USER_RANGE + appId
// PER_USER_RANGE = 100000
// 例如:UID 10140 = 0 * 100000 + 10140 (系统用户,SystemUI)
// 例如:UID 100001 = 1 * 100000 + 1 (用户1,应用ID 1)

窗口可见性判断机制

1. 主要判断方法

1
2
3
4
5
// WindowState.showToCurrentUser()
boolean showToCurrentUser() {
final WindowState win = getTopParentWindow();
return win.showForAllUsers() || mWmService.isUserVisible(win.mShowUserId);
}

2. 关键字段

  • mShowUserId:窗口应显示的用户 ID
  • mOwnerUid:创建窗口的进程 UID
  • mOwnerCanAddInternalSystemWindow:是否有系统窗口权限

窗口类型分类

1. 默认对所有用户可见

1
2
3
4
5
6
7
// 在 showForAllUsers() 的 switch 中
case TYPE_PHONE: // 来电窗口
case TYPE_STATUS_BAR: // 状态栏
case TYPE_NAVIGATION_BAR: // 导航栏
case TYPE_SYSTEM_DIALOG: // 系统对话框
case TYPE_VOLUME_OVERLAY: // 音量覆盖层
// ... 其他系统窗口

2. 默认仅对创建用户可见

1
2
3
4
case TYPE_SYSTEM_ALERT:       // 系统警告窗口
case TYPE_APPLICATION_OVERLAY: // 应用覆盖层
case TYPE_TOAST: // Toast 通知
// ... 其他应用窗口

跨用户显示机制

1. 系统权限检查

1
2
// 只有系统进程才能显示跨用户窗口
return mOwnerCanAddInternalSystemWindow;

2. 特殊标志

1
2
3
// SYSTEM_FLAG_SHOW_FOR_ALL_USERS
// 需要 INTERNAL_SYSTEM_WINDOW 权限
params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;

3. 权限要求

  • INTERNAL_SYSTEM_WINDOW:系统级窗口权限
  • SYSTEM_ALERT_WINDOW:系统警告窗口权限

实际应用场景

1. SystemUI 窗口

  • 使用 android.uid.systemui (UID: 10140)
  • 拥有系统级权限
  • 可创建跨用户窗口

2. 普通应用窗口

  • 使用应用 UID
  • 默认仅对创建用户可见
  • 需要特殊权限才能跨用户显示

3. 系统服务窗口

  • 使用系统 UID (1000)
  • 拥有系统级权限
  • 可创建跨用户窗口

设计原则

1. 安全隔离

  • 用户数据隔离
  • 窗口默认不跨用户
  • 需要显式权限

2. 系统级特权

  • 系统组件可跨用户
  • 需要系统签名
  • 受权限控制

3. 用户体验

  • 系统 UI 全局可见
  • 应用窗口用户隔离
  • 支持多用户切换

总结

  • 默认仅对创建用户可见
  • 系统级窗口可跨用户显示
  • 通过权限和标志控制可见性
  • 兼顾安全与体验