Android Vold 分析

- system/vold/main.cpp-----mian函数分析

Android2.2 Vold 分析-1---20110104

文件:system/vold/main.cpp-----mian函数分析

声明  VolumeManager *vm;  CommandListener *cl;    NetlinkManager *nm;对象指针;
创建目录/dev/block/vold    mkdir("/dev/block/vold", 0755);


分别构建VolumeManager 、 CommandListener 、NetlinkManager 对象*vm,*cl,*nm;
    if (!(vm = VolumeManager::Instance()))
    if (!(nm = NetlinkManager::Instance()))
    cl = new CommandListener();

广播相关参数  mBroadcaster = sl 设置;
    vm->setBroadcaster((SocketListener *) cl);
    nm->setBroadcaster((SocketListener *) cl);

解析 /system/etc/vold.fstab文件,做三件事:
     if (process_config(vm))
    (1). 构建DirectVolume对象 :中定义的挂载项构建对应的DirectVolume对象 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);

启动NetlinkManager,创建相应的socket,通过NetlinkHandler的start函数启动 SocketListener::startListen,关于SocketListener到后面再进行分析;
    nm->start()
int NetlinkManager::start()------->mHandler->start()-------->this->startListener()调用 SocketListener::startListen();
递归打开sys/block目录下的所有子目录    coldboot("/sys/block");
    /*
     * Switch uevents are broken.
     * For now we manually bootstrap
     * the ums switch
     */
查询/sys/devices/virtual/switch/usb_mass_storage/state状态信息,并发送广播
        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);        
监听命令,并进行相应的处理,Eventually we'll become the monitoring thread .
       cl->startListener()  调用SocketListener::startListener(),在startListener函数中启动线程pthread_create(&mThread, NULL, SocketListener::threadStart, this) ;

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener(); ------------>void SocketListener::runListener()无限循环,监听消息及消息出理
    pthread_exit(NULL);
    return NULL;
}

 

Vold 中 Netlink事件通信机制分析

Android2.2 Vold 分析-2---20110105

Vold 中 Netlink事件通信机制分析

NetlinkHandler的成员函数start()会调用SocketListener::startListen()

在system/vold/main.cpp main()函数中调用nl->start(),就是调用int NetlinkManager::start() 函数,该函数主要功能:

    (1). 创建NETLINK socket
    (2). 构建NetlinkHandler对象,并通过其成员函数start()调用SocketListener::startListen();
分析如下:
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) {}
    if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) { }
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {}

    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {  }
    return 0;
}
调用startListen,mSock前面创建,
int SocketListener::startListener() {

    if (!mSocketName && mSock == -1) { }
    else if (mSocketName) {
        if ((mSock = android_get_control_socket(mSocketName)) < 0) { }
    }
    if (mListen && listen(mSock, 4) < 0) {} //监听套接字执行这一部分
     else if (!mListen)   //如果非监听套接字(TCP有监听套接字,和数据交换套接字,UDP只有数据交换套接字),Netlink为UDP,所以执行这一部分;
         mClients->push_back(new SocketClient(mSock));          //直接执行这一行,将NetLink的socket添加到mClient容器中;
    if (pipe(mCtrlPipe)) { }
    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {  } //启动新的线程,这里的this 指的是NetlinkHandler的对象 如下:
    return 0;
}
线程函数:
void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);  //将NetlinkHandler对象强制转换为SocketListener类型对象,调用其runListener函数
    me->runListener();
 }
线程真正执行的函数: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);
        if (mCtrlPipe[0] > max)
            max = mCtrlPipe[0];

        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {   //将容器nClient中的sockets添加到文件描述符集read_fds
            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) {   //等待文件描述符中某一文件描述符或者说socket有数据到来
             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器;
                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);
    }
}

分析函数: onDataAvailable(*it)
onDataAvailable是在类SocketListener中定义的纯虚函数,在Android2.2中共有五个类继承该类,并对函数onDataAvailable进行了实现,分别是:
    DhcpListener(system\core\nexus)、
    FrameworkListener(system\core\libsysutils\src)、
    NetlinkListener(system\core\libsysutils\src)、
    SupplicantListener(system\core\nexus)、
    TiwlanEventListener(system\core\nexus);

针对Netlink创建的套接字,是由NetlinkHandler对象调用的startListen函数,并开启的相关线程,而且NetlinkHandler继承了NetlinkListener,
所以此处调用的是NetlinkListener类的成员函数onDataAvailable;
system\core\libsysutils\src/NetlinkListener.cpp
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
    int socket = cli->getSocket();
    int count;

    if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {  } //读取数据

    NetlinkEvent *evt = new NetlinkEvent(); 
    if (!evt->decode(mBuffer, count)) {  }

    onEvent(evt);   //NetlinkListener类定义了纯虚函数,其子类NetlinkHandler对其进行了实现,所以此处调用子类NetlinkHandler的onEvent函数;
out:
    delete evt;
    return true;
}

onEvent 函数分析:
system/vold/NetlinkHandler.cpp

void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();

    if (!subsys) {
        SLOGW("No subsystem found in netlink event");
        return;
    }

    if (!strcmp(subsys, "block")) {
        vm->handleBlockEvent(evt); 
    } else if (!strcmp(subsys, "switch")) {
        vm->handleSwitchEvent(evt);
    } else if (!strcmp(subsys, "battery")) {
    } else if (!strcmp(subsys, "power_supply")) {
    }
}

这下子又回到了vold进程中,到此在android中vold相关部分的Netlink event传递机制分析完成,下一步该分析真正的vold管理部分了

 

Vold 中 volumeManager分析

Android2.2 Vold 分析-2---20110105-2

Vold 中 volumeManager分析

void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();

    if (!strcmp(subsys, "block")) {
        vm->handleBlockEvent(evt);     //udisk/sdcard 主要涉及这一部分,调用VolumeManager类的成员函数handleBlockEvent;
    } else if (!strcmp(subsys, "switch")) {
        vm->handleSwitchEvent(evt);
    } else if (!strcmp(subsys, "battery")) {
    } else if (!strcmp(subsys, "power_supply")) {
    }
}
VolumeManager的成员函数handleBlockEvent 遍历mVolumes容器中的所有volume,进行处理;
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    const char *devpath = evt->findParam("DEVPATH");

    /* Lookup a volume to handle this device */
    VolumeCollection::iterator it;
    bool hit = false;
    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
        if (!(*it)->handleBlockEvent(evt)) {   }  
                //由于VolumeCollection是Volume类型的容器,所以这里应该是调用volume类的成员函数handleBlockEvent()或其子类DirectVolume的成员函数handleBlockEvent();
    }
}
在我的博文 “Android Vold 分析(一)--system/vold/main.cpp-----mian函数分析”中分析了process_config函数,该函数的一个功能就是为system/etc/vold.fstab中定义的每一挂载项构建一个DirectVolume对象,然后将这个DirectVolume对象添加到容器mVolumes,所以这里执行的一定是DirectVolume类的成员函数;
volume类的成员函数handleBlockEvent()
int Volume::handleBlockEvent(NetlinkEvent *evt) {
    errno = ENOSYS;
    return -1;
}
DirectVolume的成员函数handleBlockEvent()
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
    const char *dp = evt->findParam("DEVPATH");
在我的博文 “Android Vold 分析(一)--system/vold/main.cpp-----mian函数分析”中分析了process_config函数,该函数的一个功能就是将system/etc/vold.fstab中定义的每一挂载的sysfs_path添加到容器mPaths;
    PathCollection::iterator  it;
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        if (!strncmp(dp, *it, strlen(*it))) {                                      //遍历mPaths容器,寻找与event对应的sysfs_path是否存在于容器mPaths中;
            /* We can handle this disk */
            int action = evt->getAction();
            const char *devtype = evt->findParam("DEVTYPE");
//针对Event中的action 有四种处理方式:Add,  Remove, Change,noaction;分别如下:
            if (action == NetlinkEvent::NlActionAdd) {
                int major = atoi(evt->findParam("MAJOR"));
                int minor = atoi(evt->findParam("MINOR"));
                char nodepath[255];

                snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",major, minor);
                if (createDeviceNode(nodepath, major, minor)) { }        //创建设备节点;
//每一种处理方式中按照devtype又分为disk和partion分别进行处理;
                if (!strcmp(devtype, "disk")) {
                    handleDiskAdded(dp, evt);
                } else {
                    handlePartitionAdded(dp, evt);
                }
     ...   ... 
}

分析 handleDiskAdded(dp, evt)

void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
    mDiskMajor = atoi(evt->findParam("MAJOR"));
    mDiskMinor = atoi(evt->findParam("MINOR"));

    const char *tmp = evt->findParam("NPARTS");   //分区个数
    if (tmp) {
        mDiskNumParts = atoi(tmp);
    } else {
        SLOGW("Kernel block uevent missing 'NPARTS'");
        mDiskNumParts = 1;
    }
    char msg[255];
    int partmask = 0;
    int i;
    for (i = 1; i <= mDiskNumParts; i++) {
        partmask |= (1 << i);
    }
    mPendingPartMap = partmask;

    setState(Volume::State_Idle);

    snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); 广播disk insert消息,请求对该事件进行处理;

//这里对该消息的广播对象也就是发给谁分析一下:
mVm是DirectVolume集成自Volume类的成员调用mVm->getBroadcaster()返回的是 VolumeManager类对象的成员mBroadcaster,mBroadcast 是在main.cpp中调用vm->setBroadcaster((SocketListener *) cl)而来的,所以其实mVm->getBroadcaster()返回的是经过强制类型转换的cl对象指针((SocketListener *) cl);相当于cl->sendBroadcast(...);
*********************
class VolumeManager 部分
 void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
    SocketListener *getBroadcaster() { return mBroadcaster; }
*********************
所以消息发送的对象还是cl->mClients容器中的socket;
}
下节分析消息接收部分

 

Vold 消息接收及挂载/卸载处理部分分析

Android2.2 Vold 分析-(四)---20110106

Vold 消息接收及挂载/卸载处理部分分析

我们知道在关于Vold分析的第一篇“system/vold/main.cpp-----mian函数分析” 中,除了NetlinkManager 对象nm间接启动了startListner线程之外,还有一个CommandListener对象cl启动了startListener线程;

     cl->startListener()  调用SocketListener::startListener(),在startListener函数中启动线程pthread_create(&mThread, NULL, SocketListener::threadStart, this) ;
下面我们顺着这条线分析命令监听:
类的集成关系
    CommandListener ------> FrameworkListener ----------> SocketListener(基类)
所以此处是cl调用了基类SocketListener的成员函数SocketListener::startListener();

这一部分与Android2.2 Vold分析(二)中一样,不再赘述。
startListener()开启线程SocketListener::threadStart,并把cl(this)作为参数传递给线程函数SocketListener::threadStart();
在threadStart()函数中以传进来的this对象指针调用SocketListener::runListener(),在该函数中完成监听套接字的处理及非监听套接字的数据获取函数调用onDataAvailable(*it);
这里有两个问题:
    (1). 究竟调用那个类的onDataAvailable(*it);
    (2). 该线程处理的是那个套接字?是否为监听套接字?
下面先分析问题(2):
    在main.cpp中构建CommandListener对象时,除构建自身外还向其父类传递了参数"vold",如下:
CommandListener::CommandListener() :
                 FrameworkListener("vold") {
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ShareCmd());
    registerCmd(new StorageCmd());
    registerCmd(new XwarpCmd());
}
同时构建该对像的父类FrameworkListener部分,并向其父类传递参数socketName, true(“vold”,true),套接字名称vold为监听套接字;
FrameworkListener::FrameworkListener(const char *socketName) :
                            SocketListener(socketName, true) {
    mCommands = new FrameworkCommandCollection();
}
同时构建该对像的父类的父类部分SocketListener;
SocketListener::SocketListener(const char *socketName, bool listen) {
    mListen = listen;             //true 是监听套接字
    mSocketName = socketName;
    mSock = -1;
    pthread_mutex_init(&mClientsLock, NULL);
    mClients = new SocketClientCollection();
}
这里会声明一个该对像自己的SocketClientCollection容器mClients;
这里可以回答问题(2)了:套接字“vold”在init进程启动vold是创建,并且为监听套接字,可以从init.rc中看出
**********************
init.rc部分
service vold /system/bin/vold
    socket vold stream 0660 root mount  //流式套接字
    ioprio be 2

**********************
int SocketListener::startListener() {

    if (!mSocketName && mSock == -1) {  }
    else if (mSocketName) {
        if ((mSock = android_get_control_socket(mSocketName)) < 0) { } //根据mSocketName 查找获得对应的socket文件描述符
    }

    if (mListen && listen(mSock, 4) < 0) {   }          //阻塞监听,如果有连接请求到来则正确返回执行下面的线程函数threadStart函数,如果没有则一直阻塞,或错误返回;另依当前的代码,当正确接收到一个链接请求返回后,不会再继续监听,所以此处只能是有一对连接;
    else if (!mListen)
        mClients->push_back(new SocketClient(mSock));
    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {  }
    return 0;
}
线程函数:传递的obj是this指针,调用这是CommandListener对象指针cl,所以此时this指的是cl;
void *SocketListener::threadStart(void *obj) {
     me->runListener();      //相当于cl调用runListener();
  }
真正的线程执行函数
该线程是cl对象指针调用,并且接收cl->sendBroadcast()发来的消息,进行处理;
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);            //将监听套接字添加到文件描述符集read_fds;
        } 
        ... ...
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            FD_SET((*it)->getSocket(), &read_fds);         //将容器nClient中的sockets添加到文件描述符集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容器,cl调用执行这一步
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c));     //将以c为参数构建新的SocketClient,并添加到cl->mClient容器;
            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)) {                   //调用相应的数据读取函数,读取数据,这里自然是调用cl->onDataAvailable(),但是cl类中没有该成员函数,那么在其父类FrameworkListener中查找
                        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);
    }
}

实际执行FrameworkListener::onDataAvailable(SocketClient *c)

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    char buffer[255];
    int len;

    if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
        SLOGE("read() failed (%s)", strerror(errno));
        return errno;
    } else if (!len)
        return false;

    int offset = 0;
    int i;

    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {
            dispatchCommand(c, buffer + offset);    //分发命令
            offset = i + 1;
        }
    }
    return true;
}

分发命令,cl对象在构建是注册了许多命令,在这里查找,并执行相关命令
CommandListener::CommandListener() :
                 FrameworkListener("vold") {
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ShareCmd());
    registerCmd(new StorageCmd());
    registerCmd(new XwarpCmd());
}
调用其父类FrameworkListener的成员函数registerCmd将命令注册到mCommands容器;
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    mCommands->push_back(cmd);
}

分析接收到的数据,解析出命令,在mCommands中进行查找,然后执行
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
    FrameworkCommandCollection::iterator i;
    int argc = 0;
    char *argv[FrameworkListener::CMD_ARGS_MAX];
          。。。 。。。   
    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
        FrameworkCommand *c = *i;

        if (!strcmp(argv[0], c->getCommand())) {
            if (c->runCommand(cli, argc, argv)) {          //调用相应的命令执行
                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
            }
            goto out;
        }
    }

    cli->sendMsg(500, "Command not recognized", false);
out:
    int j;
    for (j = 0; j < argc; j++)
        free(argv[j]);
    return;
}
到此vold分析完成,下面以磁盘挂载为例说明消息接收及处理部分函数,下一篇对vold的整体实现机制进行总结
例如,handleDiskAdded发送的消息是ResponseCode::VolumeDiskInserted;
snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) 执行c->runCommand(cli,argc,argv)
argc = 3;
然后调用vm->mountVolume(argv[2]);
int VolumeManager::mountVolume(const char *label) {
    Volume *v = lookupVolume(label);

    if (!v) {
        errno = ENOENT;
        return -1;
    }

    return v->mountVol();
}
真正的磁盘挂载执行函数
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(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;
    }

    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);

        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;
        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();

        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.
         */
        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);
        mCurrentlyMountedKdev = deviceNodes[i];
        return 0;
    }

    SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
    setState(Volume::State_Idle);

    return -1;
}


本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-02/32094p4.htm

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值