3.挂载磁盘。这里都有一个const char *类型的参数,这参数保存着每个磁盘的标签信息,比如sd卡的label是sdcard。
int VolumeManager::mountVolume(const char *label) { Volume *v = lookupVolume(label); if (!v) { errno = ENOENT; return -1; } return v->mountVol(); }
Volume *VolumeManager::lookupVolume(const char *label) { VolumeCollection::iterator i; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { if (label[0] == '/') { if (!strcmp(label, (*i)->getMountpoint())) return (*i); } else { if (!strcmp(label, (*i)->getLabel())) return (*i); } } return NULL; }
int Volume::mountVol() { dev_t deviceNodes[4]; int n, i, rc = 0; char errmsg[255]; if (getState() == Volume::State_NoMedia) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } /*判断该挂载点是否已经挂载,若已经挂载,则直接返回。*/ if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); /*这里的setState函数用得很频繁,这函数就是将状态通知给framework*/ 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; } /*将循环挂载n个分区,但从代码上看,只适用于挂载一个分区*/ for (i = 0; i < n; i++) { char devicePath[255]; /*这里看到了吧,用这种方式来使用磁盘的设备节点很方便,直接用主次设备号来命令*/ sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]), MINOR(deviceNodes[i])); SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; setState(Volume::State_Checking); /*挂载之前先检测一下该分区是否是fat分区,如果不是fat格式,返回-1*/ if (Fat::check(devicePath)) { if (errno == ENODATA) { SLOGW("%s does not contain a FAT 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; } /* * Mount the device on our internal staging mountpoint so we can * muck with it before exposing it to non priviledged users. */ errno = 0; /*将设备节点挂载在/mnt/secure/staging目录*/ if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, 1000, 1015, 0702, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); protectFromAutorunStupidity(); /*挂载一个只有root用户能够访问的目录,这函数挂载了两次 将/mnt/secure/staging/.android_secure 挂载在 /mnt/secure/asec, 将tmpfs 挂载在 /mnt/secure/staging/.android_secure*/ 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. */ /*将挂载点挂载的目录再挂载到最终的目录/mnt/sdcard*/ 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); mLastMountedKdev = mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); setState(Volume::State_Idle); return -1; }
int DirectVolume::getDeviceNodes(dev_t *devs, int max) { if (mPartIdx == -1) { // If the disk has no partitions, try the disk itself if (!mDiskNumParts) { devs[0] = MKDEV(mDiskMajor, mDiskMinor); return 1; } int i; for (i = 0; i < mDiskNumParts; i++) { if (i == max) break; devs[i] = MKDEV(mDiskMajor, mPartMinors[i]); } return mDiskNumParts; } devs[0] = MKDEV(mDiskMajor, mPartMinors[mPartIdx -1]); return 1; }
int Fat::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]; 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; } sprintf(mountData, "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed", ownerUid, ownerGid, permMask, permMask); rc = mount(fsPath, mountPoint, "vfat", flags, mountData); if (rc && errno == EROFS) { SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); flags |= MS_RDONLY; rc = mount(fsPath, mountPoint, "vfat", flags, mountData); } 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; } int Volume::createBindMounts() { unsigned long flags; /* * Rename old /android_secure -> /.android_secure */ if (!access("/mnt/secure/staging/android_secure", R_OK | X_OK) && access(SEC_STG_SECIMGDIR, R_OK | X_OK)) { if (rename("/mnt/secure/staging/android_secure", SEC_STG_SECIMGDIR)) { SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno)); } } /* * Ensure that /android_secure exists and is a directory */ if (access(SEC_STG_SECIMGDIR, R_OK | X_OK)) { if (errno == ENOENT) { if (mkdir(SEC_STG_SECIMGDIR, 0777)) { SLOGE("Failed to create %s (%s)", SEC_STG_SECIMGDIR, strerror(errno)); return -1; } } else { SLOGE("Failed to access %s (%s)", SEC_STG_SECIMGDIR, strerror(errno)); return -1; } } else { struct stat sbuf; if (stat(SEC_STG_SECIMGDIR, &sbuf)) { SLOGE("Failed to stat %s (%s)", SEC_STG_SECIMGDIR, strerror(errno)); return -1; } if (!S_ISDIR(sbuf.st_mode)) { SLOGE("%s is not a directory", SEC_STG_SECIMGDIR); errno = ENOTDIR; return -1; } } /* * Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll * have a root only accessable mountpoint for it. */ if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) { SLOGE("Failed to bind mount points %s -> %s (%s)", SEC_STG_SECIMGDIR, SEC_ASECDIR, strerror(errno)); return -1; } /* * Mount a read-only, zero-sized tmpfs on <mountpoint>/android_secure to * obscure the underlying directory from everybody - sneaky eh? ;) */ if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=000,uid=0,gid=0")) { SLOGE("Failed to obscure %s (%s)", SEC_STG_SECIMGDIR, strerror(errno)); umount("/mnt/asec_secure"); return -1; } return 0; } int Volume::doMoveMount(const char *src, const char *dst, bool force) { unsigned int flags = MS_MOVE; int retries = 5; while(retries--) { if (!mount(src, dst, "", flags, NULL)) { if (mDebug) { SLOGD("Moved mount %s -> %s sucessfully", src, dst); } return 0; } else if (errno != EBUSY) { SLOGE("Failed to move mount %s -> %s (%s)", src, dst, strerror(errno)); return -1; } int action = 0; if (force) { if (retries == 1) { action = 2; // SIGKILL } else if (retries == 2) { action = 1; // SIGHUP } } SLOGW("Failed to move %s -> %s (%s, retries %d, action %d)", src, dst, strerror(errno), retries, action); Process::killProcessesWithOpenFiles(src, action); usleep(1000*250); } errno = EBUSY; SLOGE("Giving up on move %s -> %s (%s)", src, dst, strerror(errno)); return -1; }