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

        在上一篇Android4.4----Vold挂载管理分析USB挂载(二)中分析了Vold如何接收kernel的uevent并传递到VolumeManager的过程,这里继上篇文章继续分析VolumeManager接收到uevent事件后的处理过程!

         那我们先分析一下VolumeManager!

一:VolumeManager

       VolumeManager就是整个Android 磁盘挂载Vold机制的核心调度,上下连接的中转站!

         在system/vold/main.cpp的主函数中

   /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {//构造VolumeManager
        SLOGE("Unable to create VolumeManager");
        exit(1);
    };
........................
 vm->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));
    }

VolumeManager::VolumeManager() {
    mDebug = false;
    mVolumes = new VolumeCollection();//在构造函数中new一个VolumeCollection用来保存Volume的容器
    mActiveContainers = new AsecIdCollection();//活动容器,mount/unmount asec obb时的记录
    mBroadcaster = NULL;//指向SocketListener,用于发送挂载事件
    mUmsSharingCount = 0;
    mSavedDirtyRatio = -1;
    // set dirty ratio to 0 when UMS is active
    mUmsDirtyRatio = 0;
    mVolManagerDisabled = 0;
}

加打印看了一下process_config(vm),发现是去解析fstab.madison文件,但是在真正做动作的地方没有跑进去,也就是说main函数里面最主要的就是new了一个VolumeCollection容器

然后接着看上篇接收到kernel的uevent后的动作!

vm->handleBlockEvent(evt);
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    const char *devpath = evt->findParam("DEVPATH");
    const char *devtype = evt->findParam("DEVTYPE");
    const char *dn = evt->findParam("DEVNAME");
    int major = -1;
    int minor = -1;
    bool isRawDisk = false;
    bool isPartition = false;
    int partIdx = -1;
    bool isSDCard = false;
    char device[255];
    char uuid[255];
    VolumeCollection::iterator it;
    bool hit = false;
    static bool preDiskChangeEvent = false;
.............
    major = atoi(evt->findParam("MAJOR"));
    minor = atoi(evt->findParam("MINOR"));
...........
 snprintf(device,255,"/dev/block/vold/%d:%d",major,minor);
    SLOGD("Javen.tang handlerBlockEvent major = %d, minor = %d, device = %s, devtype = %s\n", major, minor, device ,devtype);
...........
if (isRawDisk || isPartition) {
        //first find uuid from cache
        UUIDCache::Entry *entry = uuidCache.searchEntry(device);

        if (evt->getAction() == NetlinkEvent::NlActionAdd) {
            mode_t mode = 0660 | S_IFBLK;
            dev_t dev = (major << 8) | minor;

            //if device has been now added, not add again
            if (entry != NULL && entry->uuid != NULL) {
                return;
            }

            if (mknod(device, mode, dev) < 0) {//创建设备索引点
                if (errno != EEXIST) {
                    return ;
                }
            }
            if (!getVolumeUUID(device, uuid, 255)) {//根据device获取一个uuid
        #ifdef NETLINK_DEBUG
                SLOGD("can not get the uuid of %s when device add",device);
        #endif
                return ;
            }
........

    if (!hit) {
        static char index = 'a'-1;
        char * mountPoint = NULL;
        const char *dp = NULL;
        Volume *volume = NULL;

    #ifdef NETLINK_DEBUG
        SLOGW("No volumes handled block event for '%s'", devpath);
    #endif
        if (evt->getAction() != NetlinkEvent::NlActionAdd) {
            return;
        }
..........
} else {
                if (preDiskChangeEvent) {
                    ++index;
                    preDiskChangeEvent = false;
                }
            }
...........
 else if (isPartition) {
                asprintf(&mountPoint,"/mnt/usb/sd%c%i",index,partIdx);//U盘的挂载点
            }
............
 volume = new DirectVolume(this, &rec, flags);
            addVolume(volume);//根据挂载点new一个volume,然后add到mVolumes容器中去
...........
 if ( volume->handleBlockEvent(evt) !=0 ) {//然后执行volume->handleBlockEvent(evt)
            SLOGD("New add volume fail to handle the event of %s",devpath);
        }
注意当我们插上U盘时,会创建两个索引点,一个disk,一个partition,我们真正挂载的是partition

D/Vold    (  976): Javen.tang handlerBlockEvent major = 8, minor = 0, device = /dev/block/vold/8:0, devtype = disk
D/Vold    (  976): Javen.tang handlerBlockEvent major = 8, minor = 1, device = /dev/block/vold/8:1, devtype = partition
也就是说在VolumeManager中的handleBlockEvent主要做了这几件事

1、根据主次设备号创建索引点;

2、寻找挂载点,这里U盘的挂载点为/mnt/usb/sd%c%i;

3、根据挂载点创建一个DirectVolume,DirectVolume是继承于Volume,Volume就想当于一个存储设备,new了一个Volume后add到mVolumes这个容器中去;

4、调用volume的handleBlockEvent(evt)函数;

二:DirectVolume

        接着看看DirectVolume的handleBlockEvent(evt)函数!

if (!strcmp(devtype, "disk")) {
            handleDiskAdded(dp, evt);
        } else {
            handlePartitionAdded(dp, evt);
        }
void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) {
    int major = atoi(evt->findParam("MAJOR"));
    int minor = atoi(evt->findParam("MINOR"));
    // MStar Android Patch Begin
    char msg[255];
    // MStar Android Patch End

    int part_num;
    //devpath = /devices/platform/Mstar-ehci-1.0/usb4/4-1/4-1:1.0/host1/target1:0:0/1:0:0:0/block/sda/sda1
    const char *tmp = evt->findParam("PARTN");

    if (tmp) {
        part_num = atoi(tmp);
    } else {
        SLOGW("Kernel block uevent missing 'PARTN'");
        part_num = 1;
    }
.........................
  if (getState() != Volume::State_Formatting) {
            setState(Volume::State_Idle);
            snprintf(msg, sizeof(msg), "Volume %s %s Partition Added (%d:%d)",
             getLabel(), getFuseMountpoint(), mDiskMajor, mDiskMinor);
            mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
                                                msg, false);
        }

void Volume::setState(int state) {
    char msg[255];
    int oldState = mState;
    if (oldState == state) {
        SLOGW("Duplicate state (%d)\n", state);
        return;
    }

    if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) {
        mRetryMount = false;
    }

    mState = state;

    SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,
         oldState, stateToStr(oldState), mState, stateToStr(mState));
    snprintf(msg, sizeof(msg),
             "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
             getFuseMountpoint(), oldState, stateToStr(oldState), mState,
             stateToStr(mState));
    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
                                         msg, false);
}
这里主要会发送两个广播到frameworks的MountService中去。

先在Volume::setState中通过mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,msg, false);发送一个VolumeStateChange类型的广播,代表挂载状态在改变,发送的信息为msg,msg的打印如下:

D/Vold    (  977): Javen.tang setState msg=Volume CAA5-CD0B /mnt/usb/sda1 state changed from 0 (No-Media) to 1 (Idle-Unmounted)
然后接着调用 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false);发送一个 VolumeDiskInserted类型的广播,代表U盘插入的意思,信息也是msg,打印msg信息可以看到:

D/DirectVolume(  977): Javen.tang msg=Volume CAA5-CD0B /mnt/usb/sda1 Partition Added (8:1)

接下来就要到jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java的onEvent()方法中去查看接收到广播之后执行的动作了!



你可能感兴趣的:(android)