Android netd和Framework以及netd和kernel之间的通信

来源:互联网 发布:糖豆网广场舞软件下载 编辑:程序博客网 时间:2024/06/14 09:46

我们整天在用Android终端,但是我们知道当我们的Android终端在拔掉网线时,Android系统是怎么从kernel一步步的通知到应用层的?而当我们在应用层设置网络参数,应用层的命令和设置信息又是怎么一步步传到kernel的?

在应用到Linux内核之间需要一个桥梁,这个桥梁就是Netd守护进程,我们就从Netd守护进程开始去了解一些Android网络系统的工作流程。

Netd进程是通过init进程启动的,我们来看看它在init.rc中的定义:

service netd /system/bin/netd

    class main

    socket netd stream 0660 root system

    socket dnsproxyd stream 0660 root inet

socket mdns stream 0660 root system

显然netd启动时创建三个TCP监听socket,其名称分别为netddnsproxydmdns。当设备启动后,到/dev/socket/下会看见有netddnsproxydmdns这三个文件。netd守护进程的Socket资源和netddnsproxydmdns名称绑定起来。netd通过Socket接收并处理来自Framework层中NetworkManagementServiceNsdService的命令。netd通过Socket接收并解析来自KernelUEvent消息,然后再通过Socket转发给Framework层中对应Service去处理。为了证实我们的想法,我们先来看一下TCP/IP网络进程间通信的流程,只有了解Socket通信的流程我们才更容易理解netd的工作流程:

服务器端

客户端

1.创建socket

1.创建socket

2.bind()

 

3.listen()

 

4.accecp()

 

等待客户端连接……

2.connect()

5.读数据(recv

3.写数据(send

6.写数据(send

4.读数据(recv

7.关闭socketclosesocket()

5.关闭socketclosesocket()

也就是说netdFramework层,以及netdkernel之间要通过Socket来通信的话,所做的事情肯定是上面提到的这些。

下面分析netdmain函数

main()

{

   //new NetlinkManager对象nm

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

       ALOGE("Unable to create NetlinkManager");

       exit(1);

};

//new CommandListener对象cl,将cl设置成nmNetlinkManager)的消息发送者(mBroadcaster

cl = new CommandListener(rangeMap);

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

 

/*

*分析CommandListener的构造函数后发现,CommandListener将创建名为“netd”的监听Socket

*/

 

   //启动nmNetlinkManager

   if (nm->start()) {

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

       exit(1);

   }

 

   //创建DnsProxyListener对象dpl,并启动监听,DnsProxyListener将会创建名为“dnsproxyd”监听Socket

   dpl = new DnsProxyListener(rangeMap);

   if (dpl->startListener()) {

       ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));

       exit(1);

   }

 

   //创建MDnsSdListener对象mdnsl,并启动监听,MDnsSdListener将会创建名为“mdns”的监听Socket

   mdnsl = new MDnsSdListener();

   if (mdnsl->startListener()) {

       ALOGE("Unable to start MDnsSdListener (%s)", strerror(errno));

       exit(1);

   }

 

   //启动clCommandListener)监听

   if (cl->startListener()) {

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

       exit(1);

   }

}

netdmain函数比较简单,就是创建几个重要的成员并启动成员的工作,笔者这里只讲解netd里重要的成员NetlinkManager。下面看NetlinkManager的类图。

显然NetlinkManager里有三个NetlinkHandler和一个SocketListener对象,NetlinkHandler继承于NetlinkListener,而NetlinkListener又继承于SocketListener。由代码nm->setBroadcaster((SocketListener *) cl);可以知道NetlinkManager里的mBroadcaster其实就是由CommandListener向上转型来的,而CommandListener又继承于FrameworkListener,FrameworkListener继承于SocketListener。

分析NetlinkManager的start函数

int NetlinkManager::start() {

   //创建接收NETLINK_KOBJECT_UEVENT消息的socket,其值保存在mUeventSock

   if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,

        0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {

       return -1;

   }

 

   //创建接收RTMGPR_LINK消息的socket,其值保存在mRouteSock

   if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,

                                    RTMGRP_LINK |

                                    RTMGRP_IPV4_IFADDR |

                                    RTMGRP_IPV6_IFADDR,

        NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {

       return -1;

   }

 

   //创建接收NETLINK_NFLOG消息的socket,其值保存在mQuotaSock

   if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,

       NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {

       ALOGE("Unable to open quota2 logging socket");

       // TODO: return -1 once the emulator gets a new kernel.

   }

 

   return 0;

}

 

NetlinkManagerstart函数就是向Kernel注册了三个用于接收UEvent事件的socket。我们接着进到setupSocket里看看,看是不是创建了Socket了,是不是bing了?

NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily,

int groups, int format)  {

 

   //创建Socket

   if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {

       ALOGE("Unable to create netlink socket: %s", strerror(errno));

       return NULL;

}

 

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

       ALOGE("Unable to bind netlink socket: %s", strerror(errno));

       close(*sock);

       return NULL;

}

 

   //如果没有猜错在NetlinkHandlerstart里一定会调用listen接着另起一线程进行accept和等待客户端的连接以及不停的接收来自kernelUEvent消息。

   NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);

   if (handler->start()) {

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

       close(*sock);

       return NULL;

}

 

}

 

int SocketListener::startListener() {

 

   //调用listen

   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, mUseCmdNum));

 

   //另起线程

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

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

       return -1;

}

 

}

 

void SocketListener::runListener() {

 

while(1) {

 

       //调用select

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

           if (errno == EINTR)

               continue;

           SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);

           sleep(1);

           continue;

       } else if (!rc)

           continue;

 

}

 

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

 

           //调用accept

           do {

               alen = sizeof(addr);

               c = accept(mSock, &addr, &alen);

               SLOGV("%s got %d from accept", mSocketName, c);

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

 

}

 

}

 

当我们拔掉终端的网线时,我们监听的Socket会收到RTMGPR_LINK事件。来到这里我们已经知道NetlinkManager是怎么收到来自kernel的UEvent事件的,但是收到这个UEvent事件后,netd又是怎么通知Framework层的呢?

NetlinkHandler接收到的UEvent消息会转换成一个NetlinkEvent对象。NetlinkEvent对象封装了对UEvent消息的解析方法,UEvent消息经解析后将经由mBroadcaster对象传递给Framework层的接收者。我们下面将分析mBroadcaster来验证我们的想法。

上面已经说过了mBroadcaster其实就是CommandListener向上转型得到的东西,我们可以从CommandListener着手分析。

CommandListener::CommandListener(UidMarkMap *map) :

                FrameworkListener("netd", true) {

   //注册11个命令类对象

   registerCmd(new InterfaceCmd());

   registerCmd(new IpFwdCmd());

   registerCmd(new TetherCmd());

   registerCmd(new NatCmd());

   registerCmd(new ListTtysCmd());

   registerCmd(new PppdCmd());

   registerCmd(new SoftapCmd());

   registerCmd(new BandwidthControlCmd());

   registerCmd(new IdletimerControlCmd());

   registerCmd(new ResolverCmd());

   registerCmd(new FirewallCmd());

registerCmd(new ClatdCmd());

 

}

CommandListener的构造函数里最主要的函数是FrameworkListener("netd", true),显然验证了上面说法,这里要创建名为“netd”的监听Socket。在netdmain函数里我们有调用过cl->startListener(),我们到CommandListenerstartListener里看看,CommandListenerstartListener调用其实就是其父类的父类SocketListenerstartListener

int SocketListener::startListener() {

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

       SLOGE("Failed to start unbound listener");

       errno = EINVAL;

       return -1;

} else if (mSocketName) {

   //获取名称为“netd”的监听Socket

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

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

                mSocketName, strerror(errno));

           return -1;

       }

       SLOGV("got mSock = %d for %s", mSock, mSocketName);

   }

 

   //调用listen

   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, mUseCmdNum));

 

   //创建新线程

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

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

       return -1;

   }

 

}

 

分析到这里下面就不需要详细讲了,因为和刚才创建Socket监听kernelUEvent事件的过程一样。到这里netd的工作基本已经清楚了,就是获取名称为“netd”的Socket并启动监听,同时创建3Socket用于监听来自kernel3中不同的UEvent事件,解析kernel发送过来的UEvent事件,将解析结果通过名称为“netd”的监听Socket发送给Framework层的服务,同时名称为“netd”的Socket也接收来自Framework层的消息(即用户通过Framework层设置网络的命令和信息),把接收到的消息在通过相应的Socket发送给kernel。整个过程中netd进程一直是Socket通信的服务端,而kernel的客户端的代码是怎么样子的,笔者这里不讲,因为那是驱动的事情,而作为另外一个客户端Framework层里的代码到底是什么样子的呢?

 

public static NetworkManagementService create(Context context) throws InterruptedException {

   // NETD_SOCKET_NAME就是我们要找的“netd

   return create(context, NETD_SOCKET_NAME);

}

 

static NetworkManagementService create(Context context,

       String socket) throws InterruptedException {

final NetworkManagementService service = new NetworkManagementService(context, socket);

 

   //启动线程

service.mThread.start();

 

}

 

NetworkManagementService的构造函数看看

private NetworkManagementService(Context context, String socket) {

 

   mConnector = new NativeDaemonConnector(

           new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160);

   mThread = new Thread(mConnector, NETD_TAG);

 

}

 

我们到NativeDaemonConnectorrun函数里去看看,是不是在run函数里,都做了客户端需要做的事情,以接收和发送消息给netd

 

public void run() {

 

listenToSocket() {

   //创建Socket

   socket = new LocalSocket();

   

   //设置连接地址

   LocalSocketAddress address = determineSocketAddress();

 

   //建立连接

   socket.connect(address);

 

   //获取输入流

   InputStream inputStream = socket.getInputStream();

 

   //获取输出流

   mOutputStream = socket.getOutputStream();

}

 

}

 

分析到这里,我们已经知道在Framework层和netd通信的服务是NetworkManagementService。读完这篇文章后,大伙应该基本了解Android系统的以太网的工作流程了,关键是我们学到了Android的其中一个设计方法,Framework层怎么和Native层的另外一个进程通信,我们可以模仿上面讲到的方法,用Socket

1 0
原创粉丝点击