Android磁盘管理-之vold源码分析(4)

13 篇文章 0 订阅

作者:gzshun. 原创作品,转载请标明出处!

上篇文章分析到了NetlinkHandler类中的onEvent函数,该函数由NetlinkListener::onDataAvailable函数调用,当SocketListener类监听到内核的uevent事件,调用该函数,之后的事情交给onEvent来负责。


file:system/vold/NetlinkHandler.cpp
现在来说onEvent函数,在vold中,磁盘的热插拔事件都是通过上述那些间接的过程来调用到

该函数,该函数再调用vold中的处理事件的函数,这样vold就能得到最新的磁盘热插拔事件;

void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
    VolumeManager *vm = VolumeManager::Instance();  
    const char *subsys = evt->getSubsystem();  
      
    if (!subsys) {  
        SLOGW("No subsystem found in netlink event");  
        return;  
    }  
      
    if (!strcmp(subsys, "block")) {  
        vm->handleBlockEvent(evt);  
    } else if (!strcmp(subsys, "switch")) {  
        vm->handleSwitchEvent(evt);  
    } else if (!strcmp(subsys, "battery")) {  
    } else if (!strcmp(subsys, "power_supply")) {  
    }  
}  

file:system/vold/VolumeManager.cpp
vm->handleSwitchEvent(evt)函数涉及的比较少,先来分析;
该函数是用来处理大容量存储设备,也就是otg功能,NetlinkEvent类提供的findParam函数
可以获取到该事件的具体信息,比如设备路径,设备名称,状态,分区数量等等。。
如果判断是“online”状态,那么就向framework发送状态消息。使用notifyUmsConnected函数
进行广播。
void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {  
    const char *devpath = evt->findParam("DEVPATH");  
    const char *name = evt->findParam("SWITCH_NAME");  
    const char *state = evt->findParam("SWITCH_STATE");  
      
    if (!name || !state) {  
        SLOGW("Switch %s event missing name/state info", devpath);  
        return;  
    }  
      
    if (!strcmp(name, "usb_mass_storage")) {  
        if (!strcmp(state, "online"))  {  
            notifyUmsConnected(true);  
        } else {  
            notifyUmsConnected(false);  
        }  
        } else {  
            SLOGW("Ignoring unknown switch '%s'", name);  
        }  
}  
notifyUmsConnected函数将otg的状态发送给framework,
命令为:Share method ums now available/unavailable;
getBroadcaster()->sendBroadcast()广播函数,这在main函数分析中就涉及到了,
源码:
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
将CommandListener对象强制转换成SocketListener类型,这样cl对象就能够调用SocketListener
类的setBroadcaster广播函数;
getBroadcaster()的源码:
SocketListener *getBroadcaster() { return mBroadcaster; }
直接将刚才被强制转换成SocketListener类型返回,相当于如下:
(SocketListener *)cl->sendBroadcast(xxx);

[cpp]  view plain copy
  1. void VolumeManager::notifyUmsConnected(bool connected) {  
  2.     char msg[255];  
  3.       
  4.     if (connected) {  
  5.         mUsbMassStorageConnected = true;  
  6.     } else {  
  7.         mUsbMassStorageConnected = false;  
  8.     }  
  9.     snprintf(msg, sizeof(msg), "Share method ums now %s",   (connected ? "available" : "unavailable"));  
  10.       
  11.     getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange, msg, false);  
  12. }  

file:system/vold/ResponseCode.cpp
该类没做什么事,也就是提供一些出错标志,下面将写出出错原因;
这些标志都会在不同的操作(命令)反馈不同的值。

[cpp]  view plain copy
  1. class ResponseCode {  
  2. public:  
  3.     // 100 series - Requestion action was initiated; expect another reply  
  4.     // before proceeding with a new command.  
  5.     static const int ActionInitiated  = 100;  
  6.       
  7.     static const int VolumeListResult         = 110;  
  8.     static const int AsecListResult           = 111;  
  9.     static const int StorageUsersListResult   = 112;  
  10.       
  11.     // 200 series - Requested action has been successfully completed  
  12.     static const int CommandOkay              = 200;  
  13.     static const int ShareStatusResult        = 210;  
  14.     static const int AsecPathResult           = 211;  
  15.     static const int ShareEnabledResult       = 212;  
  16.     static const int XwarpStatusResult        = 213;  
  17.       
  18.     // 400 series - The command was accepted but the requested action  
  19.     // did not take place.//这几个标志有点重复性,其实vold里面也没有这几个标志。  
  20.     static const int OperationFailed          = 400;  
  21.     static const int OpFailedNoMedia          = 401;   
  22.     static const int OpFailedMediaBlank       = 402;   
  23.     static const int OpFailedMediaCorrupt     = 403;   
  24.     static const int OpFailedVolNotMounted    = 404;   
  25.     static const int OpFailedStorageBusy      = 405;   
  26.     static const int OpFailedStorageNotFound  = 406;   
  27.       
  28.     // 500 series - The command was not accepted and the requested  
  29.     // action did not take place.  
  30.     static const int CommandSyntaxError = 500;//  
  31.     static const int CommandParameterError = 501;//  
  32.       
  33.     // 600 series - Unsolicited broadcasts  
  34.     static const int UnsolicitedInformational       = 600;   
  35.     static const int VolumeStateChange              = 605;   
  36.     static const int VolumeMountFailedBlank         = 610;   
  37.     static const int VolumeMountFailedDamaged       = 611;   
  38.     static const int VolumeMountFailedNoMedia       = 612;   
  39.       
  40.     static const int ShareAvailabilityChange        = 620;   
  41.       
  42.     static const int VolumeDiskInserted            = 630;   
  43.     static const int VolumeDiskRemoved             = 631;   
  44.     static const int VolumeBadRemoval              = 632;   
  45.       
  46.     static int convertFromErrno();  
  47. };  

file:system/vold/VolumeManager.cpp
该函数用来捕获磁盘的热插拔事件信息。
[cpp]  view plain copy
  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     const char *devpath = evt->findParam("DEVPATH");  
  3.       
  4.     VolumeCollection::iterator it;  
  5.     bool hit = false;  
  6.     /********************************************************************************** 
  7.     **mVolumes是一个存放volume*的容器,类型如下: 
  8.     **typedef android::List<Volume *> VolumeCollection; 
  9.     **mVolumes是在main函数中添加进磁盘的,在mian函数中,使用process_config函数分析 
  10.     **/etc/vold.fstab配置文件,然后将磁盘的信息添加进该容器,以便后续的操作。  
  11.     **********************************************************************************/  
  12.     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {  
  13.         if (!(*it)->handleBlockEvent(evt)) {  
  14.             #ifdef NETLINK_DEBUG  
  15.             SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());  
  16.             #endif  
  17.             hit = true;  
  18.             break;  
  19.         }  
  20.     }  
  21.     if (!hit) {  
  22.         #ifdef NETLINK_DEBUG  
  23.         SLOGW("No volumes handled block event for '%s'", devpath);  
  24.         #endif  
  25.     }  
  26. }  

这里使用(*it)调用handleBlockEvent函数,可以看出handleBlockEvent在Volume类对象实现,
源码在system/vold/Volume.cpp
可以发现,该函数并没有做什么事情,其实handleBlockEvent函数在Volume的子类DirectVolume
中重写了。

[cpp]  view plain copy
  1. int Volume::handleBlockEvent(NetlinkEvent *evt) {  
  2.     errno = ENOSYS;  
  3.     return -1;  
  4. }  

file:system/vold/DirectVolume.cpp
这函数是处理热插拔事件最重要的函数,Volume若要操作磁盘,肯定先要从这个函数获取到
磁盘事件和信息。

[cpp]  view plain copy
  1. int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {  
  2.     const char *dp = evt->findParam("DEVPATH");  
  3.       
  4.     PathCollection::iterator  it;  
  5.     for (it = mPaths->begin(); it != mPaths->end(); ++it) {  
  6.         size_t len = strlen(*it);  
  7.         if (!strncmp(dp, *it, len) && (dp[len] == '\0' || dp[len] == '/')) {  
  8.             /* We can handle this disk */  
  9.             int action = evt->getAction();  
  10.             const char *devtype = evt->findParam("DEVTYPE");  
  11.             /********************************************************************************** 
  12.             **NetlinkEvent提供4个uevent状态,代码: 
  13.             **const int NetlinkEvent::NlActionUnknown = 0; 
  14.                 const int NetlinkEvent::NlActionAdd = 1; //增加硬盘或分区的事件 
  15.                 const int NetlinkEvent::NlActionRemove = 2;//移除硬盘或分区的事件 
  16.                 const int NetlinkEvent::NlActionChange = 3;//改变硬盘或分区的事件 
  17.             **这里的事件是增加存储设备 
  18.             **********************************************************************************/  
  19.             if (action == NetlinkEvent::NlActionAdd) {  
  20.                 /*从这里获取到主次设备号*/  
  21.                 int major = atoi(evt->findParam("MAJOR"));  
  22.                 int minor = atoi(evt->findParam("MINOR"));  
  23.                 char nodepath[255];  
  24.                   
  25.                 /********************************************************************************** 
  26.                 **之前有提到过,vold在/dev/block/vold创建了相应的设备节点,诸如8:0形式的节点,这里 
  27.                 **就是创建节点的位置,createDeviceNode函数。 
  28.                 **********************************************************************************/  
  29.                 snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d",   major, minor);  
  30.                 if (createDeviceNode(nodepath, major, minor)) {  
  31.                         SLOGE("Error making device node '%s' (%s)", nodepath, strerror(errno));  
  32.                 }  
  33.                 /*磁盘类型,指的就是一块存储设备*/  
  34.                 if (!strcmp(devtype, "disk")) {  
  35.                     handleDiskAdded(dp, evt);  
  36.                 } else {/*分区类型,指的是一块存储设备的某个分区*/  
  37.                     handlePartitionAdded(dp, evt);  
  38.                 }  
  39.             }  
  40.             /*移除存储设备*/  
  41.             else if (action == NetlinkEvent::NlActionRemove) {  
  42.                     if (!strcmp(devtype, "disk")) {  
  43.                         handleDiskRemoved(dp, evt);  
  44.                 } else {  
  45.                     handlePartitionRemoved(dp, evt);  
  46.                 }  
  47.             }  
  48.             /*改变存储设备*/  
  49.             else if (action == NetlinkEvent::NlActionChange) {  
  50.                     if (!strcmp(devtype, "disk")) {  
  51.                     handleDiskChanged(dp, evt);  
  52.                 } else {  
  53.                     handlePartitionChanged(dp, evt);  
  54.                 }  
  55.             } else {  
  56.                 SLOGW("Ignoring non add/remove/change event");  
  57.             }  
  58.             return 0;  
  59.         }  
  60.     }  
  61.     errno = ENODEV;  
  62.     return -1;  
  63. }  

该函数主要对存储设备或分区处理,每个存储设备或分区都有增加、删除和改变的事件,下一篇文章介绍
每个不同事件和函数的处理,有以下6个函数:

[cpp]  view plain copy
  1. void handleDiskAdded(const char *devpath, NetlinkEvent *evt);  
  2. void handleDiskRemoved(const char *devpath, NetlinkEvent *evt);  
  3. void handleDiskChanged(const char *devpath, NetlinkEvent *evt);  
  4. void handlePartitionAdded(const char *devpath, NetlinkEvent *evt);  
  5. void handlePartitionRemoved(const char *devpath, NetlinkEvent *evt);  
  6. void handlePartitionChanged(const char *devpath, NetlinkEvent *evt);  

下一篇文章继续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值