您的位置:首页 > 移动开发 > Android开发

采用 UBIFS 制作 Android 的文件系统

2013-07-08 16:12 381 查看
采用 UBIFS 制作 Android 的文件系统
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))

$(hide)

echo
"[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)

$(hide)

chmod 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)

$(hide)

chmod 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)

$(hide)

chmod 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(MTD)

support --->

<*> 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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: