android usb挂载分析--各种格式支持
16lz
2021-01-26
前面对usb挂载的流程及各种格式的支持做了分析,这一篇也基本是收尾篇了,主要是把各种格式的挂载在vold模块种加进去,这里对这部分做了一些更改,如直接 挂载到/mnt/sdcard,没有先挂载到/mnt/secure/staging,还有把一些状态的转换去掉了,以及格式化、格式检查的去掉了,因为暂时还没听到这方面的奢求,哈哈,也是为了省事吧,这里把所有的挂载都在一个文件中实现了,先看下Android.mk
BUILD_VOLD2 := falseifneq ($(TARGET_SIMULATOR),true) BUILD_VOLD2 := trueendififeq ($(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.cppcommon_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; //FAT32SLOGW("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的。
类型判断好之后,就可以挂载了,这里根据不同的类型,挂载的时候参数或命令不一样。
更多相关文章
- android 中.9图片的用法 详解
- Android(安卓)TextView 判断文字内容是否超出显示省略号
- Android把svg图片转为jpg保存到相册图库
- YUV 400 格式图像转换成 ARGB 格式图像中犯的一个低级 Bug
- 【原创】Android(安卓)判断默认数据网络是否为开,若关则跳转到网
- android 判断当前所否为锁屏界面
- android app develop utils
- RingTest
- android调试中怎样使用gcc提供的工具