Android 4.4.2插入exFAT格式U盘识别及加载的解决方案
简介
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平台上编译通过还需要修改若干文件,这里我就取巧了,直接用别人整理好的库文件下载。但是这个源码已经修正了编译时的错误,直接可以开始配置Vold挂载的源码修改了。
第二步:实现拔插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 binaryPRODUCT_PACKAGES += \ ntfs-3g \ ntfsfix# exfat binaryPRODUCT_PACKAGES += \ mount.exfat
更多相关文章
- Android中使用pull解析器操作xml文件的解决办法
- rdp文件和vnc软件
- Android AIDL分析例子源码
- 在eclipse中查看android源码
- Android so 文件进阶 从dlsym()源码看android 动态链接过程
- Android使用JNI生成.so文件并调用(使用传统生成.h的方法)
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码
- Android消息循环机制源码深入理解
- Android条码扫描二维码扫描——ZXing android 源码简化