背景

在 Linux 桌面环境中运行 Waydroid 时,宿主机的音量控制与 Android 容器内部的媒体音量并不总是完全一致。

Waydroid 内部的 Android 媒体音量可以通过下面的命令直接设置:

sudo waydroid shell -- \
  /system/bin/cmd media_session volume \
  --show --stream 3 --set 10

其中:

  • --stream 3 表示 Android 的媒体音量;
  • --set 10 表示直接将音量设置为某个固定等级;
  • 音量范围通常为 0..15

但固定设置音量并不适合绑定键盘快捷键。更自然的方式是像物理音量键一样,每按一次增加或降低一级。

对应命令为:

sudo waydroid shell -- \
  /system/bin/cmd media_session volume \
  --show --stream 3 --adj raise

以及:

sudo waydroid shell -- \
  /system/bin/cmd media_session volume \
  --show --stream 3 --adj lower

问题在于,waydroid shell 通常需要 root 权限。如果直接将这两个命令绑定为桌面快捷键,系统无法在快捷键触发时交互式输入 sudo 密码。

最简单但风险很高的做法,是把密码写入脚本。更合理的方案,是通过 sudoers 仅放行两条完整、固定的音量命令。


设计目标

整个配置需要满足以下要求:

  1. 每按一次快捷键,只增加或降低一级音量;
  2. 快捷键触发时不弹出密码输入框;
  3. 不在脚本中保存 sudo 密码;
  4. 不开放任意 Waydroid root shell;
  5. 用户脚本保存在长期使用的个人脚本目录中;
  6. 所有系统级变更都能明确识别并完整撤销。

最终结构只有三项:

<用户脚本目录>/<音量增加脚本>
<用户脚本目录>/<音量降低脚本>
/etc/sudoers.d/<Waydroid 音量规则>

没有修改主 /etc/sudoers 文件,也没有修改 Waydroid 程序本身。


一、确认环境

首先确认当前用户名、sudo 路径以及 Waydroid 路径:

id -un

command -v sudo
command -v waydroid

典型输出可能为:

<当前用户名>
/usr/bin/sudo
/usr/local/bin/waydroid

在编写 sudoers 规则时,应使用实际查询到的绝对路径,而不是依赖 PATH 环境变量。

还可以先读取当前 Android 媒体音量:

sudo <Waydroid绝对路径> shell -- \
  /system/bin/cmd media_session volume \
  --stream 3 --get

输出类似:

[V] volume is 10 in range [0..15]

这说明媒体音量命令可正常工作。


二、创建音量增加脚本

在个人脚本目录中创建一个音量增加脚本:

#!/bin/sh

exec /usr/bin/sudo -n -- \
    <Waydroid绝对路径> shell -- \
    /system/bin/cmd media_session volume \
    --show --stream 3 --adj raise

例如保存为:

<用户脚本目录>/<音量增加脚本>

然后设置执行权限:

chmod 0755 <用户脚本目录>/<音量增加脚本>

三、创建音量降低脚本

音量降低脚本内容如下:

#!/bin/sh

exec /usr/bin/sudo -n -- \
    <Waydroid绝对路径> shell -- \
    /system/bin/cmd media_session volume \
    --show --stream 3 --adj lower

保存为:

<用户脚本目录>/<音量降低脚本>

设置执行权限:

chmod 0755 <用户脚本目录>/<音量降低脚本>

这里使用了:

sudo -n

-n 表示非交互模式。

如果 sudoers 规则没有正确配置,命令会立即失败,而不是在后台等待密码输入。对于桌面快捷键,这一点非常重要,否则快捷键调用可能产生不可见的挂起进程。


四、检查脚本语法

分别执行:

sh -n <用户脚本目录>/<音量增加脚本>
sh -n <用户脚本目录>/<音量降低脚本>

没有输出即表示 shell 语法检查通过。

还应检查脚本权限和所有者:

ls -l \
  <用户脚本目录>/<音量增加脚本> \
  <用户脚本目录>/<音量降低脚本>

预期权限类似:

-rwxr-xr-x

脚本应由普通用户拥有,不需要设置为 root 所有。


五、创建独立 sudoers 规则

不要直接修改主 /etc/sudoers 文件,而是在标准的模块化配置目录中创建独立规则:

/etc/sudoers.d/<Waydroid 音量规则>

规则内容为两条精确命令:

<用户名> ALL=(root) NOPASSWD: <Waydroid绝对路径> shell -- /system/bin/cmd media_session volume --show --stream 3 --adj raise
<用户名> ALL=(root) NOPASSWD: <Waydroid绝对路径> shell -- /system/bin/cmd media_session volume --show --stream 3 --adj lower

这里没有使用通配符,也没有只写:

<用户名> ALL=(root) NOPASSWD: <Waydroid绝对路径>

后者会允许用户免密码执行任意 Waydroid 子命令,权限范围明显过大。

当前规则只允许两种完整参数组合:

媒体音量增加一级
媒体音量降低一级

其他命令,包括读取音量、进入任意 shell、修改 Android 设置等,仍然需要正常输入 sudo 密码。


六、先验证,再安装

sudoers 文件一旦存在语法错误,可能影响 sudo 的正常使用。因此不应直接写入正式目录。

更安全的流程是:

  1. 在临时目录创建规则文件;
  2. 使用 visudo 验证;
  3. 验证通过后再安装到 /etc/sudoers.d/
  4. 正式安装后再次验证。

临时规则检查:

sudo visudo -cf <临时规则文件>

正常输出:

<临时规则文件>: parsed OK

安装正式规则:

sudo install \
  -o root \
  -g root \
  -m 0440 \
  <临时规则文件> \
  /etc/sudoers.d/<Waydroid 音量规则>

再次检查:

sudo visudo -cf /etc/sudoers.d/<Waydroid 音量规则>

预期输出:

/etc/sudoers.d/<Waydroid 音量规则>: parsed OK

检查文件属性:

sudo ls -l /etc/sudoers.d/<Waydroid 音量规则>

应类似:

-r--r----- 1 root root ...

也就是:

所有者:root
用户组:root
权限:0440

七、清除 sudo 缓存后测试

刚刚执行过 sudo 命令时,系统可能仍保留短时间的认证缓存。

如果直接测试脚本,即使 sudoers 规则没有生效,也可能暂时不要求密码,从而形成误判。

因此必须先执行:

sudo -k

这会清除当前 sudo 认证缓存。

然后分别测试:

<用户脚本目录>/<音量增加脚本>
<用户脚本目录>/<音量降低脚本>

如果两条命令都能够:

  • 不要求输入密码;
  • 正常显示 Android 音量提示;
  • 每次只改变一个音量等级;

说明 NOPASSWD 规则已正确生效。


八、验证权限没有过度开放

为了确认 sudoers 没有放行任意 Waydroid 命令,可以再次清除缓存:

sudo -k

然后执行一条未写入规则的命令,例如读取当前音量:

sudo <Waydroid绝对路径> shell -- \
  /system/bin/cmd media_session volume \
  --stream 3 --get

如果该命令仍然要求输入密码,说明权限边界正确。

最终效果应为:

操作是否免密码
音量增加一级
音量降低一级
读取当前音量
任意 Waydroid shell 命令

这比直接为整个 Waydroid 程序配置 NOPASSWD 更安全。


九、配置 KDE Plasma 快捷键

进入:

System Settings → Keyboard → Shortcuts

添加两个自定义命令。

音量增加命令:

<用户脚本目录>/<音量增加脚本>

音量降低命令:

<用户脚本目录>/<音量降低脚本>

快捷键配置中只填写脚本路径,不要再次添加 sudo,因为脚本内部已经使用了:

/usr/bin/sudo -n

保存配置后,即使 Waydroid 窗口处于前台,也可以通过全局快捷键调整 Android 媒体音量。


十、实际验证结果

配置完成后的验证过程显示:

  • 两个用户脚本语法正常;
  • 脚本权限为 0755
  • sudoers 文件权限为 0440
  • sudoers 临时文件和正式文件均通过 visudo 检查;
  • 执行 sudo -k 后,两个音量脚本仍可免密码运行;
  • 未放行的音量读取命令仍要求密码;
  • 连续执行音量增加和降低命令后,Android 媒体音量数值变化与操作次数一致;
  • KDE 全局快捷键可正常触发脚本。

这证明功能和权限控制均符合预期。


十一、这是否属于“污染系统”

/etc/sudoers.d/ 中增加独立配置文件,是 sudo 官方支持的标准系统管理方式,不属于修改程序文件,也不是临时补丁。

该方案具有几个特点:

  • 不修改 Waydroid;
  • 不修改 sudo 软件包;
  • 不直接编辑主 /etc/sudoers
  • 不在脚本中保存密码;
  • 系统级改动只有一个明确的配置文件;
  • 删除该文件后,免密码权限立即消失;
  • 用户脚本和系统权限规则可以分别管理。

因此这属于正常、模块化、可审计的系统配置。


十二、完整撤销

不再需要该功能时,删除 sudoers 规则:

sudo rm -- /etc/sudoers.d/<Waydroid 音量规则>

删除两个用户脚本:

rm -- \
  <用户脚本目录>/<音量增加脚本> \
  <用户脚本目录>/<音量降低脚本>

检查 sudoers 整体语法:

sudo visudo -c

最后在 KDE Plasma 的快捷键设置中删除对应的两个自定义项目。

这样即可恢复到配置前状态,不会留下隐藏服务、后台进程或额外软件包。


总结

Waydroid 的 Android 媒体音量可以通过 media_session 命令逐级调节:

--adj raise
--adj lower

要将其绑定为桌面全局快捷键,关键并不是把密码写入脚本,而是通过 sudoers 精确放行两条固定命令。

最终方案只包含:

  • 两个普通用户脚本;
  • 一个独立 sudoers 配置文件;
  • 两个 KDE 全局快捷键。

既实现了接近物理音量键的操作体验,也保持了最小权限原则和良好的可撤销性。

Leave a Reply

Your email address will not be published. Required fields are marked *