android usb挂载分析--各种格式支持

前面对usb挂载的流程及各种格式的支持做了分析,这一篇也基本是收尾篇了,主要是把各种格式的挂载在vold模块种加进去,这里对这部分做了一些更改,如直接 挂载到/mnt/sdcard,没有先挂载到/mnt/secure/staging,还有把一些状态的转换去掉了,以及格式化、格式检查的去掉了,因为暂时还没听到这方面的奢求,哈哈,也是为了省事吧,这里把所有的挂载都在一个文件中实现了,先看下Android.mk

BUILD_VOLD2 := false
ifneq ($(TARGET_SIMULATOR),true)
    BUILD_VOLD2 := true
endif

ifeq ($(BUILD_VOLD2),true)

LOCAL_PATH:= $(call my-dir)

common_src_files := \
	VolumeManager.cpp \
	CommandListener.cpp \
	VoldCommand.cpp \
	NetlinkManager.cpp \
	NetlinkHandler.cpp \
	Volume.cpp \
	DirectVolume.cpp \
	logwrapper.c \
	Process.cpp \
	StorageMount.cpp \
	Loop.cpp \
	Devmapper.cpp \
	ResponseCode.cpp \
	Xwarp.cpp

common_c_includes := \
	$(KERNEL_HEADERS) \
	kernel/include \
	external/openssl/include
   ...
这里去掉了FAT.cpp,把真正的挂载都在StorageMount.cpp实现了。

对mountVol函数进行了修改。

int Volume::mountVol() {
    dev_t deviceNodes[4];
    int n, i, rc = 0;
    char errmsg[255];
    char  file_type[8]  = {0};
    bool mountflat = false;
    int loopCount = 10;
	
loop:    
	if (getState() == Volume::State_NoMedia) {
        snprintf(errmsg, sizeof(errmsg),
                 "Volume %s %s mount failed - no media",
                 getLabel(), getMountpoint());
		if(loopCount > 0)
		{
			loopCount --;
			sleep(1);
			SLOGW("loopCount = %d.", loopCount);
			goto loop;
		}
        mVm->getBroadcaster()->sendBroadcast(
                                         ResponseCode::VolumeMountFailedNoMedia,
                                         errmsg, false);
        errno = ENODEV;
        return -1;
    } else if (getState() != Volume::State_Idle) {
    	if(loopCount > 0)
	{
		loopCount --;
		sleep(1);
		SLOGW("loopCount = %d.", loopCount);
		goto loop;
	}
        errno = EBUSY;
        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, 4);
    if (!n) {
        SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
        return -1;
    }

    for (i = 0; i < n; i++) {
        char devicePath[255];
        int result = 0;
        const char *disktype = "fat";

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

        SLOGI("%s being considered for volume %s\n", devicePath, getLabel());
        if((StorageMount::doMount(devicePath, "/mnt/secure/staging", false, false, 1000, 1015, 0702, true)) != 0)
			continue;
		
        SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());

        protectFromAutorunStupidity();

        if (createBindMounts()) {
            SLOGE("Failed to create bindmounts (%s)", strerror(errno));
            umount("/mnt/secure/staging");
            setState(Volume::State_Idle);
            return -1;
        }

        /*
         * Now that the bindmount trickery is done, atomically move the
         * whole subtree to expose it to non priviledged users.
         */
        if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
            SLOGE("Failed to move mount (%s)", strerror(errno));
            umount("/mnt/secure/staging");
            setState(Volume::State_Idle);
            return -1;
        }
        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;
}
这里开始加了个loop,是因为有时候已经发送了VolumeDiskInserted给FrameWork层,FrameWork层会下发挂载命令,但在这里判断状态的时候不对,因为DirectVolume类中的handlePartitionAdded函数还未调用 完,未将状态改过来

在挂载的时候直接调用StorageMount::doMount进行挂载,这里代码还有点问题,没有去掉一些没用的代码。

int StorageMount::doMount(const char *fsPath, const char *mountPoint,
                 bool ro, bool remount, int ownerUid, int ownerGid,
                 int permMask, bool createLost) 
{
	int rc;
	unsigned long flags;
	char mountData[255];
	char filetype[8];
	int fd;
	bool mountDataFlag = true;
	enum ANDROID_FILESYSTEM_TYPE  e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_UNKNOW;
	enum ANDROID_MOUNT_FLAG e_mount_flag = IPANEL_ANDROID_MOUNT_FLAG_FAT;
	flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;

	flags |= (ro ? MS_RDONLY : 0);
	flags |= (remount ? MS_REMOUNT : 0);

	/*
	* 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;
	}


	fd = open(fsPath, O_RDONLY | O_NONBLOCK, 777);
	if(fd < 0)
	{
		return -1;
	}
	e_filesystem_type = disk_get_file_system(fd);
	switch(e_filesystem_type)
	{
		case IPANEL_ANDROID_FILESYSTEM_NTFS:
			strcpy(filetype, "ntfs");
			e_mount_flag= IPANEL_ANDROID_MOUNT_FLAG_NTFS;
			break;

		case IPANEL_ANDROID_FILESYSTEM_FAT16:
			strcpy(filetype, "vfat");
			e_mount_flag= IPANEL_ANDROID_MOUNT_FLAG_NTFS;
			break;

		case IPANEL_ANDROID_FILESYSTEM_FAT32:
			strcpy(filetype, "vfat");			
			e_mount_flag= IPANEL_ANDROID_MOUNT_FLAG_FAT;
			break;

		case IPANEL_ANDROID_FILESYSTEM_EXT2:
			strcpy(filetype, "ext2");
			e_mount_flag= IPANEL_ANDROID_MOUNT_FLAG_EXT;
			break;

		case IPANEL_ANDROID_FILESYSTEM_EXT3:
			strcpy(filetype, "ext3");
			e_mount_flag= IPANEL_ANDROID_MOUNT_FLAG_EXT;
			break;

		case IPANEL_ANDROID_FILESYSTEM_EXT4:
			strcpy(filetype, "ext4");
			e_mount_flag= IPANEL_ANDROID_MOUNT_FLAG_EXT;
			break;

		case IPANEL_ANDROID_FILESYSTEM_UNKNOW:
			SLOGE("filesystem unknow or not support");
			return -1;
	}
	if(IPANEL_ANDROID_MOUNT_FLAG_EXT == e_mount_flag
		|| IPANEL_ANDROID_MOUNT_FLAG_NTFS == e_mount_flag)
	{
		sprintf(mountData, "uid=%d,gid=%d,fmask=%o,dmask=%o",           
								ownerUid, ownerGid, permMask, permMask);
	}
	else if(IPANEL_ANDROID_MOUNT_FLAG_FAT == e_mount_flag)
	{
		sprintf(mountData, "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",           
								ownerUid, ownerGid, permMask, permMask);
	}
	else
	{

	}
	SLOGI("mountData = %s. \n", mountData);

	if(e_filesystem_type == IPANEL_ANDROID_FILESYSTEM_NTFS)
	{
		const char *args[8];
		args[0] = "/system/bin/ntfs-3g";
		args[1] = fsPath;
		args[2] = mountPoint;
		args[3] = NULL;    

		rc = logwrap(7, args, 0);
		}
	else
	{
		rc = mount(fsPath, mountPoint, filetype, flags, mountData);
	}
	SLOGI("rc = %d.", 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, 0075)) 
			{
				SLOGE("Unable to create LOST.DIR (%s)", strerror(errno));
			}
		}
		free(lost_path);
	}

	return rc;

ERR:
	return -1;
}
这里会打开这个文件系统的,获取超级块,然后判断是什么类型的文件系统,再进行挂载,判断文件类型的函数:

ANDROID_FILESYSTEM_TYPE StorageMount::disk_get_file_system(int  fd)
{
	unsigned char fsystem[8];
	unsigned char FAT[8];
	int i;
	unsigned char *blockbuffer;
	int file_system;
	unsigned char hasjounal;
	int sec_size = disk_get_sector_size(fd);
	enum ANDROID_FILESYSTEM_TYPE  e_filesystem_type;
	SLOGW("lijj disk_get_file_system");
	blockbuffer = (unsigned char*)calloc(1,sec_size);
	disk_read_sector(fd, 0, blockbuffer);
	//dump_disk_sector(DBR,512);
	/*0x03--0x0a 为 OEM ID*/
	for (i = 0; i < 8; i++) //modify by yanglb (i<=8 Memory out of bounds)
		fsystem[i] = blockbuffer[0x3 + i];
	/*OEM ID 等于 "NTFS",则为NTFS文件系统*/
	if (    fsystem[0] == 0x4e 
		&& fsystem[1] == 0x54 
		&& fsystem[2] == 0x46 
		&& fsystem[3] == 0x53 
		&& fsystem[4] == 0x20    
		&& fsystem[5] == 0x20 
		&& fsystem[6] == 0x20 
		&& fsystem[7] == 0x20    )
	{
		e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_NTFS;
		SLOGW("lijj IPANEL_ANDROID_FILESYSTEM_NTFS");
		goto FS_END;
	}

	/*FAT32 在 0x52-0x59描述了文件系统*/
	for (i = 0; i < 8; i++) //modify by yanglb (i<=8 Memory out of bounds)
		FAT[i] = blockbuffer[0x52 + i];
	if (    FAT[0] == 0x46 
		&& FAT[1] == 0x41 
		&& FAT[2] == 0x54 
		&& FAT[3] == 0x33 
		&& FAT[4] == 0x32 
		&& FAT[5] == 0x20
		&& FAT[6] == 0x20 
		&& FAT[7] == 0x20    )
	{
		e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_FAT32; //FAT32
		SLOGW("lijj IPANEL_ANDROID_FILESYSTEM_FAT32");
        	goto FS_END;
	}
	/*FAT16在 0x36-0x3d字节描述了文件系统*/
	for (i = 0; i < 8; i++) //modify by yanglb (i<=8 Memory out of bounds)
		FAT[i] = blockbuffer[0x36 + i];
	if (    FAT[0] == 0x46 
		&& FAT[1] == 0x41 
		&& FAT[2] == 0x54 
		&& FAT[3] == 0x31 
		&& FAT[4] == 0x36 
		&& FAT[5] == 0x20 
		&& FAT[6] == 0x20 
		&& FAT[7] == 0x20    )
	{
        	e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_FAT16; //FAT16
        	SLOGW("lijj IPANEL_ANDROID_FILESYSTEM_FAT16");
        	goto FS_END;
	}
	if( blockbuffer[0x1FE] == 0x55 && blockbuffer[0x1FF] == 0xaa)
		goto FS_ERR;

	/*如果分区引导记录PBR没有描述NTFS,FAT,则查询是否为EXT*/
	/*查询超级块,若0x38,0x39位和EXT格式的魔数吻合,则可确定为EXT*/
	/*另根据无日志判断EXT2,有日志默认为EXT3*/
	memset(blockbuffer, 0, sec_size);
	disk_read_sector(fd,  2, blockbuffer);
	if (blockbuffer[0x38] != 0x53 || blockbuffer[0x39] != 0xef)
	{
		goto  FS_ERR;
	}
	/*ext2 ext3 从0x178开始的后面几位都为0*/
	if (blockbuffer[0x178] != 0 || blockbuffer[0x179] != 0
		||blockbuffer[0x17a] != 0 || blockbuffer[0x17b] != 0
		||blockbuffer[0x17c] != 0 || blockbuffer[0x17d] != 0
		||blockbuffer[0x17e] != 0 || blockbuffer[0x17f] != 0)
	{
		e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_EXT4; //ext3
        	goto FS_END;
	}

	hasjounal = (blockbuffer[0x5c] >> 2) &0x1;
	if (hasjounal == 1)
	{
		e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_EXT3; //ext3
        	goto FS_END;
	}
	else
	{
		
		e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_EXT2; //ext3
        	goto FS_END;
	}
FS_END:
	free(blockbuffer);
	return e_filesystem_type;
	
FS_ERR:
	e_filesystem_type = IPANEL_ANDROID_FILESYSTEM_UNKNOW;
	free(blockbuffer);
	return e_filesystem_type;
}

这里ext4类型的判断粊笨拙,这里的方法是因为ext4超级块的结构比其它ext2 ext3大,后面的 这引起字段不为0,而其它两种格式这些字段都是0的。


类型判断好之后,就可以挂载了,这里根据不同的类型,挂载的时候参数或命令不一样。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值