挂载磁盘。这里都有一个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. }