Android-vold源码分析之格式化SD卡(10)

作者:gzshun. 原创作品,转载请标明出处!
来源:http://blog.csdn.net/gzshun

本文开始讨论sd卡的格式化功能,平时使用windows操作系统,也经常格式化磁盘。涉及到的

操作有这几步:

1.将分区信息写到硬盘的第一个设备节点的MBR结构中的分区表;

2.格式化分区到指定的文件系统类型。

MBR中存放分区表的位置在446-509,占用了64字节,MBR结构只支持4个主分区,所以

有4个16字节的区域,先简要说明一下MBR的分区表的结构:

《Android-vold源码分析之格式化SD卡(10)》
从这个表格可以看出,相对于446-509的分区表区域,每个主分区的第5个字节存放的是文件
系统标志位,用来识别什么分区,用fdisk工具查看一下,有如下文件系统对应的十六进制标志:

《Android-vold源码分析之格式化SD卡(10)》
若需要读取这些文件系统标志,只需读取MBR的450个位置,占用一个字节大小。

扯得太远了,回到正题,本文是要分析Android格式化sd卡的功能,在格式化部分,涉及到
了系统的一些函数,与vold无关,简单的说明一下即可。
Android系统在格式化sd卡的时候,首先会判断sd卡是否存在分区,如果sd卡不存在分区,
那么需要重新初始化MBR区域,所以上面简要的介绍了MBR结构中分区表的区域。

int Volume::formatVol() {
    if (getState() == Volume::State_NoMedia) {
        errno = ENODEV;
        return -1;
    } else if (getState() != Volume::State_Idle) {
        errno = EBUSY;
        return -1;
    }
    /*如果该分区为卸载,那么格式化失败,返回错误*/
    if (isMountpointMounted(getMountpoint())) {
        SLOGW("Volume is idle but appears to be mounted - fixing");
        setState(Volume::State_Mounted);
        // mCurrentlyMountedKdev = XXX
        errno = EBUSY;
        return -1;
    }

    char devicePath[255];
    dev_t diskNode = getDiskDevice();
    dev_t partNode;

    if (mDebug) {
        SLOGI("Formatting volume %s (%s)", getLabel(), devicePath);
    }
    setState(Volume::State_Formatting);

    if (!mLastMountedKdev) {
        dev_t deviceNodes[2];
        int n = getDeviceNodes(deviceNodes, 2);
        // initialize MBR if no partition, or has multiple partitions
        // but none is selected
        if ((diskNode == deviceNodes[0]) || (n > 1)) {
            sprintf(devicePath, "/dev/block/vold/%d:%d",
                    MAJOR(diskNode), MINOR(diskNode));
            if (initializeMbr(devicePath)) {
                SLOGE("Failed to initialize MBR (%s)", strerror(errno));
                partNode = diskNode; // try to use whole disk
            } else {
                partNode = MKDEV(MAJOR(diskNode), MINOR(diskNode) + 1);
            }
        } else {
            partNode = deviceNodes[0];
        }
    } else {
        partNode = mLastMountedKdev;
    }

    sprintf(devicePath, "/dev/block/vold/%d:%d",
            MAJOR(partNode), MINOR(partNode));

    int ret = Fat::format(devicePath, 0);
    SLOGE_IF(ret, "Failed to format (%s)", strerror(errno));

    setState(Volume::State_Idle);
    return ret;
}

格式化函数两个主要工作交给了initializeMbr和Fat::format函数:

1.initializeMbr函数负责初始化MBR;

2.Fat::format函数负责格式化分区。

先来看initializeMbr函数的初始化工作:

int Volume::initializeMbr(const char *deviceNode) {
    struct disk_info dinfo;

    memset(&dinfo, 0, sizeof(dinfo));

    if (!(dinfo.part_lst = (struct part_info *) malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) {
        SLOGE("Failed to malloc prt_lst");
        return -1;
    }

    memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
    dinfo.device = strdup(deviceNode);
    dinfo.scheme = PART_SCHEME_MBR;
    dinfo.sect_size = 512;
    dinfo.skip_lba = 2048;
    dinfo.num_lba = 0;
    dinfo.num_parts = 1;

    struct part_info *pinfo = &dinfo.part_lst[0];

    pinfo->name = strdup("android_sdcard");
    pinfo->flags |= PART_ACTIVE_FLAG;
    pinfo->type = PC_PART_TYPE_FAT32;
    pinfo->len_kb = -1;

    int rc = apply_disk_config(&dinfo, 0);

    if (rc) {
        SLOGE("Failed to apply disk configuration (%d)", rc);
        goto out;
    }

 out:
    free(pinfo->name);
    free(dinfo.device);
    free(dinfo.part_lst);

    return rc;
}

这里贴出一些重要的结构体:

struct part_info {
    char *name;
    uint8_t flags;
    uint8_t type;
    uint32_t len_kb;       /* in 1K-bytes */
    uint32_t start_lba;    /* the LBA where this partition begins */
};
struct disk_info {
    char *device;
    uint8_t scheme;
    int sect_size;       /* expected sector size in bytes. MUST BE POWER OF 2 */
    uint32_t skip_lba;   /* in sectors (1 unit of LBA) */
    uint32_t num_lba;    /* the size of the disk in LBA units */
    struct part_info *part_lst;
    int num_parts;
};

初始化完成后,将该结构体变量pinfo通过apply_disk_config函数进行设置:

int apply_disk_config(struct disk_info *dinfo, int test)
{
    int fd;
    struct write_list *wr_lst = NULL;
    int rv;

    if (validate_and_config(dinfo, &fd, &wr_lst) != 0) {
        LOGE("Configuration is invalid.");
        goto fail;
    }

    if ((rv = wlist_commit(fd, wr_lst, test)) >= 0)
        rv = test ? 0 : sync_ptable(fd);

    close(fd);
    wlist_free(wr_lst);
    return rv;

fail:
    close(fd);
    if (wr_lst)
        wlist_free(wr_lst);
    return 1;
}

该函数先打开sd卡的设备节点,然后将MBR的初始化信息写到第一个block(512B)中,

这里涉及到非常多函数,不在vold的讨论范围。

写完MBR后,就要对分区进行格式化,要格式化成FAT32格式,Fat::format函数直接调用

系统命令newfs_msdos来格式化新分区,检测磁盘是,Fat::check函数直接调用系统命令

fsck_msdos来检测分区。

最后格式化完成功,通知Framework,sd卡处于空闲状态:

setState(Volume::State_Idle);

然后,Framework又要重复挂载和卸载的操作了。

下篇文章介绍Android系统与电脑的连接,OTG功能,全称on-the-go。

待续。。

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/gzshun/article/details/7170017
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞