2025-05-23

上一篇https://www.aiwalls.com/kf/201203/124631.html 講到通過NetlinkManager發送uevent 命令到NetlinkHandler 的onEvent,代碼如下:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();

    if (!subsys) {
        SLOGW("No subsystem found in netlink event");
        return;
    }
    SLOGD("NetlinkHandler:OnEvent subsys values is %s",subsys);
    if (!strcmp(subsys, "block")) {
        SLOGD("NetlinkHandler:onEvent");
        vm->handleBlockEvent(evt);
    }

 在NetlinkHandler 裡面得一個VolumeManager,當收到的命令為block時調用VolumnManager的handleBlockEvent,如上加紅加粗的代碼。
handleBlockEvent實則是通過一個循環將事先將main事先讀取的配置文件:etc/vold.fstab存進VolumeCollection,得到VolumeCollection的對象,然後調用Volume 的handleBlockEvent,如代碼:
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    const char *devpath = evt->findParam("DEVPATH");

    /* Lookup a volume to handle this device */
    VolumeCollection::iterator it;
    bool hit = false;
    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
        if (!(*it)->handleBlockEvent(evt)) {
#ifdef NETLINK_DEBUG
            SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
#endif
            hit = true;
            break;
        }
    }

    if (!hit) {
#ifdef NETLINK_DEBUG
        SLOGW("No volumes handled block event for '%s'", devpath);
#endif
    }

看一下Volume 的handleblockEvent代碼:
int Volume::handleBlockEvent(NetlinkEvent *evt) {
    errno = ENOSYS;
    return -1;

 看起來好像沒做什麼事,其實真的實現在於Volume 的子類,DirectVolume,DirectVolme 中重寫瞭handleBlockEvent,看代碼:
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
    const char *dp = evt->findParam("DEVPATH");

    PathCollection::iterator  it;
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        if (!strncmp(dp, *it, strlen(*it))) {
            /* We can handle this disk */
            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"));
                char nodepath[255];

                snprintf(nodepath,
                         sizeof(nodepath), "/dev/block/vold/%d:%d",
                         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) {
                if (!strcmp(devtype, "disk")) {
                    handleDiskRemoved(dp, evt);
                } else {
                    SLOGD("DirectVolume:handleBlockEvent—>handlePartitionRemoved");
                    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;

 
因為我的板子還未完善,所以這裡它認為我的sdcard是一個分區,但無關緊要,原理一樣,就根據分區的代碼跟蹤。:handlePartitionRemoved,由於代碼過多,隻貼出核心代碼:
void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt) {

 if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {
        /*
         * Yikes, our mounted partition is going away!
         */

        snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",
                 getLabel(), getMountpoint(), major, minor);
        SLOGD("DirectVolume:(dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev:%d,msg is :%s.",mCurrentlyMountedKdev,msg);
        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
                                             msg, false);

    if (mVm->cleanupAsec(this, true)) {
            SLOGE("Failed to cleanup ASEC – unmount will probably fail!");
        }

        if (Volume::unmountVol(true, false)) {
            SLOGE("Failed to unmount volume on bad removal (%s)",
                 strerror(errno));
            // XXX: At this point we're screwed for now
        } else {
            SLOGD("Crisis averted");
        }
    }

 
 到此,直接調用父類的unmountVol方法,unmountVol會通過setState通知框架狀態改變。代碼太多,隻推薦核心代碼:
int Volume::unmountVol(bool force, bool revert) {
 setState(Volume::State_Unmounting);

 
 而setState會通過socket將msg消息傳給框架
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
                                         msg, false); 

接下去的步驟是關於socket的操作,就不深入瞭。
小結
   到瞭這一步,Vold 向上層反饋的動作基本己經完成,下一篇文章將會講解Framework 如何取得Vold 反饋過來的數據。

 

摘自 Terry_龍  

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *