Android exfat移植指南


1 将exfat拷贝到external
2 将fuse拷贝到external,并改名为libfuse_forextat
3 修改device\fsl\imx6\imx6.mk 
  在PRODUCT_PACKAGES +=下增加 libfuse_forextat mount.exfat
  
4 在exfat 的Android.mk文件中增加 LOCAL_LDFLAGS += -ldl
  将-I$(EXFAT_ROOT)/../fuse/include更改为 -I$(EXFAT_ROOT)/../fuse_forexfat/include
  将LOCAL_STATIC_LIBRARIES += libexfat libfuse 改为LOCAL_STATIC_LIBRARIES += libexfat libfuse_forextat


5 修改libfuse_forextat的Android.mk文件
  将LOCAL_MODULE := libfuse 改为LOCAL_MODULE := libfuse_forextat


6 重新编译,这时可以看到在system/bin 下有一个mount.exfat的可执行文件


7 修改exfat 的Android.mk文件
 增加 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)


8 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;
}


9 在system/vold/Android.mk中添加exfat.cpp


10 修改system\vold\Volume.cpp
修改函数int Volume::mountVol如下
int Volume::mountVol() {
    dev_t deviceNodes[MAX_PARTITIONS];
    int n, i, rc = 0;
    char errmsg[255];


    int flags = getFlags();
    bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;


    // TODO: handle "bind" style mounts, for emulated storage


    char decrypt_state[PROPERTY_VALUE_MAX];
    char crypto_state[PROPERTY_VALUE_MAX];
    char encrypt_progress[PROPERTY_VALUE_MAX];


    property_get("vold.decrypt", decrypt_state, "");
    property_get("vold.encrypt_progress", encrypt_progress, "");


    /* Don't try to mount the volumes if we have not yet entered the disk password
     * or are in the process of encrypting.
     */
    if ((getState() == Volume::State_NoMedia) ||
        ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && providesAsec)) {
        snprintf(errmsg, sizeof(errmsg),
                 "Volume %s %s mount failed - no media",
                 getLabel(), getFuseMountpoint());
        mVm->getBroadcaster()->sendBroadcast(
                                         ResponseCode::VolumeMountFailedNoMedia,
                                         errmsg, false);
        errno = ENODEV;
        return -1;
    } else if (getState() != Volume::State_Idle) {
        errno = EBUSY;
        if (getState() == Volume::State_Pending) {
            mRetryMount = true;
        }
        return -1;
    }


    if (isMountpointMounted(getMountpoint())) {
        SLOGW("Volume is idle but appears to be mounted - fixing");
        setState(Volume::State_Mounted);
        // mCurrentlyMountedKdev = XXX
        return 0;
    }


    n = getDeviceNodes((dev_t *) &deviceNodes, MAX_PARTITIONS);
    if (!n) {
        SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
        return -1;
    }


    /* If we're running encrypted, and the volume is marked as encryptable and nonremovable,
     * and also marked as providing Asec storage, then we need to decrypt
     * that partition, and update the volume object to point to it's new decrypted
     * block device
     */
    property_get("ro.crypto.state", crypto_state, "");
    if (providesAsec &&
        ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) &&
        !strcmp(crypto_state, "encrypted") && !isDecrypted()) {
       char new_sys_path[MAXPATHLEN];
       char nodepath[256];
       int new_major, new_minor;


       if (n != 1) {
           /* We only expect one device node returned when mounting encryptable volumes */
           SLOGE("Too many device nodes returned when mounting %d\n", getMountpoint());
           return -1;
       }


       if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]),
                                new_sys_path, sizeof(new_sys_path),
                                &new_major, &new_minor)) {
           SLOGE("Cannot setup encryption mapping for %d\n", getMountpoint());
           return -1;
       }
       /* We now have the new sysfs path for the decrypted block device, and the
        * majore and minor numbers for it.  So, create the device, update the
        * path to the new sysfs path, and continue.
        */
        snprintf(nodepath,
                 sizeof(nodepath), "/dev/block/vold/%d:%d",
                 new_major, new_minor);
        if (createDeviceNode(nodepath, new_major, new_minor)) {
            SLOGE("Error making device node '%s' (%s)", nodepath,
                                                       strerror(errno));
        }


        // Todo: Either create sys filename from nodepath, or pass in bogus path so
        //       vold ignores state changes on this internal device.
        updateDeviceInfo(nodepath, new_major, new_minor);


        /* Get the device nodes again, because they just changed */
        n = getDeviceNodes((dev_t *) &deviceNodes, MAX_PARTITIONS);
        if (!n) {
            SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
            return -1;
        }
    }


    for (i = 0; i < n; i++) {
        char devicePath[255];


        sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
                MINOR(deviceNodes[i]));


        SLOGW("%s being considered for volume %s\n", devicePath, getLabel());


        errno = 0;
        setState(Volume::State_Checking);


        int ntfs = 0;
        int exfat = 0;
        if (Fat::check(devicePath)) {
            if (errno == ENODATA) {
                SLOGW("%s does not contain a FAT filesystem\n", devicePath);
                /* try the NTFS filesystem */
                if (!Exfat::check(devicePath)) { //add by steven
                        exfat = 1;
                        SLOGW("%s contain a EXFAT filesystem\n", devicePath);
                        goto mnt;
                }
                else
                {
                            SLOGW("%s does not contain a exfat filesystem\n", devicePath);
                }
                if (!Ntfs::check(devicePath)) {
                
                    ntfs = 1;
                    SLOGI("%s contain a NTFS filesystem\n", devicePath);
                    goto mnt;
                } else{
                        SLOGW("%s does not contain a NTFS filesystem\n", devicePath);    
                }


                continue;
            }
            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, 0007, true)) {
                SLOGE("%s failed to mount via NTFS (%s)\n", devicePath, strerror(errno));
                continue;
            }
        }else if (exfat) { 
                SLOGW("start mount exfat"); 
            if (Exfat::doMount(devicePath, getMountpoint(), false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, 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, 0007, true)) {
            SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
            continue;
        }


        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];
        SLOGW("  mount return 0"); 
        return 0;
    }


    SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
    setState(Volume::State_Idle);


    return -1;

}


已经移植好的代码已经上传到https://download.csdn.net/download/wince_lover/10433502,有兴趣的读者可以知己下载

你可能感兴趣的:(android)