Android(安卓)exfat移植指南
16lz
2021-01-25
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,有兴趣的读者可以知己下载
更多相关文章
- 一款常用的 Squid 日志分析工具
- GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
- RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
- Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
- 如何监听Phone的状态,第三方App如何拨打/接听电话?
- android调用matlab中的函数方法
- Android媒体扫描代码分析
- Mac下 android 模拟器 host修改
- 用Preferences,通过xml文件跳转到另一个Activity