SD 汇总

http://blog.csdn.net/yihongyuelan/article/category/844867

Android 2.3 SD卡挂载流程浅析(一)

Android 2.3中关于SD卡挂载简介
      在Android 2.3中,当SD卡插入系统之后,系统会自动挂载。Vold 就是负责挂载SD卡的,vold 的全称是volume daemon。实际上是负责完成系统的CDROM,USB 大容量存储,MMC 卡(后文有简介,具体请百度)等扩展存储的挂载任务自动完成的守护进程。它提供的主要特点是支持这些存储外设的热插拔。在Android上的这个vold系统和GNU/Linux的之间存在很大的差异。自Android 2.2开始,vold又做了大改动,升级为vold 2.0,之前的配置文件是system/etc/vold.conf,vold 2.0变为system/etc/vold.fstab。

vold.fstab中的内容显示如下:


## Vold 2.0 Generic fstab
## - San Mehat (san@android.com)
##

#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
## label        - Label for the volume
## mount_point  - Where the volume will be mounted
## part         - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
######################

## Example of a standard sdcard mount for the emulator / Dream
# Mounts the first usable partition of the specified device
dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1

## Example of a dual card setup
# dev_mount left_sdcard  /sdcard1  auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
# dev_mount right_sdcard /sdcard2  auto /devices/platform/goldfish_mmc.1 /devices/platform/msm_sdcc.3/mmc_host/mmc1

## Example of specifying a specific partition for mounts
# dev_mount sdcard /sdcard 2 /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1

可以看到大部分是注释,最重要的为以下这句:
dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1

这句代码意思是:外置SD卡的挂载路径,auto 代表挂载SD卡的第一个分区,后面是vold监测的路径,当插入sd时,/devices/platform/msm_sdcc.2/mmc_host/mmc1 路径下会多出一个文件夹,在该文件夹中包含了SD卡的各种ID信息,以及生产日期等。


如果把sd卡插入设备,在 /dev/block/ 目录下面也会多出几个设备节点,证明sd卡的驱动已经成功加载。 我自己测试的目录下面会形成 mmcblk0  和 mmcblk0p1 节点,注意:这两个节点的意思,mmcblk0代表第一个SD卡设备,mmcblk0p1代表第一个SD卡设备的第一个分区。真正挂载到系统中的是mmcblk0p1而不是mmcblk0,这一点很重要。


PS:

MMC(MultiMedia Card)卡由西门子公司和首推CF的SanDisk于1997年推出。1998年1月十四家公司联合成立了MMC协会(MultiMedia Card Association简称MMCA),现在已经有超过84个成员。MMC的发展目标主要是针对数码影像、音乐、手机、PDA、电子书、玩具等产品,号称是目前世界上最小的Flash Memory存贮卡,尺寸只有32mm x 24mm x 1.4mm。虽然比SmartMedia厚,但整体体积却比SmartMedia小,而且也比SmartMedia轻,只有1.5克。MMC也是把存贮单元和控制器一同做到了卡上,智能的控制器使得MMC保证兼容性和灵活性。

MMC_百度百科

SD/MMC 卡的设备构造差不多,不过 MMC 当时的设计比 SD 小一半。所以,SD/MMC 的驱动通用,进一步的,Linux 的设备节点就延续了 MMC 的这个名字,后面的 blk 是块设备这个英文的简写, mmcblk 也就是“ mmc/sd 块设备”,0 就是这个 mmc/sd 设备的顺序编号,p1 就是第一个分区。


挂载流程简析
内核层(kernel):
当有新的SD/USB设备插入时,kernel将自动检测并加载对应的驱动,同时kernel中的sysfs机制会在有新的驱动加载时给用户层发送相应的event,然后将kernel产生的这些event传递给vold。
用户层(user):
用户层通过sysfs可以接收来自kernel的uevent,这些收到的信息可以在/sys/block/mmcblk0下用命令cat *来查看,如:

# cat *
bdi: invalid length
10
179:0
device: invalid length
8
holders: invalid length
power: invalid length
queue: invalid length
8
0
0
524288
slaves: invalid length
     278      813     8686     1050        0        0        0        0        0      240     1040
subsystem: invalid length
MAJOR=179
MINOR=0
DEVTYPE=disk
NPARTS=0
#
如果这时候在终端输入"pwd"指令,大家会发现路径并不是我们之前进入的路径/sys/block/mmcblk0,而是/sys/devices/platform/goldfish_mmc.0/mmc_host/mmc0/mmc0:e118/block/mmcblk0。其中mmc0:e118这个文件是插入SD卡之后生成的文件。Sysfs传递来的是一个多行的文档,vold需要解析这个文档。Vold将处理之后的事件传递给MountService,然后MoutService会将信息进一步处理传递给StorageManager,最后我们可以在系统设置界面看到SD卡挂载成功的信息,这包括了SD卡的总容量以及可用空间如下图:


SD卡的挂载流程大致如此,MountServie实际上还会通知PackageManagerService,因为这里分析的是SD卡挂载从底层到上层的表现,因此这里暂不分析。简约流程图如下:



Android 2.3 SD卡挂载流程浅析(二)

     在上一篇博文《Android 2.3 SD卡挂载流程浅析(一)主要简单的介绍了SD卡的挂载流程。包括了从内核层到用户层事件消息的传递,以及Vold的简介。本文将继续介绍SD卡的挂载,但文中并不会涉及代码的详细分析,因为这部分网上已有资料,我会在文章结尾贴出来供大家参考。本文主要目的是一方面对自己学习这一部分的总结,另一方面希望大家能够指出文中理解错误的地方。


      1.SD卡挂载流程图

      SD卡的挂载流程图如下:



        绿色箭头:表示插入SD卡后事件传递以及SD卡挂载

        红色箭头:表示挂载成功后的消息传递流程

        黄色箭头:表示MountService发出挂载/卸载SD卡的命令

        大家可能对图中突然出现的这么多的名称感到奇怪,这些都是在Android 2.3 源码中可以找到的,接下来我会为大家一一解释这些类的作用。


       2.各个文件的主要作用

    (1)Kernel:这个是系统内核啦。不是我要分析的文件,本文涉及内容不是内核级的哦!(努力学习中...)


       (2)NetlinkManager:全称是NetlinkManager.cpp位于Android 2.3源码位置/system/vold/NetlinkManager.cpp。该类的主要通过引用NetlinkHandler类中的onEvent()方法来接收来自内核的事件消息,NetlinkHandler位于/system/vold/NetlinkHandler.cpp。


    (3)VolumeManager:全称是VolumeManager.cpp位于Android 2.3源码位置/system/vold/VolumeManager.cpp。该类的主要作用是接收经过NetlinkManager处理过后的事件消息。因为我们这里是SD卡的挂载,因此经过NetlinkManager处理过后的消息会分为五种,分别是:block,switch,usb_composite,battery,power_supply。这里SD卡挂载的事件是block。


       (4)DirectVolume:位于/system/vold/DirectVolume.cpp。该类的是一个工具类,主要负责对传入的事件进行进一步的处理,block事件又可以分为:Add,Removed,Change,Noaction这四种。后文通过介绍Add事件展开。


       (5)Volume:Volume.cpp位于/system/vold/Volume.cpp,该类是负责SD卡挂载的主要类。Volume.cpp主要负责检查SD卡格式,以及对复合要求的SD卡进行挂载,并通过Socket将消息SD卡挂载的消息传递给NativeDaemonConnector。


       (6)NativeDaemonConnector:该类位于frameworks/base/services/java/com.android.server/NativeDaemonConnector.java。该类用于接收来自Volume.cpp 发来的SD卡挂载消息并向上传递。


       (7)MountService:位于frameworks/base/services/java/com.android.server/MountService.java。MountService是一个服务类,该服务是系统服务,提供对外部存储设备的管理、查询等。在外部存储设备状态发生变化的时候,该类会发出相应的通知给上层应用。在Android系统中这是一个非常重要的类。


       (8)StorageManaer:位于frameworks/base/core/java/andriod/os/storage/StorageManager.java。在该类的说明中有提到,该类是系统存储服务的接口。在系统设置中,有Storage相关项,同时Setting也注册了该类的监听器。而StorageManager又将自己的监听器注册到了MountService中,因此该类主要用于上层应用获取SD卡状态。

    通过上文对各个文件的作用简介,以及整个SD卡的挂载流程图可以知道,Android 系统是如何从底层获取SD卡挂载信息的。

       后文将继续分析程序调用流程图。

Android 2.3 SD卡挂载流程浅析(三)

在前面两篇博文《Android 2.3 SD卡挂载流程浅析(一)》《Android 2.3 SD卡挂载流程浅析(二)》中,主要简单介绍了SD卡的挂载流程以及所涉及的关键文件。在《Android 2.3 SD卡挂载流程浅析(三)》中,将简要介绍Android 2.3中Vold的运行机制,并从接收内核uevent开始介绍程序调用流程。

      1. Vold

     Vold的全称是volume daemon。主要负责系统对大容量存储设备(USB/SD)的挂载/卸载任务,它是一个守护进程,该进程支持这些存储外设的热插拔。自Android 2.2开始,Vold升级为vold 2.0,之前的配置文件路径在system/etc/vold.conf,Android 2.3之后变为system/etc/vold.fstab。

     2.Vold工作流程

    Vold的工作流程大致可以分为三个部分:创建监听、引导、事件处理。

     (1)创建监听

     创建监听指的是创建监听链接,一方面用于监听来自内核的uevent,另一方面用于监听来自上层的控制命令,这些命令包括控制SD卡的挂载与卸载,这里所说的链接也就是Socket。在Android 系统启动的时候,init进程会去解析init.rc文件,在该文件中,有如下代码:

Service vold /system/bin/vold
             Socket vold stream 0660 root mount
             Iprio be 2

     这样系统会在启动的时候创建与上层通信的Socket。

      在Android 2.3源码/system/vold路径下的main.cpp中创建了与内核通信的Socket。在main.cpp中通过实例化VolumeManager和NetlinkManager时创建。

     (2)引导

     Vold进程启动时候会对现有的外部存储设备进行检查。首先加载并解析vold.fstab,并检查挂载点是否已被挂载。然后执行SD卡的挂载,最后处理USB大容量存储。因为系统是按行解析的,通过查看vold.fstab可以很清楚的知道这一点。
vold.fatab中最重要的语句:

dev_mount        sdcard         /mnt/sdcard              auto                    /devices/platform/goldfish_mmc.0              /devices/platform/msm_sdcc.2/mmc_host/mmc1

dev_mount       <lable>     <mount_point>           <part>                   <sysfs_path…>
挂载命令            标签                挂载点              子分区个数                挂载路径
注:
       子分区个数如果为auto则表示只有1个子分区,也可以为任何不为0的整数。
       参数之间不能有空格,只能以tab为间隔(注意:这里为了对齐因此采用空格隔开,如果自行修改vold.fstab之后加以空格的话系统会识别不到的)。
       如果vold.fstab解析无误,VolueManager将创建DirectVolume,若vold.fstab解析不存在或者打开失败,Vold将会读取Linux内核中的参数,此时如果参数中存在SDCARD(也就是SD的默认路径),VolumeManager则会创建AutoVolume,如果不存在这个默认路径那么就不会创建。

     (3)事件处理

     通过对两个socket的监听,完成对事件的处理以及对上层应用的响应。

       a.     Kernel发出uevent
       NetlinkManager检测到kernel发出的uevent,解析后调用NetlinkHandler::onEvent()方法。该方法会分别处理不同的事件,这里重要的事件有:
       “block”事件主要指Volume的mount、unmount、createAsec等。由VolumeManager的handleBlockEvent(evt)来处理,根据多态性最终将会调用AutoVolume或者DirectVolume的handleBlockEvent方法来处理。
       “switch”事件主要指Volume的connet、disconnet等。根据相关操作,改变设备参数(设备类型、挂载点等)通过CommandListener告知FrameWork层。

       b.    FrameWork发出控制命令
       与a相反,CommandListener检测到FrameWork层的命令(MountService发出的命令)调用VolumeManager的函数,VolumeManager找出对应的Volume,调用Volume函数去挂载/卸载操作。而Volume类中的相关操作最终通过调用Linux函数完成。

    这里再次贴上这张流程图:



             3.SD卡挂载流程代码浅析
     
这里只是简要的分析SD卡挂载过程中重要的代码调用,并没有深入分析代码,因为这一部分网上已有牛人比较详尽的分析了,后面我会贴出这些参考文章。
       整个过程从Kernel检测到SD卡插入事件开始,之前的一些硬件中断的触发以及driver的加载这里并不叙述,一直到SD卡挂载消息更新到“Android——系统设置——存储”一项中。
       1.    Kernel发出SD卡插入uevent。
       2.    NetlinkHandler::onEvent()接收内核发出的uevent并进行解析。
       3.    VolumeManager::handlBlockEvent()处理经过第二步处理后的事件。
       4.    接下来调用DirectVolume:: handleBlockEvent()。
              在该方法中主要有两点需要注意:
              第一,程序首先会遍历mPath容器,寻找与event对应的sysfs_path是否存在与mPath容器中。
              第二,针对event中的action有4种处理方式:Add,Removed,Change,Noaction 。
              例如:在Add action中会有如下操作(因为我们这里所讲的是SD卡的挂载流程,因此以Add来说明),首先创建设备节点,其次对disk和partition两种格式的设备分别进行处理。SD卡属于disk类型。
       5.    经过上一步之后会调用DirectVolume::handleDiskAdded()方法,在该方法中会广播disk insert消息。
       6.    SocketListener::runListener会接收DirectVolume::handleDiskAdded()广播的消息。该方法主要完成对event中数据的获取,通过Socket。(PS:这里的SocketListener.cpp位于Android源码/system/core/libsysutils/src/中,后文的FramworkListener.cpp也是,之前自己找了很久 T_T)
       7.    调用FrameworkListener::onDataAvailable()方法处理接收到的消息内容。
       8.    FrameworkListener::dispatchCommand()该方法用于分发指令。
       9.    在FrameworkListener::dispatchCommand()方法中,通过runCommand()方法去调用相应的指令。
      10.   在/system/vold/CommandListener.cpp中有runCommand()的具体实现。在该类中可以找到这个方法:CommandListener::VolumeCmd::runCommand(),从字面意思上来看这个方法就是对Volume分发指令的解析。该方法中会执行“mount”函数:vm->mountVolume(arg[2])。
     11.    mountVolume(arg[2])在VolumeManager::mountVolume()中实现,在该方法中调用v->mountVol()。
     12.    mountVol()方法在Volume::mountVol()中实现,该函数是真正的挂载函数。(在该方法中,后续的处理都在该方法中,在Mount过程中会广播相应的消息给上层,通过setState()函数。)
     13.    setState(Volume::Checking);广播给上层,正在检查SD卡,为挂载做准备。
     14.    Fat::check();SD卡检查方法,检查SD卡是否是FAT格式。
     15.    Fat::doMount()挂载SD
     至此,SD的挂载已算初步完成,接下来应该将SD卡挂载后的消息发送给上层,在13中也提到过,在挂载以及检查的过程中其实也有发送消息给上层的。
     16.    MountService的构造函数中会开启监听线程,用于监听来自vold的socket信息。
              Thread thread = new Thread(mConnector,VOLD_TAG); thread.start();
     17.    mConnector是NativeDaemonConnector的对象,NativeDaemonConnector继承了Runnable并Override了run方法。在run方法中通过一个while(true)调用ListenToSocket()方法来实现实时监听。
     18.    在ListenToSocket()中,首先建立与Vold通信的Socket Server端,然后调用MountService中的onDaemonConnected()方法。(PS:Java与Native通信可以通过JNI,那么Native与Java通信就需要通过Socket来实现了。Android中Native与Frameworks通信  这篇文章中有简介,感兴趣的朋友可以参考一下)
     19.    onDaemonConnected()方法是在接口INativeDaemonConnectorCallbacks中定义的,MountService实现了该接口并Override了onDaemonConnected()方法。该方法开启一个线程用于更新外置存储设备的状态,主要更新状态的方法也在其中实现。
     20.    然后回到ListenToSocket中,通过inputStream来获取Vold传递来的event,并存放在队列中。
     21.    然后这些event会在onDaemonConnected()通过队列的”队列.take()”方法取出。并根据不同的event调用updatePublicVolumeState()方法,在该方法中调用packageManagerService中的updateExteralState()方法来更新存储设备的状态。(注:这里不太理解packageManagerService中的unloadAllContainers(args)方法)
     22.    更新是通过packageHelper.getMountService().finishMediaUpdate()方法来实现的。
     23.    在updatePublicVolumeState()方法中,更新后会执行如下代码:
              bl.mListener.onStorageStateChanged();
              在Android源码/packages/apps/Settings/src/com.android.settings.deviceinfo/Memory.java代码中,实现了StorageEventListener 的匿名内部类,并Override了onStorageStateChanged();方法。因此在updatePublicVolumeState()中调用onStorageStateChanged();方法后,Memory.java中也会收到。在Memory.java中收到以后会在Setting界面进行更新,系统设置——存储中会更新SD卡的状态。从而SD卡的挂载从底层到达了上层。

      在经过了上面步骤之后,SD卡的挂载的消息已经从底层到达了上层。这是自己在网上查找资料同时一边跟踪代码后得出的结论,其中可能还有很多不正确的地方,也有很多自己没有理解的地方,希望大家能够帮忙指正,感激不尽。
      后续将继续分析SD挂载广播的发出流程,以及SD卡挂载程序调用流程图。

Android 2.3 SD卡挂载流程浅析(四)

前面的三篇博文《Android 2.3 SD卡挂载流程浅析(一)》Android 2.3 SD卡挂载流程浅析(二)Android 2.3 SD卡挂载流程浅析(三)的分析,知道了SD卡挂载的消息是如何从底层传递到上层的,在《Android 2.3 SD卡挂载流程浅析(三)》中,我们已经知道了最后是在updatePublicVolumeState()中调用onStorageStateChanged(),从而达到更新SD卡挂载信息的。在本文《Android 2.3 SD卡挂载流程浅析(四)》中,我会将前文提到的程序调用流程图画出来,并对代码进行简单的分析。

      首先,还是挂出这张老图(因为每次都用这张图0_0...)。

       就权当复习吧,这是SD卡的整个挂载流程,而程序的调用也是根据这个流程图来的。

       1.接收并处理uevent

       首先是接收因为插入SD卡被内核检测到而发出的Event;

       NetlinkHandler::onEvent(NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/NetlinkHandler.cpp

//该方法主要通过evt->getSubsystem();方法来获取系统的event

  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.     VolumeManager *vm = VolumeManager::Instance();  
  3.     const char *subsys = evt->getSubsystem();  
  4.   
  5.     if (!subsys) {  
  6.         SLOGW("No subsystem found in netlink event");  
  7.         return;  
  8.     }  
  9.   
  10.     if (!strcmp(subsys, "block")) {  
  11.         vm->handleBlockEvent(evt);  
  12.     } else if (!strcmp(subsys, "switch")) {  
  13.         vm->handleSwitchEvent(evt);  
  14.     } else if (!strcmp(subsys, "usb_composite")) {  
  15.         vm->handleUsbCompositeEvent(evt);  
  16.     } else if (!strcmp(subsys, "battery")) {  
  17.     } else if (!strcmp(subsys, "power_supply")) {  
  18.     }  
  19. }  
  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.     VolumeManager *vm = VolumeManager::Instance();  
  3.     const char *subsys = evt->getSubsystem();  
  4.   
  5.     if (!subsys) {  
  6.         SLOGW("No subsystem found in netlink event");  
  7.         return;  
  8.     }  
  9.   
  10.     if (!strcmp(subsys, "block")) {  
  11.         vm->handleBlockEvent(evt);  
  12.     } else if (!strcmp(subsys, "switch")) {  
  13.         vm->handleSwitchEvent(evt);  
  14.     } else if (!strcmp(subsys, "usb_composite")) {  
  15.         vm->handleUsbCompositeEvent(evt);  
  16.     } else if (!strcmp(subsys, "battery")) {  
  17.     } else if (!strcmp(subsys, "power_supply")) {  
  18.     }  
  19. }  
      2.对SD卡挂载事件开始处理

      void VolumeManager::handleBlockEvent(NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/VolumeManager.cpp

//该方法的主要作用是:
//第一,    遍历mPath容器,寻找与event对应的sysfs_path是否存在与mPath容器中。
//第二,    针对Event中的action有4种处理方式:Add,Removed,Change,Noaction。

  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     const char *devpath = evt->findParam("DEVPATH");  
  3.   
  4.     /* Lookup a volume to handle this device */  
  5.     VolumeCollection::iterator it;  
  6.     bool hit = false;  
  7.     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {  
  8.         if (!(*it)->handleBlockEvent(evt)) {  
  9. #ifdef NETLINK_DEBUG  
  10.             SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());  
  11. #endif  
  12.             hit = true;  
  13.             break;  
  14.         }  
  15.     }  
  16.   
  17.     if (!hit) {  
  18. #ifdef NETLINK_DEBUG  
  19.         SLOGW("No volumes handled block event for '%s'", devpath);  
  20. #endif  
  21.     }  
  22. }  
  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     const char *devpath = evt->findParam("DEVPATH");  
  3.   
  4.     /* Lookup a volume to handle this device */  
  5.     VolumeCollection::iterator it;  
  6.     bool hit = false;  
  7.     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {  
  8.         if (!(*it)->handleBlockEvent(evt)) {  
  9. #ifdef NETLINK_DEBUG  
  10.             SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());  
  11. #endif  
  12.             hit = true;  
  13.             break;  
  14.         }  
  15.     }  
  16.   
  17.     if (!hit) {  
  18. #ifdef NETLINK_DEBUG  
  19.         SLOGW("No volumes handled block event for '%s'", devpath);  
  20. #endif  
  21.     }  
  22. }  
     3.对Block挂载事件进行处理

     DirectVolume::handleBlockEvent(NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/DirectVolume.cpp

//在Add action中首先会创建设备节点,然后对disk和partion两种格式的设备分别进行处理。这里是disk格式。

  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.         if (!strncmp(dp, *it, strlen(*it))) {  
  7.             /* We can handle this disk */  
  8.             int action = evt->getAction();  
  9.             const char *devtype = evt->findParam("DEVTYPE");  
  10.   
  11.             if (action == NetlinkEvent::NlActionAdd) {  
  12.                 int major = atoi(evt->findParam("MAJOR"));  
  13.                 int minor = atoi(evt->findParam("MINOR"));  
  14.                 char nodepath[255];  
  15.   
  16.                 snprintf(nodepath,  
  17.                          sizeof(nodepath), "/dev/block/vold/%d:%d",  
  18.                          major, minor);  
  19.                 if (createDeviceNode(nodepath, major, minor)) {  
  20.                     SLOGE("Error making device node '%s' (%s)", nodepath,  
  21.                                                                strerror(errno));  
  22.                 }  
  23.                 if (!strcmp(devtype, "disk")) {  
  24.                     <span style="color:#ff0000;">handleDiskAdded(dp, evt);<span style="color:#33cc00;">//SD卡插入是Add事件</span></span>  
  25.                 } else {  
  26.                     handlePartitionAdded(dp, evt);  
  27.                 }  
  28.             } else if (action == NetlinkEvent::NlActionRemove) {  
  29.                 if (!strcmp(devtype, "disk")) {  
  30.                     handleDiskRemoved(dp, evt);  
  31.                 } else {  
  32.                     handlePartitionRemoved(dp, evt);  
  33.                 }  
  34.             } else if (action == NetlinkEvent::NlActionChange) {  
  35.                 if (!strcmp(devtype, "disk")) {  
  36.                     handleDiskChanged(dp, evt);  
  37.                 } else {  
  38.                     handlePartitionChanged(dp, evt);  
  39.                 }  
  40.             } else {  
  41.                     SLOGW("Ignoring non add/remove/change event");  
  42.             }  
  43.   
  44.             return 0;  
  45.         }  
  46.     }  
  47.     errno = ENODEV;  
  48.     return -1;  
  49. }  
  1. int  
  2.  DirectVolume::handleBlockEvent(NetlinkEvent *evt) {  
  3.     const char *dp = evt->findParam("DEVPATH");  
  4.   
  5.     PathCollection::iterator  it;  
  6.     for (it = mPaths->begin(); it != mPaths->end(); ++it) {  
  7.         if (!strncmp(dp, *it, strlen(*it))) {  
  8.             /* We can handle this disk */  
  9.             int action = evt->getAction();  
  10.             const char *devtype = evt->findParam("DEVTYPE");  
  11.   
  12.             if (action == NetlinkEvent::NlActionAdd) {  
  13.                 int major = atoi(evt->findParam("MAJOR"));  
  14.                 int minor = atoi(evt->findParam("MINOR"));  
  15.                 char nodepath[255];  
  16.   
  17.                 snprintf(nodepath,  
  18.                          sizeof(nodepath), "/dev/block/vold/%d:%d",  
  19.                          major, minor);  
  20.                 if (createDeviceNode(nodepath, major, minor)) {  
  21.                     SLOGE("Error making device node '%s' (%s)",   
  22. nodepath,  
  23.                                                                  
  24. strerror(errno));  
  25.                 }  
  26.                 if (!strcmp(devtype, "disk")) {  
  27.                     <span   
  28. style="color:#ff0000;">handleDiskAdded(dp, evt);<span   
  29. style="color:#33cc00;">//SD卡插入是Add事件</span></span>  
  30.                 } else {  
  31.                     handlePartitionAdded(dp, evt);  
  32.                 }  
  33.             } else if (action == NetlinkEvent::NlActionRemove) {  
  34.                 if (!strcmp(devtype, "disk")) {  
  35.                     handleDiskRemoved(dp, evt);  
  36.                 } else {  
  37.                     handlePartitionRemoved(dp, evt);  
  38.                 }  
  39.             } else if (action == NetlinkEvent::NlActionChange) {  
  40.                 if (!strcmp(devtype, "disk")) {  
  41.                     handleDiskChanged(dp, evt);  
  42.                 } else {  
  43.                     handlePartitionChanged(dp, evt);  
  44.                 }  
  45.             } else {  
  46.                     SLOGW("Ignoring non add/remove/change event");  
  47.             }  
  48.   
  49.             return 0;  
  50.         }  
  51.     }  
  52.     errno = ENODEV;  
  53.     return -1;  
  54. }  
      4.处理DiskAdd事件

DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/DirectVolume.cpp

//在该方法中广播disk insert的广播消息(这里的广播不同于Java中的广播,这里实际上是Socket)。

  1. void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {  
  2.     mDiskMajor = atoi(evt->findParam("MAJOR"));  
  3.     mDiskMinor = atoi(evt->findParam("MINOR"));  
  4.   
  5.     const char *tmp = evt->findParam("NPARTS");  
  6.     if (tmp) {  
  7.         mDiskNumParts = atoi(tmp);  
  8.     } else {  
  9.         SLOGW("Kernel block uevent missing 'NPARTS'");  
  10.         mDiskNumParts = 1;  
  11.     }  
  12.   
  13.     char msg[255];  
  14.   
  15.     int partmask = 0;  
  16.     int i;  
  17.     for (i = 1; i <= mDiskNumParts; i++) {  
  18.         partmask |= (1 << i);  
  19.     }  
  20.     mPendingPartMap = partmask;  
  21.   
  22.     if (mDiskNumParts == 0) {  
  23. #ifdef PARTITION_DEBUG  
  24.         SLOGD("Dv::diskIns - No partitions - good to go son!");  
  25. #endif  
  26.         setState(Volume::State_Idle);  
  27.     } else {  
  28. #ifdef PARTITION_DEBUG  
  29.         SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",  
  30.              mDiskNumParts, mPendingPartMap);  
  31. #endif  
  32.         setState(Volume::State_Pending);  
  33.     }  
  34.   
  35.     snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",  
  36.              getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);  
  37.     <span style="color:#ff0000;">mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,  
  38.                                              msg, false);  
  39. </span>}  
  1. void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {  
  2.     mDiskMajor = atoi(evt->findParam("MAJOR"));  
  3.     mDiskMinor = atoi(evt->findParam("MINOR"));  
  4.   
  5.     const char *tmp = evt->findParam("NPARTS");  
  6.     if (tmp) {  
  7.         mDiskNumParts = atoi(tmp);  
  8.     } else {  
  9.         SLOGW("Kernel block uevent missing 'NPARTS'");  
  10.         mDiskNumParts = 1;  
  11.     }  
  12.   
  13.     char msg[255];  
  14.   
  15.     int partmask = 0;  
  16.     int i;  
  17.     for (i = 1; i <= mDiskNumParts; i++) {  
  18.         partmask |= (1 << i);  
  19.     }  
  20.     mPendingPartMap = partmask;  
  21.   
  22.     if (mDiskNumParts == 0) {  
  23. #ifdef PARTITION_DEBUG  
  24.         SLOGD("Dv::diskIns - No partitions - good to go son!");  
  25. #endif  
  26.         setState(Volume::State_Idle);  
  27.     } else {  
  28. #ifdef PARTITION_DEBUG  
  29.         SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",  
  30.              mDiskNumParts, mPendingPartMap);  
  31. #endif  
  32.         setState(Volume::State_Pending);  
  33.     }  
  34.   
  35.     snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",  
  36.              getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);  
  37.     <span style="color:#ff0000;">mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,  
  38.                                              msg, false);  
  39. </span>}  
      5.处理广播消息
       SocketListener::runListener()

//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/SocketListener.cpp

//完成对Socket的监听以及对数据的处理onDataAvailable(* it );

  1. void SocketListener::runListener() {  
  2.   
  3.     while(1) {  
  4.         SocketClientCollection::iterator it;  
  5.         fd_set read_fds;  
  6.         int rc = 0;  
  7.         int max = 0;  
  8.   
  9.         FD_ZERO(&read_fds);  
  10.   
  11.         if (mListen) {  
  12.             max = mSock;  
  13.             FD_SET(mSock, &read_fds);  
  14.         }  
  15.   
  16.         FD_SET(mCtrlPipe[0], &read_fds);  
  17.         if (mCtrlPipe[0] > max)  
  18.             max = mCtrlPipe[0];  
  19.   
  20.         pthread_mutex_lock(&mClientsLock);  
  21.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  22.             FD_SET((*it)->getSocket(), &read_fds);  
  23.             if ((*it)->getSocket() > max)  
  24.                 max = (*it)->getSocket();  
  25.         }  
  26.         pthread_mutex_unlock(&mClientsLock);  
  27.   
  28.         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {  
  29.             SLOGE("select failed (%s)", strerror(errno));  
  30.             sleep(1);  
  31.             continue;  
  32.         } else if (!rc)  
  33.             continue;  
  34.   
  35.         if (FD_ISSET(mCtrlPipe[0], &read_fds))  
  36.             break;  
  37.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  38.             struct sockaddr addr;  
  39.             socklen_t alen = sizeof(addr);  
  40.             int c;  
  41.   
  42.             if ((c = accept(mSock, &addr, &alen)) < 0) {  
  43.                 SLOGE("accept failed (%s)", strerror(errno));  
  44.                 sleep(1);  
  45.                 continue;  
  46.             }  
  47.             pthread_mutex_lock(&mClientsLock);  
  48.             mClients->push_back(new SocketClient(c));  
  49.             pthread_mutex_unlock(&mClientsLock);  
  50.         }  
  51.   
  52.         do {  
  53.             pthread_mutex_lock(&mClientsLock);  
  54.             for (it = mClients->begin(); it != mClients->end(); ++it) {  
  55.                 int fd = (*it)->getSocket();  
  56.                 if (FD_ISSET(fd, &read_fds)) {  
  57.                     pthread_mutex_unlock(&mClientsLock);  
  58.                     if (!<span style="color:#ff0000;">onDataAvailable(*it)</span>) {  
  59.                         close(fd);  
  60.                         pthread_mutex_lock(&mClientsLock);  
  61.                         delete *it;  
  62.                         it = mClients->erase(it);  
  63.                         pthread_mutex_unlock(&mClientsLock);  
  64.                     }  
  65.                     FD_CLR(fd, &read_fds);  
  66.                     pthread_mutex_lock(&mClientsLock);  
  67.                     continue;  
  68.                 }  
  69.             }  
  70.             pthread_mutex_unlock(&mClientsLock);  
  71.         } while (0);  
  72.     }  
  73. }  
  1. void SocketListener::runListener() {  
  2.   
  3.     while(1) {  
  4.         SocketClientCollection::iterator it;  
  5.         fd_set read_fds;  
  6.         int rc = 0;  
  7.         int max = 0;  
  8.   
  9.         FD_ZERO(&read_fds);  
  10.   
  11.         if (mListen) {  
  12.             max = mSock;  
  13.             FD_SET(mSock, &read_fds);  
  14.         }  
  15.   
  16.         FD_SET(mCtrlPipe[0], &read_fds);  
  17.         if (mCtrlPipe[0] > max)  
  18.             max = mCtrlPipe[0];  
  19.   
  20.         pthread_mutex_lock(&mClientsLock);  
  21.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  22.             FD_SET((*it)->getSocket(), &read_fds);  
  23.             if ((*it)->getSocket() > max)  
  24.                 max = (*it)->getSocket();  
  25.         }  
  26.         pthread_mutex_unlock(&mClientsLock);  
  27.   
  28.         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {  
  29.             SLOGE("select failed (%s)", strerror(errno));  
  30.             sleep(1);  
  31.             continue;  
  32.         } else if (!rc)  
  33.             continue;  
  34.   
  35.         if (FD_ISSET(mCtrlPipe[0], &read_fds))  
  36.             break;  
  37.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  38.             struct sockaddr addr;  
  39.             socklen_t alen = sizeof(addr);  
  40.             int c;  
  41.   
  42.             if ((c = accept(mSock, &addr, &alen)) < 0) {  
  43.                 SLOGE("accept failed (%s)", strerror(errno));  
  44.                 sleep(1);  
  45.                 continue;  
  46.             }  
  47.             pthread_mutex_lock(&mClientsLock);  
  48.             mClients->push_back(new SocketClient(c));  
  49.             pthread_mutex_unlock(&mClientsLock);  
  50.         }  
  51.   
  52.         
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值