在应用到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,其名称分别为netd、dnsproxyd和mdns。当设备启动后,到/dev/socket/下会看见有netd、dnsproxyd和mdns这三个文件。netd守护进程的Socket资源和netd、dnsproxyd和mdns名称绑定起来。netd通过Socket接收并处理来自Framework层中NetworkManagementService或NsdService的命令。netd通过Socket接收并解析来自Kernel的UEvent消息,然后再通过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.关闭socket(closesocket())
5.关闭socket(closesocket())
也就是说netd和Framework层,以及netd和kernel之间要通过Socket来通信的话,所做的事情肯定是上面提到的这些。
下面分析netd的main函数
main()
{
//new NetlinkManager对象nm
if (!(nm = NetlinkManager::Instance())) {
ALOGE(“Unable to create NetlinkManager”);
exit(1);
};
//new CommandListener对象cl,将cl设置成nm(NetlinkManager)的消息发送者(mBroadcaster)
cl = new CommandListener(rangeMap);
nm->setBroadcaster((SocketListener *) cl);

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

//启动nm(NetlinkManager)
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);
}

//启动cl(CommandListener)监听
if (cl->startListener()) {
ALOGE(“Unable to start CommandListener (%s)”, strerror(errno));
exit(1);
}
}
netd的main函数比较简单,就是创建几个重要的成员并启动成员的工作,笔者这里只讲解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;
}

NetlinkManager的start函数就是向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;
}

//如果没有猜错在NetlinkHandler的start里一定会调用listen接着另起一线程进行accept和等待客户端的连接以及不停的接收来自kernel的UEvent消息。
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。在netd的main函数里我们有调用过cl->startListener(),我们到CommandListener的startListener里看看,CommandListener的startListener调用其实就是其父类的父类SocketListener的startListener。
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监听kernel的UEvent事件的过程一样。到这里netd的工作基本已经清楚了,就是获取名称为“netd”的Socket并启动监听,同时创建3个Socket用于监听来自kernel的3中不同的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);

}

我们到NativeDaemonConnector的run函数里去看看,是不是在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. Android(安卓)Sqlite3 使用
  2. Android(安卓)使用Socket实现服务器与手机客户端的长连接四:使用
  3. Android中Gallery和ImageSwitcher同步自动(滚动)播放图片库
  4. Android(安卓)NDK c创建java对象
  5. android AlertDialog对话框
  6. Win10 + cygwin64 + ndk 配置ijkplayer android
  7. android 启动自动调用自己创建的脚本(应用程序)
  8. Android(安卓)Camera2 Hal3(二)startPreview预览过程
  9. Android(安卓)中ActionBar+fragment实现页面导航的实例

随机推荐

  1. Mysql单文件存储删除数据文件容量不会减
  2. mysql模糊查询like与REGEXP的使用详细介
  3. Mysql存储引擎详解
  4. mysql 正则表达式查询含有非数字和字符的
  5. MySQL的隐式类型转换整理总结
  6. Mysql利用group by分组排序
  7. Mysql百万级分页优化技巧
  8. MySql创建带解释的表及给表和字段加注释
  9. 详解Centos7 修改mysql指定用户的密码
  10. MySQL5.7安装过程并重置root密码的方法(sh