系统源码分析 Android磁盘管理总共涉及到四大部分源码: 1.Linux kernel: Android建立在Linux内核的基础上,最底层的部分是由Linux kernel来负责的,用于检测热插拔事件; 2.Vold:Android没有使用Linux平台下的udev来处理,于是Google写了一个类似udev功能的vold,充当了kernel与framework之间的桥梁; 3.Framework:Android的核心框架,(仅仅磁盘管理这部分)负责操作vold,给vold下发操作命令; 4.UI:Androidd的系统应用,与Framework进行交互,用于挂载/卸载SD卡。 Android挂载SD卡,流程如下: 1.用户在“设置”页面的“SD卡和手机内存”中,点击“挂载”; 2.UI从Framework获取操作磁盘的函数(向Framework注册,才能使用的函数),然后调用挂载的处理函数; 3.该处理函数通过广播机制发送挂载命令“volume mount sdcard”,vold接受命令并挂载SD卡后,用广播通知Framework; 4.Framework收到挂载SD卡的回复,通知UI的处理结果; 5.界面显示挂载成功/挂载失败。 从这里可以看出,Android的磁盘管理涉及到整个系统框架,这是Android系统很重要的一个子系统,通过磁盘管理的子系统来熟悉Android系 统架构,能够了解到Android的多方面知识。从SD卡的挂载流程可以看出,Android系统大量地使用IPC,从而做到了模块独立的效果。从磁盘管 理的那四大部分来看,四个部分之间的相互联系均是使用socket进行通信,没有使用到传统的API调用,整个系统就显得非常的独立。 源码的位置: Vold:system/vold Framework: frameworks/base/services/java/com/android/server UI: android-2.2r2/packages/apps/Settings/src/com/android/settings/deviceinfo/ 下篇文章开始分析源码,从下往上走。。 vold源码分析(2) Vold是Android系统处理磁盘的核心部分,取代了原来Linux系统中的udev,主要用来处理Android系统的热插拔存储设备。在Android2.2以后的系统中,vold源码已经移到了system目录下,vold目录包含以下源码: ├── Android.mk ├── Asec.h ├── CleanSpec.mk ├── CommandListener.cpp ├── CommandListener.h ├── Devmapper.cpp ├── Devmapper.h ├── DirectVolume.cpp ├── DirectVolume.h ├── Fat.cpp ├── Fat.h ├── hash.h ├── logwrapper.c ├── Loop.cpp ├── Loop.h ├── main.cpp ├── NetlinkHandler.cpp ├── NetlinkHandler.h ├── NetlinkManager.cpp ├── NetlinkManager.h ├── Process.cpp ├── Process.h ├── ResponseCode.cpp ├── ResponseCode.h ├── vdc.c ├── VoldCommand.cpp ├── VoldCommand.h ├── Volume.cpp ├── Volume.h ├── VolumeManager.cpp ├── VolumeManager.h ├── Xwarp.cpp └── Xwarp.h 先简要说明一下类的继承关系,vold中比较重要的有以下几个类: 三大管理类:VolumeManager,CommandListener,NetlinkManager 其他处理类:Volume,DirectVolume,NetlinkHandler,Fat,ResponseCode 其他相关的类:NetlinkListener,SocketListener 1.VolumeManager管理Volume类; 2.DirectVolume类继承于Volume类,保存着磁盘信息与操作函数; 3.NetlinkManager类负责与内核uevent事件通信,期间,使用到了NetlinkListener和SocketListener类的函数; 4.Fat是格式化sd卡的函数; 5.ResponseCode保存着vold向framework反馈的值。 本文讲解main.cpp文件的源代码:
- int main() {
-
-
-
-
-
-
- VolumeManager *vm;
- CommandListener *cl;
- NetlinkManager *nm;
-
- SLOGI("Vold 2.1 (the revenge) firing up");
-
-
-
-
-
-
-
-
- mkdir("/dev/block/vold", 0755);
-
-
-
-
-
-
-
-
-
-
- if (!(vm = VolumeManager::Instance())) {
- SLOGE("Unable to create VolumeManager");
- exit(1);
- };
-
-
-
-
-
-
-
-
-
-
- if (!(nm = NetlinkManager::Instance())) {
- SLOGE("Unable to create NetlinkManager");
- exit(1);
- };
-
-
-
-
-
-
-
-
-
-
-
- cl = new CommandListener();
- vm->setBroadcaster((SocketListener *) cl);
- nm->setBroadcaster((SocketListener *) cl);
-
-
-
-
-
-
-
-
- if (vm->start()) {
- SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
- exit(1);
- }
-
-
-
-
-
-
- if (process_config(vm)) {
- SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
- }
-
-
-
-
-
-
-
-
- if (nm->start()) {
- SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
- exit(1);
- }
-
- coldboot("/sys/block");
-
-
-
-
-
-
-
- {
- FILE *fp;
- char state[255];
-
- if ((fp = fopen("/sys/devices/virtual/switch/usb_mass_storage/state","r"))) {
- if (fgets(state, sizeof(state), fp)) {
- if (!strncmp(state, "online", 6)) {
- vm->notifyUmsConnected(true);
- } else {
- vm->notifyUmsConnected(false);
- }
- } else {
- SLOGE("Failed to read switch state (%s)", strerror(errno));
- }
-
- fclose(fp);
- } else {
- SLOGW("No UMS switch available");
- }
- }
-
-
-
-
-
-
- if (cl->startListener()) {
- SLOGE("Unable to start CommandListener (%s)", strerror(errno));
- exit(1);
- }
-
-
-
-
-
-
- while(1) {
- sleep(1000);
- }
-
- SLOGI("Vold exiting");
- exit(0);
- }
-
-
-
-
-
-
- static void do_coldboot(DIR *d, int lvl)
- {
- struct dirent *de;
- int dfd, fd;
-
- dfd = dirfd(d);
-
- fd = openat(dfd, "uevent", O_WRONLY);
- if(fd >= 0) {
- write(fd, "add\n", 4);
- close(fd);
- }
-
- while((de = readdir(d))) {
- DIR *d2;
-
- if (de->d_name[0] == '.')
- continue;
-
- if (de->d_type != DT_DIR && lvl > 0)
- continue;
-
- fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
- if(fd < 0)
- continue;
-
- d2 = fdopendir(fd);
- if(d2 == 0)
- close(fd);
- else {
- do_coldboot(d2, lvl + 1);
- closedir(d2);
- }
- }
- }
-
- static void coldboot(const char *path)
- {
- DIR *d = opendir(path);
- if(d) {
- do_coldboot(d, 0);
- closedir(d);
- }
- }
-
-
-
-
-
-
-
-
- static int process_config(VolumeManager *vm) {
- FILE *fp;
- int n = 0;
- char line[255];
-
- if (!(fp = fopen("/etc/vold.fstab", "r"))) {
- return -1;
- }
-
- while(fgets(line, sizeof(line), fp)) {
- char *next = line;
- char *type, *label, *mount_point;
-
- n++;
- line[strlen(line)-1] = '\0';
-
- if (line[0] == '#' || line[0] == '\0')
- continue;
-
- if (!(type = strsep(&next, " \t"))) {
- SLOGE("Error parsing type");
- goto out_syntax;
- }
- if (!(label = strsep(&next, " \t"))) {
- SLOGE("Error parsing label");
- goto out_syntax;
- }
- if (!(mount_point = strsep(&next, " \t"))) {
- SLOGE("Error parsing mount point");
- goto out_syntax;
- }
-
- if (!strcmp(type, "dev_mount")) {
- DirectVolume *dv = NULL;
- char *part, *sysfs_path;
-
- if (!(part = strsep(&next, " \t"))) {
- SLOGE("Error parsing partition");
- goto out_syntax;
- }
- if (strcmp(part, "auto") && atoi(part) == 0) {
- SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part);
- goto out_syntax;
- }
-
-
-
-
- if (!strcmp(part, "auto")) {
- dv = new DirectVolume(vm, label, mount_point, -1);
- } else {
- dv = new DirectVolume(vm, label, mount_point, atoi(part));
- }
-
- while((sysfs_path = strsep(&next, " \t"))) {
-
-
-
-
-
-
-
- if (dv->addPath(sysfs_path)) {
- SLOGE("Failed to add devpath %s to volume %s", sysfs_path,
- label);
- goto out_fail;
- }
- }
-
-
-
-
-
- vm->addVolume(dv);
- } else if (!strcmp(type, "map_mount")) {
- } else {
- SLOGE("Unknown type '%s'", type);
- goto out_syntax;
- }
- }
-
- fclose(fp);
- return 0;
-
-
-
-
-
-
-
-
-
-
-
- out_syntax:
- SLOGE("Syntax error on config line %d", n);
- errno = -EINVAL;
- out_fail:
- fclose(fp);
- return -1;
- }
下篇文章开始从main函数的入口点深入分析流程。。 vold源码分析(3) NetlinkManager类负责管理捕获内核的uevent事件,这里使用了Netlink套接字。 Netlink的概念: Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。Netlink套接字可以使用标准的套接字APIs来创建。socket(), bind(), sendmsg(), recvmsg() 和 close()很容易地应用到 netlink socket。netlink包含于头文件linux/netlink.h中。 平时的应用层一般都不会用到Netlink这个套接字,了解就行。 在Main.cpp文件中的main函数里面,有一个准备工作是用来开启监听内核uevent事件的线程,源码如下:
- if (nm->start()) {
- SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
- exit(1);
- }
nm是NetlinkManager类实例化的一个对象,以下是start()函数的源码:
-
-
-
-
- int NetlinkManager::start() {
- struct sockaddr_nl nladdr;
- int sz = 64 * 1024;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
- nladdr.nl_pid = getpid();
- nladdr.nl_groups = 0xffffffff;
-
- if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
- SLOGE("Unable to create uevent socket: %s", strerror(errno));
- return -1;
- }
-
- if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
- SLOGE("Unable to set uevent socket options: %s", strerror(errno));
- return -1;
- }
-
- if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
- SLOGE("Unable to bind uevent socket: %s", strerror(errno));
- return -1;
- }
-
-
-
-
-
- mHandler = new NetlinkHandler(mSock);
- if (mHandler->start()) {
- SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
- return -1;
- }
- return 0;
- }
-
-
-
-
-
- int NetlinkHandler::start() {
- return this->startListener();
- }
-
-
-
-
- int SocketListener::startListener() {
- if (!mSocketName && mSock == -1) {
- SLOGE("Failed to start unbound listener");
- errno = EINVAL;
- return -1;
- } else if (mSocketName) {
- if ((mSock = android_get_control_socket(mSocketName)) < 0) {
- SLOGE("Obtaining file descriptor socket '%s' failed: %s",
- mSocketName, strerror(errno));
- return -1;
- }
- }
-
- if (mListen && listen(mSock, 4) < 0) {
- SLOGE("Unable to listen on socket (%s)", strerror(errno));
- return -1;
- } else if (!mListen)
- mClients->push_back(new SocketClient(mSock));
-
- if (pipe(mCtrlPipe)) {
- SLOGE("pipe failed (%s)", strerror(errno));
- return -1;
- }
-
-
-
- if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
- SLOGE("pthread_create (%s)", strerror(errno));
- return -1;
- }
-
- return 0;
- }
-
-
-
-
-
-
-
-
- void *SocketListener::threadStart(void *obj) {
- SocketListener *me = reinterpret_cast<SocketListener *>(obj);
-
- me->runListener();
- pthread_exit(NULL);
- return NULL;
- }
-
-
-
-
-
- void SocketListener::runListener() {
- while(1) {
- SocketClientCollection::iterator it;
- fd_set read_fds;
- int rc = 0;
- int max = 0;
-
- FD_ZERO(&read_fds);
-
- if (mListen) {
- max = mSock;
- FD_SET(mSock, &read_fds);
- }
-
- FD_SET(mCtrlPipe[0], &read_fds);
- if (mCtrlPipe[0] > max)
- max = mCtrlPipe[0];
-
- pthread_mutex_lock(&mClientsLock);
- for (it = mClients->begin(); it != mClients->end(); ++it) {
- FD_SET((*it)->getSocket(), &read_fds);
- if ((*it)->getSocket() > max)
- max = (*it)->getSocket();
- }
- pthread_mutex_unlock(&mClientsLock);
-
- if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
- SLOGE("select failed (%s)", strerror(errno));
- sleep(1);
- continue;
- } else if (!rc)
- continue;
-
- if (FD_ISSET(mCtrlPipe[0], &read_fds))
- break;
- if (mListen && FD_ISSET(mSock, &read_fds)) {
- struct sockaddr addr;
- socklen_t alen = sizeof(addr);
- int c;
-
- if ((c = accept(mSock, &addr, &alen)) < 0) {
- SLOGE("accept failed (%s)", strerror(errno));
- sleep(1);
- continue;
- }
- pthread_mutex_lock(&mClientsLock);
- mClients->push_back(new SocketClient(c));
- pthread_mutex_unlock(&mClientsLock);
- }
-
- do {
- pthread_mutex_lock(&mClientsLock);
- for (it = mClients->begin(); it != mClients->end(); ++it) {
- int fd = (*it)->getSocket();
- if (FD_ISSET(fd, &read_fds)) {
- pthread_mutex_unlock(&mClientsLock);
-
-
-
-
-
- if (!onDataAvailable(*it)) {
- close(fd);
- pthread_mutex_lock(&mClientsLock);
- delete *it;
- it = mClients->erase(it);
- pthread_mutex_unlock(&mClientsLock);
- }
- FD_CLR(fd, &read_fds);
- continue;
- }
- }
- pthread_mutex_unlock(&mClientsLock);
- } while (0);
- }
- }
-
-
-
-
-
-
- bool NetlinkListener::onDataAvailable(SocketClient *cli)
- {
- int socket = cli->getSocket();
- int count;
-
- if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
- SLOGE("recv failed (%s)", strerror(errno));
- return false;
- }
-
- NetlinkEvent *evt = new NetlinkEvent();
- if (!evt->decode(mBuffer, count)) {
- SLOGE("Error decoding NetlinkEvent");
- goto out;
- }
-
- onEvent(evt);
- out:
- delete evt;
- return true;
- }
|