当前位置: 移动技术网 > 移动技术>移动开发>Android > Android 4.4.2 exfat 移植

Android 4.4.2 exfat 移植

2019年04月18日  | 移动技术网移动技术  | 我要评论

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网