`
jgsj
  • 浏览: 962306 次
文章分类
社区版块
存档分类
最新评论

Android之vold进程启动源码分析

 
阅读更多

1.Vold (Volume Daemon)介绍

vold进程接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等;当外部设备发生变化时,内核通过Netlink发送uEvent格式的消息给用户空间程序,Netlink 是一种基于异步通信机制,在内核与用户应用间进行双向数据传输的特殊 socket,用户态应用使用标准的socket API 就可以使用 netlink 提供的强大功能;

2.Vold 框架设计




Vold是native程序,用于管理和控制Android平台外部存储设备的管控中心,是一个后台运行的进程。它与Java层的MountService交互,Vold接收来自kernel的uevent消息,然后向上层转发,MountService接收来自vold的消息,同时也可以向vold发送控制命令。从以上Vold设计框架图中可以看到,Vold有三个模块,分别为NetlinkManager,VolumeManager,CommandListener。
NetlinkManager模块专门接收来自Linux内核uevent消息,并将消息转发给VolumeManager处理,VolumeManager模块接着又把相关信息通过CommandListener发送给MountService,MountService根据收到的消息会发送相应的处理命令给VolumeManager,VolumeManager接收到命令后直接对外部存储设备进行操作。
CommandListener模块内部封装良一个Socket用于跨进程通信,Java层的客户端MountService就是通过该Socket和服务端Vold进行通信的。


1.Netlink介绍

Netlink是Linux系统中用户空间进程和Kernel进行通信的一种机制,用户空间进程可以接收来自Kernel的消息,同时也可以向Kernel发送一些控制命令。LINUX netlink机制一文中详细介绍了Netlink的用法。

2.Uevent介绍

uevent和Linux的设备文件系统及设备模型有关,是sysfs向用户空间发送的消息。消息格式实际上是一串字符串。当外部设备发生变化时,会引起Kernel发送Uevent消息;一般设备在/sys对应的目录下有个叫uevent的文件,往该文件里写入指定数据,也会触发Kernel发送和该设备相关的uevent消息,内核通过uevent告知外部存储系统发生的变化。

3.Vold 源码分析

\system\vold\main.cpp
int main() 
{
        VolumeManager *vm;
        CommandListener *cl;
        NetlinkManager *nm;
        //创建vold设备文件夹
        mkdir("/dev/block/vold", 0755);
        
        //初始化Vold相关的类实例 single
        vm = VolumeManager::Instance();
        nm = NetlinkManager::Instance();
        
        //CommandListener 创建vold socket监听上层消息
        cl = new CommandListener();
        vm->setBroadcaster((SocketListener *) cl);
        nm->setBroadcaster((SocketListener *) cl);
        
        //启动VolumeManager 
        vm->start();
        
        //根据配置文件/etc/vold.fstab 初始化VolumeManager 
        process_config(vm);
        
        //启动NetlinkManager socket监听内核发送uevent
        nm->start();
        
        //向/sys/block/目录下所有设备uevent文件写入“add\n”,
        //触发内核sysfs发送uevent消息
        coldboot("/sys/block");
        
        //启动CommandListener监听vold socket
        cl->startListener();
        
        // Eventually we'll become the monitoring thread
        while(1) {
            sleep(1000);
        }
        
        exit(0);
}
/etc/vold.fstab的内容如下:
#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
## label        - Label for the volume
## mount_point  - Where the volume will be mounted
## part         - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
######################

# Mounts the first usable partition of the specified device
#dev_mount sdcard /mnt/sdcard auto /block/mmcblk0
dev_mount internal /mnt/sdcard 19 /devices/platform/sprd-sdhci.3/mmc_host/mmc3
dev_mount sdcard /mnt/sdcard/external auto /devices/platform/sprd-sdhci.0/mmc_host/mmc0

process_config解析vold.fstab文件:
static int process_config(VolumeManager *vm) {
        //打开vold.fstab的配置文件
        fp = fopen("/etc/vold.fstab", "r")
        //解析vold.fstab 配置存储设备的挂载点
    while(fgets(line, sizeof(line), fp)) {
        const char *delim = " \t";
        char *type, *label, *mount_point, *part, *mount_flags, *sysfs_path;

        type = strtok_r(line, delim, &save_ptr)
        label = strtok_r(NULL, delim, &save_ptr)
        mount_point = strtok_r(NULL, delim, &save_ptr)
              //判断分区 auto没有分区
        part = strtok_r(NULL, delim, &save_ptr)
        if (!strcmp(part, "auto")) {
             //创建DirectVolume对象 相关的挂载点设备的操作
           dv = new DirectVolume(vm, label, mount_point, -1);
        } else {
           dv = new DirectVolume(vm, label, mount_point, atoi(part));
        }
                //添加挂载点设备路径
        while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {
            dv->addPath(sysfs_path)
        }
              //将DirectVolume 添加到VolumeManager管理
              vm->addVolume(dv);
    }

    fclose(fp);
    return 0;
}

4.Vold各模块分析

前面介绍了Vold包含NetlinkManager,VolumeManager,CommandListener三大模块,他们之间的关系如下:

接下来就分别针对每个模块进行详细分析。

1.NetlinkManager模块

NetlinkManager模块接收从Kernel发送的Uevent消息,解析转换成NetlinkEvent对象;再将此NetlinkEvent对象传递给VolumeManager处理。
启动流程
1)构造NetlinkManager实例:nm = NetlinkManager::Instance()
2)设置事件广播监听:nm->setBroadcaster((SocketListener *) cl)
3)启动NetlinkManager:nm->start()

构造NetlinkManager实例

NetlinkManager *NetlinkManager::Instance() {
    if (!sInstance) //采用单例模式创建NetlinkManager实例
        sInstance = new NetlinkManager();
    return sInstance;
}

启动NetlinkManager

int NetlinkManager::start() {
    //netlink使用的socket结构
    struct sockaddr_nl nladdr;
        
    //初始化socket数据结构
    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = 0xffffffff;
    //创建socket PF_NETLINK类型
    mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
    //配置socket 大小
    setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz);
    setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on);
    //bindsocket地址
    bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr);
        
    //创建NetlinkHandler 传递socket标识,并启动
    mHandler = new NetlinkHandler(mSock);
    mHandler->start();
    return 0;
}
在启动NetlinkManager时,初始化socket用于创建NetlinkManager的属性变量mHandle实例,并启动NetlinkHandler,NetlinkHandler继承于NetlinkListener,NetlinkListener又继承于SocketListener,因此在构造NetlinkHandler实例时首先构造SocketListener及NetlinkListener,构造NetlinkListener对象的父类对象SocketListener:
SocketListener::SocketListener(int socketFd, bool listen) {
    init(NULL, socketFd, listen, false);
}
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
    mListen = listen;
    mSocketName = socketName;
    mSock = socketFd;
    mUseCmdNum = useCmdNum;
    pthread_mutex_init(&mClientsLock, NULL);
    mClients = new SocketClientCollection();
}
NetlinkListener构造函数:
NetlinkListener::NetlinkListener(int socket) :
                            SocketListener(socket, false) {
    mFormat = NETLINK_FORMAT_ASCII;
}
NetlinkHandler构造函数:
NetlinkHandler::NetlinkHandler(int listenerSocket) :
                NetlinkListener(listenerSocket) {
}
因此构造NetlinkHandler实例过程仅仅创建良一个socket客户端连接。
NetlinkHandler start:
int NetlinkHandler::start() {
    //父类startListener
    return this->startListener();
}
SocketListenerstart:
int SocketListener::startListener() {
   //NetlinkHandler mListen为false 
    if (mListen && listen(mSock, 4) < 0) {
        return -1;
    } else if (!mListen){
        //mListen为false 用于netlink消息监听
        //创建SocketClient作为SocketListener 的客户端 
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
    }

    //创建匿名管道
    pipe(mCtrlPipe);
    //创建线程执行函数threadStart    参this
    pthread_create(&mThread, NULL, SocketListener::threadStart, this);
}

uevent消息监听线程

启动NetlinkHandler过程通过创建一个SocketListener工作线程来监听Kernel netlink发送的UEvent消息,该线程完成的工作:
void *SocketListener::threadStart(void *obj) {

    //参数转换
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();

    pthread_exit(NULL);

    return NULL;

}
SocketListener线程消息循环:
void SocketListener::runListener() {
        //SocketClient List
    SocketClientCollection *pendingList = new SocketClientCollection();

    while(1) {
        fd_set read_fds;
        //mListen 为false
        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }
        //加入一组文件描述符集合 选择fd最大的max
        FD_SET(mCtrlPipe[0], &read_fds);
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max)
                max = fd;
        }
        pthread_mutex_unlock(&mClientsLock);
        
        //监听文件描述符是否变化
        rc = select(max + 1, &read_fds, NULL, NULL, NULL);
        //匿名管道被写,退出线程
        if (FD_ISSET(mCtrlPipe[0], &read_fds))
            break;
        //mListen 为false
        if (mListen && FD_ISSET(mSock, &read_fds)) {
                //mListen 为ture 表示正常监听socket
            struct sockaddr addr;
            do {
                //接收客户端连接
                c = accept(mSock, &addr, &alen);
            } while (c < 0 && errno == EINTR);
            
            //此处创建一个客户端SocketClient加入mClients列表中,异步延迟处理
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
        pendingList->clear();
        //将所有有消息的Client加入到pendingList中
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                pendingList->push_back(*it);
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        //处理所有消息
        while (!pendingList->empty()) {
            it = pendingList->begin();
            SocketClient* c = *it;
            pendingList->erase(it);
               //处理有数据发送的socket 虚函数
            if (!onDataAvailable(c) && mListen) {
               //mListen为false
            }
        }
    }
}
在消息循环中调用onDataAvailable处理消息,onDataAvailable是个虚函数,NetlinkListener重写了此函数。
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
    //获取socket id
    int socket = cli->getSocket();
    //接收netlink uevent消息
    count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(
                                 socket, mBuffer, sizeof(mBuffer), &uid));
    //解析uevent消息为NetlinkEvent消息
    NetlinkEvent *evt = new NetlinkEvent();
    evt->decode(mBuffer, count, mFormat);
    
    //处理NetlinkEvent onEvent虚函数
    onEvent(evt);
}
将接收的Uevent数据转化成NetlinkEvent数据,调用onEvent处理,NetlinkListener子类NetlinkHandler重写了此函数。
void NetlinkHandler::onEvent(NetlinkEvent *evt) {

    //获取VolumeManager实例
    VolumeManager *vm = VolumeManager::Instance();

    //设备类型
    const char *subsys = evt->getSubsystem();
                 
    //将消息传递给VolumeManager处理
    if (!strcmp(subsys, "block")) {
        vm->handleBlockEvent(evt);

    }
}

NetlinkManager通过NetlinkHandler将接收到Kernel内核发送的Uenvet消息,转化成了NetlinkEvent结构数据传递给VolumeManager处理,uevent消息的上传流程:


2.VolumeManager模块

启动流程
1)构造VolumeManager对象实例
2)设置事件广播监听
3)启动VolumeManager
4)配置VolumeManager

VolumeManager类关系图:


DirectVolume是一个实体存储设备的抽象,通过系统调用直接操作存储设备。VolumeManager的SocketListenner与NetlinkManager的SocketListenner有所不同的:

NetlinkManager构造的SocketListenner:Kernel与Vold通信;

VolumeManager构造的SocketListenner:Native Vold与Framework MountService 通信;

NetlinkManager与VolumeManager交互流程图:



1.构造VolumeManager对象

VolumeManager *VolumeManager::Instance() {
    if (!sInstance)
        sInstance = new VolumeManager();
    return sInstance;
}

VolumeManager::VolumeManager() {
    mDebug = false;
    mVolumes = new VolumeCollection();
    mActiveContainers = new AsecIdCollection();
    mBroadcaster = NULL;
    mUmsSharingCount = 0;
    mSavedDirtyRatio = -1;
    // set dirty ratio to 20 when UMS is active
    mUmsDirtyRatio = 20;
    mVolManagerDisabled = 0;
}

2.启动VolumeManager

int VolumeManager::start() {
    return 0;
}
VolumeManager启动过程什么都没有做。

3.uevent事件处理

前面NetlinkManager模块中介绍到,NetlinkHandler在onEvent函数中,将NetlinkEvent事件转交给VolumeManager处理:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
        ……
            //将消息传递给VolumeManager处理
        if (!strcmp(subsys, "block")) {
            vm->handleBlockEvent(evt);
        }
}

    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
        //有状态变化设备路径
      const char *devpath = evt->findParam("DEVPATH");

      //遍历VolumeManager中所管理Volume对象(各存储设备代码抽象)
      for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
          if (!(*it)->handleBlockEvent(evt)) {
              hit = true;
              break;
          }
    }
VolumeManager将消息交给各个DirectVolume对象处理:
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
    //从NetlinkEvent消息中取出有状态变化设备路径
    const char *dp = evt->findParam("DEVPATH");

    PathCollection::iterator  it;
    //遍历所有的存储设备
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        //根据存储设备路径进行匹配
        if (!strncmp(dp, *it, strlen(*it))) {
            /* 从NetlinkEvent消息中取出设备变化的动作 */
            int action = evt->getAction();
            /* 从NetlinkEvent消息中取出设备类型 */
            const char *devtype = evt->findParam("DEVTYPE");
            SLOGE("DirectVolume::handleBlockEvent() evt's DEVPATH= %s DEVTYPE= %s action= %d",dp, devtype, action);    //设备插入
            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);
                SLOGE("DirectVolume::handleBlockEvent() NlActionAdd - /dev/block/vold/%d:%d\n", major, minor);
                if (createDeviceNode(nodepath, major, minor)) {
                    SLOGE("Error making device node '%s' (%s)", nodepath,strerror(errno));
                }
                //新增磁盘
                if (!strcmp(devtype, "disk")) {
                    handleDiskAdded(dp, evt);
                //新增分区
                } else {
                    handlePartitionAdded(dp, evt);
                }
            //设备移除
            } else if (action == NetlinkEvent::NlActionRemove) {
                SLOGE("Volume  partition %d:%d removed",  atoi(evt->findParam("MAJOR")), atoi(evt->findParam("MINOR")));
                //删除磁盘
                if (!strcmp(devtype, "disk")) {
                    handleDiskRemoved(dp, evt);
                //删除分区
                } else {
                    handlePartitionRemoved(dp, evt);
                }
            //设备改变
            } else if (action == NetlinkEvent::NlActionChange) {
                //磁盘变化
                if (!strcmp(devtype, "disk")) {
                    handleDiskChanged(dp, evt);
                //分区变化
                } else {
                    handlePartitionChanged(dp, evt);
                }
            } else {
                    SLOGW("Ignoring non add/remove/change event");
            }

            return 0;
        }
    }
    errno = ENODEV;
    return -1;
}

每一个Volume可能对应多个Path;即一个挂载点对应多个物理设备,因此VolumeManager中的每一个Volume对象都需要处理SD状态变换消息,当新增一个disk时:

void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
    //主次设备号
    mDiskMajor = atoi(evt->findParam("MAJOR"));
    mDiskMinor = atoi(evt->findParam("MINOR"));
        
    //设备分区情况
    const char *tmp = evt->findParam("NPARTS");
  mDiskNumParts = atoi(tmp);
    
    if (mDiskNumParts == 0) {
        //没有分区,Volume状态为Idle
        setState(Volume::State_Idle);
    } else {
        //有分区未加载,设置Volume状态Pending
        setState(Volume::State_Pending);
    }
    //格式化通知msg:"Volume sdcard /mnt/sdcard disk inserted (179:0)"
    char msg[255];
    snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
    //调用VolumeManager中的Broadcaster——>CommandListener 发送此msg
    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);
}
将新增一个disk以消息的方式通过CommandListener向MountService发送,由于CommandListener继承于FrameworkListener,而FrameworkListener又继承于SocketListener,CommandListener和FrameworkListener都没用重写父类的sendBroadcast方法,因此消息是通过SocketListener的sendBroadcast函数向上层发送的,VolumeManager通知上层的消息流程图:

void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) 
{
    pthread_mutex_lock(&mClientsLock);
    //遍历所有的消息接收时创建的Client SocketClient
    // SocketClient将消息通过socket(“vold”)通信
    for (i = mClients->begin(); i != mClients->end(); ++i) {
        (*i)->sendMsg(code, msg, addErrno, false);
    }
    pthread_mutex_unlock(&mClientsLock);
}

3.CommandListener模块

1)构造CommandListener对象实例
2)调用startListener函数启动监听

1.构造CommandListener对象

CommandListener::CommandListener() :
                FrameworkListener("vold", true) {

    //注册Framework发送的相关命令 Command模式

    registerCmd(new DumpCmd());

    registerCmd(new VolumeCmd());

    registerCmd(new AsecCmd());

    registerCmd(new ObbCmd());

    registerCmd(new StorageCmd());

    registerCmd(new XwarpCmd());

    registerCmd(new CryptfsCmd());

}
父类FrameworkListener构造:
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
                            SocketListener(socketName, true, withSeq) {
    init(socketName, withSeq);
}
直接调用init函数;
void FrameworkListener::init(const char *socketName, bool withSeq) {
    mCommands = new FrameworkCommandCollection();
    errorRate = 0;
    mCommandCount = 0;
    mWithSeq = withSeq;
}
SocketListener的构造函数:
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
    init(socketName, -1, listen, useCmdNum);
}
同样调用init函数进行初始化:
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
    mListen = listen;
    mSocketName = socketName;
    mSock = socketFd;
    mUseCmdNum = useCmdNum;
    pthread_mutex_init(&mClientsLock, NULL);
    mClients = new SocketClientCollection();
}
构造CommandListener对象过程中,首先注册了各种命令,并创建良一个socket客户端连接。命令注册过程:
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    mCommands->push_back(cmd);
}
将各种命令存放到mCommand列表中。

2.启动CommandListener监听

int SocketListener::startListener() {
    //mSocketName = “Vold”
    mSock = android_get_control_socket(mSocketName);
        
    //NetlinkHandler mListen为true 监听socket
    if (mListen && < 0) {
        return -1;
    } else if (!mListen){
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
    }
        
    //创建匿名管道
    pipe(mCtrlPipe);
    //创建线程执行函数threadStart 参数this
    pthread_create(&mThread, NULL, SocketListener::threadStart, this);
}

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

void SocketListener::runListener() {
    //SocketClient List
    SocketClientCollection *pendingList = new SocketClientCollection();

    while(1) {
        fd_set read_fds;
                //mListen 为true
        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }
                //加入一组文件描述符集合 选择fd最大的max select有关
        FD_SET(mCtrlPipe[0], &read_fds);
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max)
                max = fd;
        }
        pthread_mutex_unlock(&mClientsLock);
        
        //监听文件描述符是否变化
        rc = select(max + 1, &read_fds, NULL, NULL, NULL);
        //匿名管道被写,退出线程
        if (FD_ISSET(mCtrlPipe[0], &read_fds))
            break;

        //mListen 为true
        if (mListen && FD_ISSET(mSock, &read_fds)) {
            //mListen 为ture 表示正常监听socket
            struct sockaddr addr;
            do {
                c = accept(mSock, &addr, &alen);
            } while (c < 0 && errno == EINTR);
            
            //创建一个客户端SocketClient,加入mClients列表中 到异步延迟处理
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
        pendingList->clear();
        //将所有有消息的Client加入到pendingList中
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                pendingList->push_back(*it);
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        /* Process the pending list, since it is owned by the thread,*/
        while (!pendingList->empty()) {
            it = pendingList->begin();
            SocketClient* c = *it;
               //处理有数据发送的socket 
            if (!onDataAvailable(c) && mListen) {
               //mListen为true
               ……
            }
        }
    }
}

启动CommandListener监听过程其实就是创建一个监听的工作线程,用于监听客户端即MountService发过来的命令。

3.消息处理

当接收到MountService发送的消息时,将回调onDataAvailable函数进行处理。CommandListener父类FrameworkCommand重写了消息处理onDataAvailable函数。

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    char buffer[255];
    //读取socket消息
    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {
            //根据消息内容 派发命令
            dispatchCommand(c, buffer + offset);
            offset = i + 1;
        }
    }
    return true;
}

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
   char *argv[FrameworkListener::CMD_ARGS_MAX];
    //解析消息内容 命令 参数
    ……
    
    //执行对应的消息
    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
        FrameworkCommand *c = *i;
        //匹配命令
        if (!strcmp(argv[0], c->getCommand())) {
            //执行命令
            c->runCommand(cli, argc, argv);
            goto out;
        }
    }
out:
        return;
}


对于VolumeCommand,其runCommand函数为:

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,int argc, char **argv) {
    dumpArgs(argc, argv, -1);
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }
    VolumeManager *vm = VolumeManager::Instance();
    int rc = 0;
    //查看存储设备
    if (!strcmp(argv[1], "list")) {
        return vm->listVolumes(cli);
    } else if (!strcmp(argv[1], "debug")) {
        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
            return 0;
        }
        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
    //挂载存储设备
    } else if (!strcmp(argv[1], "mount")) {
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
            return 0;
        }
        rc = vm->mountVolume(argv[2]);
    //卸载存储设备
    } else if (!strcmp(argv[1], "unmount")) {
        if (argc < 3 || argc > 4 ||
           ((argc == 4 && strcmp(argv[3], "force")) &&
            (argc == 4 && strcmp(argv[3], "force_and_revert")))) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);
            return 0;
        }

        bool force = false;
        bool revert = false;
        if (argc >= 4 && !strcmp(argv[3], "force")) {
            force = true;
        } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {
            force = true;
            revert = true;
        }
        rc = vm->unmountVolume(argv[2], force, revert);
    //格式化存储设备
    } else if (!strcmp(argv[1], "format")) {
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);
            return 0;
        }
        rc = vm->formatVolume(argv[2]);
    //共享存储设备
    } else if (!strcmp(argv[1], "share")) {
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: volume share <path> <method>", false);
            return 0;
        }
        rc = vm->shareVolume(argv[2], argv[3]);
    } else if (!strcmp(argv[1], "unshare")) {
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: volume unshare <path> <method>", false);
            return 0;
        }
        rc = vm->unshareVolume(argv[2], argv[3]);
    } else if (!strcmp(argv[1], "shared")) {
        bool enabled = false;
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: volume shared <path> <method>", false);
            return 0;
        }

        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
            cli->sendMsg(
                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
        } else {
            cli->sendMsg(ResponseCode::ShareEnabledResult,
                    (enabled ? "Share enabled" : "Share disabled"), false);
        }
        return 0;
    } else {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
    }

    if (!rc) {
        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
    } else {
        int erno = errno;
        rc = ResponseCode::convertFromErrno();
        cli->sendMsg(rc, "volume operation failed", true);
    }
    return 0;
}
针对不同的命令,调用VolumeManager的不同函数对存储设备进行操作,如挂载磁盘命令,则调用mountVolume函数:

int VolumeManager::mountVolume(const char *label) {
    //根据卷标查找Volume
    Volume *v = lookupVolume(label);
    if (!v) {
        errno = ENOENT;
        return -1;
    }
    return v->mountVol();
}
调用Volume的mountVol函数来挂载设备。MountServcie发送命令的流程图:




整个Vold处理过程框架图如下:


分享到:
评论

相关推荐

    《深入理解Android:卷I》试读本

    第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理等问题;第5章讲解了Android系统中常用的类,包括sp、wp、RefBase、Thread等类,...

    深入理解Android:卷I--详细书签版

    CruiseYoung提供的带有详细书签的电子书籍目录 ... 深入理解Android:卷I(51CTO网站“2011年度最受读者喜爱的原创IT技术... //这里是源码分析和一些注释。  如有一些需要特别说明的地方,则会用下面的格式表示:  ...

    深入理解Android 卷1.pdf

    第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理等问题;第5章讲解了Android系统中常用的类,包括sp、wp、RefBase、Thread等类,...

    深入理解Android++卷1pdf电子书

    第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理等问题;第5章讲解了Android系统中常用的类,包括sp、wp、RefBase、Thread等类,...

    深入理解Android卷1

    第4章分析了Z ygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理等问题;第5章讲解了Android系统中常用的类,包括sp、wp、RefBase、Thread等类,...

    深入理解Android:卷2

    第4章分析了Z ygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理等问题;第5章讲解了Android系统中常用的类,包括sp、wp、RefBase、Thread等类,...

    深入理解Android 卷I

    第4章分析了zygote、systemserver等进程的工作机制,同时还讨论了android的启动速度、虚拟机heapsize的大小调整、watchdog工作原理等问题;第5章讲解了android系统中常用的类,包括sp、wp、refbase、thread等类,...

    深入理解Android

    第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理等问题;第5章讲解了Android系统中常用的类,包括sp、wp、RefBase、Thread等类,...

Global site tag (gtag.js) - Google Analytics