# [求助] Deepin 下 Android 手机 USB 连接反复报错，根因疑似 ostree 只读根导致 adb 无法写配置

> 版本：Deepin 25（内核 6.18.48-amd64-desktop-rolling，`ostree=auto` 部署）
> 设备：HUAWEI STK-AL00（Android 10 / HarmonyOS 底层）
> 现状：USB 传输可用，但 adb 每次重启都报错，MTP 偶发掉挂载

---

## 一、现象

1. 手机 USB 插上后，文件管理器偶尔能打开 MTP，但**频繁提示各种错误**；
2. `adb devices` 有时只剩 `192.168.238.25:5555`（WiFi 无线调试），**USB 设备行消失**；
3. 日志中反复出现：

```
adb: main.cpp:238 failed to write server path to
     /home/Run/tools/Android-SDK/platform-tools/adb: Read-only file system
```

4. 文件管理器日志持续刷：

```
dde-file-manager-daemon[2820]: UDisksObject is not valid for "/org/freedesktop/UDisks2/block_devices/sr0"
dde-file-manager-daemon[2820]: Failed to create block device: ".../block_devices/sr0"
dde-file-dialog[135192]: Item not found in cache for removal, url: QUrl("entry:mtp://HUAWEI_STK-AL00_7PRDU19B20015852/.protodev")
```

> 注：`.protodev` 在手机上实际不存在（`ls /sdcard/.protodev` → No such file）。它是 dde 文件管理器 MTP 后端（dfm-mount/jmtpfs）产生的代理/占位等虚拟节点，手机在 MTP 模式下会隐藏点文件，故该路径必然“找不到”。这一条属于 dde 的已知噪音，不是根因，但会放大“一直在报错”的观感。**这一点我判断不确定，欢迎知情者补充。**

---

## 二、排查过程与关键证据

### 1. 先排除硬件、线材、供电

- `lsusb` 显示设备稳定在 `Bus 003 Device 014: ID 12d1:107e Huawei Technologies Co., Ltd. P10 smartphone`，USB 2.0 端口（`speed 480`），供电 `bMaxPower 500mA`；
- 手机端 `sys.usb.state` = `hisuite,mtp,mass_storage,adb`，三个接口齐全：

| 接口 | Class/Sub/Proto | 对应功能 |
|---|---|---|
| `3-2.2.2:1.0` | `ff/ff/00` | ADB（Vendor Specific） |
| `3-2.2.2:1.1` | `08/06/50` | Mass Storage → `sr0`（虚拟光驱） |
| `3-2.2.2:1.2` | `ff/42/01` | MTP / hisuite |

- USB adb 恢复后连跑 30 次命令全通过，`adb kill-server && adb start-server` 3 轮均能稳定重连；
- MTP 真实文件读测试成功（`dd` 读取 `/sdcard/DCIM/.tmfs/.turing.dat`）。**故 USB 物理链路、内核识别、手机端功能都正常。**

### 2. 真正的问题藏在挂载选项里

```
$ findmnt -T /
TARGET SOURCE        FSTYPE OPTIONS
/      /dev/nvme0n1p3 ext4  ro,nosuid,nodev,relatime

$ findmnt -T /home
TARGET SOURCE         FSTYPE OPTIONS
/home  /dev/nvme1n1p1 ext4  ro,nosuid,nodev,relatime
```

但 `fstab` 与 systemd 记录的却是 **rw**：

```
$ grep -E "^UUID=.*(/|/home)\s" /etc/fstab
UUID=2c0a4376-... /     ext4 rw,relatime 0 1
UUID=7a6e0465-... /home ext4 rw,relatime 0 2

$ systemctl show home.mount -p Options -p Result
Options=rw,relatime
Result=success
```

**这三组证据互相矛盾**：fstab 写 rw，systemd 认为 rw 且挂载成功，但实际生效的是 ro。

### 3. 不是磁盘故障，也不是容器

```
$ cat /sys/fs/ext4/nvme1n1p1/errors_count
0
$ cat /sys/fs/ext4/nvme1n1p1/first_error_time
0

$ ls /.dockerenv /run/.containerenv
（均不存在）
```

结论：**不是内核 ext4 出错后的自动 `remount-ro` 保护**（errors_count 为 0），也不是 Docker/容器权限问题。

### 4. 真凶：ostree 不可变根

`/proc/self/mountinfo` 暴露了部署结构：

```
$ grep -E " / | /home " /proc/self/mountinfo
499 ... /     ro,nosuid,nodev,relatime master:1  - ext4 /dev/nvme0n1p3 rw
500 ... /usr  ro,nosuid,nodev,relatime master:2  - overlay usr-overlay rw,lowerdir=/root/persistent/overlay/...,upperdir=...
502 ... /opt  ro,nosuid,nodev,relatime master:4  - overlay opt-overlay rw,lowerdir=...,upperdir=...
503 ... /etc  ro,nosuid,nodev,relatime master:5  - overlay etc-overlay rw,lowerdir=...,upperdir=...
552 ... /home ro,nosuid,nodev,relatime master:11 - ext4 /dev/nvme1n1p1 rw
```

（为便于阅读，省略了 mountinfo 的 parent ID / maj:min / root 字段与 lowerdir/upperdir 完整路径）

- 底层分区 `ext4 ... rw`，但**挂载点被以 `ro` 挂出**，这正是 Deepin 的 **ostree 不可变根**（immutable root）机制；
- `/usr`、`/opt`、`/etc` 都是 `ro` 挂载的 overlay（`lowerdir` 指向 ostree 部署 + `upperdir` 指向上层可写层）；
- `/home` 虽独立分区（`/dev/nvme1n1p1`），但同样被以 `ro` 挂出（`master:11`）；
- `/run/user/1000`（tmpfs）同样是 `ro`，且写入实测失败；
- 注意：同一路径存在**多层挂载叠加**（mount stack）。例如 `/tmp` 在 mountinfo 中先有一条 `ro,nosuid,nodev master:51`，其上又叠了一条 `rw,nosuid,nodev,relatime`，实际写入测试通过（rw）。所以判断是否可写**必须以写入测试为准**，不能只看 `findmnt`：

```bash
$ for p in / /home /run/user/1000 /tmp /dev/shm; do
    touch "$p/.rt_$$" 2>/dev/null && { echo "$p rw"; rm -f "$p/.rt_$$"; } || echo "$p ro"
  done
/ ro
/home ro
/run/user/1000 ro
/tmp rw
/dev/shm rw
```
- `ostree admin status` 因权限（`fstatat(boot/loader): 权限不够`）无法直接读部署信息；`/proc/cmdline` 含 `ostree=auto`，`/ostree/deploy/deepin` 存在，确认为 ostree 部署。

---

## 三、问题闭环：只读根如何导致“USB 一直报错”

| 链路 | 后果 |
|---|---|
| adb 二进制位于 `/home/Run/tools/Android-SDK/platform-tools/`（在 ro 的 `/home` 上） | adb server 启动时需向同目录写 server path → `Read-only file system` |
| adb 需在 `~/.android/` 写 `adb.5037`、`adbkey` 等运行态文件 | 运行态被冻结在开机瞬间，任何 server 重启/重连都无法刷新状态 |
| adb 无法正常写状态 → USB 传输通道重建失败 | `adb devices` 掉成只剩 WiFi 行，看起来像“USB 坏了” |
| dde 的 MTP 后端与 UDisks 交互时读 `sr0`（手机 mass_storage 暴露的虚拟光驱） | `UDisksObject is not valid` / `Failed to create block device` 持续刷日志 |

**一句话**：**USB 硬件没坏，手机没坏；是 ostree 只读根让 adb 无法在运行期落盘运行态，从而反复报错并表现为 USB 掉线。**

<details>
<summary>想验证的下一条命令（需要 root）：</summary>

```bash
mount | grep -E " / | /home "
# 预期看到 / 与 /home 为 ro，而底层 ext4 ro 属性为 rw
```
</details>

---

## 四、当前临时缓解（已生效，但治标不治本）

```bash
# 1. USB adb 掉线时重建通道
adb kill-server && adb start-server && adb devices

# 2. MTP 列表空 / 报错时重挂
gio mount -u "mtp://HUAWEI_STK-AL00_7PRDU19B20015852/"
gio mount -a "mtp://HUAWEI_STK-AL00_7PRDU19B20015852/"

# 3. 证明是只读导致：改用可写 HOME 启动 adb，不再报 server path 错误
mkdir -p /tmp/adb_home/.android
cp ~/.android/adbkey ~/.android/adbkey.pub /tmp/adb_home/.android/
HOME=/tmp/adb_home adb kill-server && HOME=/tmp/adb_home adb start-server
HOME=/tmp/adb_home adb devices        # USB 设备行正常出现
```

另外手机侧建议：开发者选项里把 USB 默认配置设为 **“传输文件（MTP）”**，不要同时启用 `mass_storage`，可减少 `sr0` 带来的 dde 报错噪音。

---

## 五、想请教大家的问题

1. **Deepin 的 ostree 不可变根下，`/home` 为什么也被以 `ro` 挂出？** 这是设计如此，还是部署异常？正常设备应如何恢复 `/home` 为 rw？
2. 如果确实要长期 rw，正确姿势是 `ostree admin unlock`（或 `unlock --hotfix`）吗？还是应该把 adb/SDK 等运行态目录迁出 ro 分区（例如放到 `/var` 或 `/persistent`）？
3. `etc-overlay`/`usr-overlay` 的 upperdir 在 `/root/persistent/overlay/`，如果只需让**部分**目录可写（如 `~/.android`），是否有官方推荐的 overlay/绑定挂载方案？
4. 有没有人遇到 `sudo: /etc/sudo.conf is owned by uid 65534` + `no new privileges` 同时出现？（本环境无法直接 `sudo`，这可能是 `ro` 下 `/etc` 元数据异常导致）

## 六、环境信息

```text
$ uname -r
6.18.48-amd64-desktop-rolling

$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Deepin 25"

$ cat /proc/cmdline | tr ' ' '\n' | grep ostree
ostree=auto

$ adb --version
Android Debug Bridge version 1.0.41 / Version 37.0.1-15733141

$ dpkg -l | grep -E "dde-file-manager|gvfs-backends|libmtp"
dde-file-manager 6.6.3
dde-file-manager-services-plugins 6.6.3
gvfs-backends 1.54.2-2deepin3
libmtp9 1.1.21-3.1deepin1
```

> 附：`adb` 是自建 SDK（version 37.0.1），未安装发行版 android-tools 包；`/usr/bin/adb` 不存在，`PATH` 中仅有 `/home/Run/tools/Android-SDK/platform-tools`。

---

**结论**：优先确认 ostree 只读根是否属于预期行为，再决定是“解锁可写根”还是“把 adb 运行态迁出只读区”。谢谢大家。
