网上看了一圈,关于Android移植exfat支持的文章大多停留在Android 4.x,Android 6.0或7.0以上的基本空缺,所以决定自己写一篇,本文实践环境是MTK的Android 7.0系统。

部分代码参考了wince_lover的移植指南,感谢:

https://blog.csdn.net/wince_lover/article/details/80426796

一、关于fuse和no-fuse

简单概括,fuse是用户空间层的文件系统,no-fuse是位于内核驱动层的。

实际上,一开始是希望直接在内核层支持exfat。根据github上star最多的项目 https://github.com/dorimanx/exfat-nofuse,做完了移植后,插入exfat格式的SD卡也确实能挂载,但是只要开始读写SD卡,就会报'sector_read: out of range error'的错误,然后就被remount成ro模式。这在项目的issues中也有类似的讨论https://github.com/dorimanx/exfat-nofuse/issues/131

由于没能解决这个问题,所以最后还是放弃了no-fuse的方式,转为使用fuse方式。

二、fuse方式移植exfat过程

1.下载exfat相关代码,代码地址,https://github.com/Lurker00/Android-fs

只需下载其中的jni/external/exfat 和 jni/external/fuse
拷贝exfat目录到android源码中external目录下,
拷贝fusefuse目录到android源码中external目录下,并改名为libfuse_forexfat

2.修改libfuse_forexfat下的Android.mk

LOCAL_MODULE := libfuse

修改为 LOCAL_MODULE := libfuse_forexfat

3.修改exfat下的Android.mk
-I$(EXFAT_ROOT)/../fuse/include  修改为  -I$(EXFAT_ROOT)/../libfuse_forexfat/include
LOCAL_STATIC_LIBRARIES += libexfat libfuse  修改为  LOCAL_STATIC_LIBRARIES += libexfat libfuse_forexfat
然后在include $(BUILD_EXECUTABLE)之后加上以下代码

LINKS := fsck.exfat mkfs.exfat
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)
这样编译以后,会在out目录system/bin下生成可执行文件mount.exfat,另外有两个指向它的软连接fsck.exfat和mkfs.exfat

4.接下来做sd卡的自动挂载修改

system/vold/fs/Exfat.cpp

static const char* kMkfsPath = "/system/bin/mkexfat";
static const char* kFsckPath = "/system/bin/exfatfsck";
修改为
static const char* kMkfsPath = "/system/bin/mkfs.exfat";
static const char* kFsckPath = "/system/bin/fsck.exfat";
static const char* exfatMountPath = "/system/bin/mount.exfat";

然后修改exfat.cpp的Mount函数,注释其中的 rc = mount(c_source, c_target, "exfat", flags, mountData);
并替换为如下代码,不使用mount函数,直接用上面编译出来的mount.exfat进行挂载

//leung modify
//rc = mount(c_source, c_target, "exfat", flags, mountData);
std::string exec;
exec = exfatMountPath;
exec = exec + " " + c_source + " " + c_target;
rc = system(exec.c_str());
if (rc == 0) {

SLOGI("exfat Filesystem mounted OK");

} else {

SLOGE("exfat Filesystem mounted failed");
errno = EROFS;

}

//add end

5.修改系统中的blkid工具

该工具会在挂载之前调用,获取sd卡的uuid等信息,需要先让它支持exfat

blkid这个工具位于Android工程的external/e2fsprogs/lib/blkid/

查看github上项目https://github.com/tytso/e2fsprogs

其中commit a850bc56e0aa7370b7e0e81d8dbab93841829f98 已有支持exfat的提交记录,我们把该记录的修改导出来作为patch
加入到android工程的代码中即可

commit a850bc56e0aa7370b7e0e81d8dbab93841829f98
Author: liminghao <liminghao@xiaomi.com>
Date:   Wed Mar 1 17:54:42 2017 +0800AOSP: blkid: add support to recognize exfat to blkid.we can now identify exfat filesystem.Change-Id: I870e59a14b6bcd8b45562cdd02c2502d60a9eeffSigned-off-by: liminghao <liminghao@xiaomi.com>From AOSP commit: 1206f6d8c5ed47ba19cfc30a19dba51fcd2cd5cbSigned-off-by: Theodore Ts'o <tytso@mit.edu>diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c
index 66ecbc4..fae74a7 100644
--- a/lib/blkid/probe.c
+++ b/lib/blkid/probe.c
@@ -106,7 +106,6 @@ static int check_mdraid(int fd, unsigned char *ret_uuid)if (blkid_llseek(fd, offset, 0) < 0 ||read(fd, buf, 4096) != 4096)return -BLKID_ERR_IO;
-/* Check for magic number */if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4))return -BLKID_ERR_PARAM;
@@ -330,7 +329,7 @@ static int probe_ext4dev(struct blkid_probe *probe,EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)return -BLKID_ERR_PARAM;- /*
+  /** If the filesystem does not have a journal and ext2 and ext4* is not present, then force this to be detected as an* ext4dev filesystem.
@@ -374,7 +373,7 @@ static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id,EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)return -BLKID_ERR_PARAM;-    /*
+  /** If the filesystem does not have a journal and ext2 is not* present, then force this to be detected as an ext2* filesystem.
@@ -452,7 +451,7 @@ static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id,EXT2_FEATURE_INCOMPAT_UNSUPPORTED))return -BLKID_ERR_PARAM;-   /*
+  /** If ext2 is not present, but ext4 or ext4dev are, then* disclaim we are ext2*/
@@ -1403,6 +1402,99 @@ static int probe_f2fs(struct blkid_probe *probe,return 0;}+static uint64_t exfat_block_to_offset(const struct exfat_super_block *sb,
+                                      uint64_t block)
+{
+    return block << sb->block_bits;
+}
+
+static uint64_t exfat_cluster_to_block(const struct exfat_super_block *sb,
+                                       uint32_t cluster)
+{
+    return sb->cluster_block_start +
+            ((uint64_t)(cluster - EXFAT_FIRST_DATA_CLUSTER) << sb->bpc_bits);
+}
+
+static uint64_t exfat_cluster_to_offset(const struct exfat_super_block *sb,
+                                        uint32_t cluster)
+{
+    return exfat_block_to_offset(sb, exfat_cluster_to_block(sb, cluster));
+}
+
+static uint32_t exfat_next_cluster(struct blkid_probe *probe,
+                                   const struct exfat_super_block *sb,
+                                   uint32_t cluster)
+{
+    uint32_t *next;
+    uint64_t offset;
+
+    offset = exfat_block_to_offset(sb, sb->fat_block_start)
+            + (uint64_t) cluster * sizeof (cluster);
+    next = (uint32_t *)get_buffer(probe, offset, sizeof (uint32_t));
+
+    return next ? *next : 0;
+}
+
+static struct exfat_entry_label *find_exfat_entry_label(
+    struct blkid_probe *probe, const struct exfat_super_block *sb)
+{
+    uint32_t cluster = sb->rootdir_cluster;
+    uint64_t offset = exfat_cluster_to_offset(sb, cluster);
+    uint8_t *entry;
+    const size_t max_iter = 10000;
+    size_t i = 0;
+
+    for (; i < max_iter; ++i) {
+        entry = (uint8_t *)get_buffer(probe, offset, EXFAT_ENTRY_SIZE);
+        if (!entry)
+            return NULL;
+        if (entry[0] == EXFAT_ENTRY_EOD)
+            return NULL;
+        if (entry[0] == EXFAT_ENTRY_LABEL)
+            return (struct exfat_entry_label*) entry;
+
+        offset += EXFAT_ENTRY_SIZE;
+        if (offset % CLUSTER_SIZE(sb) == 0) {
+            cluster = exfat_next_cluster(probe, sb, cluster);
+            if (cluster < EXFAT_FIRST_DATA_CLUSTER)
+                return NULL;
+            if (cluster > EXFAT_LAST_DATA_CLUSTER)
+                return NULL;
+            offset = exfat_cluster_to_offset(sb, cluster);
+        }
+    }
+
+    return NULL;
+}
+
+static int probe_exfat(struct blkid_probe *probe, struct blkid_magic *id,
+                       unsigned char *buf)
+{
+    struct exfat_super_block *sb;
+    struct exfat_entry_label *label;
+    uuid_t uuid;
+    sb = (struct exfat_super_block *)buf;
+    if (!sb || !CLUSTER_SIZE(sb)) {
+        DBG(DEBUG_PROBE, printf("bad exfat superblock.\n"));
+        return errno ? - errno : 1;
+    }
+
+    label = find_exfat_entry_label(probe, sb);
+    if (label) {
+        blkid_set_tag(probe->dev, "LABEL", label->name, label->length);
+    } else {
+        blkid_set_tag(probe->dev, "LABEL", "disk", 4);
+    }
+
+    snprintf(uuid, sizeof (uuid), "%02hhX%02hhX-%02hhX%02hhX",
+             sb->volume_serial[3], sb->volume_serial[2],
+             sb->volume_serial[1], sb->volume_serial[0]);
+
+    set_uuid(probe->dev, uuid, 0);
+
+    return 0;
+}
+/** Various filesystem magics that we can check for.  Note that kboff and* sboff are in kilobytes and bytes respectively.  All magics are in
@@ -1512,6 +1604,7 @@ static struct blkid_magic type_array[] = {{ "lvm2pv",  1,  0x218,  8, "LVM2 001",       probe_lvm2 },{ "btrfs",    64,  0x40,  8, "_BHRfS_M",       probe_btrfs },{ "f2fs",    1,      0,  4, "\x10\x20\xf5\xf2",   probe_f2fs },
+  { "exfat",     0,      3,  8, "EXFAT   ",             probe_exfat },{   NULL,    0,  0,  0, NULL,           NULL }};diff --git a/lib/blkid/probe.h b/lib/blkid/probe.h
index 9d02695..c46a332 100644
--- a/lib/blkid/probe.h
+++ b/lib/blkid/probe.h
@@ -14,6 +14,8 @@#ifndef _BLKID_PROBE_H#define _BLKID_PROBE_H+#include <stdint.h>
+#include <blkid/blkid_types.h>struct blkid_magic;
@@ -763,6 +765,46 @@ struct f2fs_super_block {__u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */} attribute((packed));+struct exfat_super_block {
+    uint8_t jump[3];
+    uint8_t oem_name[8];
+    uint8_t __unused1[53];
+    uint64_t block_start;
+    uint64_t block_count;
+    uint32_t fat_block_start;
+    uint32_t fat_block_count;
+    uint32_t cluster_block_start;
+    uint32_t cluster_count;
+    uint32_t rootdir_cluster;
+    uint8_t volume_serial[4];
+    struct {
+        uint8_t vermin;
+        uint8_t vermaj;
+    } version;
+    uint16_t volume_state;
+    uint8_t block_bits;
+    uint8_t bpc_bits;
+    uint8_t fat_count;
+    uint8_t drive_no;
+    uint8_t allocated_percent;
+} attribute((packed));
+
+struct exfat_entry_label {
+    uint8_t type;
+    uint8_t length;
+    uint8_t name[30];
+} attribute((packed));
+
+#define BLOCK_SIZE(sb)   (1 << (sb)->block_bits)
+#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits)
+
+#define EXFAT_FIRST_DATA_CLUSTER 2
+#define EXFAT_LAST_DATA_CLUSTER  0xffffff6
+#define EXFAT_ENTRY_SIZE         32
+
+#define EXFAT_ENTRY_EOD   0x00
+#define EXFAT_ENTRY_LABEL 0x83
+/** Byte swap functions*/

6.下一步,在mk文件中,将一开始添加的external/exfat,/external/libfuse_forexfat加入编译,如
device/mediatek/common/device.mk
+PRODUCT_PACKAGES += libfuse_forexfat
+PRODUCT_PACKAGES += mount.exfat

7.然后make一次,测试在7.0上使用fuse方式支持exfat文件系统是否ok

8.要是发现无法自动挂载上,如果有adb root权限,可以先在adb中手动挂载试试

mount.exfat /dev/block/vold/publicxxx /mnt/media_rw/xxx

因为自动挂载的代码可能会遇到selinux的问题,需要按照不同平台,关闭selinux或者让报错的地方能被通过。

文章中的移植代码已经是完整可用的,有兴趣的朋友参考移植即可。

移植好的代码补丁也已传到csdn,有积分的童鞋可以自行下载。

https://download.csdn.net/download/huolinliang/10944533

Android 7.0支持exfat文件系统相关推荐

  1. Android 11.0 支持exFAT文件系统

    Android 11.0 支持exFAT文件系统 U盘常见文件系统类型有FAT32.NTFS.exFAT, Android默认支持FAT32,  一般也有NTFS类型编译选项, 但是exFAT由于版权 ...

  2. Android 11.0 支持exfat格式

    点滴积累,记录自己的成长. 最近系统要支持exfat格式,参考了大佬们的帖子之后,终于搞定了. 由于之前都是Android.mk,自己系统中使用的Android.bp,而且要求以模块的形式调用对应的k ...

  3. Android 9.0 支持NTFS和Exfat 格式U盘开发

    前言 最近有个需求要求在Android 9.0上面支持NTFS和Exfat 格式的U盘.网上有很多资料都是基于Android 4.4 的系统,系统版本太陈旧没有办法借鉴,通过两周的摸索终于搞定了这个功 ...

  4. Android9.0支持exFat格式u盘识别

    前言 前几天因工作需要在Android9.0上增加exfat格式u盘识别,查找相关资料之后只找到了Android4.4以及Android7.0的教程.fuse和no-fuse两种实现方法选其一即可,实 ...

  5. CentOS8.0支持NTFS文件系统解决

    近日在ThinkPad E490笔记本电脑新安装了CentOS8.0操作系统,发现不支持NTFS文件系统. 移动硬盘插入USB后,采用df -h查看,发现没有自动挂载. [root@client ~] ...

  6. MTK平台 Android11 支持exFat格式T卡

    最近项目中想在MTK 的Android11版本中增加支持exfat格式的t卡,参考了CSDN上的几个博客的方法,成功实现了该功能. 因为几个博客的kernel和external 的代码的版本都各有不同 ...

  7. android 是否可触摸,android 2.0可能支持多点触摸?

    android 2.0可能支持多点触摸? 最近有流言称google即将推出的android 2.0操作系统,即大家认为的donut(名字好怪,叫油炸焦圈)会支持多点触摸功能,类似zoom in/out ...

  8. DSM 6.0不安装exfat access支持exFAT

    DSM 6.0 6.2.3 不安装exfat access套件支持exFAT读写 打开DSM的SSH管理 SSH连接,并使用管理员账户登录 执行: wget -P /tmp/ http://mirro ...

  9. Android 8.0学习(5)---模块化内核

    模块化内核要求 在 Android 8.0 中,设备内核分为系统芯片 (SoC).设备和板专属组件.基于这种分层结构的内核和 Android 使得原始设计制造商 (ODM) 和原始设备制造商 (OEM ...

最新文章

  1. PTA 基础编程题目集 7-33 有理数加法 C语言
  2. android studio 编译报错:download fastutil-7.2.0.jar
  3. shell中字符串基本用法
  4. 输入十个数,输出其中最大数、下标,用函数实现
  5. saltstack mysql模块_SaltStack工具中MySQL的模块返回值问题解决
  6. mysql 文件放网络盘_MySQL InnoDB的磁盘文件及落盘机制
  7. jvm ide_预热JVM –超快速生产服务器和IDE
  8. kali 切换root权限_Ubuntu 被曝严重漏洞:切换系统语言 + 输入几行命令,就能获取 root 权限...
  9. wxpython textctrl_wxpython中Textctrl回车事件无效的解决方法
  10. pandas - pd.date_range-生成时间索引
  11. 自动化接口用例从 1 到 1000 过程中的实践和思考
  12. JUnit 5和JUnit 4比较
  13. ba无标度网络python_python绘制BA无标度网络示例代码
  14. Android应用中保存网络图片功能实现详解
  15. sql trace基础
  16. 第一次独立使用大型无人船记录日志—第2天
  17. Debian 制作U盘安装盘启动器
  18. linux安装socket.io,Socket.IO
  19. XML 解析生成工具
  20. Castor简单介绍实体类和xml互转

热门文章

  1. 电子签章盖章之jQuery插件jquery.zsign
  2. left of 'name' specifies undefined struct/union '$S1'
  3. Android开发-如何获取so的路径以及so是x86还是arm架构
  4. ChatGPT为什么不受开发者喜欢?
  5. 关于TJJTDS出生的故事:
  6. vue 判断数组是否为空
  7. Python抓取花瓣网高清美图
  8. python计算bmi_免费在线 BMI 计算器编码Python版代码(两条解决思路) - 李金龙
  9. NodeList对象
  10. 2012年个人所得税税率表