挂载磁盘。这里都有一个const char *类型的参数,这参数保存着每个磁盘的标签信息,比如sd卡的label是sdcard。
1. int VolumeManager::mountVolume(const char *label) {
2. Volume *v = lookupVolume(label);
3.
4. if (!v) {
5. errno = ENOENT;
6. return -1;
7. }
8.
9. return v->mountVol();
10. }
lookupVolume函数寻找与label匹配的对象:
1. Volume *VolumeManager::lookupVolume(const char *label) {
2. VolumeCollection::iterator i;
3.
4. for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
5. if (label[0] == '/') {
6. if (!strcmp(label, (*i)->getMountpoint()))
7. return (*i);
8. else {
9. if (!strcmp(label, (*i)->getLabel()))
10. return (*i);
11. }
12. }
13. return NULL;
14. }
如果找到,直接返回磁盘对象Volume*,挂载操作在mountVol函数里面,该函数内容有点多,贴源码:
1. int Volume::mountVol() {
2. dev_t deviceNodes[4];
3. int n, i, rc = 0;
4. char errmsg[255];
5.
6. if (getState() == Volume::State_NoMedia) {
7. sizeof(errmsg),
8. "Volume %s %s mount failed - no media",
9. getLabel(), getMountpoint());
10. mVm->getBroadcaster()->sendBroadcast(
11. ResponseCode::VolumeMountFailedNoMedia,
12. false);
13. errno = ENODEV;
14. return -1;
15. else if (getState() != Volume::State_Idle) {
16. errno = EBUSY;
17. return -1;
18. }
19. /*判断该挂载点是否已经挂载,若已经挂载,则直接返回。*/
20. if (isMountpointMounted(getMountpoint())) {
21. "Volume is idle but appears to be mounted - fixing");
22. /*这里的setState函数用得很频繁,这函数就是将状态通知给framework*/
23. setState(Volume::State_Mounted);
24. // mCurrentlyMountedKdev = XXX
25. return 0;
26. }
27. /*获取磁盘的设备号与分区数量,在下面说明*/
28. n = getDeviceNodes((dev_t *) &deviceNodes, 4);
29. if (!n) {
30. "Failed to get device nodes (%s)\n", strerror(errno));
31. return -1;
32. }
33. /*将循环挂载n个分区,但从代码上看,只适用于挂载一个分区*/
34. for (i = 0; i < n; i++) {
35. char devicePath[255];
36. /*这里看到了吧,用这种方式来使用磁盘的设备节点很方便,直接用主次设备号来命令*/
37. "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
38. MINOR(deviceNodes[i]));
39.
40. "%s being considered for volume %s\n", devicePath, getLabel());
41.
42. errno = 0;
43. setState(Volume::State_Checking);
44. /*挂载之前先检测一下该分区是否是fat分区,如果不是fat格式,返回-1*/
45. if (Fat::check(devicePath)) {
46. if (errno == ENODATA) {
47. "%s does not contain a FAT filesystem\n", devicePath);
48. continue;
49. }
50. errno = EIO;
51. /* Badness - abort the mount */
52. "%s failed FS checks (%s)", devicePath, strerror(errno));
53. setState(Volume::State_Idle);
54. return -1;
55. }
56.
57. /*
58. * Mount the device on our internal staging mountpoint so we can
59. * muck with it before exposing it to non priviledged users.
60. */
61. errno = 0;
62. /*将设备节点挂载在/mnt/secure/staging目录*/
63. if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, 1000, 1015, 0702, true)) {
64. "%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
65. continue;
66. }
67.
68. "Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());
69.
70. protectFromAutorunStupidity();
71. /*挂载一个只有root用户能够访问的目录,这函数挂载了两次
72. 将/mnt/secure/staging/.android_secure 挂载在 /mnt/secure/asec,
73. 将tmpfs 挂载在 /mnt/secure/staging/.android_secure*/
74. if (createBindMounts()) {
75. "Failed to create bindmounts (%s)", strerror(errno));
76. "/mnt/secure/staging");
77. setState(Volume::State_Idle);
78. return -1;
79. }
80.
81. /*
82. * Now that the bindmount trickery is done, atomically move the
83. * whole subtree to expose it to non priviledged users.
84. */
85. /*将挂载点挂载的目录再挂载到最终的目录/mnt/sdcard*/
86. if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
87. "Failed to move mount (%s)", strerror(errno));
88. "/mnt/secure/staging");
89. setState(Volume::State_Idle);
90. return -1;
91. }
92. setState(Volume::State_Mounted);
93. mLastMountedKdev = mCurrentlyMountedKdev = deviceNodes[i];
94. return 0;
95. }
96.
97. "Volume %s found no suitable devices for mounting :(\n", getLabel());
98. setState(Volume::State_Idle);
99.
100. return -1;
101. }
这个挂载函数看起来,会发现很繁琐,好几个目录的挂载关系,有以下挂载目录:
/dev/block/vold/8:1 挂载在-> /mnt/secure/staging
/mnt/secure/staging/.android_secure 挂载在-> /mnt/secure/asec
tmpfs 挂载在-> /mnt/secure/staging/.android_secure
/mnt/secure/staging 挂载在-> /mnt/sdcard
从程序的注释看,这样的目的是挂载一个只有root用户能查看的目录,具体还是没搞清楚谷歌为什么要这样挂载,
还是有疑问,希望有清楚的高手指点一下。
sd卡的挂载比较清楚,中间多了一个中介,将设备节点8:1挂载在/mnt/secure/staging,最后又将该目录挂载在/mnt/sdcard,
这目录就是最终用户能够看到文件的目录。
函数里面涉及到几个函数:
getDeviceNodes函数获取挂载设备的设备号与分区数量,是Volume类的一个纯虚函数,在子类DirectVolume中实现,源码:
1. int DirectVolume::getDeviceNodes(dev_t *devs, int max) {
2. if (mPartIdx == -1) {
3. // If the disk has no partitions, try the disk itself
4. if (!mDiskNumParts) {
5. devs[0] = MKDEV(mDiskMajor, mDiskMinor);
6. return 1;
7. }
8.
9. int i;
10. for (i = 0; i < mDiskNumParts; i++) {
11. if (i == max)
12. break;
13. devs[i] = MKDEV(mDiskMajor, mPartMinors[i]);
14. }
15. return mDiskNumParts;
16. }
17. devs[0] = MKDEV(mDiskMajor, mPartMinors[mPartIdx -1]);
18. return 1;
19. }
下面贴一些mountVol里面挂载的源码:
1. int Fat::doMount(const char *fsPath, const char *mountPoint,
2. bool ro, bool remount, int ownerUid, int ownerGid,
3. int permMask, bool createLost) {
4. int rc;
5. long flags;
6. char mountData[255];
7.
8. flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
9.
10. flags |= (ro ? MS_RDONLY : 0);
11. flags |= (remount ? MS_REMOUNT : 0);
12.
13. /*
14. * Note: This is a temporary hack. If the sampling profiler is enabled,
15. * we make the SD card world-writable so any process can write snapshots.
16. *
17. * TODO: Remove this code once we have a drop box in system_server.
18. */
19. char value[PROPERTY_VALUE_MAX];
20. "persist.sampling_profiler", value, "");
21. if (value[0] == '1') {
22. "The SD card is world-writable because the"
23. " 'persist.sampling_profiler' system property is set to '1'.");
24. permMask = 0;
25. }
26.
27. sprintf(mountData,
28. "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
29. ownerUid, ownerGid, permMask, permMask);
30.
31. "vfat", flags, mountData);
32.
33. if (rc && errno == EROFS) {
34. "%s appears to be a read only filesystem - retrying mount RO", fsPath);
35. flags |= MS_RDONLY;
36. "vfat", flags, mountData);
37. }
38.
39. if (rc == 0 && createLost) {
40. char *lost_path;
41. "%s/LOST.DIR", mountPoint);
42. if (access(lost_path, F_OK)) {
43. /*
44. * Create a LOST.DIR in the root so we have somewhere to put
45. * lost cluster chains (fsck_msdos doesn't currently do this)
46. */
47. if (mkdir(lost_path, 0755)) {
48. "Unable to create LOST.DIR (%s)", strerror(errno));
49. }
50. }
51. free(lost_path);
52. }
53.
54. return rc;
55. }
56.
57. int Volume::createBindMounts() {
58. long flags;
59.
60. /*
61. * Rename old /android_secure -> /.android_secure
62. */
63. if (!access("/mnt/secure/staging/android_secure", R_OK | X_OK) &&
64. access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
65. if (rename("/mnt/secure/staging/android_secure", SEC_STG_SECIMGDIR)) {
66. "Failed to rename legacy asec dir (%s)", strerror(errno));
67. }
68. }
69.
70. /*
71. * Ensure that /android_secure exists and is a directory
72. */
73. if (access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
74. if (errno == ENOENT) {
75. if (mkdir(SEC_STG_SECIMGDIR, 0777)) {
76. "Failed to create %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
77. return -1;
78. }
79. else {
80. "Failed to access %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
81. return -1;
82. }
83. else {
84. struct stat sbuf;
85.
86. if (stat(SEC_STG_SECIMGDIR, &sbuf)) {
87. "Failed to stat %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
88. return -1;
89. }
90. if (!S_ISDIR(sbuf.st_mode)) {
91. "%s is not a directory", SEC_STG_SECIMGDIR);
92. errno = ENOTDIR;
93. return -1;
94. }
95. }
96.
97. /*
98. * Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll
99. * have a root only accessable mountpoint for it.
100. */
101. if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
102. "Failed to bind mount points %s -> %s (%s)",
103. SEC_STG_SECIMGDIR, SEC_ASECDIR, strerror(errno));
104. return -1;
105. }
106.
107. /*
108. * Mount a read-only, zero-sized tmpfs on <mountpoint>/android_secure to
109. * obscure the underlying directory from everybody - sneaky eh? ;)
110. */
111. if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=000,uid=0,gid=0")) {
112. "Failed to obscure %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
113. "/mnt/asec_secure");
114. return -1;
115. }
116.
117. return 0;
118. }
119.
120. int Volume::doMoveMount(const char *src, const char *dst, bool force) {
121. int flags = MS_MOVE;
122. int retries = 5;
123.
124. while(retries--) {
125. if (!mount(src, dst, "", flags, NULL)) {
126. if (mDebug) {
127. "Moved mount %s -> %s sucessfully", src, dst);
128. }
129. return 0;
130. else if (errno != EBUSY) {
131. "Failed to move mount %s -> %s (%s)", src, dst, strerror(errno));
132. return -1;
133. }
134. int action = 0;
135.
136. if (force) {
137. if (retries == 1) {
138. // SIGKILL
139. else if (retries == 2) {
140. // SIGHUP
141. }
142. }
143. "Failed to move %s -> %s (%s, retries %d, action %d)",
144. src, dst, strerror(errno), retries, action);
145. Process::killProcessesWithOpenFiles(src, action);
146. usleep(1000*250);
147. }
148.
149. errno = EBUSY;
150. "Giving up on move %s -> %s (%s)", src, dst, strerror(errno));
151. return -1;
152. }