Vold 流程介绍

前言

印象中是参考 《深入理解 Android 卷 1 》 追的流程,差不多供参考吧
基于安卓 4.4

框架

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MountService 流程

/*

【初始化流程总结】:
SystemServer
    initAndLoop()
        ////////////////////////////////////////////////////////////
        // 创建 MountService 服务对象
        mountService = new MountService(context);
                        //////////////////////////////////////////
                        MountService::MountService(Context context) 
                            ///////////////////////////////////////////////////////////////////////////////////////////
                            // 从 xml 中读取存储设备列表,文件位于: frameworks/base/core/res/res/xml/storage_list.xml
                            readStorageListLocked();

                            ///////////////////////////////////////////////////////////////
                            // 创建并启动一个带消息循环的 MountService 工作线程  
                            HandlerThread hthread = new HandlerThread(TAG);
                            hthread.start();
                            // 为 MountService 工作线程创建一个 Handler 
                            // 有消息时时会调用 MountServiceHandler::handleMessage() 处理
                            // 处理的消息类型为: H_UNMOUNT_PM_UPDATE,H_UNMOUNT_PM_DONE,H_UNMOUNT_MS
                            mHandler = new MountServiceHandler(hthread.getLooper());

                            ///////////////////////////////////////////////////////////////
                            // Watch for user changes
                            // 注册一系列变化广播接收器
                            final IntentFilter userFilter = new IntentFilter();
                            userFilter.addAction(Intent.ACTION_USER_ADDED);
                            userFilter.addAction(Intent.ACTION_USER_REMOVED);
                            userFilter.addAction(Intent.ACTION_USER_SWITCHED);
                            mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
                            。。。
                            //////////////////////////////////////////////////////////////////////////
                           // Add OBB Action Handler to MountService thread.
                           // 为 MountService 工作线程创建一个 ObbActionHandler  
                           mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

                            ////////////////////////////////////////////////////////////////////////////
                            //
                            // Create the connection to vold with a maximum queue of twice the
                            // amount of containers we'd ever expect to have. This keeps an
                            // "asec list" from blocking a thread repeatedly.
                            //
                            mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
                            // 创建并启动一个 socket 连接监听线程
                            Thread thread = new Thread(mConnector, VOLD_TAG);
                            thread.start();// 会执行到传入参数的 run() 函数 
                                        ///////////////////////////////////////
                                        NativeDaemonConnector::run()
                                            mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
                                            while (true) {
                                                try {
                                                    // 监听套接字 vold 
                                                    listenToSocket();
                                                } catch (Exception e) {
                                                    loge("Error in NativeDaemonConnector: " + e);
                                                    SystemClock.sleep(5000);
                                                }
                                            }

                            /////////////////////////////////////////////////////////////////////////////
                            // Add ourself to the Watchdog monitors if enabled.
                            if (WATCHDOG_ENABLE) {
                                Watchdog.getInstance().addMonitor(this);
                            }

        ///////////////////////////////////////////////////////////////////////
        // 将 mountService 服务注册到 C++ 层的 service manager 进程中管理 
        ServiceManager.addService("mount", mountService);


【MountService 命令下发流程】:
MountService::mountVolume()
        // 核心函数
        int ret = doMountVolume(path); 
                // 命令交给 NativeDaemonConnector::execute() 去发送
                mConnector.execute(cmd);
                        //////////////////////////////////////////////////////////////
                        NativeDaemonConnector::execute()
                                // 构造命令
                                makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);
                                //////////////////////////////////////////////////////////////
                                // 向 socket 中写入命令
                                mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));

【MountService 消息接收流程】:
//////////////////////////////////////////////////////////////////////////// 
// 监听套接字是通过 NativeDaemonConnector 类实现的,它在 MountService 的构造函数中创建并初始化的
NativeDaemonConnector::run()
    mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
    while (true) {
        try {
            // 监听套接字 vold 
            listenToSocket();
                    //创建 Vold socket  
                    socket = new LocalSocket();
                    //向服务端发起连接请求  
                    socket.connect(address);
                    //从连接的 socket 中得到输入输出流 
                    InputStream inputStream = socket.getInputStream();
                    /////////////////////////////////////////////////////////////
                    // 对本次连接请求做一些回调处理, 连接成功回调处理
                    mCallbacks.onDaemonConnected();
                            //////////////////////////////////////////////////////
                            //////////////////////////////////////////////////////
                            MountService::onDaemonConnected()
                                /////////////////////////////////////////////
                                // 创建一个工作线程处理回调
                                new Thread("MountService#onDaemonConnected")
                                {
                                    run()
                                    {
                                       ////////////////////////////////////////////////////////////////////////
                                       // 向vold查询所有的存储设备  
                                       final String[] vols = NativeDaemonEvent.filterMessageList(
                                               mConnector.executeForList("volume", "list"),
                                               VoldResponseCode.VolumeListResult);

                                        /////////////////////////////////////////////////////////////////////////
                                        //判断存储设备状态  
                                        for (String volstr : vols) 
                                                /////////////////////////////////////////////////////////////
                                                // 更新 Volume 状态, 存储设备状态更新:
                                                updatePublicVolumeState(usbotgVolume, state);
                                                        for (int i = mListeners.size() -1; i >= 0; i--) 
                                                                // 调用已注册的 MountServiceBinderListener 来通知存储设备状态改变 
                                                                bl.mListener.onStorageStateChanged(path, oldState, state);
                                                                        ///////////////////////////////////////////////////////////////
                                                                        ////////////////////////////////////////////////////////////////
                                                                        // 这里调用的是 StorageManager::MountServiceBinderListener
                                                                        StorageManager::MountServiceBinderListener()
                                                                            for (int i = 0; i < size; i++)
                                                                                /////////////////////////////////////////////////
                                                                                // 私有类: 位于 StorageManager 
                                                                                // ListenerDelegate 的 sendStorageStateChanged()
                                                                                mListeners.get(i).sendShareAvailabilityChanged(available);
                                                                                    ////////////////////////////////////////////////////////
                                                                                    ////////////////////////////////////////////////////////
                                                                                    StorageManager::ListenerDelegate::sendStorageStateChanged() 
                                                                                            StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
                                                                                            // 给某个线程发送消息?
                                                                                            mHandler.sendMessage(e.getMessage());
                                        ////////////////////////////////////////////////////////////////////////////
                                        //进入闭环数据读取模式 
                                        while (true) {
                                            int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
                                            //当读取的数据长度小于0时,表示连接已断开,跳出循环,重新向服务端发起新的连接请求

                                            //解析读取到的数据,得到 NativeDaemonEvent 
                                            for (int i = 0; i < count; i++)
                                                final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent);
                                                //如果命令码code >= 600 && code < 700 
                                                if (event.isClassUnsolicited()) 
                                                    //将读取到的事件发送到 VoldConnector.CallbackHandler 线程中处理 
                                                    mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent()));
                                                                ///////////////////////////////////////////////////////////////////////
                                                                ///////////////////////////////////////////////////////////////////////
                                                                // NativeDaemonConnector 类中实现的
                                                                NativeDaemonConnector::handleMessage()
                                                                        //回调 MountService 的 onEvent 函数进行处理
                                                                        mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))
                                                                                /////////////////////////////////////////////////////////////////////////
                                                                                /////////////////////////////////////////////////////////////////////////
                                                                                // 回调处理接收到的消息,处理各种事件,主要是通知其他程序存储状态变化了
                                                                                // 并发送命令给 vold 进行挂卸载
                                                                                MountService::onEvent()
                                                                                        if (code == VoldResponseCode.VolumeStateChange)
                                                                                            。。。
                                                                                            notifyVolumeStateChange(
                                                                                                cooked[2], cooked[3], Integer.parseInt(cooked[7]),
                                                                                                        Integer.parseInt(cooked[10]), bValue);
                                                                                            。。。 
                                                                                        else if (code == VoldResponseCode.VolumeUuidChange) 
                                                                                            。。。
                                                                                        else if (code == VoldResponseCode.VolumeUserLabelChange)
                                                                                            。。。
                                                                                        else if ((code == VoldResponseCode.VolumeDiskInserted) ||
                                                                                                   (code == VoldResponseCode.VolumeDiskRemoved) ||
                                                                                                   (code == VoldResponseCode.VolumeBadRemoval))

                                                                                            if (code == VoldResponseCode.VolumeDiskInserted) 
                                                                                                new Thread("MountService#VolumeDiskInserted"){
                                                                                                     public void run(){
                                                                                                            //////////////////////////////
                                                                                                            // 进行实际挂载操作
                                                                                                            doMountVolume(path)      
                                                                                                            if (!path.startsWith(EXTERNAL_OTG)) {
                                                                                                                doSDSwapVolumeUpdate();
                                                                                                                updateDefaultpath();
                                                                                                                sendSDSwapIntent(); 
                                                                                                            }                       
                                                                                                            // 启动一个窗口?
                                                                                                            mContext.startActivity(intent);                                                                 
                                                                                                     }
                                                                                                }
                                                                                            。。。

                                                else {
                                                //否则将改事件添加到响应队列中
                                                    mResponseQueue.add(event.getCmdNumber(), event);
                                                }
                                                

                                        }

                                    }
                                }.start();


        } catch (Exception e) {
            loge("Error in NativeDaemonConnector: " + e);
            SystemClock.sleep(5000);
        }
    }
    
*/

Vold 流程

/* vold 进程是从 init 进程通过 init.rc 启动的 
 vold进程:
    管理和控制 Android 平台外部存储设备,包括 SD 插拨、挂载、卸载、格式化等;
    vold 进程接收来自内核的外部设备消息

*/
service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount // 语法:socket <name> <type> <perm> <user> <group>, 创建一个名字为 vold<name>,类别为 stream<type> //访问权限为 0660<perm> 用户为 root,用户组为 mount
    ioprio be 2

/* 
涉及相关类的概念:
/////// C++ /////////////////////////
    SocketClient                             // 代表一个套接字信息
    SocketListener                           // 创建线程,监听, socket,每个套接字会创建一个 SocketClient 链入链表管理
                                             //  【继承该类,会在接收到数据时,调用子类覆写的 onDataAvaible() 进行数据处理】

    NetlinkListener: public SocketListener   // 监听内核 netlink, 接收 uevent 消息,封装到 NetlinkEvent,然后调
                                             //   用具体子类 onEvent() 处理
    NetlinkHandler: public NetlinkListener   // 具体 netlink 消息命令的处理类,与 VolumeManager 交互,实现磁盘挂卸载等操作 

    FrameworkListener: public SocketListener // 用于监听远程发过来的字符串命令, 执行具体子类 runCommand() 来执行命令
    【CommandListener】: public FrameworkListener// 注册具体的命令子类,用来监听 /dev/socket/vold 上的数据发来的命令,
                                             //   该套接字用来与 Framework 通信,用注册的具体的命令子类,执行 Framework 发来的命令
    
    Volume                                   // 分卷抽象
    【DirectVolume】:public Volume          // 一个实体磁盘设备在代码中的抽象。

    NetlinkEvent                             // 解析 uevent 获得信息封装的类
    
    /////////////////////////////////////////////////////////////////////
    // 接收内核发来的消息, 解析转换成 NetlinkEvent 对象;再将此 NetlinkEvent 
    // 对象传递给 VolumeManager 处理, 他会传给具体的 DirectVolume 磁盘设备类处理
    【NetlinkManager】
    {
        // 实现单实例模式用
        NetlinkManager
                               NetlinkListener: public SocketListener
        NetlinkHandler: public NetlinkListener 
        SocketListener
     }  
    
    /////////////////////////////////////////////////////////////////////
    // 此模块管理所有挂载的设备节点以及相关操作执行
    【VolumeManager】
    {
        // 实例单例模式使用
        VolumeManager
        
        // 链表结构
        AsecIdCollection
        VolumeCollection

        SocketListener
    }
###########################################################################################################
//////////////////////////// Java ////////////////////////////////////////////////////////////////////////
// 检测外部存储卡的插入/拔出事件,这些事件是由 MountServie 通过 
// Intent 广播发出的,例如,外部存储卡插入后,MountService 就会发送 ACTION_MEDIA_MOUNTED 消息 
class MountService extends IMountService.Stub                   // 很眼熟,Binder 通信机制,Stub 是服务类需要继承实现的
    public MountService(Context context)
        mPms = (PackageManagerService) ServiceManager.getService("package");
        // 创建一个 HandlerThread 
        HandlerThread hthread = new HandlerThread(TAG);
        hthread.start();

        // Handler 类: 用于让某个线程的消息队列发送消息让其处理 
        // 创建一个 Handler,这个 Handler 使用 HandlerThread 的 Looper, 也就是说,派发给该 Handler 
        // 的消息将在另外一个线程中处理 
        mHandler = new MountServiceHandler(hthread.getLooper());
        
        // NativeDaemonConnector 用于 Socket 通信,第二个参数 vold 表示将和 vold 通信,也就是和 CommandListener 模块 
        // 中的那个 socket 建立通信连接,第二个参数为 INativeDaemonConnectorCallbacks 接口,它提供两个回调接口函数:
        //      onDaemonConnected()         // 当 NativeDaemonConnector 连接上 Vold 后回调 
        //      onEvent()                   // 当 NativeDaemonConnector 收到来自 Vold 数据后回调 
        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);

        // 再启动一个线程用于和 Vold 通信 
        Thread thread = new Thread(mConnector, VOLD_TAG);
        thread.start();
###########################################################################################################
//////////////////////////////////////////////////////////////////////////////////////
// 内核发来 uevent 消息举例:【SD 卡插入】
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0
ACTION=add                                                                              // 设备插入,还有 remove/change 动作 
DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0              // 该设备在 /sys 中的设备路径
SUBSYSTEM=block                                                                         // 设备类型:block/character 等
MAJOR=179                                                                               // 主次设备号 
MINOR=0 
DEVNAME=mmcblk0 
DEVTYPE=disk                                                                            // 设备类型为磁盘 
NPARTS=3                                                                                // 该 SD 卡有 3 个分区 
SEQNUM=1357                                                                             // 序号 

////////////////////////
// SD 卡分区的 uevent 
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0/mmcb1 k0p1
ACTION=add                                                                              // 设备插入,还有 remove/change 动作 
DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0/mmcblk0p1    // 该设备在 /sys 中的设备路径
SUBSYSTEM=block                                                                         // 设备类型:block/character 等
MAJOR=179                                                                               // 主次设备号 
MINOR=1
DEVNAME=mmcblk0p1 
DEVTYPE=partition                                                                       // 设备类型为分区 
NPARTS=1                                                                                // 该 SD 卡有 3 个分区 
SEQNUM=1358                                                                             // 序号 

//////////////// SocketListener 类具体实现/////////////////////////////////////////////
// 监听 socket 的实现:调用具体子类 onDataAvaible() 处理
SocketListener 
    入口函数:
    static void *threadStart(void *obj);
        SocketListener::runListener()   
            while(1) 
            {
                // 添加请求监听套接字描述符
                FD_SET(mSock, &read_fds);
                // 监听管道读端
                FD_SET(mCtrlPipe[0], &read_fds);
                // 遍历所有链表上 SocketClient,这个数据结构里保存了监听的套字信息 
                for (it = mClients->begin(); it != mClients->end(); ++it) {
                    int fd = (*it)->getSocket();
                    // 添加数据通信的套接字描述符
                    FD_SET(fd, &read_fds);
                    if (fd > max)
                        max = fd;
                }
                ///////////////////////////////////////////////////////
                // 通过 select 监听添加的文件描述符,看是否有数据送过来
                select(max + 1, &read_fds, NULL, NULL, NULL)

                // 如果管道上有数据传来的,则
                if (FD_ISSET(mCtrlPipe[0], &read_fds))break;

                // 如果连接请求监听套按字
                if (mListen && FD_ISSET(mSock, &read_fds))
                    do {
                       alen = sizeof(addr);
                       // 接受连接请求
                       c = accept(mSock, &addr, &alen);
                       SLOGV("%s got %d from accept", mSocketName, c);
                    } while (c < 0 && errno == EINTR);

                // 创建一个套接字客户端 SocketClient 去处理双方的数据通信
                // 这里仅将创建的客户端链入链表中管理
                mClients->push_back(new SocketClient(c, true, mUseCmdNum));        
                
                // 将所有有数据的客户端,添加到 pendingList 链表中
                pendingList->clear();
                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);
                    }
                }
                
                // 遍历的所有有数据的客户端 
                while (!pendingList->empty()) {
                   // 从链表中取出一项
                   it = pendingList->begin();
                   SocketClient* c = *it;
                   pendingList->erase(it);
                   
                   ///////////////////////////////////////////////////////////////////////
                   // 核心:调用 【onDataAvaible()】 函数处理数据,onDataAvaible() 是抽象函数,
                   //   所以是动态绑定的,有则子类处理,无则父类处理
                   if (!onDataAvailable(c) && mListen) {
                       // onDataAvailable() 出错,则返回 false 从链表中删除
                       for (it = mClients->begin(); it != mClients->end(); ++it) {
                           if (*it == c) {
                               mClients->erase(it);
                               break;
                           }
                       }
                       // Remove our reference to the client 
                       c->decRef();
                   }
                }
            }

////////////////// FrameworkListener 类具体实现 //////////////////////////////////////////////////////////////////
// 继承自 SocketListener,用于监听远程发过来的字符串命令, 执行自己实现的命令子类,调用具体子类的 runCommand()
FrameworkListener: public SocketListener
    继承 SocketListener, 主要覆写 onDataAvaible() 来处理数据
    onDataAvaible()
        // 调用 read() 来接收数据
        len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer+last_offset, sizeof(buffer)-last_offset))

        for (i = 0; i < len; i++) {
            if (buffer[i] == '\0') {
                // IMPORTANT: dispatchCommand() expects a zero-terminated string 
                ////////////////////////////////////////////////////////////////////////////////
                // 分发命令给具体的命令子类处理
                dispatchCommand(c, buffer + offset);
                            // 解析发过来的字符串命令
                            // 遍历已注册的命令集
                            for (i = mCommands->begin(); i != mCommands->end(); ++i) {
                                FrameworkCommand *c = *i;
                                if (!strcmp(argv[0], c->getCommand())) {
                                    ///////////////////////////////////////////////////////////////
                                    // 调用具体的命令子类, 具体的命令子类需要继承 FrameworkCommand 类, 并需要注册进链表
                                    // 实现其 runCommand() 方法,这里添加了一些继承 VoldCommand,具体命令子类继承 VoldCommand
                                    if (c->runCommand(cli, argc, argv)) {
                                        SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
                                    }
                                    goto out;
                                }
                            }

                offset = i + 1;
            }
        }
    //////////////////////////////////////////////////////
    // 注册具体的继承 FrameworkCommand 的命令子类,仅是简单的添加到链表中
    void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
        mCommands->push_back(cmd);
    }
////////////////// CommandListener 类具体实现 //////////////////////////////////////////////////////////////////
// 注册具体的命令子类,用来监听 /dev/socket/vold 上的数据发来的命令,
//   该套接字用来与 Framework 通信,用注册的具体的命令子类,执行 Framework 发来的命令
CommandListener : public FrameworkListener
    // 监听 /dev/socket/vold 并注册具体的命令子类 
    CommandListener::CommandListener() :
                     FrameworkListener("vold", true) // 1. 注册监听 /dev/socket/vold 套接字,与 Framework 通信
    {
        // 2. 注册具体的命令子类,当从 Framework 层有命令来时,就会调用具体命令子类的 runCommand
        registerCmd(new DumpCmd());         // 用于输出各种信息
        registerCmd(new VolumeCmd());       // 用于磁盘卷管理 
        registerCmd(new AsecCmd());         // 用于将 .apk 安装到外部存储设备如 SD 卡上 
        registerCmd(new ObbCmd());          // 不程春明二进制数据块,数据加密用
        registerCmd(new StorageCmd());      // 用于查询哪些进程正在使用某个磁盘设备
        registerCmd(new XwarpCmd());
        registerCmd(new CryptfsCmd());      // 存储区加密 
        registerCmd(new FstrimCmd());
        //M{
    #ifndef MTK_EMULATOR_SUPPORT
        registerCmd(new USBCmd());
    #endif
        registerCmd(new CDROMCmd());
        //}M
    #if defined (ENG_BUILD_ENG)    
        registerCmd(new SilkRoad());
    #endif
    }

/////////////////// NetlinkListener 类具体实现 /////////////////////////////////////////////////////////////////
// 继承自 SocketListener,用于监听内核发来的 uevent 事件,调用 NetlinkEvent 解析后
// 再调用 NetlinkListener 具体的子类 onEvent() 处理
NetlinkListener: public SocketListener
    继承 SocketListener, 主要覆写 onDataAvaible() 来处理数据
    onDataAvailable()
        // 接收来自内核的 uevent 消息
        count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(socket, mBuffer, sizeof(mBuffer), &uid))
        // 创建一个 NetlinkEvent 对象解析处理消息
        NetlinkEvent *evt = new NetlinkEvent();
        // 调用 NetlinkEvent::decode() 解析命令 
        evt->decode(mBuffer, count, mFormat)
                    NetlinkEvent::decode()
                        // 根据命令类型是二进制的还是 ascii 类型的分别解析
                        if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
                            // Parse an binary message from a NETLINK_ROUTE netlink socket.
                            return parseBinaryNetlinkMessage(buffer, size);
                        } else {
                            // 处理 uevent 消息如:add/remove/change 等 
                            // 解析后的信息保存在 NetlinkEvent::{mAction/mSeq/mSubsystem/mParames} 中 
                            return parseAsciiNetlinkMessage(buffer, size);
                        }
        
        //////////////////////////////////////////////////////////////////////////////
        // 虚函数,调用具体的继承了 NetlinkListener() 子类实现的 onEvent() 处理消息
        // 如会调用 NetlinkHandler:onEvent() 处理
        onEvent(evt);




////////////////// NetlinkManager 类具体实现 //////////////////////////////////////////////////////////////////
// 接收内核发来的消息, 解析转换成 NetlinkEvent 对象;再将此 NetlinkEvent 
// 对象传递给 VolumeManager 处理 
【NetlinkManager】
{
    // 实现单实例模式用
    NetlinkManager
                                                        SocketListener # 会调用子类 onDataAvailable() 处理接收到的数据 
                           NetlinkListener: public SocketListener      # 调用子类 onEvent() 处理接收到的 uevent 事件 
    NetlinkHandler: public NetlinkListener                             // 实现的 onEvent()
    SocketListener
}

【启用 NetLink 监听函数流程】:
    NetlinkManager::start()
        // 创建 netlink 用来监听内核消息 
        mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)
        // 绑定 netlinck 到文件描述符中 
        bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)
        
        // 创建一个 NetlinkHandler 类对象
        mHandler = new NetlinkHandler(mSock)
                        // NetlinkHandler 继承 NetlinkListener 并实现了其 onEvent() 函数,会在 NetlinkManager::onDataAvailable()
                        // 用来处理具体的 uevent 事件
                        NetlinkHandler: public NetlinkListener
        
        mHandler->start()
            //////////////////////////////////
            NetlinkHandler::start()
                SocketListener::startListener()
                    // android_get_control_socket - simple helper function to get the file
                    // descriptor of our init-managed Unix domain socket. `name' is the name of the
                    // socket, as given in init.rc. Returns -1 on error.
                    //
                    // This is inline and not in libcutils proper because we want to use this in
                    // third-party daemons with minimal modification.
                    // 从环境变量在获得已有的 socket 文件描述符, 这是在 init.rc 中注册的,用来与 framework 通信用的 /dev/socket/vold
                    mSock = android_get_control_socket(mSocketName)
                    // 监听套接字
                    listen(mSock, 4)
                    // 添加到 SocketListener 类的 mClients 链表中管理
                    mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)
                    // 创建用于退出使用的管道
                    pipe(mCtrlPipe)
                    ////////////////////////////////////////////////////////////////
                    // 创建线程进行监听
                    pthread_create(&mThread, NULL, SocketListener::threadStart, this)
                                    SocketListener::threadStart(void *obj)
                                            // 子类转为父类
                                            SocketListener *me = reinterpret_cast<SocketListener *>(obj);

                                            me->runListener();
                                                ////////////////////////////////////////////////////////////////////
                                                // 调用 SocketListener::runListener()
                                                // 具体参见上面 SocketListener 类具体实现,收到 socket 信息,则调用
                                                #####################################################
                                                // 【SocketListener 的子类 onDataAvaible() 进行处理】
                                                #       即 NetlinkListener::onDataAvaible()
                                                #           再调用  NetlinkListener 的子类覆写的 onEvent()
                                                #               即 NetlinkHandler::onEvent()
                                                #####################################################
                                                // 如果收到 pipe 管道信息,则退出线程

【处理内核传来 uevent 数据流程】:
    // 在 NetlinkListener 中被调用,传入参数为解析好的 uevent 数据封装的 NetlinkEvent 类
    // 【然后调用 volumeManager 类进行处理 】
    NetlinkHandler::onEvent(NetlinkEvent *evt)
        // 单实例模式
        VolumeManager *vm = VolumeManager::Instance()
        // 获得是什么子系统上报的 uevent 
        const char *subsys = evt->getSubsystem()

        if (!strcmp(subsys, "block")) 
            ////////////////////////////////////////////////////////////////
            // 调用 volumeManager 模块中的函数,进行具体的磁盘挂卸载操作
            // 【1】. 更新磁盘状态
            vm->updatePullOutState(evt);
                // 获得 uevent 事件类型: add/remove/change 
                int action = evt->getAction();
                VolumeCollection::iterator it;
                // 遍历的所有已有分卷 Volume 类对象 updatePullOutState() 函数,更新各个分卷状态 
                for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
                    ///////////////////////////////////////////////////////////////////////////
                    // updatePullOutState() 是一个虚函数,所以会调用具体子类 DirectVolume 处理
                    (*it)->updatePullOutState(evt);  
                            DirectVolume::updatePullOutState()
                                // 获得要更新的设备路径及行为
                                int action = evt->getAction();
                                const char *dp = evt->findParam("DEVPATH"); 
                                // 遍历所有已经注册管理的磁盘的设备
                                for (it = mPaths->begin(); it != mPaths->end(); ++it)  
                                    if (!strncmp(dp, *it, strlen(*it)))
                                        if (action == NetlinkEvent::NlActionAdd)
                                            mIsHwPullOut = false;
                                        else if (action == NetlinkEvent::NlActionRemove)
                                            mIsHwPullOut = true;
                }  
            // 【2】. 设置热插拔标志位
            vm->setHotPlug(true);
                mIsHotPlug = isPlug;
            // 【3】. 处理 uevent 事件: add/remove/change 设备 
            vm->handleBlockEvent(evt);
                // 遍历的所有已经注册管理的卷列表,卷列表根据配置文件 /etc/vold.fstab 创建添加
                // 在函数 process_config() 中创建添加的 
                for (it = mVolumes->begin(); it != mVolumes->end(); ++it)
                    /////////////////////////////////////////////////////////////////////////////////
                    // Volume::handleBlockEvent() 是一个虚函数,所以会调用具体子类 DirectVolume 处理
                    // 调用 DirectVolume::handleBlockEvent()
                    (*it)->handleBlockEvent(evt)
                        DirectVolume::handleBlockEvent()
                            // 获得磁盘变更路径
                            const char *dp = evt->findParam("DEVPATH");
                            // 遍历该设备的所有分区?
                            for (it = mPaths->begin(); it != mPaths->end(); ++it) 
                                // 获得要执行的操作: add/remove/change 以及设备类型:disk/partition 
                                int action = evt->getAction();
                                const char *devtype = evt->findParam("DEVTYPE");
                                ###########################
                                // 添加设备 
                                ###########################
                                if (action == NetlinkEvent::NlActionAdd) 
                                    // 获得要创建的设备节点主次设备号 
                                    int major = atoi(evt->findParam("MAJOR"));
                                    int minor = atoi(evt->findParam("MINOR"));
                                    // 要创建的节点路径
                                    snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", major, minor);
                                    // 创建设备节点 
                                    createDeviceNode(nodepath, major, minor)
                                        ////////////////////////////////////////////
                                        Volume::createDeviceNode()
                                            mode_t mode = 0660 | S_IFBLK;
                                            dev_t dev = (major << 8) | minor;
                                            // 创建节点 
                                            mknod(path, mode, dev)
                                            
                                    ///////////////////////////////////////
                                    // 当前创建的节点代表一个磁盘         
                                    ///////////////////////////////////////
                                    if (!strcmp(devtype, "disk"))
                                        handleDiskAdded(dp, evt)
                                            /////////////////////////////////////////
                                            DirectVolume::handleDiskAdded()
                                                mDiskMajor = atoi(evt->findParam("MAJOR"));
                                                mDiskMinor = atoi(evt->findParam("MINOR"));
                                                const char *tmp = evt->findParam("NPARTS");
                                                
                                                // 针对磁盘上的每个分区分别处理,将发送信息给 MountService
                                                for (int i = 0; i < MAX_PARTITIONS; i++)
                                                    mPartMinors[i] = -1;
                                                    // 没有分区
                                                    if (mDiskNumParts == 0) 
                                                        setState(Volume::State_Idle);
                                                    // 有分区 
                                                    else 
                                                        setState(Volume::State_Pending)
                                    
                                    ////////////////////////////////////////////////////////////////
                                    // 当前创建的节点代表一个分区 ,对于有分区的 SD 卡,会先收到 disk 消息,再收到 partition 分区消息
                                    ////////////////////////////////////////////////////////////////
                                    else
                                        handlePartitionAdded(dp, evt);
                                            DirectVolume::handlePartitionAdded()
                                                int major = atoi(evt->findParam("MAJOR"));
                                                int minor = atoi(evt->findParam("MINOR"));
                                                const char *tmp = evt->findParam("PARTN");
                                                if (getState() != Volume::State_Formatting && (part_rescan_wait == WAIT_ON_NO_EVENT))
                                                    setState(Volume::State_Idle);
                                                    if(mVm->getIpoState() == VolumeManager::State_Ipo_Start)
                                                        if (mRetryMount == true)
                                                            mRetryMount = false;
                                                            ////////////////////////////////////////////////////////////////
                                                            // 调用 Volume::mountVol() 执行挂载分区
                                                            mountVol()
                                                                Volume::mountVol()
                                                                    // 通过 CommandListener 给套接字 /dev/socket/vold 发送消息给 Framework 层 
                                                                    snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media",
                                                                                     getLabel(), getFuseMountpoint());
                                                                    //////////////////////////////////////////////////////////////////////////////////
                                                                    // 调用 VolumeManager 中的 Broadcaster->CommandListener() 发送此 msg
                                                                    // 发送消息通知 Framework 层是在 SocketListener 中完成
                                                                    //
                                                                    // 这里工作的 SocketListener 是 VolumeManager 的,SocketListener 的派生类 CommandListener,
                                                                    // 用来与 Framework 交互的,监听 Socket 消息。通过 VolumeManager 中调用 sendBroadcast,
                                                                    // 与 CommandListener 模块进行交互
                                                                    //
                                                                    // 这里的调用关系为:
                                                                    //      VolumeManger 模块调用 
                                                                    //          CommandListener 模块函数 sendBroadcast() 
                                                                    //              通过给套接字 /dev/socket/vold 发消息给 Framework 层 
                                                                    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeMountFailedNoMedia,
                                                                        SocketListener::sendBroadcast()
                                                                            for (i = mClients->begin(); i != mClients->end(); ++i)
                                                                                (*i)->sendMsg(code, msg, addErrno, false)
                                                                                    SocketListener::sendBroadcast()
                                                                                        // 遍历所有已经注册管理的 SocketClient 
                                                                                        for (i = mClients->begin(); i != mClients->end(); ++i)
                                                                                            (*i)->sendMsg(code, msg, addErrno, false)
                                                                                                SocketClient::sendMsg()
                                                                                                    sendData(msg, strlen(msg) + 1)  
                                                                                                        int rc = sendDataLocked(data, len);    
                                                                                                            // 通过套接字发消息给 Framework 层?
                                                                                                            send(mSocket, p, brtw, MSG_NOSIGNAL);                





                                                                    // 这里会对挂载标志进行处理 
                                                                    // 挂载分区,也是创建相应的设备节点 
                                                                    snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",
                                                                                     new_major, new_minor);
                                                                    // 通过 mknode 创建节点 
                                                                    createDeviceNode(nodepath, new_major, new_minor)
                                                                    
                                                                    // 更新 DirectVolume 设备状态 
                                                                    updateDeviceInfo(nodepath, new_major, new_minor);
                                                                    
                                                                    // 遍历的所有分区 
                                                                    for (i = 0; i < n; i++)
                                                                        #################################################################
                                                                        // 挂载 Fat 分区,这里只支持 Fat 分区 
                                                                        // 先将设备挂载到 /mnt/secure/staging 目录 
                                                                        Fat::doMount(devicePath, SEC_STGDIR, false, false, false,
                                                                                        AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)
                                                                        
                                                                        // 将挂载点从 /mnt/secure/staging 移动 Framework 指定目录
                                                                        // 如 SD 卡则为:/mnt/sdcard 
                                                                        doMoveMount(SEC_STGDIR, getMountpoint(), false)
                                                                        
                                                                        // 将存储卡上的 .android_secure() 目录挂载到 
                                                                        // /mnt/secure/asec 目录下,同时对 .android_secure
                                                                        // 进行一些特殊处理,这样没权限用户
                                                                        // 就无法更改破坏更改 .andoird_secure 目录的内容了
                                                                        mountAsecExternal(SEC_STGDIR)


                                                                        // 设置状态为 State_Mounted, 这个函数将发送信息给 MountService
                                                                        setState(Volume::State_Mounted, Fat::isFat32(fd))
                                                                        #################################################################

                                        if(part_rescan_wait == WAIT_ON_ADD_EVENT)
                                            // 发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行
                                            pthread_cond_signal(&part_rescan_cond);
                                    
                                    // 如果磁盘上所有分区都找到了,在上面的 setState() 函数中设备的状态的 
                                    if ((getState() == Volume::State_Idle) && (mVm->getIpoState() == VolumeManager::State_Ipo_Start))
                                        // 准备消息给 Framework 通知设备状态变化 
                                        snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(),
                                                                     getFuseMountpoint(), mDiskMajor, mDiskMinor);
                                        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false)
                                
                                ###########################
                                // 卸载设备,与挂载类似处理
                                ###########################
                                else if (action == NetlinkEvent::NlActionRemove) 
                                    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);

            // 【4】. 设置热插拔标志位                    
            vm->setHotPlug(false);


##################################################################################################################
main 流程总结:
    main()  
        ////////////////////////////////////////
        // 【1】创建 vold 设备文件夹 
        mkdir("/dev/block/vold", 0755);
    
        ////////////////////////////////////////
        // Create our singleton managers 
        // 【2】创建 VolumeManager 对象: 单实例模式 
        vm = VolumeManager::Instance())
        
        ////////////////////////////////////////
        // 【3】创建 NetlinkManager 对象: 用于监听内核发来的 uevent 信息,然后交给 VolumeManager 处理
        nm = NetlinkManager::Instance())

        /////////////////////////////////////////
        // CommandListener 创建 vold socket 监听上层消息 
        // CommandListener: 监听来自 UNIX 本地套接字(/dev/socket/vold)上的数据
        // 继承自 FrameworkListener,可以用于分发字符串命令,处理字符串命令由子类
        // DumpCmd, VolumeCmd, AsecCmd, ObbCmd, StorageCmd, XwarpCmd 和 CryptfsCmd 等去完成 
        cl = new CommandListener();
        vm->setBroadcaster((SocketListener *) cl);
        nm->setBroadcaster((SocketListener *) cl);

        //////////////////////////////////////////////////////////////////////////
        // 【4】根据配置文件 /etc/vold.fstab 初始化 VolumeManager, 用来管理 DirectVolume(磁盘抽象对象)
        process_config(vm)
                // 解析 fstab 配置文件,保存到 fstab 数据结构中 
                fstab = fs_mgr_read_fstab(fstab_filename);
                // 遍历 fstab 配置文件中的所有选项,根据 fs_mgr_flags 文件管理标志判断是否需要将其添加到 volumeManager 管理
                for (i = 0; i < fstab->num_entries; i++)
                    // 如果需要添加到 volumeManager 管理,则添加管理
                    if (fs_mgr_is_voldmanaged(&fstab->recs[i]))
                        // 创建 DirectVolume 对象 相关的挂载点设备的操作
                        dv = new DirectVolume(vm, &(fstab->recs[i]), flags);
                        //添加挂载点设备路径
                        dv->addPath(fstab->recs[i].blk_device)
                        ////////////////////////////////////////////////////
                        //将 DirectVolume 添加到 VolumeManager 管理
                        vm->addVolume(dv)

        /////////////////////////////////////////////////////////////
        // 【5】启动 NetlinkManager socket 监听内核发送 uevent, 获得具体内核消息,它会将其封装成 NetlinkEvent 信息 
        // 然后调用 NetlinkHandler::onEvent() 【然后调用 volumeManager 类进行处理 】
        // 【这里是作服务器用的】
        nm->start()
            NetlinkManager::start()
                    // 创建 PF_NETLINK 地址簇的 socket,目前只支持 SOCK_DGRAM 类型,
                    // 第三个参数,NETLINK_KOBJECT_UEVENT 表示要接收内核的 Uevent 事件
                    mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)
                    // 设置 Socket 接收缓冲区大小
                    setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz))
                    // 必须对 socket 执行 bind 操作
                    bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr))
                    // 创建一个 NetlinkHandler 类对象监听处理内核 netlinck 消息
                    // 它将根据接收的消息,调用具体的 VolumeManager 模块中的函数时行处理,如挂卸载 
                    mHandler = new NetlinkHandler(mSock)
                    //////////////////////////////////////////////////////
                    // 调用 NetlinkHandler::start() ,他会创建一个线程进行监听内核 netlink 发来的消息 
                    // 消息处理流程为:
                    //      Kernel = uevent => NetlinkManagerModule ==> VolumeManager ==> DirectVolume(磁盘抽象类)
                    //
                    //  监听线程 
                    //      // 检查 socket 上是否有数据 
                    //      SocketListener # 调用子类覆写的 onDataAvaible() 进行数据处理
                    //          // 接收 socket 上的数据,将 uevent 数据解析封装成 NetlinkEvent, 调用 volumeManager 模块处理挂卸载
                    //          NetlinkListener::onDataAvaible()         // NetlinkListener: public SocketListener, # 调用子类覆写的 onEvent() 进行数据处理
                    //              // 调用 volumeManager 模块处理挂卸载
                    //              NetlinkHandler::onEvent()  
                    //                  // VolumeManager 模块调用具体的磁盘 DirectVolume 类处理挂卸载 
                    //                  VolumeManager::handleBlockEvent()     
                    //                      // 具体磁盘类 DirectVolume 处理挂卸载
                    //                      DirectVolume::handleBlockEvent() 
                    //                          1. 创建设备节点 
                    //                          2. 挂卸载文件系统 
                    //                          3. 发送套接字消息,通知 Framework 层  
                    mHandler->start()

        //////////////////////////////////////////////////////////////////////////////
        //【6】向 /sys/block/ 目录下所有设备 uevent 文件写入 “add\n”,
        //触发内核 sysfs 发送 uevent 消息
        coldboot("/sys/block");
            DIR *d = opendir(path);

            do_coldboot(d, 0);
                dfd = dirfd(d);
                fd = openat(dfd, "uevent", O_WRONLY);
                write(fd, "add\n", 4);
                // 递归写所有子目录
                while((de = readdir(d))) 
                    fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
                    d2 = fdopendir(fd);
                    do_coldboot(d2, lvl + 1);
        
        /////////////////////////////////////////////////////////////////////////////
        // 【7】启动 CommandListener 用来监听 /dev/socket/vold 上的数据发来的命令,
        // 该套接字用来与 Framework 通信,用注册的具体的命令子类,执行 Framework 发来的命令
        cl->startListener()
            // 调用父类函数 
            SocketListener::startListener()
                // 上面有介绍,创建一个线程监听从 init.rc 中创建的 /dev/socket/vold 套接字,用来与 framework 通信 
                // 执行 Framework 发来的命令 

        /////////////////////////////////////////////////////////////////////////////
        // 【8】死循环,成为监听线程
        // Eventually we'll become the monitoring thread
        while(1) {
            sleep(1000);
        }

////////////////////////////////////////////////////////////////////////////////////////////////////
// 分析一下 SD 卡插入事件的检测:
    数据控制路径为:
        Kernel Uevent    
            SocketListener
                NetlinkListener::onDataAvaible()
                    NetlinkHandler::onEvent()  
                        VolumeManager::handleBlockEvent() 
                          // 具体磁盘类 DirectVolume 处理挂卸载
                          DirectVolume::handleBlockEvent() 
                              1. 创建设备节点 
                              2. 挂卸载文件系统 
                              3. 发送套接字消息,通知 Framework 层 : 消息为: Volume sdcard disk inserted (179:0)
                              ======= Java =
SD 卡插入: 
    Kernel 发出 uevent 消息
        add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0
        ACTION=add                                                                              // 设备插入,还有 remove/change 动作 
        DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0              // 该设备在 /sys 中的设备路径
        SUBSYSTEM=block                                                                         // 设备类型:block/character 等
        MAJOR=179                                                                               // 主次设备号 
        MINOR=0 
        DEVNAME=mmcblk0 
        DEVTYPE=disk                                                                            // 设备类型为磁盘 
        NPARTS=3                                                                                // 该 SD 卡有 3 个分区 
        SEQNUM=1357                                                                             // 序号 
          ////////////// Vold //////////////////////
          // 检查 socket 上是否有数据 
          SocketListener # 调用子类覆写的 onDataAvaible()
              // 接收 socket 上的数据,将 uevent 数据解析封装成 NetlinkEvent, 调用 volumeManager 模块处理挂卸载
              NetlinkListener::onDataAvaible()         // NetlinkListener: public SocketListener # 调用子类覆写的 onEvent()
                  // 调用 volumeManager 模块处理挂卸载
                  NetlinkHandler::onEvent()  
                      // VolumeManager 模块调用具体的磁盘 DirectVolume 类处理挂卸载 
                      VolumeManager::handleBlockEvent()     
                          // 具体磁盘类 DirectVolume 处理挂卸载
                          DirectVolume::handleBlockEvent() 
                              1. 创建设备节点 
                              2. 挂卸载文件系统 
                              3. 发送套接字消息,通知 Framework 层 : 消息为: Volume sdcard disk inserted (179:0)
                              ////////////////////// Java ////////////////////////////////////
                              MountService::onEvent() 
                                    if (code == VoldResponseCode.VolumeStateChange)
                                        ...
                                    else if (code == VoldResponseCode.VolumeUuidChange) 
                                        ...
                                    ...
                                    else if ((code == VoldResponseCode.VolumeDiskInserted) ||
                                       (code == VoldResponseCode.VolumeDiskRemoved) ||
                                       (code == VoldResponseCode.VolumeBadRemoval))
                                            // 磁盘设备插入 
                                            if (code == VoldResponseCode.VolumeDiskInserted)
                                                    // 收到 handleDiskAdded() 发送的 VolumeDiskInserted 消息了 
                                                    // 单独启动一个线程来处理这个消息 
                                                    new Thread("MountService#VolumeDiskInserted"){
                                                        public void run()
                                                            // 调用 doMountVolume 处理 
                                                            rc = doMountVolume(path)
                                                                    // 【参考 Android 2.2】,在 4.4 上未找通,太晚了,不找了
                                                                    // 通过 NativeDaemonConnector 给 Vold 发送请求
                                                                    mConnector.doCommand()
                                                                    /////////////////////// C++ //////////////////////////////////////////
                                                                    // CommandListener 从 /dev/socket/vold 中接收到这个请求 
                                                                    // 命令内容为:volume mount /mnt/sdcard 
                                                                    // 调用具体的命令子类执行 
                                                                    CommandListener::VolumeCmd::runCommand()
                                                                        VolumeManager *vm = VolumeManager::Instance();

                                                                        。。。 
                                                                        else if (!strcmp(argv[1], "mount"))
                                                                            // 调用 VolumeManager 模块的 mountVolume() 来处理 mount 命令 
                                                                            // 参数为 /mnt/sdcard 
                                                                            rc = vm->mountVolume(argv[2]);
                                                                                    VolumeManager::mountVolume()
                                                                                        Volume *v = lookupVolume(label);
                                                                                        v->mountVol()
                                                                                            Volume::mountVol()
                                                                                                // 最终调用具体文件系统的挂载函数,实现挂载
                                                                                                Fat::doMount()
                                                    }.start()
    

*/

猜你喜欢

转载自blog.csdn.net/wangjun7121/article/details/88142134