Android重学系列 NetworkManagementService,netd在DNS查询的职能

请问下,Android重学系列 NetworkManagementService,netd在DNS查询的职能
最新回答
爱哭的小鬼

2024-11-23 08:55:15

前四篇文章讲述了Okhttp的核心原理,得知Okhttp是基于Socket开发的,而不是基于HttpUrlConnection开发的。

其中对于客户端来说,核心有如下四个步骤:

本文着重来看看DNS做了什么事情。在Okhttp默认的DNS 对象就是如下这个DnsSystem对象。

然而本文并不会立即和大家聊DNS的解析过程。因为在Android的网络模块中,存在着2个十分重要的对象:

而DNS的查询恰好是通过2个模块的互相运作才能执行。

遇到什么问题可以来这里讨论
https://www.jianshu.com/p/cce3535ce457


文件:/ system / netd / server / netd.rc

关于rc文件如何解析,本文就不多赘述了。详情可以阅读我写的 系统启动到Activity(上) 一文。

能看到在这个过程中,会启动一个 netd 进程,接着会启动 netd , dnsproxyd , mdns , fwmarkd 四个socket。

文件:/ system / netd / server / main.cpp

这里我们分别看看都做了什么。

实例化NetlinkManager对象后,设置一个CommandListener 到NetlinkManager 中。

接着调用start方法启动 NetlinkManager .

这三个步骤都是生成一个socket对象,并设置domain为 PF_NETLINK ,然后设置不同的Type用于监听socket从内核模块释放的信息。

在这里面设置了一个socket名字为 netd ,并在父类 FrameworkListener 进行初始化。

在这一层构造函数中,会注册不同命令的监听。当从 netd socket中接受到信息的到来就会检测获取第一个参数,是否是对应类型的CMD。

比如说,这里注册了InterfaceCmd对象:

为这个NetdCommand 设置了一个对应的字符串 interface .当 netd socket中监听到第一个参数字符串是 interface ,找到注册到 FrameworkListener 集合中的命令数据,并且调用对应 NetdCommand 的 runCommand 方法,从而执行对应的逻辑。

文件:/ system / netd / server / DnsProxyListener.cpp

DnsProxyListener 也是 FrameworkListener 派生类。注册了 GetAddrInfoCmd 命令域名查找ip地址对象, GetHostByAddrCmd 通过返回给定ip地址服务器信息命令对象, GetHostByNameCmd 通过域名查找服务器信息命令对象.

简单来看看这几个对象注册命令是什么:

对应的命令识别字符串是 getaddrinfo

对应的命令识别字符串是 gethostbyaddr

对应的命令识别字符串是 gethostbyname

能看到这个过程中

文件:/ system / netd / server / MDnsSdListener.cpp

注册了一个 mdnssd 命令监听。当调用了startListener方法后就会构建一个 mdns socket 监听 mdnssd 命令的到来。

首先实例化一个 fwmarkd socket,并监听这个socket传递过来的内容。

注意 TrafficController 隶属于 eBPF 网络流浪监控模块 。除了标记和取消标记socket外还承担了删除流量数据的职责。可以同时从 /sys/fs/bpf 下其他文件中实时的读取不同uid,appid的流量数据。

初始化位置在为文件SystemServer中:

文件:/ frameworks / base / services / core / java / com / android / server / NetworkManagementService.java

注意 NativeDaemonConnector 是一个Runnable对象,在上面一节中进行Thread的实例化和start后会启动run方法。

这个过程实际上做的事情就是一件:

这里的 netd socket实际上就是指 netd 进程创建的时候,通过app_main 解析init.rc创建出来的socket。而在 netd 进程也构造了这个socket,随时进行发送或者监听信息。

值得注意的是,这里面有一个有趣的对象 PowerManager.WakeLock .每当从 netd 监听到消息的时候,发现从 netd 进程传送过来的事件是从 netd 主动来的请求,那么就会调用 PowerManager.WakeLock 立即唤醒设备发送通过Handler发送数据。

这也是为什么耗电量会被Android系统监听到的原因的,这个WakeLock 唤醒锁是一个重要的依据。

对NetworkManagementService以及netd 两个服务都有了大致的了解后,我们才好开展本次重点话题,Android是怎么进行通过域名进行DNS查询到ip地址的。

这个过程实际上是交给了 Inet6AddressImpl 的lookupAllHostAddr处理。

构建了一个 StructAddrinfo 对象,保存了三个十分重要的标志:

并把StructAddrinfo作为参数传入方法Libcore.os.android_getaddrinfo中处理。

这个方法实际上就是一个native方法,对应如下文件:
/ libcore / luni / src / main / native / libcore_io_Linux.cpp

这个过程实际上就是从 StructAddrinfo 中拿到 ai_flags , ai_family , ai_socktype 作为参数传递到 android_getaddrinfofornet 方法中。并把取到的数据保存到Java数组中并返回。

注意接下来分为2个分之,是调用libc中内置的 getaddrinfo 方法还是调用bionic的 android_getaddrinfofornet .

一半的jdk都是使用libc内置的方法,而android中都是使用bionic库进行处理。

文件:/ bionic / libc / dns / net / getaddrinfo.c

生成一个 android_net_context 结构体后,调用 android_getaddrinfofornetcontext .

此时App进程 ANDROID_DNS_MODE 不是 local 模式那么说明需要走代理,就会联通 netd 进程的 /dev/socket/dnsproxyd 的socket接口,并返回。