android vold浅析(1)

来源:互联网 发布:网络调查软件 编辑:程序博客网 时间:2024/05/17 02:11
vold的全称是volume daemon。实际上是负责完成系统的CDROM, USB大容量存储,MMC卡等扩展存储的挂载任务自动完成的守护进程。它提供的主要特点是支持这些存储外设的热插拔。这里有GNU/Linux vold的介绍[http://vold.sourceforge.net/]。在Android上的这个vold系统和GNU/Linux的之间存在很大的差异,这里我们主要是分析Android上的vold系统的处理过程。

Vold处理过程大致分为三步:
1.创建链接:
在 vold作为一个守护进程,一方面接受驱动的信息,并把信息传给应用层;另一方面接受上层的命令并完成相应。所以这里的链接一共有两条:
(1)vold socket: 负责vold与应用层的信息传递;
(2)访问udev的socket: 负责vold与底层的信息传递;
这两个链接都是在进程的一开始完成创建的。

2.引导:
这里主要是在vold启动时,对现有外设存储设备的处理。首先,要加载并解析vold.conf,
并检查挂载点是否已经被挂载(注:这里检查挂载点的用意不是很清楚!); 其次,执行MMC卡挂载; 最后,处理USB大容量存储。

3.事件处理:
这里通过对两个链接的监听,完成对动态事件的处理,以及对上层应用操作的响应。

我们分析具体的代码

makefile文件位于/system/vold文件夹下的Android.mk
入口函数在main.cpp中

int main() {

    VolumeManager *vm;
    CommandListener *cl;
    NetlinkManager *nm;

    SLOGI("Vold 2.1 (the revenge) firing up");

    mkdir("/dev/block/vold", 0755);

    /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {
        SLOGE("Unable to create VolumeManager");
        exit(1);
    };
    //创建一个VolumeManager实例,具体的构造函数位于文件VolumeManager.cpp中

    if (!(nm = NetlinkManager::Instance())) {
        SLOGE("Unable to create NetlinkManager");
        exit(1);
    };
    //实例化一个NetlinkManager对象,具体的构造函数位于文件NetlinkManager.cpp中

    cl = new CommandListener();
    ************************************************************************
    //构造一个CommandListener对象,这个类定义在文件CommandListener.h中,继承了类FrameworkListener,这个类定义在sysutils/FrameworkListener.h中
    //这个类又继承了类SocketListener,这个类定义在文件SocketListener.h中,我们看文件/system/core/libsysutils/src/SocketListener.cpp
    //SocketListener::SocketListener(const char *socketName, bool listen) {
            mListen = listen;
            mSocketName = socketName;
            mSock = -1;
            pthread_mutex_init(&mClientsLock, NULL);
            mClients = new SocketClientCollection();  
                 //typedef android::List<SocketClient *> SocketClientCollection; SocketClientCollection是一个SocketClient类对象的集合
    }  */
    //
    //文件/system/core/libsysutils/src/FrameworkListener.cpp中定义了FrameworkListener类的构造函数
    FrameworkListener::FrameworkListener(const char *socketName) :
                            SocketListener(socketName, true) {
            mCommands = new FrameworkCommandCollection();
                //typedef android::List<FrameworkCommand *> FrameworkCommandCollection;
    } */
   //回头我们再看看CommandListener的构造函数
    CommandListener::CommandListener() :
                 FrameworkListener("vold") {
            registerCmd(new DumpCmd());
            registerCmd(new VolumeCmd());
            registerCmd(new AsecCmd());
            registerCmd(new ShareCmd());
            registerCmd(new StorageCmd());
            registerCmd(new XwarpCmd());
    } */
   //这里会调用其继承类的protected成员函数registerCmd,其参数是一个指向类FrameworkCommand的指针。类CommandListener包含几个私有的内部类class DumpCmd : public VoldCommand
         // class VolumeCmd : public VoldCommand
            class ShareCmd : public VoldCommand
            class AsecCmd : public VoldCommand
            class StorageCmd : public VoldCommand
            class XwarpCmd : public VoldCommand
    我们分析如何实例化一个DumpCmd
        CommandListener::DumpCmd::DumpCmd() :
                     VoldCommand("dump") {
        }
       其父类在文件system/vold/VoldCommand.cpp中
              VoldCommand::VoldCommand(const char *cmd) :
                      FrameworkCommand(cmd)  {
        }
       其父类FrameworkCommand::FrameworkCommand(const char *cmd) {
                mCommand = cmd;
        }
    同理创建VolumeCmd, AsecCmd, ShareCmd, StorageCmd, XwarpCmd
    其mCommand私有成员分别取值为 dump,  volume, asec, share, storage, xwarp


    我们看看怎么注册指令的
    void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
            mCommands->push_back(cmd);
     }  
    mCommands指向FrameworkCommandCollection 而FrameworkCommandCollection是一个包含FrameworkCommand指针的链表
    typedef android::List<FrameworkCommand *> FrameworkCommandCollection
    因此这里是将创建的FrameworkCommand指针对象压入链表存储起来
    ***************************************************************************


    vm->setBroadcaster((SocketListener *) cl);
    nm->setBroadcaster((SocketListener *) cl);
    /*
    设置vm的私有成员SocketListener        *mBroadcaster;
    使得mBroadcaster指向cl
    设置nm的私有成员mBroadcaster,同样指向cl
    */

    if (vm->start()) {
        SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
        exit(1);
    }
    //vm->start()始终返回0,什么都不做

    if (process_config(vm)) {
        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
    }
    /*
    解析/system/etc/vold.fstab文件,
    读取type, label, mount_point, part
    (1). 构建DirectVolume对象 :如果part为auto, 则调用dv = new DirectVolume(vm, label, mount_point, -1);
        (2). 添加vold.fstab中定义的某一挂载项对应的sysfs_path到 DirectVolume对象的mPaths容器  dv->addPath(sysfs_path);
        (3). 将这个DirectVolume 对象添加到 VolumeManager对象的容器mVolumes中   vm->addVolume(dv);
    */

    if (nm->start()) {
        SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
        exit(1);
    }
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    nm->start()会调用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;
            }
        //创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件

            mHandler = new NetlinkHandler(mSock);
        /*    
            利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener,NetlinkListener又继承了类SocketListener
            我们看看其构造的过程
            NetlinkHandler::NetlinkHandler(int listenerSocket) :  
                            NetlinkListener(listenerSocket) {
                } //NetlinkHandler.cpp
            
            NetlinkListener::NetlinkListener(int socket) :
                                    SocketListener(socket, false) {
                }//NetlinkListener.cpp

            SocketListener::SocketListener(int socketFd, bool listen) {
                    mListen = listen;
                    mSocketName = NULL;
                    mSock = socketFd;
                    pthread_mutex_init(&mClientsLock, NULL);
                    mClients = new SocketClientCollection();
            }
            */
        
            if (mHandler->start()) {
                SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
                return -1;
            }
        /*
            mHandler->start()调用this->startListener()
            最终会调用SocketListener::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));

                //实例化一个SocketClient,并将其压入mClients容器中
                    if (pipe(mCtrlPipe)) {
                        SLOGE("pipe failed (%s)", strerror(errno));
                        return -1;
                    }
                //建立管道, 并将文件描述词存于数组mCtrlPipe[2]中,mCtrlPipe[0]为管道的读取端,mCtrlPipe[1]为管道的写入端

                    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
                        SLOGE("pthread_create (%s)", strerror(errno));
                        return -1;
                    }
                /*
                    创建线程,线程号为mThread,.
                    线程函数为
                    void *SocketListener::threadStart(void *obj) {
                            SocketListener *me = reinterpret_cast<SocketListener *>(obj);
         
                            me->runListener();//将this即NetlinkHandler对象强制转换为SocketListener类型,调用其成员函数runListener()

                            pthread_exit(NULL);//线程退出,不会跑到这里
                            return NULL;
                    }
                */
******************************************************************************        
                    线程真正执行的函数:mListen成员用来判定是否监听套接字
                    Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用相关函数读取数据。    
                    void SocketListener::runListener() {

                            while(1) {//无线循环,一直监听
                            SocketClientCollection::iterator it;
                            fd_set read_fds;
                            int rc = 0;
                            int max = 0;

                            FD_ZERO(&read_fds); //清空文件描述符集read_fds

                            if (mListen) {
                                    max = mSock;
                                    FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds
                            }

                            FD_SET(mCtrlPipe[0], &read_fds); //添加管道的读取端文件描述符到read_fds
                            if (mCtrlPipe[0] > max)
                                    max = mCtrlPipe[0];

                            pthread_mutex_lock(&mClientsLock);//对容器mClients的操作需要加锁
                            for (it = mClients->begin(); it != mClients->end(); ++it) {
                                    FD_SET((*it)->getSocket(), &read_fds); //遍历容器mClients的所有成员,调用内联函数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) { //  等待文件描述符中某一文件描述符或者说socket有数据到来
                                    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) {  //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,
                                                    将其添加到mClient容器;
                                        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);
    }
}
原创粉丝点击