我又发现了Android13的一个bug

问题回顾

之前处理了一个SDCard格式化的问题,最后定位到是底层的原因,让底层同事排查去了,底层同事排查完,没发现什么问题,最近这个问题又转到我的手里了,于是我又深入看了一下

流程梳理

之前已经梳理过了SDCard格式化的代码流程,这里只贴一个简单的流程图

在Settings -> Storage页面点击SDCard格式化,最终请求vold完成格式化。格式化完毕后,再直接访问UnixFileSystem去获取磁盘大小,得到的结果为0。

这里贴一下访问UnixFileSystem获取磁盘大小的核心代码,对上层开发有参考作用,位于libcore/ojluni/src/main/native/UnixFileSystem_md.c

c 复制代码
#define statvfs64 statvfs

// Android-changed: Name changed because of added thread policy check
JNIEXPORT jlong JNICALL
Java_java_io_UnixFileSystem_getSpace0(JNIEnv *env, jobject this,
                                      jobject file, jint t)
{
    jlong rv = 0L;

    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
        struct statvfs64 fsstat;
        memset(&fsstat, 0, sizeof(fsstat));
        if (statvfs64(path, &fsstat) == 0) {
            switch(t) {
            case java_io_FileSystem_SPACE_TOTAL:
                rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
                               long_to_jlong(fsstat.f_blocks));
                break;
            case java_io_FileSystem_SPACE_FREE:
                rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
                               long_to_jlong(fsstat.f_bfree));
                break;
            case java_io_FileSystem_SPACE_USABLE:
                rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
                               long_to_jlong(fsstat.f_bavail));
                break;
            default:
                assert(0);
            }
        }
    } END_PLATFORM_STRING(env, path);
    return rv;
}

主要是通过statvfs结构体,定义如下:

c 复制代码
struct statvfs {
    unsigned long f_bsize;   // 文件系统块大小
    unsigned long f_frsize;  // 文件系统片段大小
    fsblkcnt_t f_blocks;     // 文件系统总块数
    fsblkcnt_t f_bfree;      // 文件系统剩余块数
    fsblkcnt_t f_bavail;     // 文件系统可用块数
    fsfilcnt_t f_files;      // 文件系统节点总数
    fsfilcnt_t f_ffree;      // 文件系统剩余节点数
    fsfilcnt_t f_favail;     // 文件系统可用节点数
    unsigned long f_fsid;    // 文件系统标识
    unsigned long f_flag;    // 挂载标志
    unsigned long f_namemax; // 文件名最大长度
};

在使用 statvfs 函数获取文件系统信息时,可以通过访问 statvfs 结构体的成员来获取所需的信息。应用开发者在做文件系统相关需求时,可以考虑使用此API。

深入分析

因为问题复现后,重新切换一下SDCard或者退出重新进入StorageDashboardFragment可以恢复正常,于是,我在进入StorageDashboardFragment、切换SDCard、格式化完毕这三处代码埋下了log,打印当前SDCard的信息,发现了根本原因:

格式化前后,SDCard的路径竟然变了,而SDCard的路径是由SDCard的fsUuid组成的,fsUuid就是磁盘在文件系统中的uuid。正常情况,无论是拔插还是格式化,这个fsUuid应该是不变的。这个变动就导致格式化完之后,Settings拿着旧的路径去文件系统查找磁盘信息,结果找不到。而退出页面重新进入,相当于重新获取了磁盘信息,此时再去文件系统查找就没问题了。

解决方案

好了,上层问题根源定位到了,怎么解决这个问题呢?

  • 对于上层来说,很简单,在格式化完毕的代码处重新获取一下磁盘信息不就好了,或者干脆直接初始化StorageDashboardFragment。

  • 对于底层来说,似乎要去更改vold格式化的逻辑,使其fsUuid不随机分配。

显然这两种方案都略显粗暴,不够优雅,因为无论是上层Settings代码,还是底层vold代码,都是Google原生的代码,那么这个问题就很有可能是Android自身的bug。

惊天大坑

带着这个怀疑,我去查阅了AOSP的提交记录,果真被我找到了与此相关的一笔提交:android-review.googlesource.com/c/platform/...

并在提交里找到了该开发者提出的这个问题:issuetracker.google.com/issues/3713...

这简直就是一模一样的问题啊,只是这个问题现象是不能显示SDCard的内容,他是在Android7.0上出现的,我是Android13。并且这个哥们儿2017-03-02反馈的这个bug,2017-05-09提交了修改,但Google至今一直没有合入这笔修改,且表示不会修复这个问题

这也就意味着从Android7.0开始,以后每个版本都会有这个问题,坑爹呢这不是。

个人想法

这个bug从一月份,一直解到现在,持续了将近3个月,最终居然是Android的bug,不免让人有些欲哭无泪。不过冷静下来思考,这个问题确实影响也不大,开发者自己也能修复,Android bug那么多,Google那帮大佬们应该都忙着修复紧急bug去了吧。

相关推荐
Kapaseker28 分钟前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴1 小时前
Android17 为什么重写 MessageQueue
android
阿巴斯甜1 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android