前面刚写了给 K20 Pro 换新 ROM,顺便在 Droidspaces 里跑起了 Debian。容器能用了,手机上却碰到了一个挺莫名其妙的问题。

有些新装的应用,需要在 /storage/emulated/0/Android/data/ 下面建立自己的文件夹,但这些文件夹就是出不来。手动建好、分配好权限以后,应用又能正常使用。

最烦的是,换回原来的内核也没恢复。我还试了不少 K20 Pro 社区 ROM,在动态分区的 ROM 上配合支持容器的内核容易遇到这个问题,传统 FBE v1、静态分区的 ROM 却没有碰到。当时确实觉得有点玄学。

这次排查的设备是 Android 16、LineageOS 23.2,内核是社区的 5.4.302。后来通过 root ADB 看日志,并用 Nnngram 的新安装来复现,才找到了具体卡住的地方。

已经解锁,系统却没准备完

手机解锁以后,加密存储实际上已经能访问了,但下面这个属性还是空的:

getprop sys.user.0.ce_available

正常情况下,解锁并完成存储准备后,它应该返回 true。应用请求系统创建自己的目录时,系统还会检查这个状态,所以属性一直没就绪,建目录的请求就被拒绝了。

继续往前查,问题落在了 /data/misc_ce/0/checkin 这个目录上。它的 SELinux 安全标签少了一部分,系统在准备用户存储时想修正标签,却又被权限规则拦住。准备流程到这里失败,后面的属性自然也没设置上。

这个错误标签保存在 /data 上,换内核不会把它一起清掉,也就能解释为什么刷回去仍然有问题。

这次怎么修的

下面这些命令在 root shell 里执行,针对的是我这台手机主用户的情况。先看属性和标签:

getprop sys.user.0.ce_available
ls -ldZ /data/misc_ce/0/checkin

当时 checkin 的标签是 u:object_r:checkin_data_file:s0,系统期望的是 u:object_r:checkin_data_file:s0:c512,c768。确认日志也是这个标签修正失败以后,就把缺少的部分补上:

chcon u:object_r:checkin_data_file:s0:c512,c768 /data/misc_ce/0/checkin

如果想让这次开机立即恢复,在已经解锁的情况下,再补上状态并重启受影响的应用:

setprop sys.user.0.ce_available true

这条 setprop 只影响当前启动。修好标签以后,后续开机解锁时应当由系统自己设置这个属性,不需要额外写一个开机脚本。

实际测试也符合这个过程:补上属性后,Nnngram 自动创建了自己的 files 和 cache 目录;修正 checkin 标签后,原来失败的存储准备程序也能正常完成了。SELinux 一直保持 Enforcing。

之后又重启了两次。第一次还特意在未解锁时开始采集日志,确认解锁后是系统自己把属性设成了 true。两次解锁后的标签都保持正确,其中一次还重新启动了 Debian 容器,没有再次出现之前的异常。

至于这个标签最初为什么会少一部分,到现在还是没弄明白。动态分区、FBE 版本和容器内核都是当时观察到的线索,暂时还不能据此认定谁是最初的原因。这几条命令也只是这台手机上确认过的修复记录,其他设备遇到类似现象,还是得先看是不是同一个标签问题。