Android TF卡损坏问题

A133

Posted by LXG on May 27, 2025

整体工作流程


┌──────────────────────────────┐
│ 1. TF卡插入/拔出/异常事件     │
└────────────┬─────────────────┘
             │ 内核检测 TF 卡事件
             ▼
┌──────────────────────────────┐
│ 2. 内核发送 uevent 到用户空间 │
└────────────┬─────────────────┘
             │
             ▼
┌──────────────────────────────┐
│ 3. vold 接收并解析 uevent    │
│    - 创建 VolumeInfo         │
└────────────┬─────────────────┘
             │
             ▼
┌──────────────────────────────┐
│ 4. vold 尝试挂载 TF 卡       │
│    - 检测分区、文件系统等    │
└────────────┬─────────────────┘
      ┌──────┴──────┐
      ▼             ▼
┌─────────────┐   ┌──────────────────────────────┐
│ 挂载成功    │   │ 挂载失败(文件系统损坏等)   │
└────┬────────┘   └────────────┬─────────────────┘
     │                         ▼
     │               ┌──────────────────────────────┐
     │               │ 5. 设置状态为 STATE_UNMOUNTABLE │
     │               └────────────┬─────────────────┘
     │                         ▼
     │               ┌──────────────────────────────┐
     │               │ 6. vold 通知 StorageManager   │
     │               │    via Binder 调用            │
     │               └────────────┬─────────────────┘
     │                         ▼
     │               ┌──────────────────────────────┐
     │               │ 7. Framework 更新 UI 状态      │
     │               │    弹出“SD 卡已损坏”提示       │
     │               └────────────┬─────────────────┘
     │                         ▼
     │               ┌──────────────────────────────┐
     │               │ 8. 用户选择格式化或移除 TF 卡  │
     │               └──────────────────────────────┘
     ▼
┌──────────────────────────────┐
│ 正常使用 TF 卡               │
└──────────────────────────────┘

源码

frameworks/base/core/java/android/os/storage/VolumeInfo.java


public class VolumeInfo implements Parcelable {


    public static final int STATE_UNMOUNTED = IVold.VOLUME_STATE_UNMOUNTED;
    public static final int STATE_CHECKING = IVold.VOLUME_STATE_CHECKING;
    public static final int STATE_MOUNTED = IVold.VOLUME_STATE_MOUNTED;
    public static final int STATE_MOUNTED_READ_ONLY = IVold.VOLUME_STATE_MOUNTED_READ_ONLY;
    public static final int STATE_FORMATTING = IVold.VOLUME_STATE_FORMATTING;
    public static final int STATE_EJECTING = IVold.VOLUME_STATE_EJECTING;
    public static final int STATE_UNMOUNTABLE = IVold.VOLUME_STATE_UNMOUNTABLE;
    public static final int STATE_REMOVED = IVold.VOLUME_STATE_REMOVED;
    public static final int STATE_BAD_REMOVAL = IVold.VOLUME_STATE_BAD_REMOVAL;

    static {
        // 存储未挂载,通常表示设备已插入但尚未挂载
        sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTED, R.string.ext_media_status_unmounted);
        // 正在检查存储设备的文件系统完整性
        sStateToDescrip.put(VolumeInfo.STATE_CHECKING, R.string.ext_media_status_checking);
        // 存储已挂载且可读写
        sStateToDescrip.put(VolumeInfo.STATE_MOUNTED, R.string.ext_media_status_mounted);
        // 存储已挂载,但只能读取(只读模式)
        sStateToDescrip.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, R.string.ext_media_status_mounted_ro);
        // 正在格式化存储设备
        sStateToDescrip.put(VolumeInfo.STATE_FORMATTING, R.string.ext_media_status_formatting);
        // 正在弹出存储设备,准备移除
        sStateToDescrip.put(VolumeInfo.STATE_EJECTING, R.string.ext_media_status_ejecting);
        // 存储设备无法挂载,可能因文件系统损坏或不支持
        sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTABLE, R.string.ext_media_status_unmountable);
        // 存储设备已被物理移除
        sStateToDescrip.put(VolumeInfo.STATE_REMOVED, R.string.ext_media_status_removed);
        // 存储设备被非正常移除(未卸载就拔出)
        sStateToDescrip.put(VolumeInfo.STATE_BAD_REMOVAL, R.string.ext_media_status_bad_removal);
    }

}

frameworks/base/services/core/java/com/android/server/StorageManagerService.java


class StorageManagerService extends IStorageManager.Stub
        implements Watchdog.Monitor, ScreenObserver {

    private final IVoldListener mListener = new IVoldListener.Stub() {

        @Override
        public void onVolumeStateChanged(String volId, int state) {
            synchronized (mLock) {
                final VolumeInfo vol = mVolumes.get(volId);
                if (vol != null) {
                    final int oldState = vol.state;
                    final int newState = state;
                    vol.state = newState;
                    onVolumeStateChangedLocked(vol, oldState, newState);
                }
            }
        }

    }

    @GuardedBy("mLock")
    private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {

        mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);

        // Do not broadcast before boot has completed to avoid launching the
        // processes that receive the intent unnecessarily.
        if (mBootCompleted && isBroadcastWorthy(vol)) {
            final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
            intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
            intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
        }

    }
    
    private boolean isBroadcastWorthy(VolumeInfo vol) {
        switch (vol.getType()) {
            case VolumeInfo.TYPE_PRIVATE:
            case VolumeInfo.TYPE_PUBLIC:
            case VolumeInfo.TYPE_EMULATED:
            case VolumeInfo.TYPE_STUB:
                break;
            default:
                return false;
        }

        switch (vol.getState()) {
            case VolumeInfo.STATE_MOUNTED:
            case VolumeInfo.STATE_MOUNTED_READ_ONLY:
            case VolumeInfo.STATE_EJECTING:
            case VolumeInfo.STATE_UNMOUNTED:
            case VolumeInfo.STATE_UNMOUNTABLE:  // 此状态时会提示SD卡损坏
            case VolumeInfo.STATE_BAD_REMOVAL:
                break;
            default:
                return false;
        }

        return true;
    }

}

./system/vold/binder/android/os/IVold.aidl


interface IVold {

    const int VOLUME_STATE_UNMOUNTED = 0;
    const int VOLUME_STATE_CHECKING = 1;
    const int VOLUME_STATE_MOUNTED = 2;
    const int VOLUME_STATE_MOUNTED_READ_ONLY = 3;
    const int VOLUME_STATE_FORMATTING = 4;
    const int VOLUME_STATE_EJECTING = 5;
    const int VOLUME_STATE_UNMOUNTABLE = 6;
    const int VOLUME_STATE_REMOVED = 7;
    const int VOLUME_STATE_BAD_REMOVAL = 8;

}

错误日志分析


05-26 16:02:06.430313  1806  1819 D vold    : exfatfsck 1.3.0
05-26 16:02:06.430427  1806  1819 D vold    : 
05-26 16:02:06.430460  1806  1819 D vold    : Checking file system on /dev/block/vold/public:179,65.
05-26 16:02:06.430473  1806  1819 D vold    : 
05-26 16:02:06.430495  1806  1819 D vold    : File system version           1.0
05-26 16:02:06.430506  1806  1819 D vold    : 
05-26 16:02:06.430526  1806  1819 D vold    : Sector size                 512 bytes
05-26 16:02:06.430538  1806  1819 D vold    : 
05-26 16:02:06.430557  1806  1819 D vold    : Cluster size                128 KB
05-26 16:02:06.430569  1806  1819 D vold    : 
05-26 16:02:06.430589  1806  1819 D vold    : Volume size                 116 GB
05-26 16:02:06.430601  1806  1819 D vold    : 
05-26 16:02:06.430620  1806  1819 D vold    : Used space                   85 GB
05-26 16:02:06.430632  1806  1819 D vold    : 
05-26 16:02:06.430651  1806  1819 D vold    : Available space              32 GB
05-26 16:02:06.430664  1806  1819 D vold    : 

# 这是 exfat 文件系统解析目录项时发生异常
05-26 16:02:06.430848  2771  2771 E exfat   : unexpected entry type 0x84 after 0x85 at 1/225
05-26 16:02:07.322705  2771  2771 E exfat   : unexpected entry type 0x45 after 0x85 at 1/51
05-26 16:02:08.399323  1806  1819 D vold    : Totally 63 directories and 26236 files.
05-26 16:02:08.399643  1806  1819 D vold    : 
05-26 16:02:08.399708  1806  1819 D vold    : File system checking finished. ERRORS FOUND: 2, FIXED: 0.
05-26 16:02:08.399725  1806  1819 D vold    : 
05-26 16:02:08.402308  1806  1819 E vold    : Process exited with code: 1
05-26 16:02:08.402392  1806  1819 E vold    : Check failed (code 1)
05-26 16:02:08.402426  1806  1819 E vold    : public:179,65 failed filesystem check

05-26 16:02:08.406522  2239  2331 E StorageManagerService: 
05-26 16:02:08.406522  2239  2331 E StorageManagerService: android.os.ServiceSpecificException:  (code -5)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.Parcel.createException(Parcel.java:2085)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.Parcel.readException(Parcel.java:2039)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.Parcel.readException(Parcel.java:1987)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.IVold$Stub$Proxy.mount(IVold.java:1565)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at com.android.server.StorageManagerService.mount(StorageManagerService.java:1810)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at com.android.server.StorageManagerService.access$1600(StorageManagerService.java:188)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at com.android.server.StorageManagerService$StorageManagerServiceHandler.handleMessage(StorageManagerService.java:650)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.Handler.dispatchMessage(Handler.java:107)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.Looper.loop(Looper.java:214)
05-26 16:02:08.406522  2239  2331 E StorageManagerService: 	at android.os.HandlerThread.run(HandlerThread.java:67)

05-26 16:02:16.583012  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:02:16.583012  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:02:16.583012  2375  2375 D StorageNotification:     state=UNMOUNTABLE 
05-26 16:02:16.583012  2375  2375 D StorageNotification:     fsType=exfat fsUuid=86BA-1239 fsLabel=android 
05-26 16:02:16.583012  2375  2375 D StorageNotification:     path=null internalPath=null 

05-26 16:08:31.504062[    1.522384] FAT-fs (mmcblk0p16): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

日志分析


┌────────────────────────────────┐
│ 插入 TF 卡(含 exFAT/FAT 分区)│
└────────────┬───────────────────┘
             
      [Kernel 检测到 uevent]
             
      vold 接收设备节点
             
      检测文件系统类型
             
┌─────────────┬──────────────┐
│  执行 exfatfsck / fsck.vfat │
└─────────────┴──────────────┘
             
       检查失败 → ERRORS FOUND: 2, FIXED: 0
             
       vold 返回 code=1
             
       StorageManager 接收失败状态(code -5)
             
       标记状态为 STATE_UNMOUNTABLE
             
       UI 提示用户“SD 卡已损坏”

state=UNMOUNTABLE 时会提示已损坏

exfat 文件系统报错日志

./vendor/aw/public/package/bin/fstools/exfat


lxg@lxg:~/code/project/a133/haoqiang_BE/A133_android_10/android/vendor/aw/public/package/bin/fstools$ grep -ri "exfat_error(\"" .
./exfat/fuse/main.c:		exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
./exfat/fuse/main.c:		exfat_error("failed to open directory '%s'", path);
./exfat/fuse/main.c:		exfat_error("failed to reallocate options string");
./exfat/fuse/main.c:		exfat_error("failed to allocate escaped string for %s", spec);
./exfat/fuse/main.c:		exfat_error("failed to determine username");
./exfat/fuse/main.c:		exfat_error("failed to allocate options string");
./exfat/mkfs/fat.c:		exfat_error("failed to write FAT entry 0x%x", value);
./exfat/mkfs/uct.c:		exfat_error("failed to write upcase table of %zu bytes",
./exfat/mkfs/main.c:			exfat_error("cluster size %"PRIu64" %s is too small for "
./exfat/mkfs/main.c:		exfat_error("failed to form volume id");
./exfat/mkfs/main.c:				exfat_error("invalid option value: '%s'", optarg);
./exfat/mkfs/cbm.c:		exfat_error("failed to allocate bitmap of %zu bytes",
./exfat/mkfs/cbm.c:		exfat_error("failed to write bitmap of %zu bytes",
./exfat/mkfs/vbr.c:		exfat_error("failed to allocate sector-sized block of memory");
./exfat/mkfs/vbr.c:		exfat_error("failed to write super block sector");
./exfat/mkfs/vbr.c:			exfat_error("failed to write a sector with boot signature");
./exfat/mkfs/vbr.c:			exfat_error("failed to write an empty sector");
./exfat/mkfs/vbr.c:		exfat_error("failed to write checksum sector");
./exfat/mkfs/mkexfat.c:		exfat_error("too small device (%"PRIu64" %s)", vhb.value, vhb.unit);
./exfat/mkfs/mkexfat.c:		exfat_error("seek to 0x%"PRIx64" failed", start);
./exfat/mkfs/mkexfat.c:			exfat_error("failed to erase block %"PRIu64"/%"PRIu64
./exfat/mkfs/mkexfat.c:		exfat_error("failed to allocate erase block");
./exfat/mkfs/mkexfat.c:			exfat_error("seek to 0x%"PRIx64" failed", position);
./exfat/libexfat/repair.c:		exfat_error("failed to write correct VBR checksum");
./exfat/libexfat/node.c:	exfat_error("read %zd bytes instead of %zu bytes", size,
./exfat/libexfat/node.c:	exfat_error("wrote %zd bytes instead of %zu bytes", size,
./exfat/libexfat/node.c:		exfat_error("failed to allocate node");
./exfat/libexfat/node.c:			exfat_error("unexpected entry type %#x after %#x at %d/%d",
./exfat/libexfat/node.c:		exfat_error("'%s' has invalid checksum (%#hx != %#hx)", buffer,
./exfat/libexfat/node.c:		exfat_error("'%s' has valid size (%"PRIu64") greater than size "
./exfat/libexfat/node.c:		exfat_error("'%s' is empty but start cluster is %#x", buffer,
./exfat/libexfat/node.c:		exfat_error("'%s' points to invalid cluster %#x", buffer,
./exfat/libexfat/node.c:		exfat_error("'%s' is larger than clusters heap: %"PRIu64" > %"PRIu64,
./exfat/libexfat/node.c:		exfat_error("'%s' is empty but marked as contiguous (%#hx)", buffer,
./exfat/libexfat/node.c:		exfat_error("'%s' directory size %"PRIu64" is not divisible by %d", buffer,
./exfat/libexfat/node.c:		exfat_error("too few continuations (%hhu)", meta1->continuations);
./exfat/libexfat/node.c:		exfat_error("unknown flags in meta2 (%#hhx)", meta2->flags);
./exfat/libexfat/node.c:		exfat_error("too few continuations (%hhu < %d)",
./exfat/libexfat/node.c:				exfat_error("invalid cluster 0x%x in upcase table",
./exfat/libexfat/node.c:				exfat_error("bad upcase table size (%"PRIu64" bytes)",
./exfat/libexfat/node.c:				exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
./exfat/libexfat/node.c:				exfat_error("failed to read upper case table "
./exfat/libexfat/node.c:				exfat_error("failed to allocate decompressed upcase table");
./exfat/libexfat/node.c:				exfat_error("invalid cluster 0x%x in clusters bitmap",
./exfat/libexfat/node.c:				exfat_error("invalid clusters bitmap size: %"PRIu64
./exfat/libexfat/node.c:				exfat_error("failed to allocate clusters bitmap chunk "
./exfat/libexfat/node.c:				exfat_error("failed to read clusters bitmap "
./exfat/libexfat/node.c:				exfat_error("too long label (%hhu chars)", label->length);
./exfat/libexfat/node.c:			exfat_error("unknown entry type %#hhx", entry.type);
./exfat/libexfat/node.c:		exfat_error("failed to allocate directory bitmap (%"PRIu64")",
./exfat/libexfat/utf.c:			exfat_error("illegal UTF-16 sequence");
./exfat/libexfat/utf.c:			exfat_error("name is too long");
./exfat/libexfat/utf.c:		exfat_error("name is too long");
./exfat/libexfat/utf.c:			exfat_error("illegal UTF-8 sequence");
./exfat/libexfat/utf.c:			exfat_error("name is too long");
./exfat/libexfat/utf.c:		exfat_error("name is too long");
./exfat/libexfat/mount.c:			exfat_error("root directory cannot occupy all %d clusters",
./exfat/libexfat/mount.c:			exfat_error("bad cluster %#x while reading root directory",
./exfat/libexfat/mount.c:		exfat_error("failed to read boot sector");
./exfat/libexfat/mount.c:			exfat_error("failed to read VBR sector");
./exfat/libexfat/mount.c:		exfat_error("failed to read VBR checksum sector");
./exfat/libexfat/mount.c:			exfat_error("invalid VBR checksum 0x%x (expected 0x%x)",
./exfat/libexfat/mount.c:		exfat_error("failed to write super block");
./exfat/libexfat/mount.c:		exfat_error("failed to allocate memory for the super block");
./exfat/libexfat/mount.c:		exfat_error("failed to read boot sector");
./exfat/libexfat/mount.c:		exfat_error("exFAT file system is not found");
./exfat/libexfat/mount.c:		exfat_error("too small sector size: 2^%hhd", ef->sb->sector_bits);
./exfat/libexfat/mount.c:		exfat_error("too big cluster size: 2^(%hhd+%hhd)",
./exfat/libexfat/mount.c:		exfat_error("failed to allocate zero sector");
./exfat/libexfat/mount.c:		exfat_error("unsupported exFAT version: %hhu.%hhu",
./exfat/libexfat/mount.c:		exfat_error("unsupported FAT count: %hhu", ef->sb->fat_count);
./exfat/libexfat/mount.c:		exfat_error("file system in clusters is larger than device: "
./exfat/libexfat/mount.c:		exfat_error("failed to allocate root node");
./exfat/libexfat/mount.c:		exfat_error("upcase table is not found");
./exfat/libexfat/mount.c:		exfat_error("clusters bitmap is not found");
./exfat/libexfat/time.c:		exfat_error("bad date %u-%02hu-%02hu",
./exfat/libexfat/time.c:		exfat_error("bad time %hu:%02hu:%02u",
./exfat/libexfat/time.c:		exfat_error("bad centiseconds count %hhu", centisec);
./exfat/libexfat/io.c:			exfat_error("failed to open /dev/null");
./exfat/libexfat/io.c:		exfat_error("failed to allocate memory for device structure");
./exfat/libexfat/io.c:			exfat_error("failed to open '%s' in read-only mode: %s", spec,
./exfat/libexfat/io.c:			exfat_error("failed to open '%s' in read-write mode: %s", spec,
./exfat/libexfat/io.c:		exfat_error("failed to open '%s': %s", spec, strerror(errno));
./exfat/libexfat/io.c:		exfat_error("failed to fstat '%s'", spec);
./exfat/libexfat/io.c:		exfat_error("'%s' is neither a device, nor a regular file", spec);
./exfat/libexfat/io.c:			exfat_error("failed to get block size");
./exfat/libexfat/io.c:			exfat_error("failed to get blocks count");
./exfat/libexfat/io.c:			exfat_error("failed to get disklabel");
./exfat/libexfat/io.c:			exfat_error("failed to get size of '%s'", spec);
./exfat/libexfat/io.c:			exfat_error("failed to seek to the beginning of '%s'", spec);
./exfat/libexfat/io.c:		exfat_error("failed to initialize ublio");
./exfat/libexfat/io.c:		exfat_error("failed to close ublio");
./exfat/libexfat/io.c:		exfat_error("failed to close device: %s", strerror(errno));
./exfat/libexfat/io.c:		exfat_error("ublio fsync failed");
./exfat/libexfat/io.c:		exfat_error("fsync failed: %s", strerror(errno));
./exfat/libexfat/io.c:		exfat_error("invalid cluster 0x%x while reading", cluster);
./exfat/libexfat/io.c:			exfat_error("invalid cluster 0x%x while reading", cluster);
./exfat/libexfat/io.c:			exfat_error("failed to read cluster %#x", cluster);
./exfat/libexfat/io.c:		exfat_error("invalid cluster 0x%x while writing", cluster);
./exfat/libexfat/io.c:			exfat_error("invalid cluster 0x%x while writing", cluster);
./exfat/libexfat/io.c:			exfat_error("failed to write cluster %#x", cluster);
./exfat/libexfat/cluster.c:			exfat_error("failed to write clusters bitmap");
./exfat/libexfat/cluster.c:		exfat_error("failed to write the next cluster %#x after %#x", next,
./exfat/libexfat/cluster.c:		exfat_error("no free space left");
./exfat/libexfat/cluster.c:			exfat_error("invalid cluster 0x%x while growing", previous);
./exfat/libexfat/cluster.c:			exfat_error("invalid cluster 0x%x while shrinking", last);
./exfat/libexfat/cluster.c:			exfat_error("invalid cluster 0x%x while freeing after shrink",
./exfat/libexfat/cluster.c:		exfat_error("failed to erase %zu bytes at %"PRId64, size, offset);
./exfat/libexfat/cluster.c:		exfat_error("invalid cluster 0x%x while erasing", cluster);
./exfat/fsck/main.c:			exfat_error("file '%s' has invalid cluster 0x%x", name, c);
./exfat/fsck/main.c:			exfat_error("cluster 0x%x of file '%s' is not allocated", c, name);
./exfat/fsck/main.c:		exfat_error("out of memory");
./exfat/dump/main.c:		exfat_error("failed to read from '%s'", spec);
./exfat/dump/main.c:		exfat_error("exFAT file system is not found on '%s'", spec);
./exfat/dump/main.c:		exfat_error("'%s': %s", path, strerror(-rc));
./exfat/dump/main.c:			exfat_error("'%s' has invalid cluster %#x", path, cluster);

格式化日志


05-26 16:11:19.885454  2239  2660 V KioskMode: Resuming ActivityRecord{2d34d58 u0 com.android.settings/.deviceinfo.StorageWizardFormatProgress t549}

05-26 16:11:20.016075  1806  1819 D vold    : /system/bin/sgdisk
05-26 16:11:20.016240  1806  1819 D vold    :     --zap-all
05-26 16:11:20.016270  1806  1819 D vold    :     /dev/block/vold/disk:179,64
05-26 16:11:20.017775  2239  2331 D StorageManagerService: Volume public:179,65 broadcasting removed to UserHandle{0}
--------- switch to main
05-26 16:11:20.029110  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:11:20.029110  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:11:20.029110  2375  2375 D StorageNotification:     state=REMOVED 
05-26 16:11:20.029110  2375  2375 D StorageNotification:     fsType=exfat fsUuid=86BA-1239 fsLabel=android 
05-26 16:11:20.029110  2375  2375 D StorageNotification:     path=null internalPath=null 
05-26 16:11:21.147359  1806  1819 D vold    : 
05-26 16:11:21.147487  1806  1819 D vold    : 
05-26 16:11:21.147550  1806  1819 D vold    : ***************************************************************
05-26 16:11:21.147570  1806  1819 D vold    : 
05-26 16:11:21.147603  1806  1819 D vold    : Found invalid GPT and valid MBR; converting MBR to GPT format
05-26 16:11:21.147622  1806  1819 D vold    : 
05-26 16:11:21.147651  1806  1819 D vold    : in memory. 
05-26 16:11:21.147669  1806  1819 D vold    : 
05-26 16:11:21.147706  1806  1819 D vold    : ***************************************************************
05-26 16:11:21.147725  1806  1819 D vold    : 
05-26 16:11:21.147768  1806  1819 D vold    : 
05-26 16:11:21.147801  1806  1819 D vold    : GPT data structures destroyed! You may now partition the disk using fdisk or
05-26 16:11:21.147819  1806  1819 D vold    : 
05-26 16:11:21.147846  1806  1819 D vold    : other utilities.
05-26 16:11:21.147864  1806  1819 D vold    : 
05-26 16:11:21.148873  1806  1819 D vold    : /system/bin/sgdisk
05-26 16:11:21.148932  1806  1819 D vold    :     --new=0:0:-0
05-26 16:11:21.148961  1806  1819 D vold    :     --typecode=0:0c00
05-26 16:11:21.148989  1806  1819 D vold    :     --gpttombr=1
05-26 16:11:21.149016  1806  1819 D vold    :     /dev/block/vold/disk:179,64
05-26 16:11:22.198774  1806  1819 D vold    : Creating new GPT entries.
05-26 16:11:22.198849  1806  1819 D vold    : 
05-26 16:11:22.198899  1806  1819 D vold    : GPT data structures destroyed! You may now partition the disk using fdisk or
05-26 16:11:22.198916  1806  1819 D vold    : 
05-26 16:11:22.198944  1806  1819 D vold    : other utilities.
05-26 16:11:22.198961  1806  1819 D vold    : 
05-26 16:11:22.200371  1806  1818 D vold    : Disk at 179:64 changed
05-26 16:11:22.201923  1806  1818 D vold    : /system/bin/sgdisk
05-26 16:11:22.201997  1806  1818 D vold    :     --android-dump
05-26 16:11:22.202018  1806  1818 D vold    :     /dev/block/vold/disk:179,64
05-26 16:11:22.221743  1806  1818 D vold    : DISK mbr
05-26 16:11:22.221821  1806  1818 D vold    : 
05-26 16:11:22.221855  1806  1818 D vold    : PART 1 c
05-26 16:11:22.221870  1806  1818 D vold    : 
05-26 16:11:22.222893  1806  1818 D vold    : Device just partitioned; silently formatting
05-26 16:11:22.225588  1806  1818 I vold    : About to discard 125084089856 on /dev/block/vold/public:179,65
05-26 16:11:22.225696  1806  1818 E vold    : Discard failure on /dev/block/vold/public:179,65: Operation not supported on transport endpoint
05-26 16:11:22.225730  1806  1818 W vold    : public:179,65 failed to wipe
05-26 16:11:22.225835  1806  1818 D vold    : /system/bin/mkfs.exfat
05-26 16:11:22.225867  1806  1818 D vold    :     -n
05-26 16:11:22.225885  1806  1818 D vold    :     android
05-26 16:11:22.225905  1806  1818 D vold    :     /dev/block/vold/public:179,65
05-26 16:11:22.241836  1806  1818 D vold    : mkexfatfs 1.3.0
05-26 16:11:22.241925  1806  1818 D vold    : 
05-26 16:11:22.262466  1806  1818 D vold    : Creating... done.
05-26 16:11:22.262545  1806  1818 D vold    : 
05-26 16:11:22.400120  1806  1818 D vold    : Flushing... done.
05-26 16:11:22.400201  1806  1818 D vold    : 
05-26 16:11:22.400245  1806  1818 D vold    : File system created successfully.
05-26 16:11:22.400258  1806  1818 D vold    : 
05-26 16:11:22.401051  1806  1818 I vold    : Format OK
05-26 16:11:22.402058  1806  1818 D vold    : VolumeBase create onVolumeCreated
05-26 16:11:22.402316  1806  1818 D vold    : Disk at 179:64 changed
--------- switch to main
05-26 16:11:22.403982  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:11:22.403982  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:11:22.403982  2375  2375 D StorageNotification:     state=UNMOUNTED 
05-26 16:11:22.403982  2375  2375 D StorageNotification:     fsType=null fsUuid=null fsLabel=null 
05-26 16:11:22.403982  2375  2375 D StorageNotification:     path=null internalPath=null 
--------- switch to system
05-26 16:11:22.404312  1806  1818 D vold    : /system/bin/sgdisk
05-26 16:11:22.404376  1806  1818 D vold    :     --android-dump
05-26 16:11:22.404396  1806  1818 D vold    :     /dev/block/vold/disk:179,64
05-26 16:11:22.407516  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:11:22.407516  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:11:22.407516  2375  2375 D StorageNotification:     state=REMOVED 
05-26 16:11:22.407516  2375  2375 D StorageNotification:     fsType=null fsUuid=null fsLabel=null 
05-26 16:11:22.407516  2375  2375 D StorageNotification:     path=null internalPath=null 
--------- switch to system
05-26 16:11:22.424104  1806  1818 D vold    : DISK mbr
05-26 16:11:22.424175  1806  1818 D vold    : 
05-26 16:11:22.424206  1806  1818 D vold    : PART 1 c
05-26 16:11:22.424219  1806  1818 D vold    : 
05-26 16:11:22.425915  1806  1818 D vold    : VolumeBase create onVolumeCreated
05-26 16:11:22.426196  1806  2972 D vold    : /system/bin/blkid
05-26 16:11:22.426237  1806  2972 D vold    :     -c
05-26 16:11:22.426256  1806  2972 D vold    :     /dev/null
05-26 16:11:22.426273  1806  2972 D vold    :     -s
05-26 16:11:22.426288  1806  2972 D vold    :     TYPE
05-26 16:11:22.426303  1806  2972 D vold    :     -s
05-26 16:11:22.426318  1806  2972 D vold    :     UUID
05-26 16:11:22.426333  1806  2972 D vold    :     -s
05-26 16:11:22.426347  1806  2972 D vold    :     LABEL
05-26 16:11:22.426365  1806  2972 D vold    :     /dev/block/vold/public:179,65
05-26 16:11:22.430189  2239  3055 V KioskMode: Resuming ActivityRecord{8057b8 u0 com.android.settings/.deviceinfo.StorageWizardFormatSlow t549}
05-26 16:11:22.434692  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:11:22.434692  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:11:22.434692  2375  2375 D StorageNotification:     state=UNMOUNTED 
05-26 16:11:22.434692  2375  2375 D StorageNotification:     fsType=null fsUuid=null fsLabel=null 
05-26 16:11:22.434692  2375  2375 D StorageNotification:     path=null internalPath=null 
05-26 16:11:22.436403  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:11:22.436403  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:11:22.436403  2375  2375 D StorageNotification:     state=CHECKING 
05-26 16:11:22.436403  2375  2375 D StorageNotification:     fsType=null fsUuid=null fsLabel=null 
05-26 16:11:22.436403  2375  2375 D StorageNotification:     path=null internalPath=null 

05-26 16:11:22.625115  2239  2492 I ActivityTaskManager: START u0 {cmp=com.android.settings/.deviceinfo.StorageWizardReady (has extras)} from uid 1000
05-26 16:11:22.637249  1806  2972 D vold    : exfatfsck 1.3.0
05-26 16:11:22.637667  1806  2972 D vold    : 
05-26 16:11:22.637717  1806  2972 D vold    : Checking file system on /dev/block/vold/public:179,65.
05-26 16:11:22.637731  1806  2972 D vold    : 
05-26 16:11:22.637776  1806  2972 D vold    : File system version           1.0
05-26 16:11:22.637791  1806  2972 D vold    : 
05-26 16:11:22.637813  1806  2972 D vold    : Sector size                 512 bytes
05-26 16:11:22.637826  1806  2972 D vold    : 
05-26 16:11:22.637847  1806  2972 D vold    : Cluster size                128 KB
05-26 16:11:22.637860  1806  2972 D vold    : 
05-26 16:11:22.637881  1806  2972 D vold    : Volume size                 116 GB
05-26 16:11:22.637900  1806  2972 D vold    : 
05-26 16:11:22.637921  1806  2972 D vold    : Used space                 4336 KB
05-26 16:11:22.637934  1806  2972 D vold    : 
05-26 16:11:22.637954  1806  2972 D vold    : Available space             116 GB
05-26 16:11:22.637966  1806  2972 D vold    : 
05-26 16:11:22.637986  1806  2972 D vold    : Totally 0 directories and 0 files.
05-26 16:11:22.637998  1806  2972 D vold    : 
05-26 16:11:22.637304  2239  2492 V KioskMode: Resuming ActivityRecord{d12e3ef u0 com.android.settings/.deviceinfo.StorageWizardReady t549}
05-26 16:11:22.638018  1806  2972 D vold    : File system checking finished. No errors found.
05-26 16:11:22.638030  1806  2972 D vold    : 
05-26 16:11:22.638679  1806  2972 I vold    : Check OK
05-26 16:11:22.644355  1806  2972 E vold    : Mount failed; attempting read-only: No such device
05-26 16:11:22.646085  1806  2972 D vold    : /system/bin/mount.exfat
05-26 16:11:22.646162  1806  2972 D vold    :     -o
05-26 16:11:22.646183  1806  2972 D vold    :     uid=1023,gid=1023,fmask=7,dmask=7
05-26 16:11:22.646204  1806  2972 D vold    :     /dev/block/vold/public:179,65
05-26 16:11:22.646221  1806  2972 D vold    :     /mnt/media_rw/22A3-B024

05-26 16:11:22.901784  2375  2375 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}:
05-26 16:11:22.901784  2375  2375 D StorageNotification:     type=PUBLIC diskId=disk:179,64 partGuid= mountFlags=VISIBLE mountUserId=0 
05-26 16:11:22.901784  2375  2375 D StorageNotification:     state=MOUNTED 
05-26 16:11:22.901784  2375  2375 D StorageNotification:     fsType=exfat fsUuid=22A3-B024 fsLabel=android 
05-26 16:11:22.901784  2375  2375 D StorageNotification:     path=/storage/22A3-B024 internalPath=/mnt/media_rw/22A3-B024 

20250807 TF卡不识别问题分析


[    2.761917] mmc1: card never left busy state
[    2.761950] mmc1: error -110 whilst initialising SD card

这类问题 在 嵌入式 Android/Linux 设备中非常典型,一般是由于软重启时 TF 卡电源或复位未正确拉低,导致卡仍处于 busy 状态,无法重新初始化。

  1. 软重启时 TF 卡没有断电
  • TF 卡在 reset 过程中需要完整的断电/上电周期,否则它的控制器会残留上一次 session 的状态(即“卡一直 busy”)。
  • 断电重启时主控和卡都掉电,重新初始化 OK。
  • 软重启时,如果 TF 卡电源由某个 LDO 或 GPIO 控制,而该供电未重新拉低,那么就会出现 card never left busy state

DTS


		sdc0: sdmmc@04020000 {
			bus-width = <4>;
			cd-gpios = <&pio PF 6 6 1 3 0xffffffff>;
			/*non-removable;*/
			/*broken-cd;*/
			/*cd-inverted;*/
			/*data3-detect;*/
			cd-used-24M;
			cap-sd-highspeed;
			sd-uhs-sdr50;
			sd-uhs-ddr50;
			sd-uhs-sdr104;
			no-sdio;
			no-mmc;
			sunxi-power-save-mode;
			/*sunxi-dis-signal-vol-sw;*/
			max-frequency = <150000000>;
			ctl-spec-caps = <0x8>;
			vmmc-supply = <&reg_dcdc1>;
			vqmmc33sw-supply = <&reg_dcdc1>;
			vdmmc33sw-supply = <&reg_dcdc1>;
			vqmmc18sw-supply = <&reg_eldo1>;
			vdmmc18sw-supply = <&reg_eldo1>;
			status = "okay";
		};

a133_tf_card

a133_tf_card_vcc

结论:软重启时TF卡电源不可控

结合两张图来看,可以得出以下结论:

  1. 第一张图显示VCC-CARD通过一个0欧姆电阻RC3连接到VCC-CARD-3.3V,然后为TF卡供电。
  2. 第二张图显示VCC-CARD直接由DCDC1的3.3V输出供电。

问题点在于:

  1. DCDC1是一个电源转换器。通常在嵌入式系统中,DCDC转换器只有在系统完全关机(即硬重启)时才会断电。
  2. 当主控芯片执行软重启时,DCDC1通常会持续工作,保持3.3V输出不变。
  3. 由于VCC-CARD直接连接到DCDC1的输出,因此在软重启时,VCC-CARD(以及VCC-CARD-3.3V)的电压不会被拉低,TF卡会一直保持供电状态。

软重启导致的TF卡异常

文件系统未正常卸载

软重启过程中,TF 卡上的文件系统缓存(页缓存、写缓存)没来得及 flush 到物理卡,导致 FS 出现 dirty 标记甚至损坏。

下次挂载时可能被内核标记为“脏盘”或“只读”。

驱动/电源管理问题

某些平台(尤其 Allwinner、Rockchip 等)在 reboot 时,SDIO/SDMMC 控制器掉电不彻底,卡状态机没有复位干净。

下次挂载时,驱动读到卡状态异常,导致“掉卡”或不可识别。

TF卡修复时间过长导致watchdog超时循环重启

日志


10-09 18:17:47.887  1694  1706 D vold    : /system/bin/blkid
10-09 18:17:47.887  1694  1706 D vold    :     -c
10-09 18:17:47.887  1694  1706 D vold    :     /dev/null
10-09 18:17:47.887  1694  1706 D vold    :     -s
10-09 18:17:47.887  1694  1706 D vold    :     TYPE
10-09 18:17:47.887  1694  1706 D vold    :     -s
10-09 18:17:47.887  1694  1706 D vold    :     UUID
10-09 18:17:47.887  1694  1706 D vold    :     -s
10-09 18:17:47.887  1694  1706 D vold    :     LABEL
10-09 18:17:47.887  1694  1706 D vold    :     /dev/block/vold/public:179,65
10-09 18:17:48.123  1694  1706 D vold    : /dev/block/vold/public:179,65: LABEL="Lenovo" UUID="0B75-114C" TYPE="vfat" 
10-09 18:17:48.123  1694  1706 D vold    : 
10-09 18:17:48.129  1694  1706 D vold    : /system/bin/fsck_msdos
10-09 18:17:48.129  1694  1706 D vold    :     -p
10-09 18:17:48.129  1694  1706 D vold    :     -f
10-09 18:17:48.129  1694  1706 D vold    :     -y
10-09 18:17:48.129  1694  1706 D vold    :     /dev/block/vold/public:179,65
10-09 18:17:50.706  1694  1706 D vold    : /dev/block/vold/public:179,65: Cluster 32 is marked free in FAT 0, as EOF in FAT 1
10-09 18:17:50.706  1694  1706 D vold    : 
10-09 18:17:50.706  1694  1706 D vold    : FIXED
10-09 18:17:50.706  1694  1706 D vold    : 
10-09 18:17:50.706  1694  1706 D vold    : /dev/block/vold/public:179,65: /WifIPC/037a0002009e37c083ef starts with free cluster
10-09 18:17:50.706  1694  1706 D vold    : 
10-09 18:17:50.706  1694  1706 D vold    : FIXED
10-09 18:17:50.706  1694  1706 D vold    : 
10-09 18:17:50.706  1694  1706 D vold    : /dev/block/vold/public:179,65: /WifIPC/037a0002009e262a5afe/20250923 has entries after end of directory
10-09 18:17:50.706  1694  1706 D vold    : 
10-09 18:17:50.706  1694  1706 D vold    : FIXED
10-09 18:17:50.706  1694  1706 D vold    : 
10-09 18:17:50.706  1694  1706 D vold    : /dev/block/vold/public:179,65: /WifIPC/037a0002009e262a5afe/20250923 has entries after end of directory


10-09 18:17:55.307  1694  1706 D vold    : /dev/block/vold/public:179,65: Lost cluster chain at cluster 2869994
10-09 18:17:55.307  1694  1706 D vold    : 126 Cluster(s) lost
10-09 18:17:55.307  1694  1706 D vold    : FIXED
10-09 18:17:55.307  1694  1706 D vold    : 
10-09 18:17:55.307  1694  1706 D vold    : /dev/block/vold/public:179,65: Lost cluster chain at cluster 2870246
10-09 18:17:55.307  1694  1706 D vold    : 
10-09 18:17:55.307  1694  1706 D vold    : 126 Cluster(s) lost
10-09 18:17:55.307  1694  1706 D vold    : FIXED
10-09 18:17:55.307  1694  1706 D vold    : /dev/block/vold/public:179,65: Lost cluster chain at cluster 2870497
10-09 18:17:55.307  1694  1706 D vold    : 125 Cluster(s) lost
10-09 18:17:55.307  1694  1706 D vold    : 
10-09 18:17:55.307  1694  1706 D vold    : 118 Cluster(s) lost
10-09 18:17:55.307  1694  1706 D vold    : 
10-09 18:17:55.307  1694  1706 D vold    : FIXED
10-09 18:17:55.307  1694  1706 D vold    : 
10-09 18:17:55.307  1694  1706 D vold    : /dev/block/vold/public:179,65: Lost cluster chain at cluster 2870989

代码

A133_android_10/android/system/vold/fs/Exfat.cpp


static const char* kMkfsPath = "/system/bin/newfs_msdos";
static const char* kFsckPath = "/system/bin/fsck_msdos";

bool IsSupported() {
    return access(kMkfsPath, X_OK) == 0 && access(kFsckPath, X_OK) == 0 &&
           IsFilesystemSupported("vfat");
}

status_t Check(const std::string& source) {
    int pass = 1;
    int rc = 0;
    do {
        std::vector<std::string> cmd;
        cmd.push_back(kFsckPath);
        cmd.push_back("-p");
        cmd.push_back("-f");
        cmd.push_back("-y");
        cmd.push_back(source);

        // Fat devices are currently always untrusted
        rc = ForkExecvp(cmd, nullptr, sFsckUntrustedContext);  // 卡在了此函数无法返回

        if (rc < 0) {
            LOG(ERROR) << "Filesystem check failed due to logwrap error";
            errno = EIO;
            return -1;
        }

        switch (rc) {
            case 0:
                LOG(INFO) << "Filesystem check completed OK";
                return 0;

            case 2:
                LOG(ERROR) << "Filesystem check failed (not a FAT filesystem)";
                errno = ENODATA;
                return -1;

            case 4:
                if (pass++ <= 3) {
                    LOG(WARNING) << "Filesystem modified - rechecking (pass " << pass << ")";
                    continue;
                }
                LOG(ERROR) << "Failing check after too many rechecks";
                errno = EIO;
                return -1;

            case 8:
                LOG(ERROR) << "Filesystem check failed (no filesystem)";
                errno = ENODATA;
                return -1;

            default:
                LOG(ERROR) << "Filesystem check failed (unknown exit code " << rc << ")";
                errno = EIO;
                return -1;
        }
    } while (0);

    return 0;
}

exFAT vs FAT32

属性 FAT(FAT12/16/32) exFAT
全称 File Allocation Table Extended File Allocation Table
发布年份 1980 / 1984 / 1996 2006
文件系统类型 FAT12 / FAT16 / FAT32 exFAT
最大文件大小 FAT32: 4 GB 16 EB(理论上,实际受操作系统限制)
最大分区大小 FAT32: 2 TB 128 PB(理论上)
日志功能 无(轻量级设计)
目录条目限制 FAT12/16 小,FAT32 可扩展 几乎无限制
设计目标 小容量磁盘(软盘、U盘) 大容量闪存、存储卡

主要区别

方面 FAT exFAT
容量支持 最大 2TB 分区,单文件 ≤ 4GB 超大分区,单文件 > 4GB
性能 小分区性能好,分区越大越慢 适合大容量闪存,簇管理更高效
兼容性 极高,几乎所有系统和嵌入式设备 Windows/Mac/Linux(需驱动或新版本)
目录结构 限制根目录条目数(FAT12/16),FAT32 改进 几乎无限制,适合大文件夹
错误处理 容易碎片化,无日志,易损坏 更现代的簇分配算法,容错略好,但仍无日志
文件名编码 短文件名 8.3 + 可选 VFAT 长文件名 UTF-16 文件名,支持长文件名
用途 小容量闪存、嵌入式、相机、老设备 大容量 SD 卡、U盘、外置存储、大文件

正常TF卡


1|ceres-c3:/ $ mount | grep exfat
/dev/block/vold/public:179,65 on /mnt/media_rw/6CB2-AB67 type exfat (rw,dirsync,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,fmask=0007,dmask=0007,allow_utime=177777,iocharset=utf8,errors=remount-ro)


ceres-c3:/ # blkid /dev/block/vold/public:179,65
/dev/block/vold/public:179,65: LABEL="android" UUID="6CB2-AB67" TYPE="exfat"

09-29 18:10:46.226  1708  4393 D vold    : /system/bin/blkid
09-29 18:10:46.226  1708  4393 D vold    :     -c
09-29 18:10:46.226  1708  4393 D vold    :     /dev/null
09-29 18:10:46.226  1708  4393 D vold    :     -s
09-29 18:10:46.226  1708  4393 D vold    :     TYPE
09-29 18:10:46.226  1708  4393 D vold    :     -s
09-29 18:10:46.226  1708  4393 D vold    :     UUID
09-29 18:10:46.226  1708  4393 D vold    :     -s
09-29 18:10:46.226  1708  4393 D vold    :     LABEL
09-29 18:10:46.226  1708  4393 D vold    :     /dev/block/vold/public:179,65
09-29 18:10:46.390  1708  4393 D vold    : /dev/block/vold/public:179,65: LABEL="android" UUID="6CB2-AB67" TYPE="exfat" 

异常TF卡


09-29 18:07:09.764  1708  8708 D vold    : /system/bin/blkid
09-29 18:07:09.764  1708  8708 D vold    :     -c
09-29 18:07:09.764  1708  8708 D vold    :     /dev/null
09-29 18:07:09.765  1708  8708 D vold    :     -s
09-29 18:07:09.765  1708  8708 D vold    :     TYPE
09-29 18:07:09.765  1708  8708 D vold    :     -s
09-29 18:07:09.765  1708  8708 D vold    :     UUID
09-29 18:07:09.765  1708  8708 D vold    :     -s
09-29 18:07:09.765  1708  8708 D vold    :     LABEL
09-29 18:07:09.765  1708  8708 D vold    :     /dev/block/vold/public:179,65
09-29 18:07:09.797  1708  8708 D vold    : /dev/block/vold/public:179,65: LABEL="Lenovo" UUID="0B75-114C" TYPE="vfat"

TF卡大量视频文件fsck.exfat导致开机缓慢问题

rk3568 耗时 12s


2025-10-17 15:30:02.075   162-264   vold                    vold                                 D  /dev/block/vold/public:179,1: LABEL="android" UUID="FDCA-7843" TYPE="exfat" 
2025-10-17 15:30:02.076   162-264   vold                    vold                                 D  /system/bin/fsck.exfat
2025-10-17 15:30:02.076   162-264   vold                    vold                                 D      -y
2025-10-17 15:30:02.076   162-264   vold                    vold                                 D      /dev/block/vold/public:179,1
2025-10-17 15:30:14.436   162-264   vold                    vold                                 D  exfatprogs version : 1.2.9
2025-10-17 15:30:14.436   162-264   vold                    vold                                 D  /dev/block/vold/public:179,1: clean. directories 91, files 60222

2025-10-17 15:30:14.437   162-264   vold                    vold                                 I  Check OK

A133 耗时57秒, 接近一分钟而且是阻塞了vold主线程


2025-10-17 12:59:26.387  1716-1716  vold                    vold                                 D  /dev/block/vold/public:179,65: LABEL="android" UUID="FDCA-7843" TYPE="exfat" 
2025-10-17 12:59:26.387  1716-1716  vold                    vold                                 D  
2025-10-17 12:59:26.391  1716-1716  vold                    vold                                 D  /system/bin/fsck.exfat
2025-10-17 12:59:26.391  1716-1716  vold                    vold                                 D      -y
2025-10-17 12:59:26.391  1716-1716  vold                    vold                                 D      /dev/block/vold/public:179,65
2025-10-17 13:00:23.398  1716-1716  vold                    vold                                 D  exfatprogs version : 1.2.9
2025-10-17 13:00:23.398  1716-1716  vold                    vold                                 D  
2025-10-17 13:00:23.398  1716-1716  vold                    vold                                 D  /dev/block/vold/public:179,65: clean. directories 96, files 60228
2025-10-17 13:00:23.398  1716-1716  vold                    vold                                 D  

2025-10-17 13:00:23.399  1716-1716  vold                    vold                                 I  Check OK

TF卡诊断流程

查看挂载状态


ceres-c3:/ # cat /proc/mounts | grep -E "vold"
/dev/block/vold/public:179,65 /mnt/media_rw/40F3-8374 exfat ro,dirsync,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,fmask=0007,dmask=0007,
allow_utime=177777,iocharset=utf8,errors=remount-ro 0 0

查“出生证明”(判断是不是山寨、劣质卡)


# 逐条执行查看
cat /sys/class/mmc_host/mmc1/mmc1:0001/name      # 查型号(你测出来是正品江波龙 SD)
cat /sys/class/mmc_host/mmc1/mmc1:0001/date      # 查生产日期
cat /sys/class/mmc_host/mmc1/mmc1:0001/serial    # 查唯一的芯片序列号
cat /sys/class/mmc_host/mmc1/mmc1:0001/manfid    # 查厂商ID(0x0000fe 代表江波龙)

>cat /sys/class/mmc_host/mmc1/mmc1:0001/name
SD
>cat /sys/class/mmc_host/mmc1/mmc1:0001/date
10/2025
>cat /sys/class/mmc_host/mmc1/mmc1:0001/serial
0x00001b46
>cat /sys/class/mmc_host/mmc1/mmc1:0001/manfid
0x0000fe

查硬件底层健康度(读取状态寄存器)


>cat /sys/class/mmc_host/mmc1/mmc1:0001/ssr
000000000800000004049000080a190a000800000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000

纯检测模式:抓取具体损坏的文件(不破坏现场)


# 先强行释放挂载(避免提示设备忙)
vdc volume unmount public:179,65 force

# 纯检测不修复
fsck.exfat -n /dev/block/vold/public:179,65

翻看内核底层日志(查有没有“硬坏道”)


>dmesg | grep -i -E "mmcblk1|exfat|FAT-fs"
[ 1.134544] mmcblk1: mmc1:0001 SD 116 GiB
[ 1.136970] mmcblk1: p1
[ 1.241140] FAT-fs (mmcblk0p16): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[ 1.258641] FAT-fs (mmcblk0p16): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[ 1.551017] FAT-fs (mmcblk0p16): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[ 14.448909] exFAT-fs (mmcblk1p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[ 14.776397] sdcardfs: mounted on top of /mnt/media_rw/40F3-8374 type exfat
[ 20.717876] exFAT-fs (mmcblk1p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[ 21.148993] sdcardfs: mounted on top of /mnt/media_rw/40F3-8374 type exfat
[ 63.201232] exFAT-fs (mmcblk1p1): error, found bogus dentry(176) beyond unused empty group(174) (start_clu : 33, cur_clu : 33)
[ 63.201283] exFAT-fs (mmcblk1p1): Filesystem has been set read-only

诊断结论

  • 崩溃现场还原:在开机第 63 秒时,有应用(或者是系统)正在高频读取或写入 TF 卡。内核在解析文件目录时,在簇(Cluster)编号 33 的地方,发现了一个 bogus dentry(伪造的/错乱的目录项)。
  • 通俗解释:文件系统里的“索引目录”彻底被烧糊涂了。系统本来以为这是一个没人用的空物理组(empty group 174),结果走过去一看,里面竟然塞了一个莫名其妙的未知文件标记(dentry 176)。
  • 连锁反应:由于目录结构已经处于“完全精神分裂”的状态,Linux 内核为了防止应用继续写入导致卡内其他完好的数据被乱写覆盖,立刻执行了终极防御命令:Filesystem has been set read-only(文件系统已被强行设为只读)。

卡绝对没有物理报废:注意到整个崩溃日志里,没有出现任何类似 I/O error, dev mmcblk1 的底层硬件报错。这意味着江波龙这张卡的硬件颗粒、金手指、闪存主控全部是健康的。

确诊结果:这是最典型的“因断电引发的文件系统元数据大面积错位”。由于你们之前跳过了开机 fsck 自检(日志第 14 秒和第 20 秒,系统疯狂警告 Please run fsck,但被系统无视了),卡带着内伤强行挂载运行。直到开机第 63 秒,App 踩中了这块“错位的索引雷区”,内核直接把卡锁死成了只读。

问题发生的原因


exFAT-fs (mmcblk1p1): error, found bogus dentry(176) beyond unused empty group(174) (start_clu : 33, cur_clu : 33)

核心元凶:高频写入时突发剧烈断电(90% 的现场死因)**

  • 底层逻辑:当你的视频录制 App(比如 /WIFIPC/ 路径下的那些 .mp4 文件)正在往 TF 卡里疯狂写数据时,exFAT 文件系统为了提高效率,会使用一种叫 分配位图(Allocation Bitmap) 的机制。
  • 崩溃瞬间:系统在“分配位图”里把第 174 号组(Group 174)标记为了 unused/empty(没人使用的空白物理区)。但在写入真正的目录结构(Dentry)时,断电突然发生。此时,负责记录文件名字和位置的目录树(Dentry 176)已经抢先一步被写入了物理颗粒,而“分配位图”还没来得及更新。
  • 内核开机踩雷:下次开机,内核走到第 33 号簇(start_clu : 33)去读取目录。它先看账本总则:“嗯,174号组是一片空白荒地。” 结果一迈腿走进去,竟然一头撞上了一个已经存在且有效的目录标记(Dentry 176)。内核直接懵了:“明明账本说这里是空的,为什么里面会凭空伪造(bogus)出来一个文件目录?” 为了防止数据被交叉覆盖,Linux 选择立刻熔断锁死。

软件层的“多线程并发写入冲突”(App 代码内伤)

  • 底层逻辑:Android 的 sdcardfs(或者 MediaProvider)作为一个中间层,挂载在 exFAT 之上。如果你们的业务 App 开启了多个线程,同时对同一个文件夹进行极高频的创建、删除、写入操作(例如一边录像分段,一边疯狂删旧文件)。
  • 崩溃现场:Linux 内核的文件系统驱动在内存中缓存了 VFS(虚拟文件系统)树。如果高并发写入导致内存中的缓存还未来得及同步到 TF 卡的物理 FAT 表上,驱动在擦除一个 Group 的同时,另一个线程又在这个 Group 的边缘写入了新目录。这种软件同步时间差,就会在硬件层面上留下一个“账本对不上”的残影(bogus dentry)。

内核 exFAT 驱动版本过低或存在 Bug

  • 底层逻辑:老旧的 Android 固件(特别是有些板卡厂沿用了很多年前的 Linux 4.x 或 5.x 内核基线),其内置的 exfat 驱动并不是微软官方后来开源的那套最新驱动,而是早期的社区逆向版或老版本驱动。
  • 崩溃现场:老版本驱动在处理大容量(如 128GB)大文件簇边界(Cluster Boundary)的计算时,存在某些临界值 Bug(特别是当卡内碎片过多,文件大小跨越 Cluster 边界时)。驱动自己算错了一个偏移量,误把一个有效的目录项当成了“越界”数据,自己把自己吓死,从而报错锁死。

闪存卡主控的“垃圾回收(GC)延迟”与掉电延迟

  • 底层逻辑:TF 卡内部有一个极其微小的电脑芯片,叫 FTL(闪存转换层)。当安卓向卡内写入数据时,卡片内部其实在悄悄地做“擦除、移动、垃圾回收”等高负荷动作。
  • 崩溃现场:如果大屏突然断电,虽然板卡上的电容让主控把最后一批数据强行写进了芯片,但由于卡片内部的 FTL 账本更新(Block 映射)和安卓系统的 exFAT 账本更新产生了微秒级的时间差,导致物理上数据写进去了,而 exFAT 认为没写完;或者反过来,从而在硬件层面上固化了这个逻辑死锁。

损坏模拟

dmesg | grep -i -E “mmcblk|exfat|bogus|read-only|fsck” fsck.exfat -n /dev/block/vold/public:179,65

模拟TF卡损坏情形一


# 1. 找到块设备
cat /proc/mounts | grep vold

# 2. 卸载
sm unmount public:179,65

# 3. 用 dd 向 exfat 超级块区域写入随机数据(前 512 字节是 boot sector)
dd if=/dev/urandom of=/dev/block/vold/public:179,65 bs=512 count=1 conv=notrunc

# 4. 挂载回来(此时内核应该会报错)
sm mount public:179,65

模拟TF卡损坏情形二


sm unmount public:179,65

# 跳过超级块,直接破坏 FAT 表区域(通常在偏移 512KB 附近)
dd if=/dev/zero of=/dev/block/vold/public:179,65 bs=512 count=4 seek=1024 conv=notrunc

sm mount public:179,65
# dmesg 里应该能看到 bogus dentry / read-only 的报错

模拟断电


# 往卡里高频写入数据的同时直接 reboot -f(强制重启,不 sync)
dd if=/dev/zero of=/sdcard/test_write bs=1M & reboot -f

TF 卡性修复


# 1. 解锁挂载:利用 sm 工具强行卸载该卷,释放文件锁
sm unmount public:179,65

# 2. 精准外科手术:用 exfat 专用工具去修复内核日志里报错的 "bogus dentry"
# -p 参数代表全自动无损修复,不询问
fsck.exfat -p /dev/block/vold/public:179,65

# 3. 重新上线:修复完成后,将卡重新挂载回系统
sm mount public:179,65

先卸载


sm unmount public:179,65

修复


ceres-c3:/ # fsck.exfat -p /dev/block/vold/public:179,65                                                                                                                                           
exfatprogs version : 1.2.9
ERROR: /WIFIPC/037a0002009e366b83ef/20260429/202604290845.mp4: more clusters are allocated. truncate to 917504 bytes at 0xd39fd0600. Truncate (y/N)? y
ERROR: /WIFIPC/037a0002009e325e79ff/20260521/202605211623.mp4: more clusters are allocated. truncate to 393216 bytes at 0x7beb80. Truncate (y/N)? y
/dev/block/vold/public:179,65: clean. directories 106, files 76242
/dev/block/vold/public:179,65: files corrupted 0, files fixed 2

挂载


sm mount public:179,65