android4.0 静态注册usb热插拔,Android热插拔事件处理流程--Vold

一、Android热插拔事件处理流程图

Android热插拔事件处理流程如下图所示:

a4c26d1e5885305701be709a3d33442f.png

二、组成

1. NetlinkManager:

全称是NetlinkManager.cpp位于Android 4.x

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

2. VolumeManager:

全称是VolumeManager.cpp位于Android

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

3. DirectVolume:

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

4. Volume:

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

5. CommandListener:

该类位于位于/system/vold/CommandListener.cpp。通过vold

socket与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卡挂载流程)

整个过程从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卡的挂载从底层到达了上层。

四、Vold

1. Vold简介

Vold的全称是volume

daemon。主要负责系统对大容量存储设备(USB/SD)的挂载/卸载任务,它是一个守护进程,该进程支持这些存储外设的热插拔。自Android

2.2开始,Vold升级为vold 2.0,配置文件路径在Android

4.0之后变为/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,此socket

name为"vold"。

在Android

4.0源码/system/vold路径下的main.cpp<NetlinkManager::start():socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)

>中创建了与内核通信的socket。在main.cpp中通过实例化VolumeManager和NetlinkManager时创建。

(2)引导

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

vold.fatab中最重要的语句:

dev_mount sdcard /mnt/sdcard auto

/devices/platform/rk29_sdmmc.0/mmc_host/mmc0

dev_mount

挂载命令 标签 挂载点 第几个分区 设备的sysfs paths

注:

第几个分区:如果为auto则表示第1个分区。

参数之间不能有空格,只能以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函数完成。

五、Vold用户态

1. NetlinkManager

NetlinkManager负责与Kernel交互,通过PF_NETLINK来现。

Vlod启动代码如下(/system/vold/main.cpp):

int

main() {

VolumeManager *vm;

CommandListener *cl;

NetlinkManager *nm;

SLOGI("Vold 2.1 (the

revenge) firing up");

mkdir("/dev/block/vold", 0755);

if (!(vm =

VolumeManager::Instance())) {

SLOGE("Unable to create

VolumeManager");

exit(1);

};

if (!(nm =

NetlinkManager::Instance())) {

SLOGE("Unable to create

NetlinkManager");

exit(1);

};

cl = new

CommandListener();

vm->setBroadcaster((SocketListener *) cl);

nm->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));

}

if (nm->start())

{

SLOGE("Unable to start

NetlinkManager (%s)",

strerror(errno));

exit(1);

}

#ifdef

USE_USB_MODE_SWITCH

SLOGE("Start Misc devices

Manager...");

MiscManager *mm;

if (!(mm =

MiscManager::Instance())) {

SLOGE("Unable to create

MiscManager");

exit(1);

};

mm->setBroadcaster((SocketListener *) cl);

if

(mm->start()) {

SLOGE("Unable to start MiscManager

(%s)", strerror(errno));

exit(1);

}

G3Dev* g3 = new

G3Dev(mm);

g3->handleUsb();

mm->addMisc(g3);

#endif

coldboot("/sys/block"); // 冷启动,vold错过了一些uevent,重新触发。向sysfs的uevent文件写入”add\n”

字符也可以触发sysfs事件,相当执行了一次热插拔。

//

coldboot("/sys/class/switch");

if

(cl->startListener()) {

SLOGE("Unable to start

CommandListener (%s)",

strerror(errno));

exit(1);

}

// Eventually we'll

become the monitoring thread

while(1)

{

sleep(1000);

}

SLOGI("Vold

exiting");

exit(0);

}

int main() {

VolumeManager *vm;

CommandListener *cl;

NetlinkManager *nm;

SLOGI("Vold 2.1 (the revenge) firing up");

mkdir("/dev/block/vold", 0755);

if (!(vm = VolumeManager::Instance())) {

SLOGE("Unable to create VolumeManager");

exit(1);

};

if (!(nm = NetlinkManager::Instance())) {

SLOGE("Unable to create NetlinkManager");

exit(1);

};

cl = new CommandListener();

vm->setBroadcaster((SocketListener *) cl);

nm->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));

}

if (nm->start()) {

SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));

exit(1);

}

#ifdef USE_USB_MODE_SWITCH

SLOGE("Start Misc devices Manager...");

MiscManager *mm;

if (!(mm = MiscManager::Instance())) {

SLOGE("Unable to create MiscManager");

exit(1);

};

mm->setBroadcaster((SocketListener *) cl);

if (mm->start()) {

SLOGE("Unable to start MiscManager (%s)", strerror(errno));

exit(1);

}

G3Dev* g3 = new G3Dev(mm);

g3->handleUsb();

mm->addMisc(g3);

#endif

coldboot("/sys/block"); // 冷启动,vold错过了一些uevent,重新触发。向sysfs的uevent文件写入”add\n” 字符也可以触发sysfs事件,相当执行了一次热插拔。

// coldboot("/sys/class/switch");

if (cl->startListener()) {

SLOGE("Unable to start CommandListener (%s)", strerror(errno));

exit(1);

}

// Eventually we'll become the monitoring thread

while(1) {

sleep(1000);

}

SLOGI("Vold exiting");

exit(0);

}

NetlinkManager的家族关系如下所示:

a4c26d1e5885305701be709a3d33442f.png

上图中的虚线为启动是的调用流程。

(1) class

NetlinkManager(在其start函数中创建了NetlinkHandler对象,并把创建的socket作为参数)

(2)class NetlinkHandler: public

NetlinkListener(实现了onEvent)

(3) class NetlinkListener : public SocketListener

(实现了onDataAvailable)

(4) class

SocketListener(实现了runListener,在一个线程中通过select查看哪些socket有数据,通过调用onDataAvailable来读取数据)

2. NetlinkManager::start()

int

NetlinkManager::start() {

struct sockaddr_nl

nladdr;

int sz =

64 * 1024;

int on =

1;

memset(&nladdr, 0, sizeof(nladdr));

nladdr.nl_family = AF_NETLINK;

nladdr.nl_pid = getpid();

nladdr.nl_groups = 0xffffffff;

//

创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件

if ((mSock

= socket(PF_NETLINK,

SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {

SLOGE("Unable to create

uevent socket: %s",

strerror(errno));

return

-1;

}

if

(setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE,

&sz, sizeof(sz)) <

0) {

SLOGE("Unable to set uevent socket

SO_RECBUFFORCE option: %s",

strerror(errno));

return

-1;

}

if (setsockopt(mSock,

SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {

SLOGE("Unable to set

uevent socket SO_PASSCRED option: %s",

strerror(errno));

return

-1;

}

if

(bind(mSock, (struct

sockaddr *) &nladdr, sizeof(nladdr)) < 0) {

SLOGE("Unable to bind uevent socket:

%s", strerror(errno));

return

-1;

}

//

利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener,

//

NetlinkListener又继承了类SocketListener

mHandler = new

NetlinkHandler(mSock);

if

(mHandler->start()) { //启动NetlinkHandler

SLOGE("Unable to start

NetlinkHandler: %s",

strerror(errno));

return

-1;

}

return

0;

}

int NetlinkManager::start() {

struct sockaddr_nl nladdr;

int sz = 64 * 1024;

int on = 1;

memset(&nladdr, 0, sizeof(nladdr));

nladdr.nl_family = AF_NETLINK;

nladdr.nl_pid = getpid();

nladdr.nl_groups = 0xffffffff;

// 创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件

if ((mSock = socket(PF_NETLINK,

SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {

SLOGE("Unable to create uevent socket: %s", strerror(errno));

return -1;

}

if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {

SLOGE("Unable to set uevent socket SO_RECBUFFORCE option: %s", strerror(errno));

return -1;

}

if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {

SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));

return -1;

}

if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {

SLOGE("Unable to bind uevent socket: %s", strerror(errno));

return -1;

}

// 利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener,

// NetlinkListener又继承了类SocketListener

mHandler = new NetlinkHandler(mSock);

if (mHandler->start()) { //启动NetlinkHandler

SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));

return -1;

}

return 0;

}

把socket作为参数创建了NetlinkHandler对象,然后启动NetlinkHandler。

int

NetlinkHandler::start() {

return this->startListener();

}

int

SocketListener::startListener() {

if

(!mSocketName && mSock == -1) {

SLOGE("Failed to start unbound

listener");

errno = EINVAL;

return

-1;

} else

if (mSocketName)

{

if ((mSock =

android_get_control_socket(mSocketName)) < 0)

{

SLOGE("Obtaining file

descriptor socket '%s' failed: %s",

mSocketName, strerror(errno));

return

-1;

}

}

if

(mListen && listen(mSock, 4) < 0)

{

SLOGE("Unable to listen on socket

(%s)", strerror(errno));

return

-1;

} else if (!mListen)

mClients->push_back(new SocketClient(mSock, false));

if

(pipe(mCtrlPipe)) {

SLOGE("pipe failed

(%s)", strerror(errno));

return

-1;

}

if

(pthread_create(&mThread, NULL,

SocketListener::threadStart, this)) {

SLOGE("pthread_create

(%s)", strerror(errno));

return

-1;

}

return

0;

}

void

*SocketListener::threadStart(void *obj) {

SocketListener *me = reinterpret_cast(obj);

me->runListener();

pthread_exit(NULL);

return

NULL;

}

void

SocketListener::runListener() {

SocketClientCollection *pendingList = new

SocketClientCollection();

while(1) {

// 死循环,一直监听

SocketClientCollection::iterator

it;

fd_set read_fds;

int rc =

0;

int max =

-1;

FD_ZERO(&read_fds); //清空文件描述符集read_fds

if (mListen)

{

max = mSock;

FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds

}

FD_SET(mCtrlPipe[0], &read_fds);

//添加管道的读取端文件描述符到read_fds

if (mCtrlPipe[0] >

max)

max = mCtrlPipe[0];

pthread_mutex_lock(&mClientsLock);

//对容器mClients的操作需要加锁

for (it =

mClients->begin(); it != mClients->end(); ++it)

{

int fd =

(*it)->getSocket();

FD_SET(fd, &read_fds); 遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds

if (fd

> max)

max = fd;

}

pthread_mutex_unlock(&mClientsLock);

//

等待文件描述符中某一文件描述符或者说socket有数据到来

if ((rc = select(max +

1, &read_fds, NULL, NULL, NULL)) < 0) {

if (errno

== EINTR)

continue;

SLOGE("select failed

(%s)", strerror(errno));

sleep(1);

continue;

} else if (!rc)

continue;

if

(FD_ISSET(mCtrlPipe[0], &read_fds))

break;

if

(mListen && FD_ISSET(mSock, &read_fds)) {

//监听套接字处理

struct sockaddr

addr;

socklen_t alen;

int

c;

do

{

alen = sizeof(addr);

c = accept(mSock, &addr, &alen); //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,将其添加到mClient容器

} while (c

< 0 && errno == EINTR);

if (c < 0)

{

SLOGE("accept failed

(%s)", strerror(errno));

sleep(1);

continue;

}

pthread_mutex_lock(&mClientsLock);

mClients->push_back(new

SocketClient(c, true));

pthread_mutex_unlock(&mClientsLock);

}

pendingList->clear();

pthread_mutex_lock(&mClientsLock);

for (it =

mClients->begin(); it != mClients->end(); ++it)

{

int fd =

(*it)->getSocket();

if

(FD_ISSET(fd, &read_fds)) {

pendingList->push_back(*it);

}

}

pthread_mutex_unlock(&mClientsLock);

while

(!pendingList->empty()) { //非监听套接字处理

it = pendingList->begin();

SocketClient* c = *it;

pendingList->erase(it);

// ******

onDataAvailable在NetlinkListener中实现*********

if

(!onDataAvailable(c) && mListen) {

pthread_mutex_lock(&mClientsLock);

for (it =

mClients->begin(); it != mClients->end(); ++it)

{

if (*it ==

c) {

mClients->erase(it);

break;

}

}

pthread_mutex_unlock(&mClientsLock);

c->decRef();

}

}

}

delete

pendingList;

}

int NetlinkHandler::start() {

return this->startListener();

}

int SocketListener::startListener() {

if (!mSocketName && mSock == -1) {

SLOGE("Failed to start unbound listener");

errno = EINVAL;

return -1;

} else if (mSocketName) {

if ((mSock = android_get_control_socket(mSocketName)) < 0) {

SLOGE("Obtaining file descriptor socket '%s' failed: %s",

mSocketName, strerror(errno));

return -1;

}

}

if (mListen && listen(mSock, 4) < 0) {

SLOGE("Unable to listen on socket (%s)", strerror(errno));

return -1;

} else if (!mListen)

mClients->push_back(new SocketClient(mSock, false));

if (pipe(mCtrlPipe)) {

SLOGE("pipe failed (%s)", strerror(errno));

return -1;

}

if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {

SLOGE("pthread_create (%s)", strerror(errno));

return -1;

}

return 0;

}

void *SocketListener::threadStart(void *obj) {

SocketListener *me = reinterpret_cast(obj);

me->runListener();

pthread_exit(NULL);

return NULL;

}

void SocketListener::runListener() {

SocketClientCollection *pendingList = new SocketClientCollection();

while(1) { // 死循环,一直监听

SocketClientCollection::iterator it;

fd_set read_fds;

int rc = 0;

int max = -1;

FD_ZERO(&read_fds); //清空文件描述符集read_fds

if (mListen) {

max = mSock;

FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds

}

FD_SET(mCtrlPipe[0], &read_fds); //添加管道的读取端文件描述符到read_fds

if (mCtrlPipe[0] > max)

max = mCtrlPipe[0];

pthread_mutex_lock(&mClientsLock); //对容器mClients的操作需要加锁

for (it = mClients->begin(); it != mClients->end(); ++it) {

int fd = (*it)->getSocket();

FD_SET(fd, &read_fds); 遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds

if (fd > max)

max = fd;

}

pthread_mutex_unlock(&mClientsLock);

// 等待文件描述符中某一文件描述符或者说socket有数据到来

if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {

if (errno == EINTR)

continue;

SLOGE("select failed (%s)", strerror(errno));

sleep(1);

continue;

} else if (!rc)

continue;

if (FD_ISSET(mCtrlPipe[0], &read_fds))

break;

if (mListen && FD_ISSET(mSock, &read_fds)) { //监听套接字处理

struct sockaddr addr;

socklen_t alen;

int c;

do {

alen = sizeof(addr);

c = accept(mSock, &addr, &alen); //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,将其添加到mClient容器

} while (c < 0 && errno == EINTR);

if (c < 0) {

SLOGE("accept failed (%s)", strerror(errno));

sleep(1);

continue;

}

pthread_mutex_lock(&mClientsLock);

mClients->push_back(new SocketClient(c, true));

pthread_mutex_unlock(&mClientsLock);

}

pendingList->clear();

pthread_mutex_lock(&mClientsLock);

for (it = mClients->begin(); it != mClients->end(); ++it) {

int fd = (*it)->getSocket();

if (FD_ISSET(fd, &read_fds)) {

pendingList->push_back(*it);

}

}

pthread_mutex_unlock(&mClientsLock);

while (!pendingList->empty()) { //非监听套接字处理

it = pendingList->begin();

SocketClient* c = *it;

pendingList->erase(it);

// ****** onDataAvailable在NetlinkListener中实现*********

if (!onDataAvailable(c) && mListen) {

pthread_mutex_lock(&mClientsLock);

for (it = mClients->begin(); it != mClients->end(); ++it) {

if (*it == c) {

mClients->erase(it);

break;

}

}

pthread_mutex_unlock(&mClientsLock);

c->decRef();

}

}

}

delete pendingList;

}

SocketListener::runListener是线程真正执行的函数:mListen成员用来判定是否监听套接字,Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用函数onDataAvailable读取数据。

3. NetlinkListener::onDataAvailable

bool

NetlinkListener::onDataAvailable(SocketClient

*cli)

{

int

socket = cli->getSocket();

ssize_t count;

//

从socket中读取kernel发送来的uevent消息

count =

TEMP_FAILURE_RETRY(uevent_kernel_multicast_recv(socket, mBuffer,

sizeof(mBuffer)));

if (count < 0)

{

SLOGE("recvmsg failed

(%s)", strerror(errno));

return false;

}

NetlinkEvent *evt = new NetlinkEvent();

if

(!evt->decode(mBuffer, count, mFormat))

{

SLOGE("Error decoding

NetlinkEvent");

} else

{

onEvent(evt); //在NetlinkHandler中实现

}

delete

evt;

return

true;

}

bool NetlinkListener::onDataAvailable(SocketClient *cli)

{

int socket = cli->getSocket();

ssize_t count;

// 从socket中读取kernel发送来的uevent消息

count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_recv(socket, mBuffer, sizeof(mBuffer)));

if (count < 0) {

SLOGE("recvmsg failed (%s)", strerror(errno));

return false;

}

NetlinkEvent *evt = new NetlinkEvent();

if (!evt->decode(mBuffer, count, mFormat)) {

SLOGE("Error decoding NetlinkEvent");

} else {

onEvent(evt); //在NetlinkHandler中实现

}

delete evt;

return true;

}

4. 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;

}

if

(!strcmp(subsys, "block")) {

if(uEventOnOffFlag)

{

SLOGW("####netlink event

block ####");

evt->dump();

}

vm->handleBlockEvent(evt);

#ifdef

USE_USB_MODE_SWITCH

} else if (!strcmp(subsys, "usb")

|| !strcmp(subsys, "scsi_device")) {

SLOGW("subsystem found in netlink

event");

MiscManager *mm =

MiscManager::Instance();

mm->handleEvent(evt);

#endif

}

}

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")) {

if(uEventOnOffFlag)

{

SLOGW("####netlink event block ####");

evt->dump();

}

vm->handleBlockEvent(evt);

#ifdef USE_USB_MODE_SWITCH

} else if (!strcmp(subsys, "usb")

|| !strcmp(subsys, "scsi_device")) {

SLOGW("subsystem found in netlink event");

MiscManager *mm = MiscManager::Instance();

mm->handleEvent(evt);

#endif

}

}

5. uevent_kernel_multicast_recv

ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) {

struct

iovec iov = { buffer, length };

struct sockaddr_nl

addr;

char

control[CMSG_SPACE(sizeof(struct ucred))];

struct msghdr hdr =

{

&addr,

sizeof(addr),

&iov,

1,

control,

sizeof(control),

0,

};

ssize_t n = recvmsg(socket, &hdr, 0);

if (n

<= 0) {

return

n;

}

if

(addr.nl_groups == 0 || addr.nl_pid != 0)

{

goto

out;

}

struct cmsghdr *cmsg =

CMSG_FIRSTHDR(&hdr);

if (cmsg

== NULL || cmsg->cmsg_type != SCM_CREDENTIALS)

{

goto

out;

}

struct ucred *cred =

(struct ucred

*)CMSG_DATA(cmsg);

if

(cred->uid != 0) {

goto

out;

}

return

n;

out:

bzero(buffer, length);

errno = EIO;

return

-1;

}

ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) {

struct iovec iov = { buffer, length };

struct sockaddr_nl addr;

char control[CMSG_SPACE(sizeof(struct ucred))];

struct msghdr hdr = {

&addr,

sizeof(addr),

&iov,

1,

control,

sizeof(control),

0,

};

ssize_t n = recvmsg(socket, &hdr, 0);

if (n <= 0) {

return n;

}

if (addr.nl_groups == 0 || addr.nl_pid != 0) {

goto out;

}

struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);

if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {

goto out;

}

struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);

if (cred->uid != 0) {

goto out;

}

return n;

out:

bzero(buffer, length);

errno = EIO;

return -1;

}

六、与Vold相关的Kernel态

用户态创建的netlink

sock被kernel保存在:nl_table[sk->sk_protocol].mc_list

Kernel态创建的netlink

sock被kernel保存在:uevent_sock_list,上面的sk->sk_protocol为uevent_sock_list的协议,

二者只有协议一致才可以发送。

1. 创建kernel态sock

在用户态的socket创建方式(/system/vold/NetlinkManager.cpp):

if ((mSock

= socket(PF_NETLINK,

SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {

SLOGE("Unable to create

uevent socket: %s",

strerror(errno));

return

-1;

}

if ((mSock = socket(PF_NETLINK,

SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {

SLOGE("Unable to create uevent socket: %s", strerror(errno));

return -1;

}

在Kernel的socket创建方式(/kernel/lib/kobject_uevent.c):

static

int

uevent_net_init(struct

net *net)

{

struct

uevent_sock *ue_sk;

ue_sk = kzalloc(sizeof(*ue_sk),

GFP_KERNEL);

if

(!ue_sk)

return

-ENOMEM;

ue_sk->sk = netlink_kernel_create(net,

NETLINK_KOBJECT_UEVENT,

1, NULL, NULL, THIS_MODULE);

if

(!ue_sk->sk) {

printk(KERN_ERR

"kobject_uevent: unable

to create netlink socket!\n");

kfree(ue_sk);

return

-ENODEV;

}

mutex_lock(&uevent_sock_mutex);

list_add_tail(&ue_sk->list,

&uevent_sock_list);

mutex_unlock(&uevent_sock_mutex);

return

0;

}

static int uevent_net_init(struct net *net)

{

struct uevent_sock *ue_sk;

ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);

if (!ue_sk)

return -ENOMEM;

ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,

1, NULL, NULL, THIS_MODULE);

if (!ue_sk->sk) {

printk(KERN_ERR

"kobject_uevent: unable to create netlink socket!\n");

kfree(ue_sk);

return -ENODEV;

}

mutex_lock(&uevent_sock_mutex);

list_add_tail(&ue_sk->list, &uevent_sock_list);

mutex_unlock(&uevent_sock_mutex);

return 0;

}

从上面的代码可知,此sock被创建之后,被增加到全局变量uevent_sock_list列表中,下面的分析围绕此列表进行。

netlink_kernel_create函数原型:

struct

sock *netlink_kernel_create(struct net *net, int unit, unsigned int groups,

void

(*input)(struct

sk_buff *skb),

struct

mutex *cb_mutex, struct

module *module)

struct sock *netlink_kernel_create(struct net *net, int unit, unsigned int groups,

void (*input)(struct sk_buff *skb),

struct mutex *cb_mutex, struct module *module)

1) struct net

*net:是一个网络名字空间namespace,在不同的名字空间里面可以有自己的转发信息库,有自己的一套net_device等等。默认情况下都是使用init_net这个全局变量

2) int unit: 表示netlink协议类型,如

NETLINK_KOBJECT_UEVENT

3) unsigned int groups:

组类型

4) void (*input)(struct sk_buff

*skb):参数input则为内核模块定义的netlink消息处理函数,当有消息到达这个netlink

socket时,该input函数指针就会被调用。函数指针input的参数skb实际上就是函数netlink_kernel_create返回的

struct

sock指针,sock实际是socket的一个内核表示数据结构,用户态应用创建的socket在内核中也会有一个struct

sock结构来表示。

5) struct mutex *cb_mutex:

互斥销

6) struct module *module:

一般为THIS_MODULE

struct sock

用户态socket在kernel中的表示。

2. 相关数据结构

相关数据结构如下图所示:

a4c26d1e5885305701be709a3d33442f.png

3. 发送消息给用户空间

3.1 发送消息流程图

a4c26d1e5885305701be709a3d33442f.png

3.2 kobject_uevent_env

int

kobject_uevent_env(struct

kobject *kobj, enum

kobject_action action,

char

*envp_ext[])

{

struct kobj_uevent_env

*env;

const

char *action_string =

kobject_actions[action];

const char *devpath = NULL;

const

char

*subsystem;

struct kobject

*top_kobj;

struct

kset *kset;

const struct kset_uevent_ops

*uevent_ops;

u64 seq;

int i =

0;

int

retval = 0;

#ifdef CONFIG_NET

struct

uevent_sock *ue_sk;

#endif

pr_debug("kobject: '%s' (%p):

%s\n",

kobject_name(kobj), kobj,

__func__);

top_kobj = kobj;

while

(!top_kobj->kset &&

top_kobj->parent)

top_kobj = top_kobj->parent;

if

(!top_kobj->kset) {

pr_debug("kobject: '%s'

(%p): %s: attempted to send uevent "

"without kset!\n",

kobject_name(kobj), kobj,

__func__);

return

-EINVAL;

}

kset = top_kobj->kset;

uevent_ops = kset->uevent_ops;

if

(kobj->uevent_suppress) {

pr_debug("kobject: '%s' (%p): %s:

uevent_suppress "

"caused the event to

drop!\n",

kobject_name(kobj), kobj, __func__);

return

0;

}

if (uevent_ops

&& uevent_ops->filter)

if

(!uevent_ops->filter(kset, kobj)) {

pr_debug("kobject: '%s' (%p): %s:

filter function "

"caused the event to

drop!\n",

kobject_name(kobj), kobj, __func__);

return

0;

}

if

(uevent_ops &&

uevent_ops->name)

subsystem = uevent_ops->name(kset, kobj);

else

subsystem = kobject_name(&kset->kobj);

if

(!subsystem) {

pr_debug("kobject: '%s' (%p): %s:

unset subsystem caused the "

"event to

drop!\n", kobject_name(kobj), kobj,

__func__);

return

0;

}

env = kzalloc(sizeof(struct kobj_uevent_env),

GFP_KERNEL);

if

(!env)

return

-ENOMEM;

devpath = kobject_get_path(kobj, GFP_KERNEL);

if

(!devpath) {

retval = -ENOENT;

goto

exit;

}

retval = add_uevent_var(env, "ACTION=%s",

action_string);

if

(retval)

goto

exit;

retval = add_uevent_var(env, "DEVPATH=%s", devpath);

if

(retval)

goto

exit;

retval = add_uevent_var(env, "SUBSYSTEM=%s",

subsystem);

if

(retval)

goto

exit;

if (envp_ext)

{

for (i =

0; envp_ext[i]; i++) {

retval = add_uevent_var(env, "%s", envp_ext[i]);

if

(retval)

goto

exit;

}

}

if

(uevent_ops && uevent_ops->uevent)

{

retval = uevent_ops->uevent(kset, kobj,

env);

if

(retval) {

pr_debug("kobject: '%s' (%p): %s:

uevent() returned "

"%d\n",

kobject_name(kobj), kobj,

__func__, retval);

goto

exit;

}

}

if (action

== KOBJ_ADD)

kobj->state_add_uevent_sent = 1;

else

if (action ==

KOBJ_REMOVE)

kobj->state_remove_uevent_sent = 1;

spin_lock(&sequence_lock);

seq = ++uevent_seqnum;

spin_unlock(&sequence_lock);

retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);

if

(retval)

goto

exit;

#if defined(CONFIG_NET)

mutex_lock(&uevent_sock_mutex);

list_for_each_entry(ue_sk,

&uevent_sock_list, list) {

struct sock

*uevent_sock = ue_sk->sk;

struct

sk_buff *skb;

size_t

len;

len = strlen(action_string) + strlen(devpath)

+ 2;

skb = alloc_skb(len + env->buflen,

GFP_KERNEL);

if (skb)

{

char

*scratch;

scratch = skb_put(skb, len);

sprintf(scratch, "%s@%s", action_string, devpath);

//action_string+devpath

for (i =

0; i < env->envp_idx; i++) {

len = strlen(env->envp[i]) + 1;

scratch = skb_put(skb, len);

strcpy(scratch, env->envp[i]);

}

NETLINK_CB(skb).dst_group = 1;

retval = netlink_broadcast_filtered(uevent_sock,

skb,

0, 1, GFP_KERNEL,

kobj_bcast_filter,

kobj);

if (retval

== -ENOBUFS)

retval = 0;

} else

retval = -ENOMEM;

}

mutex_unlock(&uevent_sock_mutex);

#endif

if (uevent_helper[0]

&& !kobj_usermode_filter(kobj)) {

char

*argv [3];

argv [0] = uevent_helper;

argv [1] = (char

*)subsystem;

argv [2] = NULL;

retval = add_uevent_var(env, "HOME=/");

if

(retval)

goto

exit;

retval = add_uevent_var(env,

"PATH=/sbin:/bin:/usr/sbin:/usr/bin");

if

(retval)

goto

exit;

retval = call_usermodehelper(argv[0], argv,

env->envp, UMH_WAIT_EXEC);

}

exit:

kfree(devpath);

kfree(env);

return

retval;

}

int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,

char *envp_ext[])

{

struct kobj_uevent_env *env;

const char *action_string = kobject_actions[action];

const char *devpath = NULL;

const char *subsystem;

struct kobject *top_kobj;

struct kset *kset;

const struct kset_uevent_ops *uevent_ops;

u64 seq;

int i = 0;

int retval = 0;

#ifdef CONFIG_NET

struct uevent_sock *ue_sk;

#endif

pr_debug("kobject: '%s' (%p): %s\n",

kobject_name(kobj), kobj, __func__);

top_kobj = kobj;

while (!top_kobj->kset && top_kobj->parent)

top_kobj = top_kobj->parent;

if (!top_kobj->kset) {

pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "

"without kset!\n", kobject_name(kobj), kobj,

__func__);

return -EINVAL;

}

kset = top_kobj->kset;

uevent_ops = kset->uevent_ops;

if (kobj->uevent_suppress) {

pr_debug("kobject: '%s' (%p): %s: uevent_suppress "

"caused the event to drop!\n",

kobject_name(kobj), kobj, __func__);

return 0;

}

if (uevent_ops && uevent_ops->filter)

if (!uevent_ops->filter(kset, kobj)) {

pr_debug("kobject: '%s' (%p): %s: filter function "

"caused the event to drop!\n",

kobject_name(kobj), kobj, __func__);

return 0;

}

if (uevent_ops && uevent_ops->name)

subsystem = uevent_ops->name(kset, kobj);

else

subsystem = kobject_name(&kset->kobj);

if (!subsystem) {

pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "

"event to drop!\n", kobject_name(kobj), kobj,

__func__);

return 0;

}

env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);

if (!env)

return -ENOMEM;

devpath = kobject_get_path(kobj, GFP_KERNEL);

if (!devpath) {

retval = -ENOENT;

goto exit;

}

retval = add_uevent_var(env, "ACTION=%s", action_string);

if (retval)

goto exit;

retval = add_uevent_var(env, "DEVPATH=%s", devpath);

if (retval)

goto exit;

retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);

if (retval)

goto exit;

if (envp_ext) {

for (i = 0; envp_ext[i]; i++) {

retval = add_uevent_var(env, "%s", envp_ext[i]);

if (retval)

goto exit;

}

}

if (uevent_ops && uevent_ops->uevent) {

retval = uevent_ops->uevent(kset, kobj, env);

if (retval) {

pr_debug("kobject: '%s' (%p): %s: uevent() returned "

"%d\n", kobject_name(kobj), kobj,

__func__, retval);

goto exit;

}

}

if (action == KOBJ_ADD)

kobj->state_add_uevent_sent = 1;

else if (action == KOBJ_REMOVE)

kobj->state_remove_uevent_sent = 1;

spin_lock(&sequence_lock);

seq = ++uevent_seqnum;

spin_unlock(&sequence_lock);

retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);

if (retval)

goto exit;

#if defined(CONFIG_NET)

mutex_lock(&uevent_sock_mutex);

list_for_each_entry(ue_sk, &uevent_sock_list, list) {

struct sock *uevent_sock = ue_sk->sk;

struct sk_buff *skb;

size_t len;

len = strlen(action_string) + strlen(devpath) + 2;

skb = alloc_skb(len + env->buflen, GFP_KERNEL);

if (skb) {

char *scratch;

scratch = skb_put(skb, len);

sprintf(scratch, "%s@%s", action_string, devpath); //action_string+devpath

for (i = 0; i < env->envp_idx; i++) {

len = strlen(env->envp[i]) + 1;

scratch = skb_put(skb, len);

strcpy(scratch, env->envp[i]);

}

NETLINK_CB(skb).dst_group = 1;

retval = netlink_broadcast_filtered(uevent_sock, skb,

0, 1, GFP_KERNEL,

kobj_bcast_filter,

kobj);

if (retval == -ENOBUFS)

retval = 0;

} else

retval = -ENOMEM;

}

mutex_unlock(&uevent_sock_mutex);

#endif

if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {

char *argv [3];

argv [0] = uevent_helper;

argv [1] = (char *)subsystem;

argv [2] = NULL;

retval = add_uevent_var(env, "HOME=/");

if (retval)

goto exit;

retval = add_uevent_var(env,

"PATH=/sbin:/bin:/usr/sbin:/usr/bin");

if (retval)

goto exit;

retval = call_usermodehelper(argv[0], argv,

env->envp, UMH_WAIT_EXEC);

}

exit:

kfree(devpath);

kfree(env);

return retval;

}

int

kobject_uevent(struct

kobject *kobj, enum

kobject_action action)

{

return

kobject_uevent_env(kobj, action, NULL);

}

int kobject_uevent(struct kobject *kobj, enum kobject_action action)

{

return kobject_uevent_env(kobj, action, NULL);

}

3.3 netlink_broadcast_filtered

int

netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32

pid,

u32 group, gfp_t allocation,

int

(*filter)(struct

sock *dsk, struct

sk_buff *skb, void

*data),

void

*filter_data)

{

struct net *net =

sock_net(ssk);

struct

netlink_broadcast_data info;

struct hlist_node

*node;

struct

sock *sk;

skb = netlink_trim(skb,

allocation);

info.exclude_sk = ssk;

info.net = net;

info.pid = pid;

info.group = group;

info.failure = 0;

info.delivery_failure = 0;

info.congested = 0;

info.delivered = 0;

info.allocation = allocation;

info.skb = skb;

info.skb2 = NULL;

info.tx_filter = filter;

info.tx_data = filter_data;

netlink_lock_table();

//

向nl_table[ssk->sk_protocol].mc_list中的每个sock发送此netlink消息

sk_for_each_bound(sk, node,

&nl_table[ssk->sk_protocol].mc_list)

do_one_broadcast(sk, &info);

consume_skb(skb);

netlink_unlock_table();

if

(info.delivery_failure) {

kfree_skb(info.skb2);

return

-ENOBUFS;

} else

consume_skb(info.skb2);

if (info.delivered)

{

if

(info.congested && (allocation &

__GFP_WAIT))

yield();

return

0;

}

return

-ESRCH;

}

int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid,

u32 group, gfp_t allocation,

int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),

void *filter_data)

{

struct net *net = sock_net(ssk);

struct netlink_broadcast_data info;

struct hlist_node *node;

struct sock *sk;

skb = netlink_trim(skb, allocation);

info.exclude_sk = ssk;

info.net = net;

info.pid = pid;

info.group = group;

info.failure = 0;

info.delivery_failure = 0;

info.congested = 0;

info.delivered = 0;

info.allocation = allocation;

info.skb = skb;

info.skb2 = NULL;

info.tx_filter = filter;

info.tx_data = filter_data;

netlink_lock_table();

// 向nl_table[ssk->sk_protocol].mc_list中的每个sock发送此netlink消息

sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)

do_one_broadcast(sk, &info);

consume_skb(skb);

netlink_unlock_table();

if (info.delivery_failure) {

kfree_skb(info.skb2);

return -ENOBUFS;

} else

consume_skb(info.skb2);

if (info.delivered) {

if (info.congested && (allocation & __GFP_WAIT))

yield();

return 0;

}

return -ESRCH;

}

static struct netlink_table

*nl_table;是全局变量,它维护了用户态创建的所有netlink

sock,按协议分类,每种协议一个链表mc_list。它在函数netlink_proto_init中被初始化,向nl_table[sk->sk_protocol].mc_list中增加sock的调用流程如下(kernel/net/netlink/af_netlink.c):

a4c26d1e5885305701be709a3d33442f.png

3.4 do_one_broadcast

static

inline int do_one_broadcast(struct sock *sk,

struct

netlink_broadcast_data *p)

{

struct netlink_sock

*nlk = nlk_sk(sk);

int

val;

if

(p->exclude_sk == sk)

goto

out;

if (nlk->pid ==

p->pid || p->group - 1 >= nlk->ngroups

||

!test_bit(p->group - 1,

nlk->groups))

goto

out;

if

(!net_eq(sock_net(sk), p->net))

goto

out;

if

(p->failure) {

netlink_overrun(sk);

goto

out;

}

sock_hold(sk);

if

(p->skb2 == NULL) {

if

(skb_shared(p->skb)) {

p->skb2 = skb_clone(p->skb,

p->allocation);

} else

{

p->skb2 = skb_get(p->skb);

skb_orphan(p->skb2);

}

}

if

(p->skb2 == NULL) {

netlink_overrun(sk);

p->failure = 1;

if

(nlk->flags &

NETLINK_BROADCAST_SEND_ERROR)

p->delivery_failure = 1;

} else

if (p->tx_filter &&

p->tx_filter(sk, p->skb2, p->tx_data))

{

kfree_skb(p->skb2);

p->skb2 = NULL;

} else if (sk_filter(sk, p->skb2))

{

kfree_skb(p->skb2);

p->skb2 = NULL;

} else

if ((val =

netlink_broadcast_deliver(sk, p->skb2)) < 0)

{

netlink_overrun(sk);

if

(nlk->flags &

NETLINK_BROADCAST_SEND_ERROR)

p->delivery_failure = 1;

} else

{

p->congested |= val;

p->delivered = 1;

p->skb2 = NULL;

}

sock_put(sk);

out:

return

0;

}

static inline int do_one_broadcast(struct sock *sk,

struct netlink_broadcast_data *p)

{

struct netlink_sock *nlk = nlk_sk(sk);

int val;

if (p->exclude_sk == sk)

goto out;

if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups ||

!test_bit(p->group - 1, nlk->groups))

goto out;

if (!net_eq(sock_net(sk), p->net))

goto out;

if (p->failure) {

netlink_overrun(sk);

goto out;

}

sock_hold(sk);

if (p->skb2 == NULL) {

if (skb_shared(p->skb)) {

p->skb2 = skb_clone(p->skb, p->allocation);

} else {

p->skb2 = skb_get(p->skb);

skb_orphan(p->skb2);

}

}

if (p->skb2 == NULL) {

netlink_overrun(sk);

p->failure = 1;

if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)

p->delivery_failure = 1;

} else if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) {

kfree_skb(p->skb2);

p->skb2 = NULL;

} else if (sk_filter(sk, p->skb2)) {

kfree_skb(p->skb2);

p->skb2 = NULL;

} else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) {

netlink_overrun(sk);

if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)

p->delivery_failure = 1;

} else {

p->congested |= val;

p->delivered = 1;

p->skb2 = NULL;

}

sock_put(sk);

out:

return 0;

}

3.5 netlink_broadcast_deliver

static

inline int

netlink_broadcast_deliver(struct sock *sk,

struct sk_buff

*skb)

{

struct netlink_sock

*nlk = nlk_sk(sk);

if

(atomic_read(&sk->sk_rmem_alloc) <=

sk->sk_rcvbuf &&

!test_bit(0, &nlk->state))

{

skb_set_owner_r(skb, sk);

skb_queue_tail(&sk->sk_receive_queue,

skb);

sk->sk_data_ready(sk, skb->len);

return

atomic_read(&sk->sk_rmem_alloc) >

sk->sk_rcvbuf;

}

return

-1;

}

static inline int netlink_broadcast_deliver(struct sock *sk,

struct sk_buff *skb)

{

struct netlink_sock *nlk = nlk_sk(sk);

if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&

!test_bit(0, &nlk->state)) {

skb_set_owner_r(skb, sk);

skb_queue_tail(&sk->sk_receive_queue, skb);

sk->sk_data_ready(sk, skb->len);

return atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf;

}

return -1;

}

参考文献:

  • 0
    点赞
  • 1
    收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值