Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1490254
  • 博文数量: 267
  • 博客积分: 3010
  • 博客等级: 少校
  • 技术积分: 3089
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 17:09
个人简介

尊天命,尽人事

文章分类

全部博文(267)

文章存档

2017年(6)

2015年(4)

2014年(27)

2013年(52)

2012年(59)

2011年(120)

分类: 嵌入式

2011-11-10 20:41:08

采用 UBIFS 制作 Android 的文件系统

  Andriod 默认使用的是 YAFFS2 文件系统。相对于 YAFFS2 文件系统,UBIFS 是新一代的 Flash 文件系统,其设计以及性能都优越于 YAFFS2,特别是工作在大页 MLC NAND FLASH 上面时,读写速度比 YAFFS2 高出很多,同时 UBIFS 支持压缩,系统的高压缩率也为生产安装提高效率,如采用 YAFFS2 生成的 system.img 有120M,当采用 UBIFS 后镜像只有70~80M。可以使用下面的命令简单测试一下 UBIFS 的读写速度,Android 提供的 Toolbox 不支持下面的命令,你可以把 Busybox 装上再测试。

time dd if=/dev/zero of=/data/test.img bs=1M count=100; time sync
time cp /data/test.img /dev/null; time sync

  采用 UBIFS 制作 Android 的文件系统的详细步骤如下:

  一、准备 mkfs.ubifs 和 ubinize 这两个工具。mkfs.ubifs 用于生成 UBIFS 镜像,ubinize 用于生成 UBI 镜像。这两个工具都包含于 mtd-utils 中,你可以在你的开发主机上把 mtd-utils 这个软件包装上,或者,你可以把 mtd-utils 的源码整合到 Android 的源码中一起编译。

  二、修改 Android 的编译系统,添加生成 UBIFS 文件系统的编译规则。

# build/core/config.mk

# ---------------------------------------------------------------
# Generic tools.

......

MKYAFFS2 := $(HOST_OUT_EXECUTABLES)/mkyaffs2image$(HOST_EXECUTABLE_SUFFIX)
MKUBIFS := $(HOST_OUT_EXECUTABLES)/mkubifs$(HOST_EXECUTABLE_SUFFIX)
UBINIZE := $(HOST_OUT_EXECUTABLES)/ubinize$(HOST_EXECUTABLE_SUFFIX)

# build/core/Makefile

# #################################################################
# Targets for user images
# #################################################################

......

ifeq ($(strip $(TARGET_USERIMAGES_USE_UBIFS)),true)
INTERNAL_FLASH_PAGESIZE := $(shell echo $$(($(BOARD_KERNEL_PAGESIZE))))
INTERNAL_FLASH_PEBSIZE := $(shell echo $$(($(BOARD_FLASH_BLOCK_SIZE))))
INTERNAL_FLASH_LEBSIZE := $(shell echo \
    $$(($(INTERNAL_FLASH_PEBSIZE- 2 * $(INTERNAL_FLASH_PAGESIZE))))

INTERNAL_SYSTEM_PARTITION_LEBCOUNT := $(shell echo \
    $$(($(BOARD_SYSTEMIMAGE_PARTITION_SIZE/ $(INTERNAL_FLASH_PEBSIZE))))
INTERNAL_SYSTEM_PARTITION_SIZE := $(shell echo \
    $$(($(INTERNAL_FLASH_LEBSIZE* $(INTERNAL_SYSTEM_PARTITION_LEBCOUNT))))

INTERNAL_USERDATA_PARTITION_LEBCOUNT := $(shell echo \
    $$(($(BOARD_USERDATAIMAGE_PARTITION_SIZE/ $(INTERNAL_FLASH_PEBSIZE))))
INTERNAL_USERDATA_PARTITION_SIZE := $(shell echo \
    $$(($(INTERNAL_FLASH_LEBSIZE* $(INTERNAL_USERDATA_PARTITION_LEBCOUNT))))

INTERNAL_PERSIST_PARTITION_LEBCOUNT := $(shell echo \
    $$(($(BOARD_PERSISTIMAGE_PARTITION_SIZE/ $(INTERNAL_FLASH_PEBSIZE))))
INTERNAL_PERSIST_PARTITION_SIZE := $(shell echo \
    $$(($(INTERNAL_FLASH_LEBSIZE* $(INTERNAL_PERSIST_PARTITION_LEBCOUNT))))

# $(1): image file
# $(2): volume size
# $(3): volume name
# $(4): output file
define combine-ubinize-ini-file
    @mkdir -p $(dir $(4))
    $(hideecho "[ubifs]" > $(4); \
        echo "mode=ubi" >> $(4); \
        echo "image=$(1)" >> $(4); \
        echo "vol_id=0" >> $(4); \
        echo "vol_size=$(2)" >> $(4); \
        echo "vol_type=dynamic" >> $(4); \
        echo "vol_name=$(3)" >> $(4); \
        echo "vol_flags=autoresize" >> $(4); \
        echo "vol_alignment=1" >> $(4);
endef
else

......

endif

......

# -----------------------------------------------------------------
# system image
#
systemimage_intermediates := \
    $(call intermediates-dir-for,PACKAGING,systemimage)

BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img

INTERNAL_SYSTEMIMAGE_FILES := $(filter $(TARGET_OUT)/%, \
    $(ALL_PREBUILT\
    $(ALL_COPIED_HEADERS\
    $(ALL_GENERATED_SOURCES\
    $(ALL_DEFAULT_INSTALLED_MODULES))

ifeq ($(strip $(TARGET_USERIMAGES_USE_UBIFS)),true)
INTERNAL_SYSTEMUBIFS_ARGS := \
    -r $(TARGET_OUT\
    -m $(INTERNAL_FLASH_PAGESIZE\
    -e $(INTERNAL_FLASH_LEBSIZE\
    -c $(INTERNAL_SYSTEM_PARTITION_LEBCOUNT)

INTERNAL_SYSTEMUBI_ARGS := \
    -p $(INTERNAL_FLASH_PEBSIZE\
    -m $(INTERNAL_FLASH_PAGESIZE)

INTERNAL_SYSTEMUBIFS := $(systemimage_intermediates)/system.ubifs
$(INTERNAL_SYSTEMUBIFS): $(INTERNAL_SYSTEMIMAGE_FILES$(MKUBIFS)
    @mkdir -p $(dir $@)
    $(MKUBIFS$(INTERNAL_SYSTEMUBIFS_ARGS-o $@

INTERNAL_SYSTEMUBICFG := $(systemimage_intermediates)/system.cfg
.PHONY: $(INTERNAL_SYSTEMUBICFG)
$(INTERNAL_SYSTEMUBICFG):
    $(call combine-ubinize-ini-file,$(INTERNAL_SYSTEMUBIFS), \
        $(INTERNAL_SYSTEM_PARTITION_SIZE),system,$@)

INTERNAL_USERIMAGES_DEPS := $(UBINIZE\
                            $(INTERNAL_SYSTEMUBIFS\
                            $(INTERNAL_SYSTEMUBICFG)

## generate a ubifs image
# $(1): output file
define build-systemimage-target
    @echo "Target system fs image: $(1)"
    @mkdir -p $(dir $(1))
    $(UBINIZE-o $(1$(INTERNAL_SYSTEMUBI_ARGS$(INTERNAL_SYSTEMUBICFG)
    $(hidechmod a+r $(1)
endef

else # TARGET_USERIMAGES_USE_UBIFS != true

......

endif # TARGET_USERIMAGES_USE_UBIFS

$(BUILT_SYSTEMIMAGE): $(INTERNAL_SYSTEMIMAGE_FILES$(INTERNAL_USERIMAGES_DEPS)
    $(call build-systemimage-target,$@)

......

# -----------------------------------------------------------------
# data partition image
#
INTERNAL_USERDATAIMAGE_FILES := \
    $(filter $(TARGET_OUT_DATA)/%,$(ALL_DEFAULT_INSTALLED_MODULES))

ifeq ($(strip $(TARGET_USERIMAGES_USE_UBIFS)),true)
userdataimage_intermediates := \
    $(call intermediates-dir-for,PACKAGING,userdataimage)

INTERNAL_USERDATAUBIFS_ARGS := \
    -r $(TARGET_OUT_DATA\
    -m $(INTERNAL_FLASH_PAGESIZE\
    -e $(INTERNAL_FLASH_LEBSIZE\
    -c $(INTERNAL_USERDATA_PARTITION_LEBCOUNT)

INTERNAL_USERDATAUBI_ARGS := \
    -p $(INTERNAL_FLASH_PEBSIZE\
    -m $(INTERNAL_FLASH_PAGESIZE)

INTERNAL_USERDATAUBIFS := $(userdataimage_intermediates)/userdata.ubifs
$(INTERNAL_USERDATAUBIFS): $(INTERNAL_USERDATAIMAGE_FILES$(MKUBIFS)
    @mkdir -p $(dir $@)
    $(MKUBIFS$(INTERNAL_USERDATAUBIFS_ARGS-o $@

INTERNAL_USERDATAUBICFG := $(userdataimage_intermediates)/userdata.cfg
.PHONY: $(INTERNAL_USERDATAUBICFG)
$(INTERNAL_USERDATAUBICFG):
    $(call combine-ubinize-ini-file,$(INTERNAL_USERDATAUBIFS), \
        $(INTERNAL_USERDATA_PARTITION_SIZE),userdata,$@)

INTERNAL_USERIMAGES_DEPS := $(UBINIZE\
                            $(INTERNAL_USERDATAUBIFS\
                            $(INTERNAL_USERDATAUBICFG)

## Generate a ubifs image
define build-userdataimage-target
    $(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)")
    @mkdir -p $(TARGET_OUT_DATA)
    $(UBINIZE-o $(INSTALLED_USERDATAIMAGE_TARGET\
        $(INTERNAL_USERDATAUBI_ARGS$(INTERNAL_USERDATAUBICFG)
    $(hidechmod a+r $(INSTALLED_USERDATAIMAGE_TARGET)
endef

else # TARGET_USERIMAGES_USE_UBIFS != true

......

endif # TARGET_USERIMAGES_USE_UBIFS

BUILT_USERDATAIMAGE_TARGET := $(PRODUCT_OUT)/userdata.img

# We just build this directly to the install location.
INSTALLED_USERDATAIMAGE_TARGET := $(BUILT_USERDATAIMAGE_TARGET)
$(INSTALLED_USERDATAIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS\
                                   $(INTERNAL_USERDATAIMAGE_FILES)
    $(build-userdataimage-target)

......

# -----------------------------------------------------------------
# persist partition image
#
INTERNAL_PERSISTIMAGE_FILES := \
    $(filter $(TARGET_OUT_PERSIST)/%,$(ALL_DEFAULT_INSTALLED_MODULES))

ifeq ($(strip $(TARGET_USERIMAGES_USE_UBIFS)),true)
persistimage_intermediates := \
    $(call intermediates-dir-for,PACKAGING,persistimage)

INTERNAL_PERSISTUBIFS_ARGS := \
    -r $(TARGET_OUT_PERSIST\
    -m $(INTERNAL_FLASH_PAGESIZE\
    -e $(INTERNAL_FLASH_LEBSIZE\
    -c $(INTERNAL_PERSIST_PARTITION_LEBCOUNT)

INTERNAL_PERSISTUBI_ARGS := \
    -p $(INTERNAL_FLASH_PEBSIZE\
    -m $(INTERNAL_FLASH_PAGESIZE)

INTERNAL_PERSISTUBIFS := $(persistimage_intermediates)/persist.ubifs
$(INTERNAL_PERSISTUBIFS): $(INTERNAL_PERSISTIMAGE_FILES$(MKUBIFS)
    @mkdir -p $(dir $@)
    $(MKUBIFS$(INTERNAL_PERSISTUBIFS_ARGS-o $@

INTERNAL_PERSISTUBICFG := $(persistimage_intermediates)/persist.cfg
.PHONY: $(INTERNAL_PERSISTUBICFG)
$(INTERNAL_PERSISTUBICFG):
    $(call combine-ubinize-ini-file,$(INTERNAL_PERSISTUBIFS), \
        $(INTERNAL_PERSIST_PARTITION_SIZE),persist,$@)

INTERNAL_USERIMAGES_DEPS := $(UBINIZE\
                            $(INTERNAL_PERSISTUBIFS\
                            $(INTERNAL_PERSISTUBICFG)

## Generate a ubifs image
define build-persistimage-target
    $(call pretty,"Target persist fs image: $(INSTALLED_PERSISTIMAGE_TARGET)")
    @mkdir -p $(TARGET_OUT_PERSIST)
    $(UBINIZE-o $(INSTALLED_PERSISTIMAGE_TARGET\
        $(INTERNAL_PERSISTUBI_ARGS$(INTERNAL_PERSISTUBICFG)
    $(hidechmod a+r $(INSTALLED_PERSISTIMAGE_TARGET)
endef

else # TARGET_USERIMAGES_USE_UBIFS != true

......

endif # TARGET_USERIMAGES_USE_UBIFS

BUILT_PERSISTIMAGE_TARGET := $(PRODUCT_OUT)/persist.img

# We just build this directly to the install location.
INSTALLED_PERSISTIMAGE_TARGET := $(BUILT_PERSISTIMAGE_TARGET)
$(INSTALLED_PERSISTIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS\
                                  $(INTERNAL_PERSISTIMAGE_FILES)
    $(build-persistimage-target)

  三、修改内核配置,打开 UBIFS 文件系统的支持。如果使用高通平台,需要修改 Nand 控制器的驱动。Nand Flash 是以页面为单位读写的,对 Nand Flash 读写数据之前要进行页面对齐处理,通常驱动会封装好的,但高通的 Nand 控制器驱动没有,所以为了使 UBI 能正常工作,需要修改高通的 Nand 控制器驱动添加页面对齐处理。

Device Drivers   ---> 
    Memory Technology Device(MTDsupport  --->   
        <*> Enable UBI - Unsorted block images  
                 
File systems   ---> 
    Miscellaneous filesystems   --->   
        <*> UBIFS file system support

  四、修改设备的 AndroidBoard.mk 或 BoardConfig.mk,打开生成 UBIFS 格式的文件系统的编译开关,并在生成 boot.img 时添加内核命令行参数 androidboot.ubifs=true

TARGET_USERIMAGES_USE_UBIFS := true

ifeq ($(strip $(TARGET_USERIMAGES_USE_UBIFS)),true)
BOARD_KERNEL_CMDLINE += androidboot.ubifs=true
endif

  五、修改 init 的初始化脚本 system/core/rootdir/init.rc,添加挂载 ubifs 文件系统的动作

on ubi-fs
    mount ubifs ubi@system /system
    mount ubifs ubi@userdata /data nosuid nodev
    mount ubifs ubi@persist /persist nosuid nodev
    mount ubifs ubi@cache /cache nosuid nodev

  六、当检测到内核命令行参数 androidboot.ubifs=true 时触发挂载 ubifs 文件系统的动作

/* system/core/init/init.c */

static unsigned ubifs_enabled = 0;

static void import_kernel_nv(char *name, int in_qemu)
{
    ......
   
    if (!in_qemu)
    {
        ......
       
        } else if (!strcmp(name,"androidboot.emmc")) {
            if (!strcmp(value,"true")) {
                emmc_boot = 1;
            }
        } else if (!strcmp(name,"androidboot.ubifs")) {
            if (!strcmp(value,"true")) {
                ubifs_enabled = 1;
            }
        }
     } else {
        ......
     }
}

static int set_init_properties_action(int nargs, char **args)
{
    ......
   
    property_set("ro.emmc",emmc_boot ? "1" : "0");
    property_set("ro.ubifs",ubifs_enabled ? "1" : "0");
    return 0;
}

int main(int argc, char **argv)
{
    ......
   
    if(emmc_boot{
        action_for_each_trigger("emmc-fs", action_add_queue_tail);
    } else if(ubifs_enabled{
        action_for_each_trigger("ubi-fs", action_add_queue_tail);
    } else {
        action_for_each_trigger("fs", action_add_queue_tail);
    }

    ......
}

  七、修改 init 的内置 mount 命令以支持 ubifs 文件系统的挂载

/* system/core/init/builtins.c */

int do_mount(int nargs, char **args)
{
    ......
   
    if (!strncmp(source, "mtd@", 4)) {
        n = mtd_name_to_number(source + 4);
        if (n < 0{
            return -1;
        }

        sprintf(tmp, "/dev/block/mtdblock%d", n);

        if (wait)
            wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
        if (mount(tmp, target, system, flags, options< 0{
            return -1;
        }

        return 0;
    } else if (!strncmp(source, "ubi@", 4)) {
        n = ubi_attach_mtd(source + 4);
        if (n < 0{
            return -1;
        }

        sprintf(tmp, "/dev/ubi%d_0", n);

        if (wait)
            wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
        if (mount(tmp, target, system, flags, options< 0{
            ubi_detach_dev(n);
            return -1;
        }

        return 0;
    } else if (!strncmp(source, "loop@", 5)) {
        int mode, loop, fd;
        struct loop_info info;

        mode = (flags & MS_RDONLY? O_RDONLY : O_RDWR;
        fd = open(source + 5, mode);
        if (fd < 0{
            return -1;
        }

        for (n = 0; ; n++{
            sprintf(tmp, "/dev/block/loop%d", n);
            loop = open(tmp, mode);
            if (loop < 0{
                return -1;
            }

            /* if it is a blank loop device */
            if (ioctl(loop, LOOP_GET_STATUS, &info< 0 && errno == ENXIO{
                /* if it becomes our loop device */
                if (ioctl(loop, LOOP_SET_FD, fd>= 0{
                    close(fd);

                    if (mount(tmp, target, system, flags, options< 0{
                        ioctl(loop, LOOP_CLR_FD, 0);
                        close(loop);
                        return -1;
                    }

                    close(loop);
                    return 0;
                }
            }

            close(loop);
        }

        close(fd);
        ERROR("out of loopback devices");
        return -1;
    } else {
        if (wait)
            wait_for_file(source, COMMAND_RETRY_TIMEOUT);
        if (mount(source, target, system, flags, options< 0{
            return -1;
        }

        return 0;
    }
}

/* system/core/init/util.h */

int ubi_attach_mtd(const char *name);
int ubi_detach_dev(int dev);

/* system/core/init/util.c */

#define UBI_CTRL_DEV "/dev/ubi_ctrl"
#define UBI_SYS_PATH "/sys/class/ubi"

static int ubi_dev_read_int(int dev, const char *file, int def)
{
    int fd, val = def;
    char path[128], buf[64];

    sprintf(path, UBI_SYS_PATH "/ubi%d/%s", dev, file);
    wait_for_file(path, 5);
    fd = open(path, O_RDONLY);
    if (fd == -1{
        return val;
    }

    if (read(fd, buf, 64> 0{
        val = atoi(buf);
    }

    close(fd);
    return val;
}

int ubi_attach_mtd(const char *name)
{
    int ret;
    int mtd_num, ubi_num;
    int ubi_ctrl, ubi_dev;
    int vols, avail_lebs, leb_size;
    char path[128];
    struct ubi_attach_req attach_req;
    struct ubi_mkvol_req mkvol_req;
   
    mtd_num = mtd_name_to_number(name);
    if (mtd_num == -1{
        return -1;
    }

    ubi_ctrl = open(UBI_CTRL_DEV, O_RDONLY);
    if (ubi_ctrl == -1{
        return -1;
    }

    memset(&attach_req, 0, sizeof(struct ubi_attach_req));
    attach_req.ubi_num = UBI_DEV_NUM_AUTO;
    attach_req.mtd_num = mtd_num;

    ret = ioctl(ubi_ctrl, UBI_IOCATT, &attach_req);
    if (ret == -1{
        close(ubi_ctrl);
        return -1;
    }

    ubi_num = attach_req.ubi_num;
   
    vols = ubi_dev_read_int(ubi_num, "volumes_count", -1);
    if (vols == 0{
        sprintf(path, "/dev/ubi%d", ubi_num);
        ubi_dev = open(path, O_RDONLY);
        if (ubi_dev == -1{
            close(ubi_ctrl);
            return ubi_num;
        }
       
        avail_lebs = ubi_dev_read_int(ubi_num, "avail_eraseblocks", 0);
        leb_size = ubi_dev_read_int(ubi_num, "eraseblock_size", 0);

        memset(&mkvol_req, 0, sizeof(struct ubi_mkvol_req));
        mkvol_req.vol_id = UBI_VOL_NUM_AUTO;
        mkvol_req.alignment = 1;
        mkvol_req.bytes = (long long)avail_lebs * leb_size;
        mkvol_req.vol_type = UBI_DYNAMIC_VOLUME;
        ret = snprintf(mkvol_req.name, UBI_MAX_VOLUME_NAME + 1, "%s", name);
        mkvol_req.name_len = ret;
        ioctl(ubi_dev, UBI_IOCMKVOL, &mkvol_req);
        close(ubi_dev);
    }

    close(ubi_ctrl);
    return ubi_num;
}

int ubi_detach_dev(int dev)
{
    int ret, ubi_ctrl;

    ubi_ctrl = open(UBI_CTRL_DEV, O_RDONLY);
    if (ubi_ctrl == -1{
        return -1;
    }

    ret = ioctl(ubi_ctrl, UBI_IOCDET, &dev);
    close(ubi_ctrl);
    return ret;
}


阅读(7724) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~