24、车载多用户:Android Automotive多用户架构;用户切换与配置文件管理;多用户下的应用数据隔离;访客模式与代客泊车模式

各位同学,今天我们来聊聊车载多用户。说实话,这个功能在手机平板上可能只是个「锦上添花」的选项,但在车上,它绝对是「刚需」。你想想看,一辆车可能是全家共用,也可能是公司车队共享,甚至还有代客泊车这种临时场景。如果每个用户的数据都混在一起,那隐私和安全就全乱套了。

Android Automotive 的多用户架构,说白了就是给每个「开车的人」一个独立的虚拟空间。我最早接触这个是在一个共享出行项目里,当时客户要求「司机换人,所有数据必须清零」。嗯,那会儿我才真正意识到,多用户不是简单的切换账号,而是一整套数据隔离和生命周期管理机制。

多用户架构的核心设计

Android Automotive 的多用户架构,底层其实复用了 Android Framework 的 UserManagerUserHandle 机制。但车载场景下,有几个关键差异点:

  • 系统用户 vs 普通用户:系统用户(User 0)永远运行,负责核心服务。普通用户可以有多个,每个都有自己的应用数据和设置。
  • 前台用户唯一:同一时刻,只有一个用户处于前台(Foreground)。其他用户的应用会被暂停或缓存。
  • 用户类型丰富:除了常规用户,还有访客(Guest)和代客泊车(Valet)这种受限用户。

关键点:车载多用户不是简单的「多开」,而是「隔离+切换」。每个用户拥有独立的 /data/user/{userId} 目录,应用数据、壁纸、设置项全部隔离。

我习惯把多用户架构画成下面这张图,这样理解起来更直观:

Android Automotive 多用户架构 系统用户 (User 0) 核心服务:SystemUI、CarService、UserManager、PackageManager 用户 1(车主) /data/user/10 导航、音乐、蓝牙配对 应用数据完全隔离 用户 2(家庭成员) /data/user/11 独立设置、独立应用 可限制部分功能 访客模式 / 代客泊车模式 临时用户,退出时自动清除数据,限制车速/导航/电话

用户切换与配置文件管理

用户切换在车载系统里,比手机要复杂得多。为什么?因为车上有「驾驶安全」这个红线。你不能让用户在行驶过程中随意切换用户,那会分散注意力。

我参与的一个项目中,客户要求「车辆静止且挂P挡时,才能切换用户」。这个逻辑其实很合理。代码层面,我们通过监听车辆状态来控制切换入口的可用性:

// 检查车辆状态,决定是否允许切换用户
public boolean canSwitchUser(Context context) {
    Car car = Car.createCar(context);
    CarParkingManager parkingManager = (CarParkingManager) car.getCarManager(Car.PARKING_SERVICE);
    if (parkingManager != null) {
        // 只有P挡且车速为0时才允许切换
        return parkingManager.getParkingState() == CarParkingManager.PARKING_STATE_PARKED;
    }
    return false;
}

配置文件管理这块,Android Automotive 提供了 UserManager 的完整 API。创建用户、删除用户、设置用户类型,都是通过它来操作。我个人习惯把用户配置信息持久化到一个 SharedPreferences 里,但要注意——每个用户只能读写自己的那份配置。

避坑指南:我曾经遇到过一个问题——用户A切换后,用户B的某个后台服务还在偷偷写数据库。后来发现是 ContentProvider 没有按 userId 做隔离。记住,多用户下所有数据访问都要带上 userId 参数。

多用户下的应用数据隔离

数据隔离是多用户的核心。Android 系统通过 Linux 的用户 ID(UID)机制来实现。每个应用在安装时,系统会分配一个唯一的 UID,而不同用户下的同一个应用,UID 是不同的。

具体来说:

  • 每个用户拥有独立的 /data/user/{userId} 目录
  • 应用数据存储路径:/data/user/{userId}/{packageName}
  • SharedPreferences、数据库、文件,全部按用户隔离
  • ContentProvider 可以通过 uri 中的 userId 参数区分

举个例子,如果用户10和用户11都安装了网易云音乐,它们的数据库文件路径分别是:

/data/user/10/com.netease.cloudmusic/databases/music.db
/data/user/11/com.netease.cloudmusic/databases/music.db

这两个文件完全独立,互不干扰。但要注意一点——外部存储(SD卡)的隔离机制不同。Android 10 之后,外部存储也按用户隔离了,但如果你用了 getExternalStorageDirectory() 这种旧 API,可能会出问题。

警告:千万不要在应用里使用绝对路径访问其他用户的数据!我曾经见过一个开发者用 /data/user/10/... 硬编码路径,结果用户一切换,应用直接崩溃。正确的做法是使用 Context.createPackageContext() 并指定 userId。

访客模式与代客泊车模式

这两个模式,是车载多用户里最有特色的功能。说白了,它们都是「受限用户」,但使用场景完全不同。

特性 访客模式 代客泊车模式
使用场景 朋友临时开车 停车场工作人员挪车
数据保留 退出时可选保留或清除 退出时强制清除所有数据
功能限制 可限制导航、电话、应用安装 限制车速、限制访问后备箱、限制查看个人信息
创建方式 createGuest() 自定义 UserType,通过 createProfile()

实现代客泊车模式时,我建议你自定义一个 UserType。Android Automotive 允许 OEM 定义自己的用户类型,比如 com.example.car.VALET。然后通过 UserManager.createProfile() 创建,并设置对应的限制策略。

// 创建代客泊车用户
UserHandle createValetUser(UserManager userManager) {
    UserHandle userHandle = userManager.createProfile(
        "代客泊车",
        UserManager.USER_TYPE_PROFILE_MANAGED,  // 使用受管理用户类型
        null  // 可传入限制标志
    );
    // 设置额外限制:禁用蓝牙、限制车速显示等
    setValetRestrictions(userHandle);
    return userHandle;
}

嗯,这里有个细节要注意——代客泊车用户退出时,一定要调用 removeUser() 或者 markGuestForDeletion(),否则数据会残留。我曾经在一个演示项目里忘了这步,结果测试人员连续代客泊车5次后,存储空间爆了。

总结一下:多用户不是简单的「加个账号」,而是从系统架构到应用层都要考虑隔离。访客模式适合临时借用,代客泊车模式适合服务场景。两者都要注意数据清理和功能限制,别让用户数据「串门」。

好了,这一章的内容就到这里。多用户这块,说白了就是「分而治之」——把不同人的数据分开,把不同场景的权限分开。你只要记住这个核心思想,具体实现就是 API 调用的问题了。


公众号:蓝海资料掘金营,微信deep3321