Scope and prerequisites#
The commands and outputs use generic examples. Kernel, image, package, and service versions affect the exact behavior; check the documentation for the versions you use as you read.
Before modifying containers, images, mounts, or firewall rules, back up Android data and stop the relevant sessions. Examples that delete data or force a stop can cause data loss. On NixOS, manage system and user-environment configuration through Nix; the generic Linux sections using apt/pacman, direct writes to /etc, and pip installation do not apply to a NixOS host. The build, test, and switch stages of a rebuild are distinct from functional verification after startup.
Waydroid is neither an emulator nor a virtual machine: it does not boot a separate kernel. Its architecture centers on three principles: "direct access to the host kernel + Linux namespace isolation + Binder IPC bridging." It runs a complete Android userspace, LineageOS, as an LXC container on a standard Linux kernel.
Core architecture overview: a three-tier privilege-separation model#
Waydroid divides Android containerization into three privilege tiers. Each tier runs in a different user context, with strictly defined IPC over D-Bus.
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:#e0e0e0The three-tier privilege-separation design
| Tier | Component | Execution privileges | D-Bus bus | Responsibility |
|---|---|---|---|---|
| Tier 1 | ContainerManager |
root | System Bus | Container lifecycle: create, start, stop, freeze/unfreeze |
| Tier 2 | SessionManager |
Regular user | Session Bus | Session management: configure Wayland/PulseAudio mount points and manage Android application launches |
| Tier 3 | Background services (*_manager) |
Regular user | Session Bus | Data bridging: user management, clipboard synchronization, and notification forwarding |
Why separate privileges?
ContainerManagerneeds root privileges to operate LXC: configuring network namespaces, mounting filesystems, and managing cgroups. Putting all the logic in a root process would expand the attack surface. Waydroid isolates the "minimum set of operations requiring root" in ContainerManager and runs all other session logic as a regular user.
The dual D-Bus design
Waydroid uses two D-Bus buses to isolate privilege domains:
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): Registered in/usr/share/dbus-1/system-services/, activated on demand by the D-Bus daemon, and run as root - Session Bus (
id.waydro.Session): Managed by the user session's D-Bus daemon and run as a regular user
D-Bus security boundaries Access to the system bus depends on D-Bus policy, the service implementation, and the distribution's authorization integration. Do not assume that all calls go through PolicyKit; the action/path listed in the original notes was not confirmed in the upstream files reviewed.
The LXC container model#
Waydroid's central insight is that Android userspace needs a set of Linux kernel APIs, not virtual hardware. LXC provides isolation through namespaces while allowing the container to use the host kernel directly.
Why not boot a separate kernel?
对比三种方案:
硬件辅助虚拟化 (QEMU/KVM):
宿主内核 → KVM → 独立内核 → Android 用户空间
使用独立客体内核,性能和 GPU 集成取决于虚拟化配置
全虚拟化 (VirtualBox):
宿主内核 → Hypervisor → 独立内核 → Android 用户空间
同上,且需要内核模块
LXC 容器 (Waydroid):
宿主内核 ← lxc-start ← /init (Android init) ← Android 用户空间
不启动独立客体内核,直接复用宿主驱动 (GPU/dri/renderD128)The Linux namespace matrix
Waydroid uses the following combination of namespaces to build the container's isolated environment:
| Namespace | Purpose | Specific use in Waydroid |
|---|---|---|
| User | UID/GID mapping | Do not assume subordinate UID mappings exist; inspect the actual lxc.idmap and runtime credentials. Waydroid commonly uses a privileged container |
| PID | Process-tree isolation | Inside the container, /init sees itself as PID 1, completely isolated from the host process space |
| UTS | Hostname isolation | The container can have its own hostname without affecting the host |
| Net | Network-stack isolation | Creates a separate waydroid0 bridge; Android has its own network interfaces and routing table |
| Mount | Filesystem isolation | /system and /vendor are mounted with overlayfs; /data comes from the user-data directory |
| IPC | Interprocess-communication isolation | Android's System V IPC does not leak into the host |
The container root filesystem
# 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 配置文件The OverlayFS layering model
system.imgandvendor.imgare first mounted using their actual filesystems, then overlaid according to the layout. Writable overlays for system/vendor are separate layers from Android's/data. The user-data directory is mounted at/data; it is not a general-purpose upperdir for the system image. This means the system images themselves are not modified, and upgrades only require replacing the.imgfiles.
Dynamically generated LXC configuration
Unlike most LXC containers, which use static configuration files, Waydroid dynamically generates its LXC configuration at every startup. The core generation logic is in 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 dirWhy generate it dynamically?
- LXC version compatibility: Configuration-directive syntax differs between LXC versions, such as
lxc.cgroupversuslxc.cgroup2, requiring detection and adaptation at startup- Variable Binder-node paths:
/dev/bindermay use legacy binder or binderfs; paths and naming rules vary with the kernel version- Session paths depend on runtime state: The Wayland socket path,
$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY, and the PulseAudio socket path are determined by the user session
Binder IPC in depth#
Binder is Android's core IPC mechanism and is critical to Waydroid working correctly. Without Binder, Android system services cannot communicate.
Why is Binder the critical communication layer?
Android's system architecture is built on Binder IPC. On a physical device, the Binder driver transfers data between processes in kernel space, avoiding the overhead of repeated userspace/kernel-space copies in traditional IPC mechanisms such as pipes and sockets. In Waydroid, the Android container runs on the same host kernel, which provides the Binder driver. Android processes inside the container use the host kernel's binder device nodes directly.
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:#e0e0e0The three Binder nodes
| Node | Purpose | Android counterpart |
|---|---|---|
/dev/binder |
General-purpose IPC at the framework layer; all system services registered with servicemanager communicate through this node | frameworks/native/libs/binder |
/dev/vndbinder |
Isolated IPC channel between vendor HALs and the framework (Project Treble) | /dev/vndbinder in Android 8+ |
/dev/hwbinder |
IPC within hardware HALs, specifically for communication over HIDL interfaces | /dev/hwbinder in Android 8+ |
BinderFS vs. traditional 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 实例,安全隔离更好The following is illustrative pseudocode for preparing Binder nodes. The actual drivers.py detects existing nodes, allocates them, and creates links as needed. Do not execute this code or apply identical permissions to every binderfs node:
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 666Common Binder failures If the host kernel was not compiled with a usable Binder implementation, either built in or as a module, the Waydroid container will crash. The first thing Android init does after starting is open
/dev/binderto communicate with servicemanager. If binder is unavailable, the entire Android framework cannot initialize.
Automatic Binder protocol-version detection
Android's Binder protocol has undergone several incompatible changes across API levels. Waydroid needs to select the correct protocol version for the Android image running in the container.
Protocol-version detection logic (tools/helpers/protocol.py):
| API Level | Android version | Binder protocol | Explanation |
|---|---|---|---|
| < 28 | Android 8.x and earlier | aidl |
Original AIDL protocol |
| 28-29 | Android 9-10 | aidl2 |
Introduced protocol-version negotiation |
| 30 | Android 11 | aidl3 |
Structured binder transport |
| 31-32 | Android 12-12L | aidl4 |
Extended transport format |
| 33-34 | Android 13-14 | aidl3 |
Falls back to aidl3 (Android 13 deprecated aidl4) |
Note that aidl/aidl2 and the other names here are protocol-selection names used by libgbinder, not version numbers indicating a simple replacement of Android's kernel Binder. The service-manager protocol also changes for API 35/36; check the current protocol.py.
gbinder: the Python/C bridge library
gbinder is one of the most important glue libraries in the Waydroid ecosystem. It is a Python wrapper that calls the underlying libgbinder.so C library through CFFI, allowing Python code to communicate directly with Android Binder services:
# 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's three background services, user_manager, clipboard_manager, and notification_manager, are all Python programs that use gbinder to communicate with Android system services inside the container.
How Binder nodes enter the container
Binder nodes are bind-mounted into the container through LXC's lxc.mount.entry directive. generate_nodes_lxc_config() creates these entries dynamically:
# 传统 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 0The startup sequence in detail#
From the moment a user runs waydroid session start until the Android desktop is ready, Waydroid goes through a carefully coordinated, multistage startup process.
The complete startup sequence
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: 会话就绪A closer look at each step
The Python functions in the source notes and the workflow below are illustrative pseudocode. They are neither a line-by-line account of the upstream implementation nor directly runnable programs.
Step 1: D-Bus session validation
# SessionManager 首先检查:
# - D-Bus session bus socket 是否存在 ($DBUS_SESSION_BUS_ADDRESS)
# - Wayland display 是否设置 ($WAYLAND_DISPLAY)
# - 必要目录是否存在 (~/.local/share/waydroid)Step 2: ContainerManager.Start The first communication across the D-Bus buses. If ContainerManager is not running, the system bus daemon activates it automatically on demand through /usr/share/dbus-1/system-services/id.waydro.Container.service.
Step 3: Binder/ashmem driver detection Checks whether the host kernel has loaded the required Android drivers. If the kernel lacks the binder module and modprobe binder_linux fails, startup stops at this step with an explicit error message.
Step 4: LXC configuration generation Dynamically generates the complete LXC configuration, including:
- Base configuration: networking, cgroups, and capabilities
- Binder-node bind-mount entries
- Session-related mounts: Wayland, PulseAudio, and the data directory
- Security profiles: AppArmor and Seccomp
Step 5: Image mounting and OverlayFS
A .img file cannot be used directly as an overlay lowerdir. Mount the image at a directory first, then create the overlay with separate upperdir/workdir directories. The following illustrates the mechanism; verify paths against the actual generated configuration, and do not manually overwrite mounts used by a running Waydroid instance:
# 概念示例,不是 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/mergedAndroid's /data is a separate data mount. OTA upgrades and data migrations still require backups and version-compatibility checks.
Step 6: lxc-start The core command that starts the container:
lxc-start -F -n waydroid -- /init
# -F: foreground 模式(Waydroid 需要持续监控容器状态)
# -n waydroid: 容器名称
# -- /init: Android init 作为容器 PID 1Why
/initrather than/sbin/init? Android's init program is at/init, rather than the traditional Linux path of/sbin/init. This is a characteristic feature of Android's filesystem design. Android init readsinit.rcandinit.waydroid.rc, then starts all the core Android services, including servicemanager, surfaceflinger, and audioserver, in order.
Step 7: Android init starts the HAL services The container's /init starts services in the order defined by init.rc:
servicemanager— Binder service registryhwservicemanager— HIDL hardware-service managementvndservicemanager— vendor-service managementsurfaceflinger— compositing and displayaudioserver,cameraserver, andmediaserver— multimedia HALs
Step 8: Background-service startup Once SessionManager confirms that the container is ready, it starts the three Python background services in sequence:
# 后台服务启动策略(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() # 进入事件循环Optimizing startup time Even with an SSD, binderfs, and preloaded kernel modules, cold-start time depends on the image, device, caches, and service state. Record container startup, Android-ready, and UI-ready times separately; a fixed number of seconds cannot be guaranteed.
The security model#
When analyzing security boundaries, check namespaces, devices, system calls, capabilities, and authorization rules separately. The diagram below does not promise that five layers of protection are enabled by default. Waydroid shares the host kernel and should not be treated as a strong isolation boundary for untrusted applications.
Five layers of security protection
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:#e0e0e0Layer 1: Linux namespace isolation
Android processes inside the container are strictly confined to a separate namespace environment:
- The PID namespace ensures that Android processes cannot see other processes on the host or send signals to them
- The network namespace ensures that Android's network stack is completely separate
- The mount namespace ensures that Android cannot access sensitive paths on the host filesystem
Layer 2: AppArmor profiles
The following three names illustrate the hardening design from the original notes; they are not verified upstream default profiles. Upstream config_3 currently uses unconfined. To determine whether AppArmor is enabled, inspect distribution patches and the actual process state:
| Profile | Path | Restriction target |
|---|---|---|
lxc-waydroid |
/etc/apparmor.d/lxc-waydroid |
The LXC container as a whole: restrict filesystem and network access |
waydroid-adbd |
/etc/apparmor.d/waydroid-adbd |
The ADB daemon inside the container |
waydroid-android_app |
/etc/apparmor.d/waydroid-android_app |
Android application processes inside the container |
# 容器启动时指定的 AppArmor profile
lxc.apparmor.profile = unconfined # 此上游 config_3 的值,不代表已受 AppArmor 限制
# 查看当前加载的 Waydroid 相关 AppArmor profile
sudo aa-status | grep waydroidAppArmor considerations for NixOS users On NixOS, AppArmor support requires
security.apparmor.enable = trueto take effect. If it is not enabled, Waydroid skips the AppArmor layer, reducing security protection without preventing startup.
Layer 3: PolicyKit authorization
The XML below illustrates only the structure of a custom PolicyKit action, not a verified default Waydroid policy. Check the installed package files and calling code for the actual policy:
<!-- /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 in the example allows authorization results to be cached temporarily; it does not describe Waydroid's actual authorization model.
Layer 4: Seccomp system-call filtering
Waydroid uses Seccomp BPF filters to restrict the system calls that can be executed inside the container:
# waydroid.seccomp 黑名单示例
# 禁止通过 handle 绕路访问文件(防止容器逃逸尝试)
open_by_handle_at errno 1
# 禁止加载内核模块(容器内无需也绝不应加载模块)
init_module errno 1
finit_module errno 1
# 禁止直接操作内核密钥环
add_key errno 1
request_key errno 1The Seccomp profile is loaded as part of the LXC configuration when the container starts:
lxc.seccomp.profile = /var/lib/waydroid/waydroid.seccompLayer 5: minimal capabilities
The current upstream config_base retains a broad set of capabilities, including sys_admin, sys_ptrace, and sys_time. The following is retained as an illustration of a custom, tighter policy. It is not the upstream default, and cap.keep and cap.drop should certainly not be configured together blindly:
# 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 等)Privilege-separation summary
┌─────────────────────────────────────────────────────┐
│ root (UID 0) │
│ └─ ContainerManager (system bus) │
│ - 可以做的事:LXC 生命周期、mount 操作、 │
│ binder 节点管理 │
│ - 职责不包括:访问用户会话数据、操作剪贴板、 │
│ 管理通知 │
├─────────────────────────────────────────────────────┤
│ 普通用户 (UID 1000) │
│ ├─ SessionManager (session bus) │
│ │ - 管理 Wayland/PulseAudio 挂载 │
│ │ - 控制 Android 应用窗口 │
│ └─ 后台服务 (user/clipboard/notification_manager) │
│ - 通过 gbinder 与 Android HAL 通信 │
│ - 操作限于用户数据范围 │
└─────────────────────────────────────────────────────┘Security red lines Although the Waydroid container provides multiple layers of isolation, it shares the host kernel. If there is a kernel-level vulnerability within Android, the attack surface remains. Therefore:
- Keep the host kernel updated, especially for important security patches
- Do not run Android applications as root
- For untrusted applications, consider running them under a separate user or in a VM
Index of key source files#
| Source file | Responsibility | Language |
|---|---|---|
tools/helpers/lxc.py |
Dynamic LXC configuration generation and container-lifecycle management | Python |
tools/helpers/drivers.py |
Binder/ashmem driver detection and binderfs configuration | Python |
tools/helpers/protocol.py |
Binder protocol-version detection (aidl-aidl4) | Python |
tools/actions/container_manager.py |
System D-Bus service: root-level container management | Python |
tools/actions/session_manager.py |
Session D-Bus service: user-session management | Python |
tools/services/user_manager.py |
User-management background service | Python |
tools/services/clipboard_manager.py |
Clipboard-synchronization service | Python |
tools/services/notification_manager.py |
Notification-forwarding service | Python |
data/configs/ |
LXC base-configuration fragment template | Configuration file |
Verification sources#
Official Waydroid installation instructions.
Official Waydroid command documentation.
References & further reading
- Official Waydroid installation instructions ↗
- Official Waydroid command documentation ↗
- Waydroid upstream source ↗
- Upstream config_base ↗
- Upstream config_3 ↗
- Protocol selection ↗
- Binder detection ↗
- Linux kernel BinderFS documentation ↗
Adapted from technical notes. Examples use generic names.
Continue along a reading path
Waydroid
- 01Waydroid architecture: LXC, Binder, and session bridging
- 02Waydroid installation and basic setup
- 03Waydroid integration on NixOS
- 04Waydroid GPU detection and hardware acceleration
- 05Waydroid bridges, NAT, and security boundaries
- 06Waydroid properties, multi-window mode, and ARM translation
- 07Waydroid troubleshooting and FAQ
- 08Waydroid tips: windows, translation, and shared directories