NetlinkManager 管理 netd 中 NetlinkHandler 的初始化并启动监听和处理;
NetlinkHandler 处理和转发 Kernel 的相应事件;
SocketListener 监听 socket,启动监听并接收 socket 事件;
SocketClient 实际的消息处理者,他将 event 通过 socket 发送给 java 层进行处理;
NativeDaemonConnector java 层的 socket 通讯端,用于接收和下发事件;
NetworkManagementService Framework 层的网络相关核心服务;
① 在 netd 的 main 函数中通过 NetworkManager 的 Instance 方法创建 NetworkManager 对象,并且调用其 start 方法
int main() {
...
NetlinkManager *nm;
...
if (!(nm = NetlinkManager::Instance())) {
ALOGE("Unable to create NetlinkManager");
exit(1);
};
...
if (nm->start()) {
ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
...
}
② 在 start 接口中创建了三个 socket 用于接收 Kernel 消息
int NetlinkManager::start() {
if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
return -1;
}
if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,
RTMGRP_LINK |
RTMGRP_IPV4_IFADDR |
RTMGRP_IPV6_IFADDR,
NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
return -1;
}
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;
}
套接字的类型均为 PF_NETLINK,报文类型是 SOCK_DGRAM,协议分别为:
NETLINK_KOBJECT_UEVENT,NETLINK_ROUTE 和 NETLINK_NETFILTER;
③ 对每个新创建的 NETLINK_SOCKET 而言,又以其为参数创建了对应的 NetlinkHandler 对象,socket 的 fd 作为参数,用于 NetlinkHandler->NetlinkListener->SocketListener 的构造函数以及 init 函数初始化:
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
mListen = listen;
mSocketName = socketName;
mSock = socketFd;
mUseCmdNum = useCmdNum;
pthread_mutex_init(&mClientsLock, nullptr);
}
这里面 listen 是 false,useCmdNum 也为 false,socketName 为 nullptr;
④ 继续对每个 NetlinkHandler 调用其 start 方法,其实最终调用了 SocketListener 的 startListener 方法,进而在其中以此 socket 的 fd 为参数创建了 SocketClient 对象,存入 mClient 容器中;
⑤ 创建一个新线程而以 SocketListener 类的 threadStart 方法为入口,调用了 runListener 方法,而其中首先将 fds 全部加入 vector 中再通过 poll 来阻塞监听,当有数据时将 active 的 SocketClient 对象加入到 pending 队列,释放互斥锁和引用,对 pending 的 list 进行遍历,通过 onDataAvailable 方法处理回调;
⑥ onDataAvailable 是 NetlinkListener 中的方法,其处理过程就是调用了 uevent_kernel_recv 方法,将数据接收到 mBuffer 中,创建一个 NetlinkEvent,将 mBuffer 中的数据用其 decode 进行分析并填充 NetlinkEvent 中的字段指定 action 信息,最终调用 NetlinkHandler 的 onEvent 方法进行 NetlinkEvent 的处理工作;
⑦ onEvent 方法进行消息类型的判断根据 action 匹配对应的 notifyXXX 方法;以添加接口为例,notifyInterfaceAdded 方法被调用,这里用到了 LOG_EVENT_FUNC 宏,实际上是调用了 gCtrls 中所有的 listeners 的 onInterfaceAdded 等方法,gCtrls 分析如下面第⑧步骤分析,listener 的注册见下面第⑨点分析;
⑧ 在 main 函数中执行 NetlinkManager 的 start 方法之前创建了 gCtls:
int main() {
...
NetlinkManager *nm = NetlinkManager::Instance();
if (nm == nullptr) {
ALOGE("Unable to create NetlinkManager");
exit(1);
};
gCtls = new android::net::Controllers();
gCtls->init();
...
}
这里通过其内部的 EventReporter 对象的 getNetdEventListener 方法获得对应的 binder 服务端对象,可以对其中的方法进行调用,也就是上面讲到的 listeners 的 onInterfaceAdded 方法;
⑨ 同样 EventReporter::registerUnsolEventListener 被调用用来将 INetdUnsolicitedEventListener 对象 listener 注册到 netd 中,保存到 mUnsolListeners 中,以 NetworkManagementService 为例,其注册过程如下:
static NetworkManagementService create(Context context, SystemServices services)
throws InterruptedException {
final NetworkManagementService service =
new NetworkManagementService(context, services);
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
if (DBG) Slog.d(TAG, "Connecting native netd service");
service.connectNativeNetdService();
if (DBG) Slog.d(TAG, "Connected");
return service;
}
private void connectNativeNetdService() {
mNetdService = mServices.getNetd();
try {
mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
if (DBG) Slog.d(TAG, "Register unsolicited event listener");
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Failed to set Netd unsolicited event listener " + e);
}
}
/* system/netd/server/binder/android/net/INetd.aidl */
/**
* Register unsolicited event listener
* Netd supports multiple unsolicited event listeners.
*
* @param listener unsolicited event listener to register
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
void registerUnsolicitedEventListener(INetdUnsolicitedEventListener listener);
/* system/netd/server/NetdNativeService.h */
/* system/netd/server/NetdNativeService.cpp */
binder::Status NetdNativeService::registerUnsolicitedEventListener(
const android::sp<android::net::INetdUnsolicitedEventListener>& listener) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
gCtls->eventReporter.registerUnsolEventListener(listener);
return binder::Status::ok();
}
/* EventReporter.cpp */
void EventReporter::registerUnsolEventListener(
const android::sp<INetdUnsolicitedEventListener>& listener) {
std::lock_guard lock(mUnsolicitedMutex);
mUnsolListeners.insert(listener);
// Create the death listener.
class DeathRecipient : public android::IBinder::DeathRecipient {
public:
DeathRecipient(UnsolListeners* listeners,
android::sp<INetdUnsolicitedEventListener> listener, std::mutex& unsolMutex)
: mMutex(unsolMutex), mUnsolListeners(listeners), mListener(std::move(listener)) {}
~DeathRecipient() override = default;
private:
void binderDied(const android::wp<android::IBinder>& /* who */) override {
std::lock_guard lock(mMutex);
mUnsolListeners->erase(mListener);
}
std::mutex& mMutex;
UnsolListeners* mUnsolListeners GUARDED_BY(mMutex);
android::sp<INetdUnsolicitedEventListener> mListener;
};
android::sp<android::IBinder::DeathRecipient> deathRecipient =
new DeathRecipient(&mUnsolListeners, listener, mUnsolicitedMutex);
android::IInterface::asBinder(listener)->linkToDeath(deathRecipient);
}
这样的话 kernel 中的事件就可以通过 netd 上传回调到对应的 listener 了,比如 NetworkManagementService 服务类。WiFi 也同样注册了 listener,发生在 NetdWrapper 类中,首先定义了 NetdUnsolicitedEventListener 对象:
private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
...
@Override
public void onInterfaceChanged(String ifName, boolean up)
throws RemoteException {
mHandler.post(() -> notifyInterfaceStatusChanged(ifName, up));
}
@Override
public void onInterfaceLinkStateChanged(String ifName, boolean up)
throws RemoteException {
mHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up));
}
...
@Override
public int getInterfaceVersion() {
return INetdUnsolicitedEventListener.VERSION;
}
@Override
public String getInterfaceHash() {
return INetdUnsolicitedEventListener.HASH;
}
}
在构造函数中完成了对应对象的注册:
/* frameworks/opt/net/wifi/service/java/com/android/server/wifi/util/NetdWrapper.java */
public NetdWrapper(Context context, Handler handler) {
mNetdService = INetd.Stub.asInterface(
(IBinder) context.getSystemService(Context.NETD_SERVICE));
mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
mHandler = handler;
try {
mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
} catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Failed to set Netd unsolicited event listener " + e);
}
}
最后需要说明的是 uevent_kernel_recv 函数处理实际的收包过程,它实现在 system/core/libcutils/uevent.cpp 文件中:
/**
* Like recv(), but checks that messages actually originate from the kernel.
*/
ssize_t uevent_kernel_multicast_recv(int socket, void* buffer, size_t length) {
uid_t uid = -1;
return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid);
}
/**
* Like the above, but passes a uid_t in by pointer. In the event that this
* fails due to a bad uid check, the uid_t will be set to the uid of the
* socket's peer.
*
* If this method rejects a netlink message from outside the kernel, it
* returns -1, sets errno to EIO, and sets "user" to the UID associated with the
* message. If the peer UID cannot be determined, "user" is set to -1."
*/
ssize_t uevent_kernel_multicast_uid_recv(int socket, void* buffer, size_t length, uid_t* uid) {
return uevent_kernel_recv(socket, buffer, length, true, uid);
}
ssize_t uevent_kernel_recv(int socket, void* buffer, size_t length, bool require_group, uid_t* uid) {
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,
};
struct ucred* cred;
*uid = -1;
ssize_t n = TEMP_FAILURE_RETRY(recvmsg(socket, &hdr, 0));
if (n <= 0) {
return n;
}
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
/* ignoring netlink message with no sender credentials */
goto out;
}
cred = (struct ucred*)CMSG_DATA(cmsg);
*uid = cred->uid;
if (addr.nl_pid != 0) {
/* ignore non-kernel */
goto out;
}
if (require_group && addr.nl_groups == 0) {
/* ignore unicast messages when requested */
goto out;
}
return n;
out:
/* clear residual potentially malicious data */
bzero(buffer, length);
errno = EIO;
return -1;
}
int uevent_open_socket(int buf_sz, bool passcred) {
struct sockaddr_nl addr;
int on = passcred;
int buf_sz_readback = 0;
socklen_t optlen = sizeof(buf_sz_readback);
int s;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = 0;
addr.nl_groups = 0xffffffff;
s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if (s < 0) return -1;
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0 ||
getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz_readback, &optlen) < 0) {
close(s);
return -1;
}
/* Only if SO_RCVBUF was not effective, try SO_RCVBUFFORCE. Generally, we
* want to avoid SO_RCVBUFFORCE, because it generates SELinux denials in
* case we don't have CAP_NET_ADMIN. This is the case, for example, for
* healthd. */
if (buf_sz_readback < 2 * buf_sz) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz)) < 0) {
close(s);
return -1;
}
}
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
return s;
}
事实上其内部调用了 recvmsg 进行实际的报文接收工作,然后对报文做了简单的解析和处理。