Netd 中 NetworkManager 分析

本文介绍了NetlinkManager如何初始化并启动NetlinkHandler,监听Kernel事件并通过Socket通信。详细讲解了SocketListener、SocketClient、NativeDaemonConnector的角色,以及NetworkManagementService如何注册listener接收Kernel消息。重点涉及网络管理框架中的关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 进行实际的报文接收工作,然后对报文做了简单的解析和处理。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值