企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
在分析Vold的代码前,先介绍一下Linux系统中的Netlink和Uevent。 1. Netlink的介绍 Netlink是Linux系统中一种用户空间进程和Kernel进行通信的机制,通过这个机制,位于用户空间的进程,可接收来自Kernel的一些信息(例如Vold中用到的USB或SD的插拔消息),同时应用层也可通过Netlink向Kernel发送一些控制命令。 目前,Linux系统并没有为Netlink单独设计一套系统调用,而是复用了Socket的操作接口,只在创建Socket时会有一些特殊的地方。Netlink的具体使用方法,在进行代码分析时再来了解,读者目前只需知道,通过Netlink机制应用层,可接收来自Kernel的消息即可。 2. Uevent介绍 Uevent和Linux的Udev设备文件系统和设备模型有关系,它实际上就是一串字符串,字符串的内容可告知发生了什么事情。下面通过一个实例来直观感受Uevent: 在SD卡插入手机后(我们这里以SD卡为例),系统会检测到这个设备的插入,然后内核会通过Netlink发送一个消息给Vold,Vold将根据接收到的消息进行处理,例如挂载这个SD卡。内核发送的这个消息,就是Uevent,其中U代表User space(应用层空间)。下面看SD卡插入时Vold截获到的Uevent消息。在我的G7手机上,Uevent的内容如下,注意,其中//号或/**/号中的内容是为方便读者理解而加的注释: **SD卡插入的Uevent消息** ~~~ //mmc表示MultiMedia Card,这里统称为SD卡 add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0 ACTION=add //add表示设备插入,另外还有remove和change等动作 //DEVPATH表示该设备位于/sys目录中的设备路径 DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0 /* SUBSYSTEM表示该设备属于哪一类设备,block为块设备,磁盘也属于这一类设备,另外还有 character(字符)设备等类型。 */ SUBSYSTEM=block MAJOR=179//MAJOR和MINOR分别表示该设备的主次设备号,二者联合起来可以标识一个设备 MINOR=0 DEVNAME=mmcblk0 DEVTYPE=disk//设备Type为disk NPARTS=3 //这个表示该SD卡上的分区,我的SD卡上有三块分区 SEQNUM=1357//序号 ~~~ 由于我的SD卡上还有分区,所以还会接收到和分区相关的Uevent。简单看一下: **SD卡插入后和分区相关的Uevent消息** ~~~ add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0/mmcblk0p1 ACTION=add //比上面那个DEVPATH多了一个mmcblk0p1 DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0/mmcblk0p1 SUBSYSTEM=block MAJOR=179 MINOR=1 DEVNAME=mmcblk0p1 DEVTYPE=partition //设备类型变为partition,表示分区 PARTN=1 SEQNUM=1358 ~~~ 通过上面实例,我们和Uevent来了一次亲密接触,具体到Vold,也就是内核通过Uevent告知外部存储系统发生了哪些事情,那么Uevent在什么情况下会由Kernel发出呢? - 当设备发生变化时,这会引起Kernel发送Uevent消息,例如设备的插入和拔出等。如果Vold在设备发生变化之前已经建立了Netlink IPC通信,那么Vold可以接收到这些Uevent消息。这种情况是由设备发生变化而触发的。 - 设备一般在/sys对应的目录下有一个叫uevent的文件,往该文件中写入指定的数据,也会触Kernel发送和该设备相关的Uevent消息,这是由应用层触发的。例如Vold启动时,会往这些uevent文件中写数据,通过这种方式促使内核发送Uevent消息,这样Vold就能得到这些设备的当前信息了。 根据上面介绍可知,Netlink和Uevent的目的,就是让Vold随时获悉外部存储系统的信息,这至关重要。我们总不会希望发生诸如SD卡都被拔了,而Vold却一无所知的情况吧?