Android4.4----Vold挂载管理分析(一)

这段时间一直在研究内置SD卡和外置SD卡的挂载问题,看了网上jecese关于Android4.2的Vold挂载的博客后,结合自己在Android4.4上做的一些实验,记录下来,以便日后查阅!

一:Vold的启动

关于vold的源码在jb4.4-kikat/system/vold/,根据Android.mk可以知道编译后会生成一个可执行文件vold,并安装到system/bin下。而这个vold会作为一个服务在系统启动的时候去启动它!

在init.rc中

service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount //vold启动的时候创建socket
    ioprio be 2 //这个不是很明白


vold的入口为/system/vold/main.cpp中的main函数

int main() {

    VolumeManager *vm;//这个类主要是接收经NetlinkManager类处理过的消息进行挂载动作
    CommandListener *cl;
    NetlinkManager *nm;//这个类主要通过NetlinkHandler类中的onEvent()方法接收来自kernel发过来的事件信息

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

    mkdir("/dev/block/vold", 0755);//创建/dev/block/vold/存放设备节点

    /* For when cryptfs checks and mounts an encrypted filesystem */
    klog_set_level(6);

    /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {
        SLOGE("Unable to create VolumeManager");
        exit(1);
    };

    if (!(nm = NetlinkManager::Instance())) {
        SLOGE("Unable to create NetlinkManager");
        exit(1);
    };


    cl = new CommandListener();
    vm->setBroadcaster((SocketListener *) cl);
    nm->setBroadcaster((SocketListener *) cl);

    if (vm->start()) {//没有实际操作
        SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
        exit(1);
    }

    if (process_config(vm)) {
        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
    }

    if (nm->start()) {//创建接收来自kernel信息的socket,实例化NetlinkHandler类,并开启socket检测
        SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
        exit(1);
    }

    coldboot("/sys/block");//遍历/sys/block下全部的设备信息,并发送一个add事件
//    coldboot("/sys/class/switch");

    /*
     * Now that we're up, we can respond to commands
     */
    if (cl->startListener()) {//开启vold的socket检测
        SLOGE("Unable to start CommandListener (%s)", strerror(errno));
        exit(1);
    }

    // Eventually we'll become the monitoring thread
    while(1) {
        sleep(1000);
    }

    SLOGI("Vold exiting");
    exit(0);
}
 
  

在挂载SD卡或者U盘等存储设备前,Android是通过/system/vold/NetlinkHandler.cpp来获取kernel发过来的事件消息的,这里我们研究的SD卡

void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();
    SLOGD("Javen.tang subsys=%s\n",subsys);
    if (!subsys) {
        SLOGW("No subsystem found in netlink event");
        return;
    }

    if (!strcmp(subsys, "block")) {
        vm->handleBlockEvent(evt);
    }
SD卡与mmc类同,所以这里获取到的subsys就是block。

二:SD卡的挂载流程

1、kerner发出SD卡插入的uevent。


2、NetlinkHandler::onEvent()中接收内核发出的uevent并解析。


3、VolumeManager::handleBlockEvent()继续处理。


4、接下来会调用到DirectVolume.cpp中的handleBlockEvent函数。


5、根据类型devtype是disk还是partition来进行选择,这里我们是内置SD卡,类型为partition,并且事件action为Add,所以调用的是handlePartitionAdded(dp, evt),在该方法中首先会通过setState(Volume::State_Idle)发送广播VolumeStateChange广播,然后在发送一个VolumeDiskInserted。


6、当handlePartitionAdded中通过  mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);来发送一个广播时,在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java的onEvent()方法中能接受到。


7、然后在onEvent()中根据发送过来的广播类型,做相应动作,我们这里研究VolumeDiskInserted这个广播类型,当检测到为VolumeDiskInserted的广播类型后会new Thread.start(),然后在该线程中执行doMountVolume(path);


8、在doMountVolume()中通过mConnector.execute("volume", "mount", path)向Vold发送指令。


9、在system/core/libsysutils/src/SocketListener.cpp中有个runListener()函数一直在监听socket,接收从上层发送过来的指令


10、跟着会调用到FrameworkListener::onDataAvailable()来处理接收到的消息。


11、然后调用FrameworkListener::dispatchCommand(SocketClient *cli, char *data)通过c->runCommand(cli, argc, argv)来分发指令。


12、然后在/system/vold/CommandListener.cpp有具体的runCommand的实现,我们找到CommandListener::VolumeCmd::runCommand这个函数,这个方法就是对Volume分发指令的解析,然后在该方法中会调用rc = vm->mountVolume(argv[2]);,进而调用到VolumeManager::mountVolume方法中去,在该方法中调用v->mountVol();


13、在/system/Volume.cpp中的mountVol就是真正处理挂载的函数,挂载的结果通过setState();函数来通知上层应用。其中setState(Volume::State_Checking)通知上层正在检查SD卡, setState(Volume::State_Mounted)是通知上层SD卡已经挂载成功,最后是在Fat::doMount通过mount函数来挂载SD卡的。


---------------到这里SD卡的挂载已初步完成,接下则是挂载后的消息发送到上层---------------------------


14、如上所述,当Vold通过setState()发送广播过来的时候,在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java中的onEvent()函数接收。所以当我们发送的是

VolumeStateChange类型的广播时,onEvent中会执行:



15、然后在MountService.java中的notifyVolumeStateChange(String label, String path, int oldState, int newState) 中执行updatePublicVolumeState();同时通过sendStorageIntent(action, volume, UserHandle.ALL)发送一个action = Intent.ACTION_MEDIA_MOUNTED的挂载成功的广播,应用层可以去接收这个广播做相关动作!


16、接着在updatePublicVolumeState()中会执行到bl.mListener.onStorageStateChanged(path, oldState, state)这个函数!


17、在Android源码中的package/apps/Settings/src/com.android.settings.deviceinfo/Memory.java中,实现了StorageEventListener的内部类,并重写了onStorageStateChanged()方法,当updatePublicVolumeState()中调用了onStorageStateChanged()后,Memory.java中也会收到,在Memory.java收到后会在Setting界面进行更新,系统设置--存储中会更新SD卡的状态。

--------------------------至此SD卡从底层到上层的挂载流程就完成了----------------------------



你可能感兴趣的:(android)