OFFSET偏移
← 文章目录OFFSET / FIELD NOTESNO. 142

Waydroid 架构:LXC、Binder 与会话桥接

沿容器管理、用户会话和 Android 服务三条路径理解 Waydroid。

所在专题Waydroid ↗
约 43 分钟阅读开始阅读

适用范围与操作前提#

命令和输出使用通用示例。内核、镜像、包与服务版本会影响具体行为,阅读时应结合所用版本的文档核对。

修改容器、镜像、挂载和防火墙前先备份 Android 数据并停止相关会话;带删除或强制停止的示例可能丢失数据。NixOS 的系统与用户环境配置应通过 Nix 管理,通用 Linux 的 apt/pacman、直接写 /etc 和 pip 安装段落不用于 NixOS 宿主。重建的 build、test、switch 与启动后的功能验证是不同阶段。

Waydroid 不是模拟器,不是虚拟机——它不启动独立内核。整个架构围绕"宿主内核直通 + Linux namespace 隔离 + Binder IPC 桥接"三条主线展开,将完整的 Android 用户空间(LineageOS)作为一个 LXC 容器运行在标准 Linux 内核之上。


核心架构概览:三层分权模型#

Waydroid 将 Android 容器化分解为三个不同的特权层级,每一层运行在不同的用户上下文中,通过 D-Bus 进行严格的 IPC 通信。

graph TB
    subgraph Host["Linux 宿主 (root/用户空间)"]
        KERNEL["Linux Kernel<br/>binder + ashmem + memfd + PSI"]
        DBUS_SYS["D-Bus System Bus<br/>(root 权限域)"]
        DBUS_SES["D-Bus Session Bus<br/>(用户权限域)"]
    end

    subgraph Waydroid["Waydroid 管理层 (Python)"]
        CM["ContainerManager<br/>id.waydro.Container<br/>root 执行 / system bus"]
        SM["SessionManager<br/>id.waydro.Session<br/>用户执行 / session bus"]
        PK["授权策略<br/>按实际 D-Bus/发行版核对"]
    end

    subgraph Container["LXC Android 容器"]
        INIT["/init (Android init)<br/>PID 1 inside container"]
        HAL["HAL 层服务<br/>GPU / Audio / Input / Sensors"]
        APP["Android Apps<br/>LineageOS A13 (Android 13)"]
    end

    subgraph Services["后台桥接服务"]
        UM["user_manager"]
        CM2["clipboard_manager"]
        NM["notification_manager"]
    end

    KERNEL -->|"binder memfd"| Container
    DBUS_SYS -->|"root 鉴权"| CM
    DBUS_SES -->|"用户会话"| SM
    PK -->|"授权检查"| CM
    CM -->|".Start() D-Bus 调用"| Container
    SM -->|"Wayland socket<br/>PulseAudio pipe"| Container
    Services -->|"gbinder Python/C bridge"| HAL

    style Host fill:#1a1a2e,stroke:#0f3460,color:#e0e0e0
    style Waydroid fill:#0f3460,stroke:#16213e,color:#e0e0e0
    style Container fill:#533483,stroke:#3b2665,color:#e0e0e0
    style Services fill:#1b4332,stroke:#2d6a4f,color:#e0e0e0

三层分权设计

层级 组件 运行特权 D-Bus 总线 职责
第 1 层 ContainerManager root System Bus 容器生命周期:创建、启动、停止、冻结/解冻
第 2 层 SessionManager 普通用户 Session Bus 会话管理:配置 Wayland/PulseAudio 挂载点、管理 Android 应用启动
第 3 层 后台服务 (*_manager) 普通用户 Session Bus 数据桥接:用户管理、剪贴板同步、通知转发

为什么必须分权? ContainerManager 需要 root 权限才能操作 LXC(配置 network namespace、挂载文件系统、管理 cgroup)。但如果你把所有逻辑都放在 root 进程中,会扩大攻击面。Waydroid 将"需要 root 的最小操作集"隔离在 ContainerManager 中,其余会话逻辑全部以普通用户身份运行。

D-Bus 双总线设计

Waydroid 使用两条 D-Bus 总线做权限域隔离:

sequenceDiagram
    participant User as 普通用户 (UID 1000)
    participant SM as SessionManager<br/>(session bus)
    participant PK as PolicyKit
    participant CM as ContainerManager<br/>(system bus)
    participant LXC as LXC Container

    User->>SM: waydroid session start
    SM->>CM: D-Bus: id.waydro.Container.Start()
    Note over SM,CM: 跨总线调用 (system bus)
    CM->>PK: 检查 org.waydro.container.start
    PK-->>CM: 授权通过
    CM->>LXC: lxc-start -F -n waydroid -- /init
    LXC-->>CM: 容器运行中
    CM-->>SM: 返回状态
    SM-->>User: 会话就绪
  • System Bus (id.waydro.Container):注册在 /usr/share/dbus-1/system-services/,由 D-Bus daemon 按需激活,以 root 身份运行
  • Session Bus (id.waydro.Session):由用户会话的 D-Bus daemon 管理,以普通用户身份运行

D-Bus 安全边界 System bus 访问取决于 D-Bus 策略、服务实现和发行版授权集成。不能假定所有调用都经 PolicyKit,原笔记所列 action/path 未在核对的上游文件中确认。


LXC 容器模型#

Waydroid 的核心洞察是:Android 用户空间需要的不是虚拟硬件,而是一组 Linux kernel API。LXC 通过 namespace 提供隔离,同时让容器直接使用宿主内核。

为什么不启动独立内核?

对比三种方案:

硬件辅助虚拟化 (QEMU/KVM):
  宿主内核 → KVM → 独立内核 → Android 用户空间
  使用独立客体内核,性能和 GPU 集成取决于虚拟化配置

全虚拟化 (VirtualBox):
  宿主内核 → Hypervisor → 独立内核 → Android 用户空间
  同上,且需要内核模块

LXC 容器 (Waydroid):
  宿主内核 ← lxc-start ← /init (Android init) ← Android 用户空间
  不启动独立客体内核,直接复用宿主驱动 (GPU/dri/renderD128)

Linux Namespace 矩阵

Waydroid 使用以下 namespace 组合来构建容器的隔离环境:

Namespace 用途 Waydroid 中的具体应用
User UID/GID 映射 不能假定存在从属 UID 映射;检查实际 lxc.idmap 和运行凭据,Waydroid 常使用特权容器
PID 进程树隔离 容器内 /init 看到自己是 PID 1,与宿主进程空间完全隔离
UTS 主机名隔离 容器可以有自己的 hostname,不影响宿主
Net 网络栈隔离 创建独立的 waydroid0 网桥,Android 拥有独立的网络接口和路由表
Mount 文件系统隔离 /system、/vendor 以 overlayfs 挂载,/data 来自用户数据目录
IPC 跨进程通信隔离 Android 的 System V IPC 不会泄露到宿主

容器根文件系统

# Waydroid 根文件系统位置
/var/lib/waydroid/
├── rootfs/           # 容器内看到的 /
│   ├── system/       # LineageOS A13 系统镜像 (system.img, 只读)
│   ├── vendor/       # 厂商镜像 (vendor.img, 只读)
│   ├── data/         # 用户数据 (来自 ~/.local/share/waydroid/data)
│   └── ...
├── images/
│   ├── system.img    # → 挂载到 rootfs/system (只读, lower layer)
│   └── vendor.img    # → 挂载到 rootfs/vendor (只读, lower layer)
├── waydroid.prop     # Android 系统属性覆盖
└── lxc/              # 动态生成的 LXC 配置文件

OverlayFS 叠加模型 system.img 和 vendor.img 先以实际文件系统挂载,再按布局叠加 overlay,系统/vendor 的可写 overlay 与 Android /data 是不同层;用户数据目录挂载到 /data,不能把它当作系统镜像的通用 upperdir。这意味着系统镜像本身不会被修改,升级时只需替换 .img 文件。

LXC 配置动态生成

与大多数 LXC 容器使用静态配置文件不同,Waydroid 在每次启动时动态生成 LXC 配置。核心生成逻辑在 tools/helpers/lxc.py 中:

# 配置生成管道(简化)
def set_lxc_config():
    # 1. 复制基础配置片段
    copy_base_snippets("data/configs/config_*")

    # 2. 根据 LXC 版本适配
    apply_lxc_version_specific(lxc_version)

    # 3. 设置 AppArmor / Seccomp profile
    set_lxc_config_item("lxc.apparmor.profile", "unconfined")  # 示例,以实际模板为准
    set_lxc_config_item("lxc.seccomp.profile", "/var/lib/waydroid/waydroid.seccomp")

    # 4. 动态生成 binder 节点挂载条目
    generate_nodes_lxc_config()    # binder, vndbinder, hwbinder

    # 5. 动态生成会话相关挂载条目
    generate_session_lxc_config()  # Wayland socket, PulseAudio, data dir

为什么需要动态生成?

  1. LXC 版本兼容性:不同 LXC 版本的配置指令语法有差异(如 lxc.cgroup vs lxc.cgroup2),需要在启动时检测并适配
  2. Binder 节点路径可变:/dev/binder 可能是 legacy binder 或 binderfs,路径和命名规则随内核版本变化
  3. 会话路径依赖运行时:Wayland socket 路径($XDG_RUNTIME_DIR/$WAYLAND_DISPLAY)和 PulseAudio socket 路径由用户会话决定

Binder IPC 深度解析#

Binder 是 Android 的核心 IPC 机制,也是 Waydroid 能否正常工作的关键。没有 Binder,Android 系统服务无法通信。

为什么 Binder 是关键通信层?

Android 的系统架构建立在 Binder IPC 之上。在实体设备上,Binder 驱动负责在内核空间完成跨进程数据传递,避免了传统 IPC(管道、socket)的用户空间/内核空间多次拷贝开销。在 Waydroid 中,Android 容器运行在同一个宿主内核上,Binder 驱动由宿主内核提供,容器内的 Android 进程直接使用宿主内核的 binder 设备节点。

graph LR
    subgraph Host["宿主内核空间"]
        BINDER["/dev/binder<br/>binder 驱动"]
        VNDBINDER["/dev/vndbinder<br/>vendor binder"]
        HWBINDER["/dev/hwbinder<br/>hardware binder"]
    end

    subgraph Container["Android 容器"]
        SM["servicemanager"]
        HAL["HAL 服务"]
        APP["应用进程"]
    end

    SM -->|"注册/查询服务"| BINDER
    HAL -->|"vendor HAL 通信"| VNDBINDER
    APP -->|"应用层 IPC"| BINDER
    HAL -->|"硬件抽象层"| HWBINDER

    style Host fill:#1a1a2e,stroke:#0f3460,color:#e0e0e0
    style Container fill:#533483,stroke:#3b2665,color:#e0e0e0

三个 Binder 节点

节点 用途 Android 对应
/dev/binder Framework 层的通用 IPC,servicemanager 注册的所有系统服务通过此节点通信 frameworks/native/libs/binder
/dev/vndbinder Vendor HAL 与 Framework 之间的 IPC 隔离通道(Project Treble) /dev/vndbinder in Android 8+
/dev/hwbinder 硬件 HAL 内部 IPC,专门用于 HIDL 接口的通信 /dev/hwbinder in Android 8+

BinderFS vs 传统 Binder

传统固定 Binder 节点(与内核版本无严格分界):
  /dev/binder          ← 单一设备节点,所有 binder 通信共用
  权限:由实际 udev/发行版/LXC 设备配置管理,不向整个 binderfs 递归放权
  缺点:无法动态分配 binder 节点,所有 IPC 共享一个设备

BinderFS(自 Linux 5.0 引入):
  /dev/binderfs/       ← binder 文件系统
  ├── binder           ← 通过 ioctl(BINDER_CTL_ADD) 动态分配
  ├── vndbinder
  └── hwbinder
  优势:支持多个独立的 binder 实例,安全隔离更好

下面是 Binder 节点准备过程的说明性伪代码。实际 drivers.py 按已有节点探测、分配和链接;不执行这段代码,也不向全部 binderfs 节点套用同一权限:

def setupBinderNodes():
    # 1. 探测宿主内核是否有 binder 模块
    if not probe_binder_modules():
        raise BinderError("binder kernel module not found")

    # 2. 如果内核支持 binderfs,优先使用
    if binderfs_available():
        mount_binderfs("/dev/binderfs")
        # 通过 ioctl 分配三个节点
        ioctl(binderfs_fd, BINDER_CTL_ADD, "binder")
        ioctl(binderfs_fd, BINDER_CTL_ADD, "vndbinder")
        ioctl(binderfs_fd, BINDER_CTL_ADD, "hwbinder")
    else:
        # 3. 回退到传统 /dev/binder 节点
        use_legacy_binder_node("/dev/binder")

    # 4. 核对实际设备规则与最小访问范围;不对全部节点 chmod 666

Binder 常见故障 如果宿主内核没有编译 可用的 Binder 实现(内置或模块),Waydroid 容器会直接崩溃。Android init 启动后第一件事就是打开 /dev/binder 与 servicemanager 通信——binder 不可用意味着整个 Android 框架无法初始化。

Binder 协议版本自动检测

Android 的 Binder 协议在不同 API level 之间有过多次不兼容演进。Waydroid 需要根据容器内运行的 Android 镜像版本选择正确的协议版本。

协议版本检测逻辑(tools/helpers/protocol.py):

API Level Android 版本 Binder 协议 说明
< 28 Android 8.x 及更早 aidl 原始 AIDL 协议
28-29 Android 9-10 aidl2 引入协议版本协商
30 Android 11 aidl3 结构化 binder 传输
31-32 Android 12-12L aidl4 扩展传输格式
33-34 Android 13-14 aidl3 回退至 aidl3(Android 13 弃用 aidl4)

注意 这里的 aidl/aidl2 等是 libgbinder 使用的协议选择名称,不是 Android 内核 Binder 被简单替换的版本号。API 35/36 的 service-manager 协议还会变化,应核对当前 protocol.py。

gbinder:Python/C 桥接库

gbinder 是 Waydroid 生态中最关键的胶水库之一。它是一个 Python 封装,通过 CFFI 调用底层的 libgbinder.so(C 库),让 Python 代码可以直接与 Android Binder 服务通信:

# gbinder 使用示例:获取 Android 内的服务
import gbinder

# 连接到 servicemanager
sm = gbinder.ServiceManager("/dev/binder")

# 获取 IUserMonitor 服务
user_monitor = sm.get_service("user_monitor")
resp, status = user_monitor.transact(code=1, parcel=data)

# 获取 INotifications 服务
notifications = sm.get_service("notifications")

Waydroid 的三个后台服务(user_manager、clipboard_manager、notification_manager)都是通过 gbinder 与容器内 Android 系统服务进行通信的 Python 程序。

Binder 节点如何进入容器

Binder 节点通过 LXC 的 lxc.mount.entry 指令 bind-mount 到容器内部。generate_nodes_lxc_config() 动态创建这些条目:

# 传统 binder 模式生成的 LXC 配置片段
lxc.mount.entry = /dev/binder dev/binder none bind,create=file 0 0
lxc.mount.entry = /dev/vndbinder dev/vndbinder none bind,create=file 0 0
lxc.mount.entry = /dev/hwbinder dev/hwbinder none bind,create=file 0 0

# binderfs 模式
lxc.mount.entry = /dev/binderfs/binder dev/binder none bind,create=file 0 0
lxc.mount.entry = /dev/binderfs/vndbinder dev/vndbinder none bind,create=file 0 0
lxc.mount.entry = /dev/binderfs/hwbinder dev/hwbinder none bind,create=file 0 0

启动序列全解析#

从用户执行 waydroid session start 到 Android 桌面就绪,Waydroid 经历了一个精密的多阶段启动流程。

完整启动序列

sequenceDiagram
    participant CLI as waydroid CLI
    participant SM as SessionManager
    participant CM as ContainerManager
    participant DRV as Driver Probe
    participant LXC as LXC Config Gen
    participant CT as LXC Container
    participant INIT as Android /init

    CLI->>SM: waydroid session start

    Note over SM: Step 1: D-Bus 会话验证
    SM->>SM: 检查 D-Bus session bus 可用性
    SM->>SM: 验证 $WAYLAND_DISPLAY 已设置

    Note over SM,CM: Step 2: ContainerManager.Start()
    SM->>CM: D-Bus: id.waydro.Container.Start()
    CM->>CM: PolicyKit 权限检查

    Note over CM,DRV: Step 3: Binder/ashmem 驱动探测
    CM->>DRV: probe_binder_modules()
    CM->>DRV: setupBinderNodes()
    CM->>DRV: probe_ashmem()

    Note over CM,LXC: Step 4: LXC 配置生成
    CM->>LXC: set_lxc_config()
    LXC->>LXC: copy base configs
    LXC->>LXC: LXC version adaptation
    LXC->>LXC: generate_nodes_lxc_config()
    LXC->>LXC: generate_session_lxc_config()

    Note over CM: Step 5: OverlayFS 挂载
    CM->>CM: mount system.img + vendor.img
    CM->>CM: mount user data overlay

    Note over CM,CT: Step 6: lxc-start
    CM->>CT: lxc-start -F -n waydroid -- /init

    Note over CT,INIT: Step 7: Android init 启动 HAL
    INIT->>INIT: init.rc 解析
    INIT->>INIT: 启动 servicemanager
    INIT->>INIT: 启动 surfaceflinger
    INIT->>INIT: 启动 audioserver, cameraserver...

    Note over SM: Step 8: 后台服务启动
    CT-->>SM: 容器就绪信号
    SM->>SM: 启动 user_manager (gbinder)
    SM->>SM: 启动 clipboard_manager (gbinder)
    SM->>SM: 启动 notification_manager (gbinder)

    SM-->>CLI: 会话就绪

各步骤详解

源笔记的 Python 函数和下方流程是说明性伪代码,不能当作逐行上游实现或可直接运行的程序。

Step 1: D-Bus 会话验证

# SessionManager 首先检查:
# - D-Bus session bus socket 是否存在 ($DBUS_SESSION_BUS_ADDRESS)
# - Wayland display 是否设置 ($WAYLAND_DISPLAY)
# - 必要目录是否存在 (~/.local/share/waydroid)

Step 2: ContainerManager.Start 跨越 D-Bus 总线的首次通信。如果 ContainerManager 未运行,system bus daemon 会自动按需激活它(通过 /usr/share/dbus-1/system-services/id.waydro.Container.service)。

Step 3: Binder/ashmem 驱动探测 检查宿主内核是否加载了必要的 Android 驱动。如果内核缺少 binder 模块(modprobe binder_linux 失败),启动会在此步骤中止并给出明确错误提示。

Step 4: LXC 配置生成 动态生成完整的 LXC 配置。包括:

  • 基础配置(网络、cgroup、capabilities)
  • Binder 节点 bind-mount 条目
  • 会话相关挂载(Wayland、PulseAudio、数据目录)
  • 安全 profile(AppArmor、Seccomp)

Step 5: 镜像挂载与 OverlayFS

不能把 .img 文件直接当作 overlay 的 lowerdir;先将镜像挂载到目录,再以独立 upperdir/workdir 建立 overlay。下面是机制示意,路径必须按实际生成配置核对,不手工覆盖正在运行的 Waydroid 挂载:

# 概念示例,不是 Waydroid 的精确启动命令
mount -o loop,ro /path/to/system.img /path/to/lower
mount -t overlay overlay \
  -o lowerdir=/path/to/lower,upperdir=/path/to/upper,workdir=/path/to/work \
  /path/to/merged

Android /data 是独立的数据挂载,OTA 升级与数据迁移仍需备份和版本兼容检查。

Step 6: lxc-start 容器启动的核心命令:

lxc-start -F -n waydroid -- /init
# -F: foreground 模式(Waydroid 需要持续监控容器状态)
# -n waydroid: 容器名称
# -- /init: Android init 作为容器 PID 1

为什么用 /init 而非 /sbin/init? Android 的 init 程序路径是 /init(不是传统 Linux 的 /sbin/init)。这是 Android 文件系统设计的一个标志性特征。Android init 读取 init.rc(和 init.waydroid.rc),按顺序启动 servicemanager、surfaceflinger、audioserver 等所有 Android 核心服务。

Step 7: Android init 启动 HAL 服务 容器内的 /init 按照 init.rc 定义的服务顺序启动:

  1. servicemanager — Binder 服务注册中心
  2. hwservicemanager — HIDL 硬件服务管理
  3. vndservicemanager — Vendor 服务管理
  4. surfaceflinger — 合成与显示
  5. audioserver、cameraserver、mediaserver — 多媒体 HAL

Step 8: 后台服务启动 SessionManager 确认容器就绪后,顺序启动三个 Python 后台服务:

# 后台服务启动策略(session_manager.py 内逻辑)
services = [
    ("user_manager",        UserManager),
    ("clipboard_manager",   ClipboardManager),
    ("notification_manager", NotificationManager),
]

for name, cls in services:
    service = cls()
    service.connect_to_binder()     # 通过 gbinder 连接 Android 服务
    service.register_dbus()         # 在 session bus 上注册 D-Bus 接口
    service.run()                   # 进入事件循环

启动时间优化 在 SSD + binderfs + 预热的内核模块下,冷启动时间受镜像、设备、缓存和服务状态影响。需分别记录容器启动、Android ready 与 UI 就绪时间,不能保证固定秒数。


安全模型#

分析安全边界时应分别检查命名空间、设备、系统调用、能力和授权规则;下图不是默认已经启用五层防护的承诺。Waydroid 与宿主共享内核,不能视为运行不可信应用的强隔离边界。

五层安全防护

graph TB
    subgraph 安全层
        L1["第 1 层:Linux Namespaces<br/>PID/Net/Mount/UTS/IPC 视图隔离"]
        L2["第 2 层:AppArmor 检查<br/>所查上游默认 unconfined"]
        L3["第 3 层:PolicyKit 鉴权<br/>需核对 D-Bus 与授权规则"]
        L4["第 4 层:Seccomp Filter<br/>系统调用白名单/黑名单过滤"]
        L5["第 5 层:Capabilities 检查<br/>所查上游权限较宽"]
    end

    L1 --> L2 --> L3 --> L4 --> L5

    style L1 fill:#1a1a2e,stroke:#0f3460,color:#e0e0e0
    style L2 fill:#0f3460,stroke:#16213e,color:#e0e0e0
    style L3 fill:#1b4332,stroke:#2d6a4f,color:#e0e0e0
    style L4 fill:#3b2665,stroke:#533483,color:#e0e0e0
    style L5 fill:#5c4d7d,stroke:#7b68ae,color:#e0e0e0

第 1 层:Linux Namespaces 隔离

容器内的 Android 进程被严格限制在独立的 namespace 环境中:

  • PID namespace 确保 Android 进程无法看到(也无法向宿主上的其他进程发送信号)
  • Network namespace 确保 Android 的网络栈完全独立
  • Mount namespace 确保 Android 无法访问宿主文件系统的敏感路径

第 2 层:AppArmor Profiles

下面三个名字是原笔记中的加固设计示意,并非已核实的上游默认 profile。上游 config_3 当前使用 unconfined;是否启用 AppArmor 应检查发行版补丁与实际进程状态:

Profile 路径 约束目标
lxc-waydroid /etc/apparmor.d/lxc-waydroid LXC 容器整体——限制文件系统和网络访问
waydroid-adbd /etc/apparmor.d/waydroid-adbd 容器内的 ADB 守护进程
waydroid-android_app /etc/apparmor.d/waydroid-android_app 容器内的 Android 应用进程
# 容器启动时指定的 AppArmor profile
lxc.apparmor.profile = unconfined # 此上游 config_3 的值,不代表已受 AppArmor 限制

# 查看当前加载的 Waydroid 相关 AppArmor profile
sudo aa-status | grep waydroid

NixOS 用户的 AppArmor 注意事项 NixOS 下 AppArmor 支持需要 security.apparmor.enable = true 才能生效。如果未启用,Waydroid 将跳过 AppArmor 层(安全防御降级但不会阻止启动)。

第 3 层:PolicyKit 权限鉴权

下方 XML 只说明可自定义 PolicyKit action 的结构,不是已核实的 Waydroid 默认策略;真实策略以安装包文件和调用代码为准:

<!-- /usr/share/polkit-1/actions/id.waydro.Container.policy -->
<action id="org.waydro.container.start">
    <description>Start Waydroid container</description>
    <message>Authentication is required to start the Waydroid container</message>
    <defaults>
        <allow_any>no</allow_any>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_admin_keep</allow_active>
    </defaults>
</action>

示例中的 auth_admin_keep 会允许认证结果暂时缓存;不代表实际 Waydroid 的授权模式。

第 4 层:Seccomp 系统调用过滤

Waydroid 使用 Seccomp BPF 过滤器限制容器内可执行的系统调用:

# waydroid.seccomp 黑名单示例
# 禁止通过 handle 绕路访问文件(防止容器逃逸尝试)
open_by_handle_at  errno 1

# 禁止加载内核模块(容器内无需也绝不应加载模块)
init_module        errno 1
finit_module       errno 1

# 禁止直接操作内核密钥环
add_key            errno 1
request_key        errno 1

Seccomp profile 作为 LXC 配置的一部分在容器启动时加载:

lxc.seccomp.profile = /var/lib/waydroid/waydroid.seccomp

第 5 层:最小 Capabilities

当前上游 config_base 保留了较宽的能力集合,包括 sys_admin、sys_ptrace 和 sys_time。以下保留为自定义收紧策略示意,不能当作上游默认,更不能盲目同时配置 cap.keep 与 cap.drop:

# Waydroid 容器中保留的 capabilities
lxc.cap.drop = mac_admin mac_override
lxc.cap.drop = sys_admin   # 自定义加固示意,会影响 Android 所需操作;上游仍保留 sys_admin
lxc.cap.drop = sys_module  # 禁止加载/卸载内核模块
lxc.cap.drop = sys_time    # 自定义示意;当前上游 capability 列表包含 sys_time
lxc.cap.drop = sys_ptrace  # 禁止 ptrace 其他进程
lxc.cap.keep = net_admin   # 保留:网络配置需要
lxc.cap.keep = net_raw     # 保留:原始 socket 需要(DHCP 等)

权限分离总结

┌─────────────────────────────────────────────────────┐
│ root (UID 0)                                        │
│  └─ ContainerManager (system bus)                   │
│     - 可以做的事:LXC 生命周期、mount 操作、          │
│       binder 节点管理                               │
│     - 职责不包括:访问用户会话数据、操作剪贴板、     │
│       管理通知                                      │
├─────────────────────────────────────────────────────┤
│ 普通用户 (UID 1000)                                  │
│  ├─ SessionManager (session bus)                    │
│  │   - 管理 Wayland/PulseAudio 挂载                 │
│  │   - 控制 Android 应用窗口                        │
│  └─ 后台服务 (user/clipboard/notification_manager)  │
│      - 通过 gbinder 与 Android HAL 通信             │
│      - 操作限于用户数据范围                          │
└─────────────────────────────────────────────────────┘

安全红线 Waydroid 容器虽然提供了多层隔离,但它共享宿主内核。如果 Android 内存在内核级漏洞,攻击面仍然存在。因此:

  1. 保持宿主内核更新(重要安全补丁)
  2. 不要以 root 身份运行 Android 应用
  3. 对于不可信应用,考虑在独立用户或 VM 中运行

关键源文件索引#

源文件 职责 语言
tools/helpers/lxc.py LXC 配置动态生成 + 容器生命周期管理 Python
tools/helpers/drivers.py Binder/ashmem 驱动探测 + binderfs 配置 Python
tools/helpers/protocol.py Binder 协议版本检测 (aidl-aidl4) Python
tools/actions/container_manager.py System D-Bus 服务(root 级容器管理) Python
tools/actions/session_manager.py Session D-Bus 服务(用户会话管理) Python
tools/services/user_manager.py 用户管理后台服务 Python
tools/services/clipboard_manager.py 剪贴板同步服务 Python
tools/services/notification_manager.py 通知转发服务 Python
data/configs/ LXC 基础配置片段模板 配置文件

核对依据#

Waydroid 官方安装说明。

Waydroid 官方命令说明。

Waydroid 上游源码。

上游 config_base。

上游 config_3。

协议选择。

Binder 探测。

参考与延伸

  1. Waydroid 官方安装说明 ↗
  2. Waydroid 官方命令说明 ↗
  3. Waydroid 上游源码 ↗
  4. 上游 config_base ↗
  5. 上游 config_3 ↗
  6. 协议选择 ↗
  7. Binder 探测 ↗
  8. Linux 内核 BinderFS 文档 ↗

根据技术笔记重新整理,示例使用通用名称。

沿专题继续阅读

Waydroid

  1. 01Waydroid 架构:LXC、Binder 与会话桥接
  2. 02Waydroid 安装与基础设置
  3. 03NixOS 中的 Waydroid 集成
  4. 04Waydroid 的 GPU 检测与硬件加速
  5. 05Waydroid 网桥、NAT 与安全边界
  6. 06Waydroid 属性、多窗口与 ARM 转译
  7. 07Waydroid 故障排查与 FAQ
  8. 08Waydroid 使用技巧:窗口、转译和共享目录
CONTINUE READING / 下一篇Waydroid 安装与基础设置

检查 Wayland、内核和图形条件,再安装镜像并逐层验证启动。