Clean up dependency between NetlinkListener and TrafficController

Bug: 209935649
Test: m; flash; boot
Test: atest netd_integration_test
Change-Id: I779050cd4472395adbef06d8921884c194fd0b32
diff --git a/server/Android.bp b/server/Android.bp
index 49445db..071f467 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -29,7 +29,6 @@
         "NetdConstants.cpp",
         "InterfaceController.cpp",
         "NetlinkCommands.cpp",
-        "NetlinkListener.cpp",
         "TcUtils.cpp",
         "SockDiag.cpp",
         "XfrmController.cpp",
@@ -57,7 +56,6 @@
         "IptablesRestoreController.cpp",
         "NFLogListener.cpp",
         "NetlinkCommands.cpp",
-        "NetlinkListener.cpp",
         "NetlinkManager.cpp",
         "TcUtils.cpp",
         "RouteController.cpp",
diff --git a/server/NFLogListener.cpp b/server/NFLogListener.cpp
index 76972b6..62ac19d 100644
--- a/server/NFLogListener.cpp
+++ b/server/NFLogListener.cpp
@@ -35,6 +35,8 @@
 using netdutils::extract;
 using netdutils::findWithDefault;
 using netdutils::makeSlice;
+using netdutils::NetlinkListener;
+using netdutils::NetlinkListenerInterface;
 using netdutils::Slice;
 using netdutils::sSyscalls;
 using netdutils::Status;
diff --git a/server/NFLogListener.h b/server/NFLogListener.h
index 459b5cf..722fdd0 100644
--- a/server/NFLogListener.h
+++ b/server/NFLogListener.h
@@ -19,7 +19,7 @@
 
 #include <netdutils/Netfilter.h>
 
-#include "NetlinkListener.h"
+#include "netdutils/NetlinkListener.h"
 #include "netdutils/StatusOr.h"
 
 namespace android {
@@ -64,7 +64,7 @@
 
     // Do not invoke this constructor directly outside of tests. Use
     // makeNFLogListener() instead.
-    NFLogListener(std::shared_ptr<NetlinkListenerInterface> listener);
+    NFLogListener(std::shared_ptr<netdutils::NetlinkListenerInterface> listener);
 
     ~NFLogListener() override;
 
@@ -76,7 +76,7 @@
     netdutils::Status unsubscribe(uint16_t nfLogGroup) override;
 
   private:
-    std::shared_ptr<NetlinkListenerInterface> mListener;
+    std::shared_ptr<netdutils::NetlinkListenerInterface> mListener;
     std::mutex mMutex;
     std::map<uint16_t, DispatchFn> mDispatchMap;  // guarded by mMutex
 };
diff --git a/server/NFLogListenerTest.cpp b/server/NFLogListenerTest.cpp
index f3bd810..88ab2c6 100644
--- a/server/NFLogListenerTest.cpp
+++ b/server/NFLogListenerTest.cpp
@@ -38,9 +38,10 @@
 namespace android {
 namespace net {
 
+using netdutils::makeSlice;
+using netdutils::NetlinkListenerInterface;
 using netdutils::Slice;
 using netdutils::StatusOr;
-using netdutils::makeSlice;
 using netdutils::status::ok;
 
 constexpr int kNFLogPacketMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET;
diff --git a/server/NetlinkListener.cpp b/server/NetlinkListener.cpp
deleted file mode 100644
index a6e427d..0000000
--- a/server/NetlinkListener.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "NetlinkListener"
-
-#include "NetlinkListener.h"
-
-#include <sstream>
-#include <vector>
-
-#include <linux/netfilter/nfnetlink.h>
-
-#include <log/log.h>
-#include <netdutils/Misc.h>
-#include <netdutils/Syscalls.h>
-
-namespace android {
-namespace net {
-
-using netdutils::Fd;
-using netdutils::Slice;
-using netdutils::Status;
-using netdutils::UniqueFd;
-using netdutils::findWithDefault;
-using netdutils::forEachNetlinkMessage;
-using netdutils::makeSlice;
-using netdutils::sSyscalls;
-using netdutils::status::ok;
-using netdutils::statusFromErrno;
-
-namespace {
-
-constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR;
-
-constexpr sockaddr_nl kKernelAddr = {
-    .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0,
-};
-
-const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) {
-    std::stringstream ss;
-    ss << nlmsg;
-    ALOGE("unhandled netlink message: %s", ss.str().c_str());
-};
-
-}  // namespace
-
-NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock, const std::string& name)
-    : mEvent(std::move(event)), mSock(std::move(sock)), mThreadName(name) {
-    const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) {
-        std::stringstream ss;
-        ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32);
-        ALOGE("unhandled netlink message: %s", ss.str().c_str());
-    };
-    expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler));
-
-    mErrorHandler = [& name = mThreadName](const int fd, const int err) {
-        ALOGE("Error on NetlinkListener(%s) fd=%d: %s", name.c_str(), fd, strerror(err));
-    };
-
-    // Start the thread
-    mWorker = std::thread([this]() { run().ignoreError(); });
-}
-
-NetlinkListener::~NetlinkListener() {
-    const auto& sys = sSyscalls.get();
-    const uint64_t data = 1;
-    // eventfd should never enter an error state unexpectedly
-    expectOk(sys.write(mEvent, makeSlice(data)).status());
-    mWorker.join();
-}
-
-Status NetlinkListener::send(const Slice msg) {
-    const auto& sys = sSyscalls.get();
-    ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr));
-    if (sent != msg.size()) {
-        return statusFromErrno(EMSGSIZE, "unexpect message size");
-    }
-    return ok;
-}
-
-Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) {
-    std::lock_guard guard(mMutex);
-    mDispatchMap[type] = fn;
-    return ok;
-}
-
-Status NetlinkListener::unsubscribe(uint16_t type) {
-    std::lock_guard guard(mMutex);
-    mDispatchMap.erase(type);
-    return ok;
-}
-
-void NetlinkListener::registerSkErrorHandler(const SkErrorHandler& handler) {
-    mErrorHandler = handler;
-}
-
-Status NetlinkListener::run() {
-    std::vector<char> rxbuf(4096);
-
-    const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) {
-        std::lock_guard guard(mMutex);
-        const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn);
-        fn(nlmsg, buf);
-    };
-
-    if (mThreadName.length() > 0) {
-        int ret = pthread_setname_np(pthread_self(), mThreadName.c_str());
-        if (ret) {
-            ALOGE("thread name set failed, name: %s, ret: %s", mThreadName.c_str(), strerror(ret));
-        }
-    }
-    const auto& sys = sSyscalls.get();
-    const std::array<Fd, 2> fds{{{mEvent}, {mSock}}};
-    const int events = POLLIN;
-    const double timeout = 3600;
-    while (true) {
-        ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout));
-        // After mEvent becomes readable, we should stop servicing mSock and return
-        if (revents[0] & POLLIN) {
-            break;
-        }
-        if (revents[1] & (POLLIN|POLLERR)) {
-            auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0);
-            int err = rx.status().code();
-            if (err) {
-                // Ignore errors. The only error we expect to see here is ENOBUFS, and there's
-                // nothing we can do about that. The recvfrom above will already have cleared the
-                // error indication and ensured we won't get EPOLLERR again.
-                // TODO: Consider using NETLINK_NO_ENOBUFS.
-                mErrorHandler(((Fd) mSock).get(), err);
-                continue;
-            }
-            forEachNetlinkMessage(rx.value(), rxHandler);
-        }
-    }
-    return ok;
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/NetlinkListener.h b/server/NetlinkListener.h
deleted file mode 100644
index 6f38829..0000000
--- a/server/NetlinkListener.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETLINK_LISTENER_H
-#define NETLINK_LISTENER_H
-
-#include <functional>
-#include <map>
-#include <mutex>
-#include <thread>
-
-#include <android-base/thread_annotations.h>
-#include <netdutils/Netlink.h>
-#include <netdutils/Slice.h>
-#include <netdutils/Status.h>
-#include <netdutils/UniqueFd.h>
-
-namespace android {
-namespace net {
-
-class NetlinkListenerInterface {
-  public:
-    using DispatchFn = std::function<void(const nlmsghdr& nlmsg, const netdutils::Slice msg)>;
-
-    using SkErrorHandler = std::function<void(const int fd, const int err)>;
-
-    virtual ~NetlinkListenerInterface() = default;
-
-    // Send message to the kernel using the underlying netlink socket
-    virtual netdutils::Status send(const netdutils::Slice msg) = 0;
-
-    // Deliver future messages with nlmsghdr.nlmsg_type == type to fn.
-    //
-    // Threadsafe.
-    // All dispatch functions invoked on a single service thread.
-    // subscribe() and join() must not be called from the stack of fn().
-    virtual netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) = 0;
-
-    // Halt delivery of future messages with nlmsghdr.nlmsg_type == type.
-    // Threadsafe.
-    virtual netdutils::Status unsubscribe(uint16_t type) = 0;
-
-    virtual void registerSkErrorHandler(const SkErrorHandler& handler) = 0;
-};
-
-// NetlinkListener manages a netlink socket and associated blocking
-// service thread.
-//
-// This class is written in a generic way to allow multiple different
-// netlink subsystems to share this common infrastructure. If multiple
-// subsystems share the same message delivery requirements (drops ok,
-// no drops) they may share a single listener by calling subscribe()
-// with multiple types.
-//
-// This class is suitable for moderate performance message
-// processing. In particular it avoids extra copies of received
-// message data and allows client code to control which message
-// attributes are processed.
-//
-// Note that NetlinkListener is capable of processing multiple batched
-// netlink messages in a single system call. This is useful to
-// netfilter extensions that allow batching of events like NFLOG.
-class NetlinkListener : public NetlinkListenerInterface {
-  public:
-    NetlinkListener(netdutils::UniqueFd event, netdutils::UniqueFd sock, const std::string& name);
-
-    ~NetlinkListener() override;
-
-    netdutils::Status send(const netdutils::Slice msg) override;
-
-    netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) override EXCLUDES(mMutex);
-
-    netdutils::Status unsubscribe(uint16_t type) override EXCLUDES(mMutex);
-
-    void registerSkErrorHandler(const SkErrorHandler& handler) override;
-
-  private:
-    netdutils::Status run();
-
-    const netdutils::UniqueFd mEvent;
-    const netdutils::UniqueFd mSock;
-    const std::string mThreadName;
-    std::mutex mMutex;
-    std::map<uint16_t, DispatchFn> mDispatchMap GUARDED_BY(mMutex);
-    std::thread mWorker;
-    SkErrorHandler mErrorHandler;
-};
-
-}  // namespace net
-}  // namespace android
-
-#endif /* NETLINK_LISTENER_H */
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 5a12d9c..2b4ecb6 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -41,13 +41,13 @@
 #include <netdutils/StatusOr.h>
 
 #include <netdutils/Misc.h>
+#include <netdutils/NetlinkListener.h>
 #include <netdutils/Syscalls.h>
 #include <netdutils/Utils.h>
 #include <processgroup/processgroup.h>
 #include "TrafficController.h"
 #include "bpf/BpfMap.h"
 
-#include "NetlinkListener.h"
 #include "netdutils/DumpWriter.h"
 
 namespace android {
@@ -55,6 +55,7 @@
 
 using base::StringPrintf;
 using base::unique_fd;
+using bpf::BpfMap;
 using bpf::getSocketCookie;
 using bpf::NONEXISTENT_COOKIE;
 using bpf::OVERFLOW_COUNTERSET;
@@ -63,6 +64,8 @@
 using netdutils::DumpWriter;
 using netdutils::extract;
 using netdutils::getIfaceList;
+using netdutils::NetlinkListener;
+using netdutils::NetlinkListenerInterface;
 using netdutils::ScopedIndent;
 using netdutils::Slice;
 using netdutils::sSyscalls;
diff --git a/server/TrafficController.h b/server/TrafficController.h
index 13a1a80..2f38f6c 100644
--- a/server/TrafficController.h
+++ b/server/TrafficController.h
@@ -19,18 +19,16 @@
 
 #include <linux/bpf.h>
 
-#include "NetlinkListener.h"
 #include "Network.h"
 #include "android-base/thread_annotations.h"
 #include "android-base/unique_fd.h"
 #include "bpf/BpfMap.h"
 #include "bpf_shared.h"
 #include "netdutils/DumpWriter.h"
+#include "netdutils/NetlinkListener.h"
 #include "netdutils/StatusOr.h"
 #include "utils/String16.h"
 
-using android::bpf::BpfMap;
-
 namespace android {
 namespace net {
 
@@ -117,7 +115,8 @@
 
     int toggleUidOwnerMap(ChildChain chain, bool enable) EXCLUDES(mMutex);
 
-    static netdutils::StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener();
+    static netdutils::StatusOr<std::unique_ptr<netdutils::NetlinkListenerInterface>>
+    makeSkDestroyListener();
 
     void setPermissionForUids(int permission, const std::vector<uid_t>& uids) EXCLUDES(mMutex);
 
@@ -139,7 +138,7 @@
      * Map Key: uint64_t socket cookie
      * Map Value: UidTagValue, contains a uint32 uid and a uint32 tag.
      */
-    BpfMap<uint64_t, UidTagValue> mCookieTagMap GUARDED_BY(mMutex);
+    bpf::BpfMap<uint64_t, UidTagValue> mCookieTagMap GUARDED_BY(mMutex);
 
     /*
      * mUidCounterSetMap: Store the counterSet of a specific uid.
@@ -147,14 +146,14 @@
      * Map Value: uint32 counterSet specifies if the traffic is a background
      * or foreground traffic.
      */
-    BpfMap<uint32_t, uint8_t> mUidCounterSetMap GUARDED_BY(mMutex);
+    bpf::BpfMap<uint32_t, uint8_t> mUidCounterSetMap GUARDED_BY(mMutex);
 
     /*
      * mAppUidStatsMap: Store the total traffic stats for a uid regardless of
      * tag, counterSet and iface. The stats is used by TrafficStats.getUidStats
      * API to return persistent stats for a specific uid since device boot.
      */
-    BpfMap<uint32_t, StatsValue> mAppUidStatsMap;
+    bpf::BpfMap<uint32_t, StatsValue> mAppUidStatsMap;
 
     /*
      * mStatsMapA/mStatsMapB: Store the traffic statistics for a specific
@@ -165,22 +164,22 @@
      * Map Value: Stats, contains packet count and byte count of each
      * transport protocol on egress and ingress direction.
      */
-    BpfMap<StatsKey, StatsValue> mStatsMapA GUARDED_BY(mMutex);
+    bpf::BpfMap<StatsKey, StatsValue> mStatsMapA GUARDED_BY(mMutex);
 
-    BpfMap<StatsKey, StatsValue> mStatsMapB GUARDED_BY(mMutex);
+    bpf::BpfMap<StatsKey, StatsValue> mStatsMapB GUARDED_BY(mMutex);
 
     /*
      * mIfaceIndexNameMap: Store the index name pair of each interface show up
      * on the device since boot. The interface index is used by the eBPF program
      * to correctly match the iface name when receiving a packet.
      */
-    BpfMap<uint32_t, IfaceValue> mIfaceIndexNameMap;
+    bpf::BpfMap<uint32_t, IfaceValue> mIfaceIndexNameMap;
 
     /*
      * mIfaceStataMap: Store per iface traffic stats gathered from xt_bpf
      * filter.
      */
-    BpfMap<uint32_t, StatsValue> mIfaceStatsMap;
+    bpf::BpfMap<uint32_t, StatsValue> mIfaceStatsMap;
 
     /*
      * mConfigurationMap: Store the current network policy about uid filtering
@@ -194,19 +193,19 @@
      *    Userspace can do scraping and cleaning job on the other one depending on the
      *    current configs.
      */
-    BpfMap<uint32_t, uint8_t> mConfigurationMap GUARDED_BY(mMutex);
+    bpf::BpfMap<uint32_t, uint8_t> mConfigurationMap GUARDED_BY(mMutex);
 
     /*
      * mUidOwnerMap: Store uids that are used for bandwidth control uid match.
      */
-    BpfMap<uint32_t, UidOwnerValue> mUidOwnerMap GUARDED_BY(mMutex);
+    bpf::BpfMap<uint32_t, UidOwnerValue> mUidOwnerMap GUARDED_BY(mMutex);
 
     /*
      * mUidOwnerMap: Store uids that are used for INTERNET permission check.
      */
-    BpfMap<uint32_t, uint8_t> mUidPermissionMap GUARDED_BY(mMutex);
+    bpf::BpfMap<uint32_t, uint8_t> mUidPermissionMap GUARDED_BY(mMutex);
 
-    std::unique_ptr<NetlinkListenerInterface> mSkDestroyListener;
+    std::unique_ptr<netdutils::NetlinkListenerInterface> mSkDestroyListener;
 
     netdutils::Status removeRule(uint32_t uid, UidOwnerMatchType match) REQUIRES(mMutex);
 
diff --git a/tests/netlink_listener_test.cpp b/tests/netlink_listener_test.cpp
index 18315e8..31cd7fb 100644
--- a/tests/netlink_listener_test.cpp
+++ b/tests/netlink_listener_test.cpp
@@ -34,11 +34,11 @@
 
 #include <netdutils/Misc.h>
 #include <netdutils/Syscalls.h>
-#include "NetlinkListener.h"
 #include "TrafficController.h"
 #include "bpf/BpfMap.h"
 #include "bpf/BpfUtils.h"
 #include "netdutils/Netlink.h"
+#include "netdutils/NetlinkListener.h"
 
 // A test uid that is large enough so normal apps are not likely to take,
 constexpr uid_t TEST_UID = UID_MAX - 2;
@@ -50,6 +50,7 @@
 
 using android::base::Error;
 using android::base::Result;
+using android::bpf::BpfMap;
 
 // This test set up a SkDestroyListener that is runing parallel with the production
 // SkDestroyListener. The test will create thousands of sockets and tag them on the
@@ -100,7 +101,7 @@
     }
 
     bool checkMassiveSocketDestroy(int totalNumber, bool expectError) {
-        std::unique_ptr<android::net::NetlinkListenerInterface> skDestroyListener;
+        std::unique_ptr<android::netdutils::NetlinkListenerInterface> skDestroyListener;
         auto result = android::net::TrafficController::makeSkDestroyListener();
         if (!isOk(result)) {
             ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());