Android 4.4.2 exfat 移植
android 4.4.2 exfat 移植
android原生的平台不支持ntfs和exfat格式的文件,但是linux已经有相应的开源代码,因此只需找到相应的将其移植到android上即可。
我目前使用的系统是android 4.4.2的,系统里已经集成了对ntfs文件系统的支持。所以我现在要做的就是将exfat格式的文件系统移植过来。
基本概念
exfat(extended file allocation table),又名fat64,是一种能特别适合于闪存的文件系统,可支持单个文件超过4gb的大小。
fuse 用户空间文件系统(filesystem in userppace)是操作系统中的概念,指完全在用户态实现的文件系统。目前linux通过内核模块对此进行支持。
上面是基于fuse做的exfat文件系统的支持,还有一种是exfat-nofuse的模式,由于时间原因没有去实践了,等以后有机会再去尝试下。感兴趣的同学可以自行去研究下看可不可行。
风骚实战
第一步:下载exfat相关代码并将exfat源码导入external目录下并编译通过
我这里是使用别人开源的在android平台上的源码,exfat有官方源码,但是要在android平台上编译通过还需要修改若干文件,这里我就取巧了,直接用别人整理好的。代码下载,我现在下载的版本。但是这个源码下载下来还是有编译错误。我做的调整如下:
增加 external/exfat/android.mk
local_path := $(call my-dir) include \ $(local_path)/fuse/android.mk \ $(local_path)/exfat/android.mk \
修改 external/exfat/fuse/android.mk
local_path := $(call my-dir) include $(clear_vars) local_cflags := -o2 -g -w -wall -d_largefile_source -d_file_offset_bits=64 -dhave_config_h -dfuse_use_version=26 local_src_files := \ buffer.c \ cuse_lowlevel.c \ fuse.c \ fuse_kern_chan.c \ fuse_loop.c \ fuse_loop_mt.c \ fuse_lowlevel.c \ fuse_mt.c fuse_opt.c \ fuse_session.c \ fuse_signals.c \ helper.c \ mount.c \ mount_util.c \ ulockmgr.c local_c_includes := \ $(local_path)/include local_system_shared_libraries:= libc libcutils local_ldflags += -ldl local_module := libfuse-exfat local_module_tags := optional include $(build_static_library)
修改 external/exfat/exfat/android.mk
exfat_root := $(call my-dir) local_path := $(call my-dir) links := fsck.exfat mkfs.exfat include $(clear_vars) exfat_cflags := -o2 -g -w -wall -d_largefile_source -d_file_offset_bits=64 -dhave_config_h \ -wall -o2 -std=c99 \ -d__glibc__ \ -d_file_offset_bits=64 \ -dalways_use_sync_option=1 \ -duse_transitional_lfs=1 \ -i$(exfat_root)/libexfat \ -i$(exfat_root)/../fuse/include local_module := mount.exfat local_src_files := main.c local_static_libraries += libexfat_mount libexfat_fsck libexfat_mkfs libexfat_dump libexfat_label local_static_libraries += libexfat libfuse-exfat local_ldflags += -ldl include $(build_executable) symlinks := $(addprefix $(target_out)/bin/,$(links)) $(symlinks): exfat_binary := $(local_module) $(symlinks): $(local_installed_module) $(local_path)/android.mk @echo "symlink: $@ -> $(exfat_binary)" @mkdir -p $(dir $@) @rm -rf $@ $(hide) ln -sf $(exfat_binary) $@ all_default_installed_modules += $(symlinks) include $(exfat_root)/libexfat/android.mk include $(exfat_root)/fuse/android.mk include $(exfat_root)/mkfs/android.mk include $(exfat_root)/fsck/android.mk include $(exfat_root)/dump/android.mk include $(exfat_root)/label/android.mk
将上面三个android.mk文件修改好后,就可以编译通过啦。同时它会生成fsck.exfat、mkfs.exfat和 mount.exfat三个可执行bin文件。fsck.exfat用于检测文件系统格式是否是exfat,mkfs.exfat将文件系统格式化,mount.exfat将exfat文件系统挂载起来。将生成的bin文件push到android设备中,直接执行mount.exfat devicepath mountpoint,将exfat文件格式的系统挂载到android 对应的可访问目录下。这样就可以访问exfat文件格式的u盘了。这一步是为了测试我们的exfat源码是否可以识别和挂载exfat格式的u盘。测试通过我们就可以执行第二步,实现exfat格式的u盘自动挂载。
第二步:实现拔插exfat文件格式的u盘自动挂载
要想实现u盘自动挂载,需要修改system/vold/volume.cpp文件。因为我的系统已经实现了ntfs文件系统的自动挂载,所以我只要依葫芦画瓢就好了。
首先,在system/vold/目录下,添加exfat.h和exfat.cpp文件,代码如下:
exfat.h
#ifndef _exfat_h #define _exfat_h #include class exfat { public: static int check(const char *fspath); static int domount(const char *fspath, const char *mountpoint, bool ro, bool remount, bool executable, int owneruid, int ownergid, int permmask, bool createlost); }; #endif
exfat.cpp
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define log_tag "vold" #include #include #include #include "exfat.h" #include "voldutil.h" static char exfat_fix_path[] = "/system/bin/fsck.exfat"; static char exfat_mount_path[] = "/system/bin/mount.exfat"; int exfat::check(const char *fspath) { if (access(exfat_fix_path, x_ok)) { slogw("skipping fs checks\n"); return 0; } int rc = 0; int status; const char *args[4]; /* we first use -n to do ntfs detection */ args[0] = exfat_fix_path; args[1] = fspath; args[2] = null; rc = android_fork_execvp(array_size(args), (char **)args, &status, false, true); if (rc) { errno = enodata; return -1; } if (!wifexited(status)) { errno = enodata; return -1; } status = wexitstatus(status); switch(status) { case 0: slogi("exfat filesystem check completed ok"); break; default: sloge("filesystem check failed (unknown exit code %d)", status); errno = eio; return -1; } return 0; } int exfat::domount(const char *fspath, const char *mountpoint, bool ro, bool remount, bool executable, int owneruid, int ownergid, int permmask, bool createlost) { int rc; int status; char mountdata[255]; const char *args[6]; /* * note: this is a temporary hack. if the sampling profiler is enabled, * we make the sd card world-writable so any process can write snapshots. * * todo: remove this code once we have a drop box in system_server. */ char value[property_value_max]; property_get("persist.sampling_profiler", value, ""); if (value[0] == '1') { slogw("the sd card is world-writable because the" " 'persist.sampling_profiler' system property is set to '1'."); permmask = 0; } sprintf(mountdata, "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o," "shortname=mixed,nodev,nosuid,dirsync", owneruid, ownergid, permmask, permmask); if (!executable) strcat(mountdata, ",noexec"); if (ro) strcat(mountdata, ",ro"); if (remount) strcat(mountdata, ",remount"); slogd("mounting ntfs with options:%s\n", mountdata); args[0] = exfat_mount_path; args[1] = "-o"; args[2] = mountdata; args[3] = fspath; args[4] = mountpoint; args[5] = null; rc = android_fork_execvp(array_size(args), (char **)args, &status, false, true); if (rc && errno == erofs) { sloge("%s appears to be a read only filesystem - retrying mount ro", fspath); strcat(mountdata, ",ro"); rc = android_fork_execvp(array_size(args), (char **)args, &status, false, true); } if (!wifexited(status)) { return rc; } if (rc == 0 && createlost) { char *lost_path; asprintf(&lost_path, "%s/lost.dir", mountpoint); if (access(lost_path, f_ok)) { /* * create a lost.dir in the root so we have somewhere to put * lost cluster chains (fsck_msdos doesn't currently do this) */ if (mkdir(lost_path, 0755)) { sloge("unable to create lost.dir (%s)", strerror(errno)); } } free(lost_path); } return rc; }
然后,在android.mk中加入exfat.cpp
common_src_files := \ ... ntfs.cpp \ exfat.cpp \ ...
最后,在volume.cpp中加入相应的代码
... #include "exfat.h" ... int volume::mountvol() { ... for (i = 0; i < n; i++) { ... int ntfs = 0; int exfat = 0; //add by steven if (fat::check(devicepath)) { if (errno == enodata) { slogw("%s does not contain a fat filesystem\n", devicepath); if (fat::domount(devicepath, getmountpoint(), false, false, false, aid_media_rw, aid_media_rw, 0002, true)) { /* try the ntfs filesystem */ if (!ntfs::check(devicepath)) { ntfs = 1; slogi("%s contain a ntfs filesystem\n", devicepath); goto mnt; } /* try the exfat filesystem */ else if (!exfat::check(devicepath)) { //add by steven exfat = 1; slogi("%s contain a exfat filesystem\n", devicepath); goto mnt; } else { if (extfs::domount(devicepath, getmountpoint(), false, false, aid_media_rw, aid_media_rw, 0002)) { sloge("%s failed to mount via extfs (%s)\n", devicepath, strerror(errno)); continue; } else { goto mounted; } } } else { goto mounted; } } errno = eio; /* badness - abort the mount */ sloge("%s failed fs checks (%s)", devicepath, strerror(errno)); setstate(volume::state_idle); return -1; } mnt: errno = 0; int gid; if (ntfs) { if (ntfs::domount(devicepath, getmountpoint(), false, false, false, aid_media_rw, aid_media_rw, 0002, true)) { sloge("%s failed to mount via ntfs (%s)\n", devicepath, strerror(errno)); continue; } } else if (exfat) { //add by steven if (exfat::domount(devicepath, getmountpoint(), false, false, false, aid_media_rw, aid_media_rw, 0002, true)) { sloge("%s failed to mount via exfat (%s)\n", devicepath, strerror(errno)); continue; } } else if (fat::domount(devicepath, getmountpoint(), false, false, false, aid_media_rw, aid_media_rw, 0002, true)) { sloge("%s failed to mount via vfat (%s)\n", devicepath, strerror(errno)); continue; } mounted: extractmetadata(devicepath); if (providesasec && mountasecexternal() != 0) { sloge("failed to mount secure area (%s)", strerror(errno)); umount(getmountpoint()); setstate(volume::state_idle); return -1; } char service[64]; snprintf(service, 64, "fuse_%s", getlabel()); property_set("ctl.start", service); setstate(volume::state_mounted); mcurrentlymountedkdev = devicenodes[i]; return 0; } sloge("volume %s found no suitable devices for mounting :(\n", getlabel()); setstate(volume::state_idle); return -1; }
代码中exfat相关的都是添加的部分,主要做的事情就是检测设备节点是否是exfat文件格式,如果是就挂载它。
第三步:将exfat加入系统中编译
在device/xxx/yyy.mk中加入exfat模块。这样系统编译的时候,会把exfat相关的文件编译进系统。
注:这里的xxx/yyy请根据自己的项目来决定加在哪个mk文件中。
# ntfs-3g binary product_packages += \ ntfs-3g \ ntfsfix # exfat binary product_packages += \ mount.exfat
上一篇: Android消息机制解析
推荐阅读
-
三方移植:小米MIX 2/2S Android 10刷机包发布下载
-
Android8. 0开发之msensor移植
-
解析libcurl在android下的移植、编译与测试
-
10年前的三星Galaxy SⅡ:被开发者成功移植了Android 11系统
-
Android开发_mDNS移植Android系统方案介绍
-
Android 4.4.2 exfat 移植
-
msm8953 android8.1平台GT9xx移植
-
FT5X06 如何应用在10寸电容屏(linux-3.5电容屏驱动简析;移植10寸电容屏驱动到Android4.2)
-
快速解决Android平台移植ffmpeg的一些问题
-
ubuntu移植FFmpeg到Android平台