Merge "wifi: upgrade wifi interface to 1.5"
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index 0af81b2..8fdb70d 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -1,8 +1,5 @@
-cc_defaults {
-    name: "android.hardware.audio-impl_default",
-    relative_install_path: "hw",
-    proprietary: true,
-    vendor: true,
+filegroup {
+    name: "android.hardware.audio-impl_srcs",
     srcs: [
         "Conversions.cpp",
         "Device.cpp",
@@ -13,11 +10,24 @@
         "StreamIn.cpp",
         "StreamOut.cpp",
     ],
+}
+
+cc_library_headers {
+    name: "android.hardware.audio-impl_headers",
+    proprietary: true,
+    vendor: true,
+    export_include_dirs: ["include"],
+}
+
+cc_defaults {
+    name: "android.hardware.audio-impl_default",
+    relative_install_path: "hw",
+    proprietary: true,
+    vendor: true,
+    srcs: [":android.hardware.audio-impl_srcs"],
 
     defaults: ["hidl_defaults"],
 
-    export_include_dirs: ["include"],
-
     static_libs: [
         "libaudiofoundation",
     ],
@@ -35,12 +45,17 @@
     ],
 
     header_libs: [
+        "android.hardware.audio-impl_headers",
         "android.hardware.audio.common.util@all-versions",
         "libaudioclient_headers",
         "libaudio_system_headers",
         "libhardware_headers",
         "libmedia_headers",
     ],
+
+    export_header_lib_headers: [
+        "android.hardware.audio-impl_headers",
+    ],
 }
 
 cc_library_shared {
@@ -89,8 +104,8 @@
     ],
 }
 
-cc_library_shared {
-    name: "android.hardware.audio@6.0-impl",
+cc_defaults {
+    name: "android.hardware.audio@6.0-impl_default",
     defaults: ["android.hardware.audio-impl_default"],
     shared_libs: [
         "android.hardware.audio@6.0",
@@ -103,3 +118,8 @@
         "-include common/all-versions/VersionMacro.h",
     ],
 }
+
+cc_library_shared {
+    name: "android.hardware.audio@6.0-impl",
+    defaults: ["android.hardware.audio@6.0-impl_default"],
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index d5af335..10a1144 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -331,6 +331,9 @@
 INSTANTIATE_TEST_CASE_P(AudioHidl, AudioPolicyConfigTest,
                         ::testing::ValuesIn(getDeviceParametersForFactoryTests()),
                         &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioPolicyConfigTest);
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////// getService audio_devices_factory //////////////////////
@@ -366,6 +369,9 @@
 INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest,
                         ::testing::ValuesIn(getDeviceParametersForFactoryTests()),
                         &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioHidlTest);
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// openDevice ///////////////////////////////////
@@ -391,6 +397,9 @@
 
 INSTANTIATE_TEST_CASE_P(AudioHidlDevice, AudioHidlDeviceTest,
                         ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioHidlDeviceTest);
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// openDevice primary ///////////////////////////
@@ -418,6 +427,9 @@
 INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest,
                         ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
                         &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioPrimaryHidlTest);
 
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
@@ -513,6 +525,10 @@
 INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest,
                         ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
                         &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BoolAccessorHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BoolAccessorPrimaryHidlTest);
 
 using FloatAccessorHidlTest = AccessorHidlTest<float>;
 TEST_P(FloatAccessorHidlTest, MasterVolumeTest) {
@@ -525,6 +541,9 @@
 
 INSTANTIATE_TEST_CASE_P(FloatAccessorHidl, FloatAccessorHidlTest,
                         ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FloatAccessorHidlTest);
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////// AudioPatches ////////////////////////////////
@@ -547,6 +566,9 @@
 
 INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest,
                         ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioPatchHidlTest);
 
 // Nesting a tuple in another tuple allows to use GTest Combine function to generate
 // all combinations of devices and configs.
@@ -717,11 +739,15 @@
                 ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()),
                 ::testing::Values(AudioInputFlag::NONE)),
         &DeviceConfigParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OptionalInputBufferSizeTest);
 #elif MAJOR_VERSION >= 6
 INSTANTIATE_TEST_CASE_P(SupportedInputBufferSize, RequiredInputBufferSizeTest,
                         ::testing::ValuesIn(getInputDeviceConfigParameters()),
                         &DeviceConfigParameterToString);
 #endif
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RequiredInputBufferSizeTest);
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// setScreenState ///////////////////////////////
@@ -960,6 +986,9 @@
                         ::testing::ValuesIn(getOutputDeviceConfigParameters()),
                         &DeviceConfigParameterToString);
 #endif
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamTest);
 
 ////////////////////////////// openInputStream //////////////////////////////
 
@@ -1015,6 +1044,9 @@
                         ::testing::ValuesIn(getInputDeviceConfigParameters()),
                         &DeviceConfigParameterToString);
 #endif
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamTest);
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////////// IStream getters ///////////////////////////////
@@ -1553,6 +1585,9 @@
 INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest,
                         ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
                         &DeviceParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TtyModeAccessorPrimaryHidlTest);
 
 TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) {
     doc::test("Query and set the HAC state");
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 070242f..4787c09 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -845,3 +845,9 @@
                                    IEffectsFactory::descriptor)),
                            ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
         EffectParameterToString);
+// When the VTS test runs on a device lacking the corresponding HAL version the parameter
+// list is empty, this isn't a problem.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectsFactoryHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerAudioEffectHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerAudioEffectHidlTest);
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
index 928ad13..d49b9ab 100644
--- a/automotive/can/1.0/default/libnetdevice/Android.bp
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -28,6 +28,7 @@
         "protocols/generic/Unknown.cpp",
         "protocols/route/Link.cpp",
         "protocols/route/Route.cpp",
+        "protocols/route/structs.cpp",
         "protocols/MessageDefinition.cpp",
         "protocols/NetlinkProtocol.cpp",
         "protocols/all.cpp",
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
index 22cdbdb..91149c0 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -27,7 +27,8 @@
  */
 static constexpr bool kSuperVerbose = false;
 
-NetlinkSocket::NetlinkSocket(int protocol) : mProtocol(protocol) {
+NetlinkSocket::NetlinkSocket(int protocol, unsigned int pid, uint32_t groups)
+    : mProtocol(protocol) {
     mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
     if (!mFd.ok()) {
         PLOG(ERROR) << "Can't open Netlink socket";
@@ -35,21 +36,23 @@
         return;
     }
 
-    struct sockaddr_nl sa = {};
+    sockaddr_nl sa = {};
     sa.nl_family = AF_NETLINK;
+    sa.nl_pid = pid;
+    sa.nl_groups = groups;
 
-    if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
+    if (bind(mFd.get(), reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) < 0) {
         PLOG(ERROR) << "Can't bind Netlink socket";
         mFd.reset();
         mFailed = true;
     }
 }
 
-bool NetlinkSocket::send(struct nlmsghdr* nlmsg, size_t totalLen) {
+bool NetlinkSocket::send(nlmsghdr* nlmsg, size_t totalLen) {
     if constexpr (kSuperVerbose) {
         nlmsg->nlmsg_seq = mSeq;
-        LOG(VERBOSE) << (mFailed ? "(not)" : "")
-                     << "sending Netlink message: " << toString(nlmsg, totalLen, mProtocol);
+        LOG(VERBOSE) << (mFailed ? "(not) " : "")
+                     << "sending Netlink message: " << toString({nlmsg, totalLen}, mProtocol);
     }
 
     if (mFailed) return false;
@@ -58,12 +61,12 @@
     nlmsg->nlmsg_seq = mSeq++;
     nlmsg->nlmsg_flags |= NLM_F_ACK;
 
-    struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
+    iovec iov = {nlmsg, nlmsg->nlmsg_len};
 
-    struct sockaddr_nl sa = {};
+    sockaddr_nl sa = {};
     sa.nl_family = AF_NETLINK;
 
-    struct msghdr msg = {};
+    msghdr msg = {};
     msg.msg_name = &sa;
     msg.msg_namelen = sizeof(sa);
     msg.msg_iov = &iov;
@@ -76,15 +79,65 @@
     return true;
 }
 
+bool NetlinkSocket::send(const nlbuf<nlmsghdr>& msg, const sockaddr_nl& sa) {
+    if constexpr (kSuperVerbose) {
+        LOG(VERBOSE) << (mFailed ? "(not) " : "")
+                     << "sending Netlink message: " << toString(msg, mProtocol);
+    }
+
+    if (mFailed) return false;
+    const auto rawMsg = msg.getRaw();
+    const auto bytesSent = sendto(mFd.get(), rawMsg.ptr(), rawMsg.len(), 0,
+                                  reinterpret_cast<const sockaddr*>(&sa), sizeof(sa));
+    if (bytesSent < 0) {
+        PLOG(ERROR) << "Can't send Netlink message";
+        return false;
+    }
+    return true;
+}
+
+std::optional<nlbuf<nlmsghdr>> NetlinkSocket::receive(void* buf, size_t bufLen) {
+    sockaddr_nl sa = {};
+    return receive(buf, bufLen, sa);
+}
+
+std::optional<nlbuf<nlmsghdr>> NetlinkSocket::receive(void* buf, size_t bufLen, sockaddr_nl& sa) {
+    if (mFailed) return std::nullopt;
+
+    socklen_t saLen = sizeof(sa);
+    if (bufLen == 0) {
+        LOG(ERROR) << "Receive buffer has zero size!";
+        return std::nullopt;
+    }
+    const auto bytesReceived =
+            recvfrom(mFd.get(), buf, bufLen, MSG_TRUNC, reinterpret_cast<sockaddr*>(&sa), &saLen);
+    if (bytesReceived <= 0) {
+        PLOG(ERROR) << "Failed to receive Netlink message";
+        return std::nullopt;
+    } else if (unsigned(bytesReceived) > bufLen) {
+        PLOG(ERROR) << "Received data larger than the receive buffer! " << bytesReceived << " > "
+                    << bufLen;
+        return std::nullopt;
+    }
+
+    nlbuf<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(buf), bytesReceived);
+    if constexpr (kSuperVerbose) {
+        LOG(VERBOSE) << "received " << toString(msg, mProtocol);
+    }
+    return msg;
+}
+
+/* TODO(161389935): Migrate receiveAck to use nlmsg<> internally. Possibly reuse
+ * NetlinkSocket::receive(). */
 bool NetlinkSocket::receiveAck() {
     if (mFailed) return false;
 
     char buf[8192];
 
-    struct sockaddr_nl sa;
-    struct iovec iov = {buf, sizeof(buf)};
+    sockaddr_nl sa;
+    iovec iov = {buf, sizeof(buf)};
 
-    struct msghdr msg = {};
+    msghdr msg = {};
     msg.msg_name = &sa;
     msg.msg_namelen = sizeof(sa);
     msg.msg_iov = &iov;
@@ -102,11 +155,11 @@
         return false;
     }
 
-    for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
+    for (auto nlmsg = reinterpret_cast<nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
          nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
         if constexpr (kSuperVerbose) {
             LOG(VERBOSE) << "received Netlink response: "
-                         << toString(nlmsg, sizeof(buf), mProtocol);
+                         << toString({nlmsg, nlmsg->nlmsg_len}, mProtocol);
         }
 
         // We're looking for error/ack message only, ignoring others.
@@ -116,7 +169,7 @@
         }
 
         // Found error/ack message, return status.
-        auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
+        const auto nlerr = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(nlmsg));
         if (nlerr->error != 0) {
             LOG(ERROR) << "Received Netlink error message: " << strerror(-nlerr->error);
             return false;
@@ -127,4 +180,14 @@
     return false;
 }
 
+std::optional<unsigned int> NetlinkSocket::getSocketPid() {
+    sockaddr_nl sa = {};
+    socklen_t sasize = sizeof(sa);
+    if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
+        PLOG(ERROR) << "Failed to getsockname() for netlink_fd!";
+        return std::nullopt;
+    }
+    return sa.nl_pid;
+}
+
 }  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 387c91f..f2968fc 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -22,8 +22,6 @@
 
 namespace android::netdevice {
 
-socketparams::Params socketparams::current = general;
-
 unsigned int nametoindex(const std::string& ifname) {
     const auto ifidx = if_nametoindex(ifname.c_str());
     if (ifidx != 0) return ifidx;
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index b4f91bd..1e0d5b7 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -25,21 +25,6 @@
 
 namespace android::netdevice {
 
-namespace socketparams {
-
-struct Params {
-    int domain;
-    int type;
-    int protocol;
-};
-
-constexpr Params general = {AF_INET, SOCK_DGRAM, 0};
-constexpr Params can = {PF_CAN, SOCK_RAW, CAN_RAW};
-
-extern Params current;
-
-}  // namespace socketparams
-
 /**
  * Returns the index of a given network interface.
  *
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
index 9335021..8df6434 100644
--- a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
@@ -21,11 +21,35 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include <map>
+
 namespace android::netdevice::ifreqs {
 
+static constexpr int defaultSocketDomain = AF_INET;
+std::atomic_int socketDomain = defaultSocketDomain;
+
+struct SocketParams {
+    int domain;
+    int type;
+    int protocol;
+};
+
+static const std::map<int, SocketParams> socketParams = {
+        {AF_INET, {AF_INET, SOCK_DGRAM, 0}},
+        {AF_CAN, {AF_CAN, SOCK_RAW, CAN_RAW}},
+};
+
+static SocketParams getSocketParams(int domain) {
+    if (socketParams.count(domain)) return socketParams.find(domain)->second;
+
+    auto params = socketParams.find(defaultSocketDomain)->second;
+    params.domain = domain;
+    return params;
+}
+
 bool send(unsigned long request, struct ifreq& ifr) {
-    base::unique_fd sock(socket(socketparams::current.domain, socketparams::current.type,
-                                socketparams::current.protocol));
+    const auto sp = getSocketParams(socketDomain);
+    base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol));
     if (!sock.ok()) {
         LOG(ERROR) << "Can't create socket";
         return false;
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.h b/automotive/can/1.0/default/libnetdevice/ifreqs.h
index 25a40a6..74e5877 100644
--- a/automotive/can/1.0/default/libnetdevice/ifreqs.h
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.h
@@ -23,6 +23,11 @@
 namespace android::netdevice::ifreqs {
 
 /**
+ * \see useSocketDomain()
+ */
+extern std::atomic_int socketDomain;
+
+/**
  * Sends ioctl interface request.
  *
  * \param request Request type (such as SIOCGIFFLAGS)
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/NetlinkSocket.h
index 8900ff7..826b6b8 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/NetlinkSocket.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/NetlinkSocket.h
@@ -19,9 +19,12 @@
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 #include <libnetdevice/NetlinkRequest.h>
+#include <libnetdevice/nlbuf.h>
 
 #include <linux/netlink.h>
 
+#include <optional>
+
 namespace android::netdevice {
 
 /**
@@ -31,12 +34,23 @@
  * use multiple instances over multiple threads.
  */
 struct NetlinkSocket {
-    NetlinkSocket(int protocol);
+    /**
+     * NetlinkSocket constructor.
+     *
+     * \param protocol the Netlink protocol to use.
+     * \param pid port id. Default value of 0 allows the kernel to assign us a unique pid. (NOTE:
+     * this is NOT the same as process id!)
+     * \param groups Netlink multicast groups to listen to. This is a 32-bit bitfield, where each
+     * bit is a different group. Default value of 0 means no groups are selected. See man netlink.7
+     * for more details.
+     */
+    NetlinkSocket(int protocol, unsigned int pid = 0, uint32_t groups = 0);
 
     /**
-     * Send Netlink message to Kernel.
+     * Send Netlink message to Kernel. The sequence number will be automatically incremented, and
+     * the NLM_F_ACK (request ACK) flag will be set.
      *
-     * \param msg Message to send, nlmsg_seq will be set to next sequence number
+     * \param msg Message to send.
      * \return true, if succeeded
      */
     template <class T, unsigned int BUFSIZE>
@@ -46,12 +60,47 @@
     }
 
     /**
+     * Send Netlink message. The message will be sent as is, without any modification.
+     *
+     * \param msg Message to send.
+     * \param sa Destination address.
+     * \return true, if succeeded
+     */
+    bool send(const nlbuf<nlmsghdr>& msg, const sockaddr_nl& sa);
+
+    /**
+     * Receive Netlink data.
+     *
+     * \param buf buffer to hold message data.
+     * \param bufLen length of buf.
+     * \return nlbuf with message data, std::nullopt on error.
+     */
+    std::optional<nlbuf<nlmsghdr>> receive(void* buf, size_t bufLen);
+
+    /**
+     * Receive Netlink data with address info.
+     *
+     * \param buf buffer to hold message data.
+     * \param bufLen length of buf.
+     * \param sa Blank struct that recvfrom will populate with address info.
+     * \return nlbuf with message data, std::nullopt on error.
+     */
+    std::optional<nlbuf<nlmsghdr>> receive(void* buf, size_t bufLen, sockaddr_nl& sa);
+
+    /**
      * Receive Netlink ACK message from Kernel.
      *
      * \return true if received ACK message, false in case of error
      */
     bool receiveAck();
 
+    /**
+     * Gets the PID assigned to mFd.
+     *
+     * \return pid that mSocket is bound to.
+     */
+    std::optional<unsigned int> getSocketPid();
+
   private:
     const int mProtocol;
 
@@ -59,7 +108,7 @@
     base::unique_fd mFd;
     bool mFailed = false;
 
-    bool send(struct nlmsghdr* msg, size_t totalLen);
+    bool send(nlmsghdr* msg, size_t totalLen);
 
     DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
 };
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index 037618a..9a26ff1 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -27,15 +27,14 @@
 typedef std::array<uint8_t, ETH_ALEN> hwaddr_t;
 
 /**
- * Configures libnetdevice to use PF_CAN sockets instead of AF_INET,
+ * Configures libnetdevice to use other socket domain than AF_INET,
  * what requires less permissive SEPolicy rules for a given process.
  *
- * In such case, the process would only be able to control CAN interfaces.
- *
- * TODO(b/158011272): consider less hacky solution
- * \param yes true to use CAN sockets, false for general sockets
+ * In such case, the process would only be able to control interfaces of a given kind.
+
+ * \param domain Socket domain to use (e.g. AF_CAN), see socket(2) for details
  */
-void useCanSockets(bool yes);
+void useSocketDomain(int domain);
 
 /**
  * Checks, if the network interface exists.
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/nlbuf.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/nlbuf.h
index f7e53be..601ab94 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/nlbuf.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/nlbuf.h
@@ -53,6 +53,12 @@
     static constexpr size_t hdrlen = align(sizeof(T));
 
   public:
+    /**
+     * Constructor for nlbuf.
+     *
+     * \param data A pointer to the data the nlbuf wraps.
+     * \param bufferLen Length of buffer.
+     */
     nlbuf(const T* data, size_t bufferLen) : mData(data), mBufferEnd(pointerAdd(data, bufferLen)) {}
 
     const T* operator->() const {
@@ -60,9 +66,12 @@
         return mData;
     }
 
-    std::optional<std::reference_wrapper<const T>> getFirst() const {
-        if (!ok()) return std::nullopt;
-        return *mData;
+    std::pair<bool, const T&> getFirst() const {
+        if (!ok()) {
+            static const T dummy = {};
+            return {false, dummy};
+        }
+        return {true, *mData};
     }
 
     /**
@@ -135,7 +144,7 @@
         size_t len() const { return mBuffer.remainingLength(); }
 
       private:
-        const nlbuf<T>& mBuffer;
+        const nlbuf<T> mBuffer;
     };
 
     raw_view getRaw() const { return {*this}; }
@@ -154,8 +163,12 @@
     size_t declaredLength() const {
         // We can't even fit a header, so let's return some absurd high value to trip off
         // buffer overflow checks.
-        if (sizeof(T) > remainingLength()) return std::numeric_limits<size_t>::max() / 2;
-        return declaredLengthImpl();
+        static constexpr size_t badHeaderLength = std::numeric_limits<size_t>::max() / 2;
+
+        if (sizeof(T) > remainingLength()) return badHeaderLength;
+        const auto len = declaredLengthImpl();
+        if (sizeof(T) > len) return badHeaderLength;
+        return len;
     }
 
     size_t remainingLength() const {
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h
index efeb6b1..071fa63 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h
@@ -16,12 +16,22 @@
 
 #pragma once
 
+#include <libnetdevice/nlbuf.h>
+
 #include <linux/netlink.h>
 
 #include <string>
 
 namespace android::netdevice {
 
-std::string toString(const nlmsghdr* hdr, size_t bufLen, int protocol);
+/**
+ * Stringify a Netlink message.
+ *
+ * \param hdr Pointer to the message(s) to print.
+ * \param protocol Which Netlink protocol hdr uses.
+ * \param printPayload True will stringify message data, false will only stringify the header(s).
+ * \return Stringified message.
+ */
+std::string toString(const nlbuf<nlmsghdr> hdr, int protocol, bool printPayload = false);
 
 }  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index 4bba5f6..4293cad 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -28,8 +28,8 @@
 
 namespace android::netdevice {
 
-void useCanSockets(bool yes) {
-    socketparams::current = yes ? socketparams::can : socketparams::general;
+void useSocketDomain(int domain) {
+    ifreqs::socketDomain = domain;
 }
 
 bool exists(std::string ifname) {
diff --git a/automotive/can/1.0/default/libnetdevice/printer.cpp b/automotive/can/1.0/default/libnetdevice/printer.cpp
index a8715da..f6c9c60 100644
--- a/automotive/can/1.0/default/libnetdevice/printer.cpp
+++ b/automotive/can/1.0/default/libnetdevice/printer.cpp
@@ -62,13 +62,20 @@
 }
 
 static void toStream(std::stringstream& ss, const nlbuf<uint8_t> data) {
+    const auto rawData = data.getRaw();
+    const auto dataLen = rawData.len();
     ss << std::hex;
+    if (dataLen > 16) ss << std::endl << " 0000 ";
     int i = 0;
-    for (const auto byte : data.getRaw()) {
+    for (const auto byte : rawData) {
         if (i++ > 0) ss << ' ';
         ss << std::setw(2) << unsigned(byte);
+        if (i % 16 == 0) {
+            ss << std::endl << ' ' << std::dec << std::setw(4) << i << std::hex;
+        }
     }
     ss << std::dec;
+    if (dataLen > 16) ss << std::endl;
 }
 
 static void toStream(std::stringstream& ss, const nlbuf<nlattr> attr,
@@ -78,17 +85,16 @@
 
     ss << attrtype.name << ": ";
     switch (attrtype.dataType) {
-        case DataType::Raw: {
+        case DataType::Raw:
             toStream(ss, attr.data<uint8_t>());
             break;
-        }
         case DataType::Nested: {
             ss << '{';
             bool first = true;
-            for (auto childattr : attr.data<nlattr>()) {
+            for (const auto childattr : attr.data<nlattr>()) {
                 if (!first) ss << ", ";
                 first = false;
-                toStream(ss, childattr, attrtype.subTypes);
+                toStream(ss, childattr, std::get<protocols::AttributeMap>(attrtype.ops));
             }
             ss << '}';
             break;
@@ -98,14 +104,19 @@
             ss << '"' << sanitize({str.ptr(), str.len()}) << '"';
             break;
         }
-        case DataType::Uint: {
+        case DataType::Uint:
             ss << attr.data<uint32_t>().copyFirst();
             break;
+        case DataType::Struct: {
+            const auto structToStream =
+                    std::get<protocols::AttributeDefinition::ToStream>(attrtype.ops);
+            structToStream(ss, attr);
+            break;
         }
     }
 }
 
-static std::string toString(const nlbuf<nlmsghdr> hdr, int protocol) {
+std::string toString(const nlbuf<nlmsghdr> hdr, int protocol, bool printPayload) {
     if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
 
     std::stringstream ss;
@@ -133,10 +144,13 @@
     }
     if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq;
     if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid;
+    ss << ", len=" << hdr->nlmsg_len;
 
     ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec;
     ss << "} ";
 
+    if (!printPayload) return ss.str();
+
     if (!msgDescMaybe.has_value()) {
         toStream(ss, hdr.data<uint8_t>());
     } else {
@@ -161,8 +175,4 @@
     return ss.str();
 }
 
-std::string toString(const nlmsghdr* hdr, size_t bufLen, int protocol) {
-    return toString({hdr, bufLen}, protocol);
-}
-
 }  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h
index a25e885..3a8b2b5 100644
--- a/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h
+++ b/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h
@@ -21,6 +21,7 @@
 
 #include <map>
 #include <sstream>
+#include <variant>
 
 namespace android::netdevice::protocols {
 
@@ -57,11 +58,13 @@
         Nested,
         String,
         Uint,
+        Struct,
     };
+    using ToStream = std::function<void(std::stringstream& ss, const nlbuf<nlattr> attr)>;
 
     std::string name;
     DataType dataType = DataType::Raw;
-    AttributeMap subTypes = {};
+    std::variant<AttributeMap, ToStream> ops = AttributeMap{};
 };
 
 /**
@@ -107,13 +110,13 @@
         : MessageDescriptor(name, messageTypes, attrTypes, sizeof(T)) {}
 
     void dataToStream(std::stringstream& ss, const nlbuf<nlmsghdr> hdr) const override {
-        const auto msg = hdr.data<T>().getFirst();
-        if (!msg.has_value()) {
+        const auto& [ok, msg] = hdr.data<T>().getFirst();
+        if (!ok) {
             ss << "{incomplete payload}";
             return;
         }
 
-        toStream(ss, *msg);
+        toStream(ss, msg);
     }
 
   protected:
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp b/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp
index d42a50a..25ae680 100644
--- a/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp
+++ b/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp
@@ -30,7 +30,7 @@
 
 void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
     ss << "nlmsgerr{error=" << data.error
-       << ", msg=" << toString(&data.msg, sizeof(data.msg), mProtocol) << "}";
+       << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol) << "}";
 }
 
 }  // namespace android::netdevice::protocols::base
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp b/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp
index 08b2be7..4120008 100644
--- a/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp
@@ -37,14 +37,14 @@
     {CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
     {CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
     {CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
-    {CTRL_ATTR_OPS, {"OPS", DataType::Nested, {
-        {std::nullopt, {"OP", DataType::Nested, {
+    {CTRL_ATTR_OPS, {"OPS", DataType::Nested, AttributeMap{
+        {std::nullopt, {"OP", DataType::Nested, AttributeMap{
             {CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
             {CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
         }}},
     }}},
-    {CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, {
-        {std::nullopt, {"GRP", DataType::Nested, {
+    {CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, AttributeMap{
+        {std::nullopt, {"GRP", DataType::Nested, AttributeMap{
             {CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::String}},
             {CTRL_ATTR_MCAST_GRP_ID, {"ID", DataType::Uint}},
         }}},
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp b/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp
index 4617d92..53e1700 100644
--- a/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp
@@ -16,6 +16,10 @@
 
 #include "Link.h"
 
+#include "structs.h"
+
+#include <net/if.h>
+
 namespace android::netdevice::protocols::route {
 
 using DataType = AttributeDefinition::DataType;
@@ -29,62 +33,76 @@
     {IFLA_ADDRESS, {"ADDRESS"}},
     {IFLA_BROADCAST, {"BROADCAST"}},
     {IFLA_IFNAME, {"IFNAME", DataType::String}},
-    {IFLA_MTU, {"MTU"}},
+    {IFLA_MTU, {"MTU", DataType::Uint}},
     {IFLA_LINK, {"LINK", DataType::Uint}},
-    {IFLA_QDISC, {"QDISC"}},
-    {IFLA_STATS, {"STATS"}},
+    {IFLA_QDISC, {"QDISC", DataType::String}},
+    {IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
     {IFLA_COST, {"COST"}},
     {IFLA_PRIORITY, {"PRIORITY"}},
-    {IFLA_MASTER, {"MASTER"}},
+    {IFLA_MASTER, {"MASTER", DataType::Uint}},
     {IFLA_WIRELESS, {"WIRELESS"}},
     {IFLA_PROTINFO, {"PROTINFO"}},
-    {IFLA_TXQLEN, {"TXQLEN"}},
-    {IFLA_MAP, {"MAP"}},
-    {IFLA_WEIGHT, {"WEIGHT"}},
-    {IFLA_OPERSTATE, {"OPERSTATE"}},
-    {IFLA_LINKMODE, {"LINKMODE"}},
-    {IFLA_LINKINFO, {"LINKINFO", DataType::Nested, {
+    {IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
+    {IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
+    {IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
+    {IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
+    {IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
+    {IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
         {IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
         {IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
         {IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
-        {IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND"}},
+        {IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
         {IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
     }}},
-    {IFLA_NET_NS_PID, {"NET_NS_PID"}},
-    {IFLA_IFALIAS, {"IFALIAS"}},
-    {IFLA_NUM_VF, {"NUM_VF"}},
+    {IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
+    {IFLA_IFALIAS, {"IFALIAS", DataType::String}},
+    {IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
     {IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
-    {IFLA_STATS64, {"STATS64"}},
+    {IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
     {IFLA_VF_PORTS, {"VF_PORTS"}},
     {IFLA_PORT_SELF, {"PORT_SELF"}},
-    {IFLA_AF_SPEC, {"AF_SPEC"}},
-    {IFLA_GROUP, {"GROUP"}},
-    {IFLA_NET_NS_FD, {"NET_NS_FD"}},
-    {IFLA_EXT_MASK, {"EXT_MASK"}},
-    {IFLA_PROMISCUITY, {"PROMISCUITY"}},
-    {IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES"}},
-    {IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES"}},
-    {IFLA_CARRIER, {"CARRIER"}},
+    {IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
+        {AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
+            {IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
+        }}},
+        {AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
+            {IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
+            {IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
+            {IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
+            {IFLA_INET6_MCAST, {"INET6_MCAST"}},
+            {IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
+            {IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
+            {IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
+            {IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
+        }}},
+    }}},
+    {IFLA_GROUP, {"GROUP", DataType::Uint}},
+    {IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
+    {IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
+    {IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
+    {IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
+    {IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
+    {IFLA_CARRIER, {"CARRIER", DataType::Uint}},
     {IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
-    {IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES"}},
+    {IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
     {IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
-    {IFLA_LINK_NETNSID, {"LINK_NETNSID"}},
-    {IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME"}},
-    {IFLA_PROTO_DOWN, {"PROTO_DOWN"}},
-    {IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS"}},
-    {IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE"}},
+    {IFLA_LINK_NETNSID, {"LINK_NETNSID"}},  // NLA_S32
+    {IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
+    {IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
+    {IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
+    {IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
     {IFLA_PAD, {"PAD"}},
     {IFLA_XDP, {"XDP"}},
-    {IFLA_EVENT, {"EVENT"}},
-    {IFLA_NEW_NETNSID, {"NEW_NETNSID"}},
-    {IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}},
-    {IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT"}},
-    {IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT"}},
-    {IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}},
-    {IFLA_MIN_MTU, {"MIN_MTU"}},
-    {IFLA_MAX_MTU, {"MAX_MTU"}},
+    {IFLA_EVENT, {"EVENT", DataType::Uint}},
+    {IFLA_NEW_NETNSID, {"NEW_NETNSID"}},  // NLA_S32
+    {IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}},  // NLA_S32
+    {IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
+    {IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
+    {IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}},  // NLA_S32
+    {IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
+    {IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
     {IFLA_PROP_LIST, {"PROP_LIST"}},
-    {IFLA_ALT_IFNAME, {"ALT_IFNAME"}},
+    {IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
     {IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
 }) {}
 // clang-format off
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/structs.cpp b/automotive/can/1.0/default/libnetdevice/protocols/route/structs.cpp
new file mode 100644
index 0000000..48d64f0
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/structs.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "structs.h"
+
+namespace android::netdevice::protocols::route {
+
+void mapToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+    const auto& [ok, data] = attr.data<rtnl_link_ifmap>().getFirst();
+    if (!ok) {
+        ss << "invalid structure";
+        return;
+    }
+    ss << '{'                        //
+       << data.mem_start << ','      //
+       << data.mem_end << ','        //
+       << data.base_addr << ','      //
+       << data.irq << ','            //
+       << unsigned(data.dma) << ','  //
+       << unsigned(data.port) << '}';
+}
+
+void ifla_cacheinfoToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+    const auto& [ok, data] = attr.data<ifla_cacheinfo>().getFirst();
+    if (!ok) {
+        ss << "invalid structure";
+        return;
+    }
+    ss << '{'                         //
+       << data.max_reasm_len << ','   //
+       << data.tstamp << ','          //
+       << data.reachable_time << ','  //
+       << data.retrans_time << '}';
+}
+
+}  // namespace android::netdevice::protocols::route
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/structs.h b/automotive/can/1.0/default/libnetdevice/protocols/route/structs.h
new file mode 100644
index 0000000..e532704
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/structs.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <libnetdevice/nlbuf.h>
+
+#include <linux/rtnetlink.h>
+
+#include <sstream>
+
+namespace android::netdevice::protocols::route {
+
+// rtnl_link_ifmap
+void mapToStream(std::stringstream& ss, const nlbuf<nlattr> attr);
+
+// ifla_cacheinfo
+void ifla_cacheinfoToStream(std::stringstream& ss, const nlbuf<nlattr> attr);
+
+template <typename T>
+void arrayToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+    ss << '{';
+    for (const auto it : attr.data<T>().getRaw()) {
+        ss << it << ',';
+    }
+    ss.seekp(-1, std::ios_base::cur);
+    ss << '}';
+}
+
+// rtnl_link_stats or rtnl_link_stats64
+template <typename T>
+void statsToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+    const auto& [ok, data] = attr.data<T>().getFirst();
+    if (!ok) {
+        ss << "invalid structure";
+        return;
+    }
+    ss << '{'                              //
+       << data.rx_packets << ','           //
+       << data.tx_packets << ','           //
+       << data.rx_bytes << ','             //
+       << data.tx_bytes << ','             //
+       << data.rx_errors << ','            //
+       << data.tx_errors << ','            //
+       << data.rx_dropped << ','           //
+       << data.tx_dropped << ','           //
+       << data.multicast << ','            //
+       << data.collisions << ','           //
+       << data.rx_length_errors << ','     //
+       << data.rx_over_errors << ','       //
+       << data.rx_crc_errors << ','        //
+       << data.rx_frame_errors << ','      //
+       << data.rx_fifo_errors << ','       //
+       << data.rx_missed_errors << ','     //
+       << data.tx_aborted_errors << ','    //
+       << data.tx_carrier_errors << ','    //
+       << data.tx_fifo_errors << ','       //
+       << data.tx_heartbeat_errors << ','  //
+       << data.tx_window_errors << ','     //
+       << data.rx_compressed << ','        //
+       << data.tx_compressed << ','        //
+       << data.rx_nohandler << '}';
+}
+
+}  // namespace android::netdevice::protocols::route
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
index b5801c0..9a9d322 100644
--- a/automotive/can/1.0/default/service.cpp
+++ b/automotive/can/1.0/default/service.cpp
@@ -28,7 +28,7 @@
     configureRpcThreadpool(16, true);
     LOG(DEBUG) << "CAN controller service starting...";
 
-    netdevice::useCanSockets(true);
+    netdevice::useSocketDomain(AF_CAN);
 
     sp<CanController> canController(new CanController);
     if (canController->registerAsService("socketcan") != OK) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
index 8c9ffb9..a5c2930 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
@@ -155,6 +155,15 @@
     }
 
     if (value.areaId != 0) {
+        if (value.value.int32Values.size() >= 2 &&
+            static_cast<SwitchUserMessageType>(value.value.int32Values[1]) ==
+                    SwitchUserMessageType::VEHICLE_REQUEST) {
+            // User HAL can also request a user switch, so we need to check it first
+            ALOGD("set(SWITCH_USER) called from lshal to emulate a vehicle request: %s",
+                  toString(value).c_str());
+            return std::unique_ptr<VehiclePropValue>(new VehiclePropValue(value));
+        }
+        // Otherwise, we store it
         ALOGD("set(SWITCH_USER) called from lshal; storing it: %s", toString(value).c_str());
         mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value));
         return {};
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 6b0d106..f0de4f7 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -201,8 +201,12 @@
 
     void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
 
-    void Test_setActiveConfigWithConstraints(
-            const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss);
+    struct TestParameters {
+        nsecs_t delayForChange;
+        bool refreshMiss;
+    };
+
+    void Test_setActiveConfigWithConstraints(const TestParameters& params);
 
     void sendRefreshFrame(const VsyncPeriodChangeTimeline*);
 
@@ -453,9 +457,7 @@
 }
 
 void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(
-        const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss) {
-    VsyncPeriodChangeTimeline timeline = {};
-
+        const TestParameters& params) {
     for (Display display : mComposerCallback->getDisplays()) {
         forEachTwoConfigs(display, [&](Config config1, Config config2) {
             mComposerClient->setActiveConfig(display, config1);
@@ -470,6 +472,10 @@
                 return;  // continue
             }
 
+            VsyncPeriodChangeTimeline timeline;
+            IComposerClient::VsyncPeriodChangeConstraints constraints = {
+                    .desiredTimeNanos = systemTime() + params.delayForChange,
+                    .seamlessRequired = false};
             EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
                                            display, config2, constraints, &timeline));
 
@@ -480,7 +486,7 @@
                         kReasonableTimeForChange.count());
 
             if (timeline.refreshRequired) {
-                if (refreshMiss) {
+                if (params.refreshMiss) {
                     // Miss the refresh frame on purpose to make sure the implementation sends a
                     // callback
                     std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms);
@@ -494,7 +500,7 @@
             // cases the implementation might have missed the deadline. In this case a new
             // timeline should have been provided.
             auto newTimeline = mComposerCallback->takeLastVsyncPeriodChangeTimeline();
-            if (timeline.refreshRequired && refreshMiss) {
+            if (timeline.refreshRequired && params.refreshMiss) {
                 EXPECT_TRUE(newTimeline.has_value());
             }
 
@@ -515,28 +521,16 @@
 }
 
 TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) {
-    IComposerClient::VsyncPeriodChangeConstraints constraints;
-
-    constraints.seamlessRequired = false;
-    constraints.desiredTimeNanos = systemTime();
-    Test_setActiveConfigWithConstraints(constraints, false);
+    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false});
 }
 
 TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) {
-    IComposerClient::VsyncPeriodChangeConstraints constraints;
-
-    constexpr nsecs_t kDelayForChange = 300'000'000;  // 300ms
-    constraints.seamlessRequired = false;
-    constraints.desiredTimeNanos = systemTime() + kDelayForChange;
-    Test_setActiveConfigWithConstraints(constraints, false);
+    Test_setActiveConfigWithConstraints({.delayForChange = 300'000'000,  // 300ms
+                                         .refreshMiss = false});
 }
 
 TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) {
-    IComposerClient::VsyncPeriodChangeConstraints constraints;
-
-    constraints.seamlessRequired = false;
-    constraints.desiredTimeNanos = systemTime();
-    Test_setActiveConfigWithConstraints(constraints, true);
+    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = true});
 }
 
 TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) {
diff --git a/health/1.0/default/convert.cpp b/health/1.0/default/convert.cpp
index 7f1e3c4..3680d4d 100644
--- a/health/1.0/default/convert.cpp
+++ b/health/1.0/default/convert.cpp
@@ -79,7 +79,7 @@
 
     hc->batteryCurrentAvgPath =
         android::String8(c.batteryCurrentAvgPath.c_str(),
-                         c.batteryCurrentNowPath.size());
+                         c.batteryCurrentAvgPath.size());
 
     hc->batteryChargeCounterPath =
         android::String8(c.batteryChargeCounterPath.c_str(),
diff --git a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
index 59c70eb..8092d5e 100644
--- a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
+++ b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
@@ -337,3 +337,6 @@
         PerInstance, TvInputHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITvInput::descriptor)),
         android::hardware::PrintInstanceNameToString);
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputHidlTest);
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index b122a05..9055a43 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -163,6 +163,7 @@
     mRecordFilterIds.clear();
     mFilters.clear();
     mLastUsedFilterId = -1;
+    mTunerService->removeDemux(mDemuxId);
 
     return Result::SUCCESS;
 }
@@ -318,6 +319,12 @@
     std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
     mFrontendInputThreadRunning = true;
 
+    if (!mDvrPlayback) {
+        ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
+        mFrontendInputThreadRunning = false;
+        return;
+    }
+
     while (mFrontendInputThreadRunning) {
         uint32_t efState = 0;
         status_t status = mDvrPlayback->getDvrEventFlag()->wait(
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index bb3b087..c3edac9 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -364,7 +364,7 @@
     for (int i = 0; i < totalFrames; i++) {
         frameData.resize(esMeta[i].len);
         pid = esMeta[i].isAudio ? audioPid : videoPid;
-        memcpy(dataOutputBuffer.data() + esMeta[i].startIndex, frameData.data(), esMeta[i].len);
+        memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
         // Send to the media filter
         if (isVirtualFrontend && isRecording) {
             // TODO validate record
@@ -479,4 +479,4 @@
 }  // namespace tuner
 }  // namespace tv
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 8bf0ec5..6561c92 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -42,6 +42,7 @@
     // Reset callback
     mCallback = nullptr;
     mIsLocked = false;
+    mTunerService->removeFrontend(mId);
 
     return Result::SUCCESS;
 }
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 48ce384..9a6ecf7 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -37,7 +37,6 @@
     // Static Frontends array to maintain local frontends information
     // Array index matches their FrontendId in the default impl
     mFrontendSize = 8;
-    mFrontends.resize(mFrontendSize);
     mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
     mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
     mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
@@ -48,7 +47,6 @@
     mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
 
     FrontendInfo::FrontendCapabilities caps;
-    mFrontendCaps.resize(mFrontendSize);
     caps = FrontendInfo::FrontendCapabilities();
     caps.dvbtCaps(FrontendDvbtCapabilities());
     mFrontendCaps[0] = caps;
@@ -236,6 +234,21 @@
     }
 }
 
+void Tuner::removeDemux(uint32_t demuxId) {
+    map<uint32_t, uint32_t>::iterator it;
+    for (it = mFrontendToDemux.begin(); it != mFrontendToDemux.end(); it++) {
+        if (it->second == demuxId) {
+            it = mFrontendToDemux.erase(it);
+            break;
+        }
+    }
+    mDemuxes.erase(demuxId);
+}
+
+void Tuner::removeFrontend(uint32_t frontendId) {
+    mFrontendToDemux.erase(frontendId);
+}
+
 void Tuner::frontendStopTune(uint32_t frontendId) {
     map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
     uint32_t demuxId;
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 5de568f..1c09d6c 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -65,14 +65,16 @@
 
     void frontendStartTune(uint32_t frontendId);
     void frontendStopTune(uint32_t frontendId);
+    void removeDemux(uint32_t demuxId);
+    void removeFrontend(uint32_t frontendId);
 
   private:
     virtual ~Tuner();
     // Static mFrontends array to maintain local frontends information
-    vector<sp<Frontend>> mFrontends;
-    vector<FrontendInfo::FrontendCapabilities> mFrontendCaps;
-    std::map<uint32_t, uint32_t> mFrontendToDemux;
-    std::map<uint32_t, sp<Demux>> mDemuxes;
+    map<uint32_t, sp<Frontend>> mFrontends;
+    map<uint32_t, FrontendInfo::FrontendCapabilities> mFrontendCaps;
+    map<uint32_t, uint32_t> mFrontendToDemux;
+    map<uint32_t, sp<Demux>> mDemuxes;
     // To maintain how many Frontends we have
     int mFrontendSize;
     // The last used demux id. Initial value is -1.
diff --git a/tv/tuner/1.0/vts/functional/DescramblerTests.cpp b/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
index d7440bc..2e27475 100644
--- a/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
+++ b/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
@@ -102,13 +102,13 @@
 
 AssertionResult DescramblerTests::setKeyToken(TunerKeyToken token) {
     Result status;
-    if (mDescrambler) {
+    if (!mDescrambler) {
         ALOGW("[vts] Descrambler is not opened yet.");
         return failure();
     }
 
     status = mDescrambler->setKeyToken(token);
-    if (status == Result::SUCCESS) {
+    if (status != Result::SUCCESS) {
         ALOGW("[vts] setKeyToken failed.");
         return failure();
     }
@@ -118,13 +118,13 @@
 
 AssertionResult DescramblerTests::addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
     Result status;
-    if (mDescrambler) {
+    if (!mDescrambler) {
         ALOGW("[vts] Descrambler is not opened yet.");
         return failure();
     }
 
     status = mDescrambler->addPid(pid, optionalSourceFilter);
-    if (status == Result::SUCCESS) {
+    if (status != Result::SUCCESS) {
         ALOGW("[vts] addPid failed.");
         return failure();
     }
@@ -134,13 +134,13 @@
 
 AssertionResult DescramblerTests::removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
     Result status;
-    if (mDescrambler) {
+    if (!mDescrambler) {
         ALOGW("[vts] Descrambler is not opened yet.");
         return failure();
     }
 
     status = mDescrambler->removePid(pid, optionalSourceFilter);
-    if (status == Result::SUCCESS) {
+    if (status != Result::SUCCESS) {
         ALOGW("[vts] removePid failed.");
         return failure();
     }
@@ -150,14 +150,14 @@
 
 AssertionResult DescramblerTests::closeDescrambler() {
     Result status;
-    if (mDescrambler) {
+    if (!mDescrambler) {
         ALOGW("[vts] Descrambler is not opened yet.");
         return failure();
     }
 
     status = mDescrambler->close();
     mDescrambler = nullptr;
-    if (status == Result::SUCCESS) {
+    if (status != Result::SUCCESS) {
         ALOGW("[vts] close Descrambler failed.");
         return failure();
     }
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 9318bc4..4521824 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -292,18 +292,18 @@
         ASSERT_TRUE(mFilterTests.configFilter((*config).settings, filterId));
         filterIds.insert(filterId);
     }
-    mDescramblerTests.openDescrambler(demuxId);
+    ASSERT_TRUE(mDescramblerTests.openDescrambler(demuxId));
     TunerKeyToken token;
     ASSERT_TRUE(mDescramblerTests.getKeyToken(descConfig.casSystemId, descConfig.provisionStr,
                                               descConfig.hidlPvtData, token));
-    mDescramblerTests.setKeyToken(token);
+    ASSERT_TRUE(mDescramblerTests.setKeyToken(token));
     vector<DemuxPid> pids;
     DemuxPid pid;
     for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
         ASSERT_TRUE(mDescramblerTests.getDemuxPidFromFilterSettings((*config).type,
                                                                     (*config).settings, pid));
         pids.push_back(pid);
-        mDescramblerTests.addPid(pid, nullptr);
+        ASSERT_TRUE(mDescramblerTests.addPid(pid, nullptr));
     }
     for (id = filterIds.begin(); id != filterIds.end(); id++) {
         ASSERT_TRUE(mFilterTests.startFilter(*id));
@@ -316,9 +316,9 @@
         ASSERT_TRUE(mFilterTests.stopFilter(*id));
     }
     for (auto pid : pids) {
-        mDescramblerTests.removePid(pid, nullptr);
+        ASSERT_TRUE(mDescramblerTests.removePid(pid, nullptr));
     }
-    mDescramblerTests.closeDescrambler();
+    ASSERT_TRUE(mDescramblerTests.closeDescrambler());
     for (id = filterIds.begin(); id != filterIds.end(); id++) {
         ASSERT_TRUE(mFilterTests.closeFilter(*id));
     }
@@ -410,9 +410,9 @@
                                                filterArray[TS_PCR0].bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(pcrFilterId));
     ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_PCR0].settings, pcrFilterId));
-    mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId);
+    ASSERT_TRUE(mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId));
     ASSERT_TRUE(pcrFilterId == avSyncHwId);
-    mDemuxTests.getAvSyncTime(pcrFilterId);
+    ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId));
     ASSERT_TRUE(mFilterTests.closeFilter(pcrFilterId));
     ASSERT_TRUE(mFilterTests.closeFilter(mediaFilterId));
     ASSERT_TRUE(mDemuxTests.closeDemux());
@@ -575,8 +575,8 @@
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
-    mDescramblerTests.openDescrambler(demuxId);
-    mDescramblerTests.closeDescrambler();
+    ASSERT_TRUE(mDescramblerTests.openDescrambler(demuxId));
+    ASSERT_TRUE(mDescramblerTests.closeDescrambler());
     ASSERT_TRUE(mDemuxTests.closeDemux());
     ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
@@ -628,4 +628,14 @@
         PerInstance, TunerDescramblerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
         android::hardware::PrintInstanceNameToString);
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerLnbHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDemuxHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFilterHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerPlaybackHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerRecordHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDescramblerHidlTest);
 }  // namespace
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index f38dda4..7377f78 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -302,7 +302,8 @@
     }
 
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
@@ -347,7 +348,8 @@
     }
 
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
@@ -413,7 +415,8 @@
     }
 
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 4020298..12bd122 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -419,7 +419,8 @@
     }
 
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
@@ -470,7 +471,8 @@
     }
 
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;