Merge "wifi: Upgrade hostapd HIDL to 1.3"
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 10a1144..01bdd69 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -739,7 +739,6 @@
::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()),
@@ -747,6 +746,7 @@
#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(OptionalInputBufferSizeTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RequiredInputBufferSizeTest);
//////////////////////////////////////////////////////////////////////////////
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 8b98e5e..2efe054 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -254,7 +254,7 @@
satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
if (rule.exclude) {
- // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+ // Any exclude rule being satisfied invalidates the whole filter set.
if (satisfied) return false;
} else {
anyNonExcludeRulePresent = true;
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index 0aa5afe..083f4f0 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -20,20 +20,21 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
#include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/netlink.h>
#include <linux/can/raw.h>
+#include <linux/rtnetlink.h>
namespace android::netdevice::can {
static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
base::unique_fd socket(const std::string& ifname) {
- struct sockaddr_can addr = {};
+ sockaddr_can addr = {};
addr.can_family = AF_CAN;
addr.can_ifindex = nametoindex(ifname);
if (addr.can_ifindex == 0) {
@@ -57,7 +58,7 @@
return {};
}
- if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+ if (0 != bind(sock.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
LOG(ERROR) << "Can't bind to CAN interface " << ifname;
return {};
}
@@ -66,31 +67,30 @@
}
bool setBitrate(std::string ifname, uint32_t bitrate) {
- struct can_bittiming bt = {};
+ can_bittiming bt = {};
bt.bitrate = bitrate;
- nl::NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
- const auto ifidx = nametoindex(ifname);
- if (ifidx == 0) {
+ req->ifi_index = nametoindex(ifname);
+ if (req->ifi_index == 0) {
LOG(ERROR) << "Can't find interface " << ifname;
return false;
}
- req.data().ifi_index = ifidx;
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, "can");
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, "can");
{
- auto infodata = req.nest(IFLA_INFO_DATA);
+ auto infodata = req.addNested(IFLA_INFO_DATA);
/* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
* and IFLA_CAN_CTRLMODE as well. */
- req.addattr(IFLA_CAN_BITTIMING, bt);
+ req.add(IFLA_CAN_BITTIMING, bt);
}
}
- nl::NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
}
} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 201909f..661e3f8 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -16,8 +16,6 @@
#pragma once
-#include <libnl++/nlbuf.h>
-
#include <linux/can.h>
#include <net/if.h>
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 9a26ff1..70cb688 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -20,6 +20,7 @@
#include <array>
#include <optional>
+#include <set>
#include <string>
namespace android::netdevice {
@@ -53,14 +54,34 @@
std::optional<bool> isUp(std::string ifname);
/**
- * Checks, if the network interface exists and is up.
- *
- * This is a convenience function to call both exists() and isUp().
- *
- * \param ifname Interface to check
- * \return true if the interface is up, false otherwise
+ * Interface condition to wait for.
*/
-bool existsAndIsUp(const std::string& ifname);
+enum class WaitCondition {
+ /**
+ * Interface is present (but not necessarily up).
+ */
+ PRESENT,
+
+ /**
+ * Interface is up.
+ */
+ PRESENT_AND_UP,
+
+ /**
+ * Interface is down or not present (disconnected) at all.
+ */
+ DOWN_OR_GONE,
+};
+
+/**
+ * Listens for interface changes until anticipated condition takes place.
+ *
+ * \param ifnames List of interfaces to watch for.
+ * \param cnd Awaited condition.
+ * \param allOf true if all interfaces need to satisfy the condition, false if only one satistying
+ * interface should stop the wait.
+ */
+void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true);
/**
* Brings network interface up.
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index 04381f2..4c5b309 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -20,12 +20,15 @@
#include "ifreqs.h"
#include <android-base/logging.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
#include <linux/can.h>
+#include <linux/rtnetlink.h>
#include <net/if.h>
+#include <sstream>
+
namespace android::netdevice {
void useSocketDomain(int domain) {
@@ -36,16 +39,6 @@
return nametoindex(ifname) != 0;
}
-std::optional<bool> isUp(std::string ifname) {
- auto ifr = ifreqs::fromName(ifname);
- if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
- return ifr.ifr_flags & IFF_UP;
-}
-
-bool existsAndIsUp(const std::string& ifname) {
- return exists(ifname) && isUp(ifname).value_or(false);
-}
-
bool up(std::string ifname) {
auto ifr = ifreqs::fromName(ifname);
if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
@@ -61,25 +54,25 @@
}
bool add(std::string dev, std::string type) {
- nl::NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK,
- NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
- req.addattr(IFLA_IFNAME, dev);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+ req.add(IFLA_IFNAME, dev);
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, type);
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, type);
}
- nl::NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
}
bool del(std::string dev) {
- nl::NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
- req.addattr(IFLA_IFNAME, dev);
+ nl::MessageFactory<ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
+ req.add(IFLA_IFNAME, dev);
- nl::NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
}
std::optional<hwaddr_t> getHwAddr(const std::string& ifname) {
@@ -101,6 +94,97 @@
return ifreqs::send(SIOCSIFHWADDR, ifr);
}
+std::optional<bool> isUp(std::string ifname) {
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
+ return ifr.ifr_flags & IFF_UP;
+}
+
+struct WaitState {
+ bool present;
+ bool up;
+
+ bool satisfied(WaitCondition cnd) const {
+ switch (cnd) {
+ case WaitCondition::PRESENT:
+ if (present) return true;
+ break;
+ case WaitCondition::PRESENT_AND_UP:
+ if (present && up) return true;
+ break;
+ case WaitCondition::DOWN_OR_GONE:
+ if (!present || !up) return true;
+ break;
+ }
+ return false;
+ }
+};
+
+static std::string toString(WaitCondition cnd) {
+ switch (cnd) {
+ case WaitCondition::PRESENT:
+ return "become present";
+ case WaitCondition::PRESENT_AND_UP:
+ return "come up";
+ case WaitCondition::DOWN_OR_GONE:
+ return "go down";
+ }
+}
+
+static std::string toString(const std::set<std::string>& ifnames) {
+ std::stringstream ss;
+ std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
+ auto str = ss.str();
+ str.pop_back();
+ return str;
+}
+
+void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) {
+ nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+
+ using StatesMap = std::map<std::string, WaitState>;
+ StatesMap states = {};
+ for (const auto ifname : ifnames) {
+ const auto present = exists(ifname);
+ const auto up = present && isUp(ifname).value_or(false);
+ states[ifname] = {present, up};
+ }
+
+ const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
+ return it.second.satisfied(cnd);
+ };
+ const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() {
+ if (allOf) {
+ return std::all_of(states.begin(), states.end(), mapConditionChecker);
+ } else {
+ return std::any_of(states.begin(), states.end(), mapConditionChecker);
+ }
+ };
+
+ if (isFullySatisfied()) return;
+
+ LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to "
+ << toString(cnd);
+ for (const auto rawMsg : sock) {
+ const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+ if (!msg.has_value()) continue;
+
+ const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
+ if (ifnames.count(ifname) == 0) continue;
+
+ const bool present = (msg->header.nlmsg_type != RTM_DELLINK);
+ const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0;
+ states[ifname] = {present, up};
+
+ if (isFullySatisfied()) {
+ LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
+ << " to " << toString(cnd);
+ return;
+ }
+ }
+ LOG(FATAL) << "Can't read Netlink socket";
+}
+
} // namespace android::netdevice
bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) {
diff --git a/automotive/can/1.0/default/libnetdevice/vlan.cpp b/automotive/can/1.0/default/libnetdevice/vlan.cpp
index bcc9345..ee02f7b 100644
--- a/automotive/can/1.0/default/libnetdevice/vlan.cpp
+++ b/automotive/can/1.0/default/libnetdevice/vlan.cpp
@@ -19,8 +19,10 @@
#include "common.h"
#include <android-base/logging.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+
+#include <linux/rtnetlink.h>
namespace android::netdevice::vlan {
@@ -31,23 +33,23 @@
return false;
}
- nl::NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK,
- NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
- req.addattr(IFLA_IFNAME, vlan);
- req.addattr<uint32_t>(IFLA_LINK, ethidx);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+ req.add(IFLA_IFNAME, vlan);
+ req.add<uint32_t>(IFLA_LINK, ethidx);
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, "vlan");
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, "vlan");
{
- auto linkinfo = req.nest(IFLA_INFO_DATA);
- req.addattr(IFLA_VLAN_ID, id);
+ auto linkinfo = req.addNested(IFLA_INFO_DATA);
+ req.add(IFLA_VLAN_ID, id);
}
}
- nl::NetlinkSocket sock(NETLINK_ROUTE);
- return sock.send(req) && sock.receiveAck();
+ nl::Socket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck(req);
}
} // namespace android::netdevice::vlan
diff --git a/automotive/can/1.0/default/libnl++/Android.bp b/automotive/can/1.0/default/libnl++/Android.bp
index cffefe7..4042b16 100644
--- a/automotive/can/1.0/default/libnl++/Android.bp
+++ b/automotive/can/1.0/default/libnl++/Android.bp
@@ -31,8 +31,9 @@
"protocols/MessageDefinition.cpp",
"protocols/NetlinkProtocol.cpp",
"protocols/all.cpp",
- "NetlinkRequest.cpp",
- "NetlinkSocket.cpp",
+ "Attributes.cpp",
+ "MessageFactory.cpp",
+ "Socket.cpp",
"common.cpp",
"printer.cpp",
],
diff --git a/automotive/can/1.0/default/libnl++/Attributes.cpp b/automotive/can/1.0/default/libnl++/Attributes.cpp
new file mode 100644
index 0000000..620f57b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Attributes.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <libnl++/Attributes.h>
+
+namespace android::nl {
+
+Attributes::Attributes() {}
+
+Attributes::Attributes(Buffer<nlattr> buffer) : Buffer<nlattr>(buffer) {}
+
+const Attributes::Index& Attributes::index() const {
+ if (mIndex.has_value()) return *mIndex;
+
+ mIndex = Index();
+ auto& index = *mIndex;
+
+ for (auto attr : static_cast<Buffer<nlattr>>(*this)) {
+ index.emplace(attr->nla_type, attr);
+ }
+
+ return index;
+}
+
+bool Attributes::contains(nlattrtype_t attrtype) const {
+ return index().count(attrtype) > 0;
+}
+
+/* Parser specializations for selected types (more to come if necessary). */
+
+template <>
+Attributes Attributes::parse(Buffer<nlattr> buf) {
+ return buf.data<nlattr>();
+}
+
+template <>
+std::string Attributes::parse(Buffer<nlattr> buf) {
+ const auto rawString = buf.data<char>().getRaw();
+ std::string str(rawString.ptr(), rawString.len());
+
+ str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
+
+ return str;
+}
+
+template <typename T>
+static T parseUnsigned(Buffer<nlattr> buf) {
+ return buf.data<T>().copyFirst();
+}
+
+template <>
+uint8_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint8_t>(buf);
+}
+
+template <>
+uint16_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint16_t>(buf);
+}
+
+template <>
+uint32_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint32_t>(buf);
+}
+
+template <>
+uint64_t Attributes::parse(Buffer<nlattr> buf) {
+ return parseUnsigned<uint64_t>(buf);
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/MessageFactory.cpp b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
new file mode 100644
index 0000000..6f35897
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 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 <libnl++/MessageFactory.h>
+
+#include <android-base/logging.h>
+#include <libnl++/bits.h>
+
+namespace android::nl {
+
+static nlattr* tail(nlmsghdr* msg) {
+ return reinterpret_cast<nlattr*>(uintptr_t(msg) + impl::align(msg->nlmsg_len));
+}
+
+nlattr* MessageFactoryBase::add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+ size_t dataLen) {
+ const auto totalAttrLen = impl::space<nlattr>(dataLen);
+ const auto newLen = impl::align(msg->nlmsg_len) + totalAttrLen;
+ if (newLen > maxLen) {
+ LOG(ERROR) << "Can't add attribute of size " << dataLen //
+ << " - exceeded maxLen: " << newLen << " > " << maxLen;
+ return nullptr;
+ }
+
+ auto attr = tail(msg);
+ attr->nla_len = totalAttrLen;
+ attr->nla_type = type;
+ if (dataLen > 0) memcpy(impl::data<nlattr, void>(attr), data, dataLen);
+
+ msg->nlmsg_len = newLen;
+ return attr;
+}
+
+void MessageFactoryBase::closeNested(nlmsghdr* msg, nlattr* nested) {
+ if (nested == nullptr) return;
+ nested->nla_len = uintptr_t(tail(msg)) - uintptr_t(nested);
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/NetlinkRequest.cpp b/automotive/can/1.0/default/libnl++/NetlinkRequest.cpp
deleted file mode 100644
index e9463d1..0000000
--- a/automotive/can/1.0/default/libnl++/NetlinkRequest.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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 <libnl++/NetlinkRequest.h>
-
-#include <android-base/logging.h>
-
-namespace android::nl::impl {
-
-static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
- return reinterpret_cast<struct rtattr*>( //
- reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
-}
-
-struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
- size_t dataLen) {
- size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
- if (newLen > maxLen) {
- LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
- return nullptr;
- }
-
- auto attr = nlmsg_tail(n);
- attr->rta_len = RTA_SPACE(dataLen);
- attr->rta_type = type;
- if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
-
- n->nlmsg_len = newLen;
- return attr;
-}
-
-struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
- return addattr_l(n, maxLen, type, nullptr, 0);
-}
-
-void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
- size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
- nest->rta_len = nestLen;
-}
-
-} // namespace android::nl::impl
diff --git a/automotive/can/1.0/default/libnl++/NetlinkSocket.cpp b/automotive/can/1.0/default/libnl++/NetlinkSocket.cpp
deleted file mode 100644
index 6f0f0c2..0000000
--- a/automotive/can/1.0/default/libnl++/NetlinkSocket.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2019 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 <libnl++/NetlinkSocket.h>
-
-#include <libnl++/printer.h>
-
-#include <android-base/logging.h>
-
-namespace android::nl {
-
-/**
- * Print all outbound/inbound Netlink messages.
- */
-static constexpr bool kSuperVerbose = false;
-
-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";
- mFailed = true;
- return;
- }
-
- sockaddr_nl sa = {};
- sa.nl_family = AF_NETLINK;
- sa.nl_pid = pid;
- sa.nl_groups = groups;
-
- 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(nlmsghdr* nlmsg, size_t totalLen) {
- if constexpr (kSuperVerbose) {
- nlmsg->nlmsg_seq = mSeq;
- LOG(VERBOSE) << (mFailed ? "(not) " : "")
- << "sending Netlink message: " << toString({nlmsg, totalLen}, mProtocol);
- }
-
- if (mFailed) return false;
-
- nlmsg->nlmsg_pid = 0; // kernel
- nlmsg->nlmsg_seq = mSeq++;
- nlmsg->nlmsg_flags |= NLM_F_ACK;
-
- iovec iov = {nlmsg, nlmsg->nlmsg_len};
-
- sockaddr_nl sa = {};
- sa.nl_family = AF_NETLINK;
-
- msghdr msg = {};
- msg.msg_name = &sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- if (sendmsg(mFd.get(), &msg, 0) < 0) {
- PLOG(ERROR) << "Can't send Netlink message";
- return false;
- }
- 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];
-
- sockaddr_nl sa;
- iovec iov = {buf, sizeof(buf)};
-
- msghdr msg = {};
- msg.msg_name = &sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- const ssize_t status = recvmsg(mFd.get(), &msg, 0);
- if (status < 0) {
- PLOG(ERROR) << "Failed to receive Netlink message";
- return false;
- }
- size_t remainingLen = status;
-
- if (msg.msg_flags & MSG_TRUNC) {
- LOG(ERROR) << "Failed to receive Netlink message: truncated";
- return false;
- }
-
- 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, nlmsg->nlmsg_len}, mProtocol);
- }
-
- // We're looking for error/ack message only, ignoring others.
- if (nlmsg->nlmsg_type != NLMSG_ERROR) {
- LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
- continue;
- }
-
- // Found error/ack message, return status.
- const auto nlerr = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(nlmsg));
- if (nlerr->error != 0) {
- LOG(ERROR) << "Received Netlink error message: " << strerror(-nlerr->error);
- return false;
- }
- return true;
- }
- // Couldn't find any error/ack messages.
- 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::nl
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
new file mode 100644
index 0000000..08683ca
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 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 <libnl++/Socket.h>
+
+#include <libnl++/printer.h>
+
+#include <android-base/logging.h>
+
+namespace android::nl {
+
+/**
+ * Print all outbound/inbound Netlink messages.
+ */
+static constexpr bool kSuperVerbose = false;
+
+Socket::Socket(int protocol, unsigned pid, uint32_t groups) : mProtocol(protocol) {
+ mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
+ if (!mFd.ok()) {
+ PLOG(ERROR) << "Can't open Netlink socket";
+ mFailed = true;
+ return;
+ }
+
+ sockaddr_nl sa = {};
+ sa.nl_family = AF_NETLINK;
+ sa.nl_pid = pid;
+ sa.nl_groups = groups;
+
+ if (bind(mFd.get(), reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) < 0) {
+ PLOG(ERROR) << "Can't bind Netlink socket";
+ mFd.reset();
+ mFailed = true;
+ }
+}
+
+bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
+ if constexpr (kSuperVerbose) {
+ LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
+ << toString(msg, mProtocol);
+ }
+ if (mFailed) return false;
+
+ mSeq = msg->nlmsg_seq;
+ 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;
+ } else if (size_t(bytesSent) != rawMsg.len()) {
+ LOG(ERROR) << "Can't send Netlink message: truncated message";
+ return false;
+ }
+ return true;
+}
+
+bool Socket::increaseReceiveBuffer(size_t maxSize) {
+ if (maxSize == 0) {
+ LOG(ERROR) << "Maximum receive size should not be zero";
+ return false;
+ }
+
+ if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
+ return true;
+}
+
+std::optional<Buffer<nlmsghdr>> Socket::receive(size_t maxSize) {
+ return receiveFrom(maxSize).first;
+}
+
+std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size_t maxSize) {
+ if (mFailed) return {std::nullopt, {}};
+
+ if (!increaseReceiveBuffer(maxSize)) return {std::nullopt, {}};
+
+ sockaddr_nl sa = {};
+ socklen_t saLen = sizeof(sa);
+ const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), maxSize, MSG_TRUNC,
+ reinterpret_cast<sockaddr*>(&sa), &saLen);
+
+ if (bytesReceived <= 0) {
+ PLOG(ERROR) << "Failed to receive Netlink message";
+ return {std::nullopt, {}};
+ } else if (size_t(bytesReceived) > maxSize) {
+ PLOG(ERROR) << "Received data larger than maximum receive size: " //
+ << bytesReceived << " > " << maxSize;
+ return {std::nullopt, {}};
+ }
+
+ Buffer<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(mReceiveBuffer.data()), bytesReceived);
+ if constexpr (kSuperVerbose) {
+ LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
+ }
+ return {msg, sa};
+}
+
+bool Socket::receiveAck(uint32_t seq) {
+ const auto nlerr = receive<nlmsgerr>({NLMSG_ERROR});
+ if (!nlerr.has_value()) return false;
+
+ if (nlerr->data.msg.nlmsg_seq != seq) {
+ LOG(ERROR) << "Received ACK for a different message (" << nlerr->data.msg.nlmsg_seq
+ << ", expected " << seq << "). Multi-message tracking is not implemented.";
+ return false;
+ }
+
+ if (nlerr->data.error == 0) return true;
+
+ LOG(WARNING) << "Received Netlink error message: " << strerror(-nlerr->data.error);
+ return false;
+}
+
+std::optional<Buffer<nlmsghdr>> Socket::receive(const std::set<nlmsgtype_t>& msgtypes,
+ size_t maxSize) {
+ if (mFailed || !increaseReceiveBuffer(maxSize)) return std::nullopt;
+
+ for (const auto rawMsg : *this) {
+ if (msgtypes.count(rawMsg->nlmsg_type) == 0) {
+ LOG(WARNING) << "Received (and ignored) unexpected Netlink message of type "
+ << rawMsg->nlmsg_type;
+ continue;
+ }
+
+ return rawMsg;
+ }
+
+ return std::nullopt;
+}
+
+std::optional<unsigned> Socket::getPid() {
+ if (mFailed) return std::nullopt;
+
+ sockaddr_nl sa = {};
+ socklen_t sasize = sizeof(sa);
+ if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
+ PLOG(ERROR) << "Failed to get PID of Netlink socket";
+ return std::nullopt;
+ }
+ return sa.nl_pid;
+}
+
+Socket::receive_iterator::receive_iterator(Socket& socket, bool end)
+ : mSocket(socket), mIsEnd(end) {
+ if (!end) receive();
+}
+
+Socket::receive_iterator Socket::receive_iterator::operator++() {
+ CHECK(!mIsEnd) << "Trying to increment end iterator";
+ ++mCurrent;
+ if (mCurrent.isEnd()) receive();
+ return *this;
+}
+
+bool Socket::receive_iterator::operator==(const receive_iterator& other) const {
+ if (mIsEnd != other.mIsEnd) return false;
+ if (mIsEnd && other.mIsEnd) return true;
+ return mCurrent == other.mCurrent;
+}
+
+const Buffer<nlmsghdr>& Socket::receive_iterator::operator*() const {
+ CHECK(!mIsEnd) << "Trying to dereference end iterator";
+ return *mCurrent;
+}
+
+void Socket::receive_iterator::receive() {
+ CHECK(!mIsEnd) << "Trying to receive on end iterator";
+ CHECK(mCurrent.isEnd()) << "Trying to receive without draining previous read";
+
+ const auto buf = mSocket.receive();
+ if (buf.has_value()) {
+ mCurrent = buf->begin();
+ } else {
+ mIsEnd = true;
+ }
+}
+
+Socket::receive_iterator Socket::begin() {
+ return {*this, false};
+}
+
+Socket::receive_iterator Socket::end() {
+ return {*this, true};
+}
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/common.cpp b/automotive/can/1.0/default/libnl++/common.cpp
index 7848646..23c2d94 100644
--- a/automotive/can/1.0/default/libnl++/common.cpp
+++ b/automotive/can/1.0/default/libnl++/common.cpp
@@ -32,16 +32,14 @@
return 0;
}
-std::string sanitize(std::string str) {
- str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
-
+std::string printableOnly(std::string str) {
const auto isInvalid = [](char c) { return !isprint(c); };
std::replace_if(str.begin(), str.end(), isInvalid, '?');
return str;
}
-uint16_t crc16(const nlbuf<uint8_t> data, uint16_t crc) {
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc) {
for (const auto byte : data.getRaw()) {
crc ^= byte;
for (unsigned i = 0; i < 8; i++) {
diff --git a/automotive/can/1.0/default/libnl++/common.h b/automotive/can/1.0/default/libnl++/common.h
index dc5777c..38263c5 100644
--- a/automotive/can/1.0/default/libnl++/common.h
+++ b/automotive/can/1.0/default/libnl++/common.h
@@ -16,7 +16,7 @@
#pragma once
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
#include <linux/can.h>
#include <net/if.h>
@@ -37,11 +37,14 @@
unsigned int nametoindex(const std::string& ifname);
/**
- * Sanitize a string of unknown contents.
+ * Filter a string against non-printable characters.
*
- * Trims the string to the first '\0' character and replaces all non-printable characters with '?'.
+ * Replaces all non-printable characters with '?'.
+ *
+ * \param str String to filter.
+ * \return Filtered string.
*/
-std::string sanitize(std::string str);
+std::string printableOnly(std::string str);
/**
* Calculates a (optionally running) CRC16 checksum.
@@ -54,6 +57,6 @@
* \param crc Previous CRC16 value to continue calculating running checksum
* \return CRC16 checksum
*/
-uint16_t crc16(const nlbuf<uint8_t> data, uint16_t crc = 0);
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc = 0);
} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
new file mode 100644
index 0000000..f16d997
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
@@ -0,0 +1,170 @@
+/*
+ * 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 <android-base/logging.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+#include <utils/Mutex.h>
+
+#include <map>
+
+namespace android::nl {
+
+/**
+ * Netlink attribute map.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message attributes. The class doesn't own the underlying data, so the instance is valid as long
+ * as the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+class Attributes : private Buffer<nlattr> {
+ public:
+ /**
+ * Constructs empty attribute map.
+ */
+ Attributes();
+
+ /**
+ * Construct attribute map from underlying buffer.
+ *
+ * \param buffer Source buffer pointing at the first attribute.
+ */
+ Attributes(Buffer<nlattr> buffer);
+
+ /**
+ * Checks, if the map contains given attribute type (key).
+ *
+ * \param attrtype Attribute type (such as IFLA_IFNAME).
+ * \return true if attribute is in the map, false otherwise.
+ */
+ bool contains(nlattrtype_t attrtype) const;
+
+ /**
+ * Fetches attribute of a given type by copying it.
+ *
+ * While this is quite efficient for simple types, fetching nested attribute creates a new copy
+ * of child attribute map. This may be costly if you calculate the index for child maps multiple
+ * times. Examples below.
+ *
+ * BAD:
+ * ```
+ * const auto flags = msg->attributes.
+ * get<nl::Attributes>(IFLA_AF_SPEC).
+ * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index lazy-calculated
+ * get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated
+ * const auto& cacheinfo = msg->attributes.
+ * get<nl::Attributes>(IFLA_AF_SPEC). // new instance of IFLA_AF_SPEC index
+ * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index calculated again
+ * getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // AF_INET6 calculated again
+ * ```
+ *
+ * GOOD:
+ * ```
+ * const auto inet6 = msg->attributes.
+ * get<nl::Attributes>(IFLA_AF_SPEC).
+ * get<nl::Attributes>(AF_INET6);
+ * const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated
+ * const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // index reused
+ * ```
+ *
+ * If the attribute doesn't exists, default value of a given type is returned and warning
+ * spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+ *
+ * \param attrtype Attribute to fetch.
+ * \return Attribute value.
+ */
+ template <typename T>
+ T get(nlattrtype_t attrtype) const {
+ const auto& ind = index();
+ const auto it = ind.find(attrtype);
+ if (it == ind.end()) {
+ LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+ return T{};
+ }
+
+ return parse<T>(it->second);
+ }
+
+ /**
+ * Fetches a reference to a given attribute's data.
+ *
+ * This method is intended for arbitrary structures not specialized with get(nlattrtype_t)
+ * template and slightly more efficient for larger payloads due to not copying its data.
+ *
+ * If the attribute doesn't exists, a reference to empty value of a given type is returned and
+ * warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+ *
+ * \param attrtype Attribute to fetch.
+ * \return Reference to the attribute's data.
+ */
+ template <typename T>
+ const T& getStruct(nlattrtype_t attrtype) const {
+ const auto& ind = index();
+ const auto it = ind.find(attrtype);
+ if (it == ind.end()) {
+ LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+ static const T empty = {};
+ return empty;
+ }
+
+ const auto& [ok, val] = it->second.data<T>().getFirst();
+ if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T);
+ return val;
+ }
+
+ private:
+ using Index = std::map<nlattrtype_t, Buffer<nlattr>>;
+
+ /**
+ * Attribute index.
+ *
+ * Since this field is not protected by mutex, the use of \see index() dependent methods
+ * (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the
+ * following assumptions:
+ *
+ * 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the
+ * buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the
+ * underlying data buffer.
+ *
+ * 2. Index calculation and access would come with performance penalty never justified in most
+ * or all use cases (see the previous point). Since Index is not a trivially assignable data
+ * structure, it's not possible to use it with atomic types only and avoid mutexes.
+ */
+ mutable std::optional<Index> mIndex;
+
+ /**
+ * Lazy-calculate and cache index.
+ *
+ * \return Attribute index.
+ */
+ const Index& index() const;
+
+ /**
+ * Parse attribute data into a specific type.
+ *
+ * \param buf Raw attribute data.
+ * \return Parsed data.
+ */
+ template <typename T>
+ static T parse(Buffer<nlattr> buf);
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
similarity index 71%
rename from automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h
rename to automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
index 4c0e581..bf83fbc 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/logging.h>
+#include <libnl++/bits.h>
#include <linux/netlink.h>
@@ -25,7 +26,7 @@
namespace android::nl {
/**
- * Buffer containing netlink structure (e.g. struct nlmsghdr, struct nlattr).
+ * Buffer wrapper containing netlink structure (e.g. nlmsghdr, nlattr).
*
* This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
*
@@ -33,7 +34,7 @@
* not be trusted - the value may either be larger than the buffer message is allocated in or
* smaller than the header itself (so it couldn't even fit itself).
*
- * As a solution, nlbuf<> keeps track of two lengths (both attribute for header with payload):
+ * As a solution, Buffer<> keeps track of two lengths (both attribute for header with payload):
* - buffer length - how much memory was allocated to a given structure
* - declared length - what nlmsg_len or nla_len says how long the structure is
*
@@ -42,24 +43,20 @@
* this template attempts to protect against.
*/
template <typename T>
-class nlbuf {
- // The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h
-
- static constexpr size_t alignto = NLMSG_ALIGNTO;
- static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
-
- static constexpr size_t align(size_t ptr) { return (ptr + alignto - 1) & ~(alignto - 1); }
-
- static constexpr size_t hdrlen = align(sizeof(T));
-
+class Buffer {
public:
/**
- * Constructor for nlbuf.
- *
- * \param data A pointer to the data the nlbuf wraps.
- * \param bufferLen Length of buffer.
+ * Constructs empty buffer of size 0.
*/
- nlbuf(const T* data, size_t bufferLen) : mData(data), mBufferEnd(pointerAdd(data, bufferLen)) {}
+ Buffer() : mData(nullptr), mBufferEnd(nullptr) {}
+
+ /**
+ * Buffer constructor.
+ *
+ * \param data A pointer to the data the Buffer wraps.
+ * \param bufLen Length of the buffer.
+ */
+ Buffer(const T* data, size_t bufLen) : mData(data), mBufferEnd(pointerAdd(data, bufLen)) {}
const T* operator->() const {
CHECK(firstOk()) << "buffer can't fit the first element's header";
@@ -68,8 +65,8 @@
std::pair<bool, const T&> getFirst() const {
if (!ok()) {
- static const T dummy = {};
- return {false, dummy};
+ static const T empty = {};
+ return {false, empty};
}
return {true, *mData};
}
@@ -78,7 +75,8 @@
* Copy the first element of the buffer.
*
* This is a memory-safe cast operation, useful for reading e.g. uint32_t values
- * from 1-byte buffer.
+ * from 1-byte buffer. If the buffer is smaller than the copied type, the rest is
+ * padded with default constructor output (usually zeros).
*/
T copyFirst() const {
T val = {};
@@ -89,38 +87,38 @@
bool firstOk() const { return sizeof(T) <= remainingLength(); }
template <typename D>
- const nlbuf<D> data(size_t offset = 0) const {
- // Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset)
- const D* dptr = reinterpret_cast<const D*>(uintptr_t(mData) + hdrlen + align(offset));
- return {dptr, dataEnd()};
+ const Buffer<D> data(size_t offset = 0) const {
+ return {impl::data<const T, const D>(mData, offset), dataEnd()};
}
class iterator {
public:
iterator() : mCurrent(nullptr, size_t(0)) {
- CHECK(!mCurrent.ok()) << "end() iterator should indicate it's beyond end";
+ CHECK(isEnd()) << "end() iterator should indicate it's beyond end";
}
- iterator(const nlbuf<T>& buf) : mCurrent(buf) {}
+ iterator(const Buffer<T>& buf) : mCurrent(buf) {}
iterator operator++() {
// mBufferEnd stays the same
mCurrent.mData = reinterpret_cast<const T*>( //
- uintptr_t(mCurrent.mData) + align(mCurrent.declaredLength()));
+ uintptr_t(mCurrent.mData) + impl::align(mCurrent.declaredLength()));
return *this;
}
bool operator==(const iterator& other) const {
// all iterators beyond end are the same
- if (!mCurrent.ok() && !other.mCurrent.ok()) return true;
+ if (isEnd() && other.isEnd()) return true;
return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
}
- const nlbuf<T>& operator*() const { return mCurrent; }
+ const Buffer<T>& operator*() const { return mCurrent; }
+
+ bool isEnd() const { return !mCurrent.ok(); }
protected:
- nlbuf<T> mCurrent;
+ Buffer<T> mCurrent;
};
iterator begin() const { return {*this}; }
iterator end() const { return {}; }
@@ -136,7 +134,7 @@
class raw_view {
public:
- raw_view(const nlbuf<T>& buffer) : mBuffer(buffer) {}
+ raw_view(const Buffer<T>& buffer) : mBuffer(buffer) {}
raw_iterator begin() const { return {mBuffer}; }
raw_iterator end() const { return {}; }
@@ -144,7 +142,7 @@
size_t len() const { return mBuffer.remainingLength(); }
private:
- const nlbuf<T> mBuffer;
+ const Buffer<T> mBuffer;
};
raw_view getRaw() const { return {*this}; }
@@ -153,7 +151,7 @@
const T* mData;
const void* mBufferEnd;
- nlbuf(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
+ Buffer(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
bool ok() const { return declaredLength() <= remainingLength(); }
@@ -186,16 +184,16 @@
}
template <typename D>
- friend class nlbuf; // calling private constructor of data buffers
+ friend class Buffer; // calling private constructor of data buffers
};
template <>
-inline size_t nlbuf<nlmsghdr>::declaredLengthImpl() const {
+inline size_t Buffer<nlmsghdr>::declaredLengthImpl() const {
return mData->nlmsg_len;
}
template <>
-inline size_t nlbuf<nlattr>::declaredLengthImpl() const {
+inline size_t Buffer<nlattr>::declaredLengthImpl() const {
return mData->nla_len;
}
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Message.h b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
new file mode 100644
index 0000000..50b3c4b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <libnl++/Attributes.h>
+#include <libnl++/Buffer.h>
+
+#include <set>
+
+namespace android::nl {
+
+/**
+ * In-place Netlink message parser.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message contents. The class doesn't own the underlying data, so the instance is valid as long as
+ * the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+template <typename T>
+class Message {
+ public:
+ /**
+ * Validate buffer contents as a message carrying T data and create instance of parsed message.
+ *
+ * \param buf Buffer containing the message.
+ * \return Parsed message or nullopt, if the buffer data is invalid.
+ */
+ static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf) {
+ const auto& [nlOk, nlHeader] = buf.getFirst();
+ if (!nlOk) return std::nullopt;
+
+ const auto& [dataOk, dataHeader] = buf.data<T>().getFirst();
+ if (!dataOk) return std::nullopt;
+
+ const auto attributes = buf.data<nlattr>(sizeof(T));
+
+ return Message<T>(nlHeader, dataHeader, attributes);
+ }
+
+ /**
+ * Validate buffer contents as a message of a given type and create instance of parsed message.
+ *
+ * \param buf Buffer containing the message.
+ * \param msgtypes Acceptable message types (within a specific Netlink protocol)
+ * \return Parsed message or nullopt, if the buffer data is invalid or message type
+ * doesn't match.
+ */
+ static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf,
+ const std::set<nlmsgtype_t>& msgtypes) {
+ const auto& [nlOk, nlHeader] = buf.getFirst(); // we're doing it twice, but it's fine
+ if (!nlOk) return std::nullopt;
+
+ if (msgtypes.count(nlHeader.nlmsg_type) == 0) return std::nullopt;
+
+ return parse(buf);
+ }
+
+ /**
+ * Netlink message header.
+ *
+ * This is a generic Netlink header containing information such as message flags.
+ */
+ const nlmsghdr& header;
+
+ /**
+ * Netlink message data.
+ *
+ * This is a payload specific to a given message type.
+ */
+ const T& data;
+
+ /**
+ * Netlink message attributes.
+ */
+ const Attributes attributes;
+
+ const T* operator->() const { return &data; }
+
+ private:
+ Message(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes)
+ : header(nlHeader), data(dataHeader), attributes(attributes) {}
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
new file mode 100644
index 0000000..c3d72c5
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 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 <android-base/macros.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+
+#include <linux/netlink.h>
+
+#include <string>
+
+namespace android::nl {
+
+class MessageFactoryBase {
+ protected:
+ static nlattr* add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+ size_t dataLen);
+ static void closeNested(nlmsghdr* msg, nlattr* nested);
+};
+
+/**
+ * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
+ *
+ * \param T Message payload type (such as ifinfomsg).
+ * \param BUFSIZE how much space to reserve for attributes.
+ */
+template <class T, unsigned int BUFSIZE = 128>
+class MessageFactory : private MessageFactoryBase {
+ struct alignas(NLMSG_ALIGNTO) Message {
+ nlmsghdr header;
+ T data;
+ uint8_t attributesBuffer[BUFSIZE];
+ };
+
+ public:
+ /**
+ * Create empty message.
+ *
+ * \param type Message type (such as RTM_NEWLINK).
+ * \param flags Message flags (such as NLM_F_REQUEST).
+ */
+ MessageFactory(nlmsgtype_t type, uint16_t flags)
+ : header(mMessage.header), data(mMessage.data) {
+ mMessage.header.nlmsg_len = offsetof(Message, attributesBuffer);
+ mMessage.header.nlmsg_type = type;
+ mMessage.header.nlmsg_flags = flags;
+ }
+
+ /**
+ * Netlink message header.
+ *
+ * This is a generic Netlink header containing information such as message flags.
+ */
+ nlmsghdr& header;
+
+ /**
+ * Netlink message data.
+ *
+ * This is a payload specific to a given message type.
+ */
+ T& data;
+
+ T* operator->() { return &mMessage.data; }
+
+ /**
+ * Build netlink message.
+ *
+ * In fact, this operation is almost a no-op, since the factory builds the message in a single
+ * buffer, using native data structures.
+ *
+ * A likely failure case is when the BUFSIZE template parameter is too small to acommodate
+ * added attributes. In such a case, please increase this parameter.
+ *
+ * \return Netlink message or std::nullopt in case of failure.
+ */
+ std::optional<Buffer<nlmsghdr>> build() const {
+ if (!mIsGood) return std::nullopt;
+ return {{&mMessage.header, mMessage.header.nlmsg_len}};
+ }
+
+ /**
+ * Adds an attribute of a trivially copyable type.
+ *
+ * Template specializations may extend this function for other types, such as std::string.
+ *
+ * If this method fails (i.e. due to insufficient space), a warning will be printed to the log
+ * and the message will be marked as bad, causing later \see build call to fail.
+ *
+ * \param type attribute type (such as IFLA_IFNAME)
+ * \param attr attribute data
+ */
+ template <class A>
+ void add(nlattrtype_t type, const A& attr) {
+ add(type, &attr, sizeof(attr));
+ }
+
+ template <>
+ void add(nlattrtype_t type, const std::string& s) {
+ add(type, s.c_str(), s.size() + 1);
+ }
+
+ /** Guard class to frame nested attributes. \see addNested(nlattrtype_t). */
+ class [[nodiscard]] NestedGuard {
+ public:
+ NestedGuard(MessageFactory & req, nlattrtype_t type) : mReq(req), mAttr(req.add(type)) {}
+ ~NestedGuard() { closeNested(&mReq.mMessage.header, mAttr); }
+
+ private:
+ MessageFactory& mReq;
+ nlattr* mAttr;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedGuard);
+ };
+
+ /**
+ * Add nested attribute.
+ *
+ * The returned object is a guard for auto-nesting children inside the argument attribute.
+ * When the guard object goes out of scope, the nesting attribute is closed.
+ *
+ * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
+ * inside IFLA_LINKINFO:
+ * MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+ * {
+ * auto linkinfo = req.addNested(IFLA_LINKINFO);
+ * req.add(IFLA_INFO_KIND, "can");
+ * {
+ * auto infodata = req.addNested(IFLA_INFO_DATA);
+ * req.add(IFLA_CAN_BITTIMING, bitTimingStruct);
+ * }
+ * }
+ * // use req
+ *
+ * \param type attribute type (such as IFLA_LINKINFO)
+ */
+ NestedGuard addNested(nlattrtype_t type) { return {*this, type}; }
+
+ private:
+ Message mMessage = {};
+ bool mIsGood = true;
+
+ nlattr* add(nlattrtype_t type, const void* data = nullptr, size_t len = 0) {
+ if (!mIsGood) return nullptr;
+ auto attr = MessageFactoryBase::add(&mMessage.header, sizeof(mMessage), type, data, len);
+ if (attr == nullptr) mIsGood = false;
+ return attr;
+ }
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkRequest.h b/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkRequest.h
deleted file mode 100644
index 3b30a2a..0000000
--- a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkRequest.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2019 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 <android-base/macros.h>
-#include <libnl++/types.h>
-
-#include <linux/rtnetlink.h>
-
-#include <string>
-
-namespace android::nl {
-
-/** Implementation details, do not use outside NetlinkRequest template. */
-namespace impl {
-
-// TODO(twasilczyk): use nlattr instead of rtattr
-struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
- size_t dataLen);
-struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
-void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
-
-} // namespace impl
-
-// TODO(twasilczyk): rename to NetlinkMessage
-/**
- * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
- *
- * \param T specific message header (such as struct ifinfomsg)
- * \param BUFSIZE how much space to reserve for payload (not counting the header size)
- */
-template <class T, unsigned int BUFSIZE = 128>
-struct NetlinkRequest {
- struct RequestData {
- struct nlmsghdr nlmsg;
- T data;
- char buf[BUFSIZE];
- };
-
- static constexpr size_t totalLength = sizeof(RequestData);
-
- /**
- * Create empty message.
- *
- * \param type Message type (such as RTM_NEWLINK)
- * \param flags Message flags (such as NLM_F_REQUEST)
- */
- NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
- mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
- mRequest.nlmsg.nlmsg_type = type;
- mRequest.nlmsg.nlmsg_flags = flags;
- }
-
- /** \return pointer to raw netlink message header. */
- struct nlmsghdr* header() {
- return &mRequest.nlmsg;
- }
- /** Reference to message-specific header. */
- T& data() { return mRequest.data; }
-
- /**
- * Adds an attribute of a simple type.
- *
- * If this method fails (i.e. due to insufficient space), the message will be marked
- * as bad (\see isGood).
- *
- * \param type attribute type (such as IFLA_IFNAME)
- * \param attr attribute data
- */
- template <class A>
- void addattr(rtattrtype_t type, const A& attr) {
- if (!mIsGood) return;
- auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
- if (ap == nullptr) mIsGood = false;
- }
-
- template <>
- void addattr(rtattrtype_t type, const std::string& s) {
- if (!mIsGood) return;
- auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
- if (ap == nullptr) mIsGood = false;
- }
-
- /** Guard class to frame nested attributes. See nest(int). */
- struct Nest {
- Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
- ~Nest() { mReq.nestEnd(mAttr); }
-
- private:
- NetlinkRequest& mReq;
- struct rtattr* mAttr;
-
- DISALLOW_COPY_AND_ASSIGN(Nest);
- };
-
- /**
- * Add nested attribute.
- *
- * The returned object is a guard for auto-nesting children inside the argument attribute.
- * When the Nest object goes out of scope, the nesting attribute is closed.
- *
- * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
- * inside IFLA_LINKINFO:
- * NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
- * {
- * auto linkinfo = req.nest(IFLA_LINKINFO);
- * req.addattr(IFLA_INFO_KIND, "can");
- * {
- * auto infodata = req.nest(IFLA_INFO_DATA);
- * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
- * }
- * }
- * // use req
- *
- * \param type attribute type (such as IFLA_LINKINFO)
- */
- Nest nest(int type) { return Nest(*this, type); }
-
- /**
- * Indicates, whether the message is in a good state.
- *
- * The bad state is usually a result of payload buffer being too small.
- * You can modify BUFSIZE template parameter to fix this.
- */
- bool isGood() const { return mIsGood; }
-
- private:
- bool mIsGood = true;
- RequestData mRequest = {};
-
- struct rtattr* nestStart(rtattrtype_t type) {
- if (!mIsGood) return nullptr;
- auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
- if (attr == nullptr) mIsGood = false;
- return attr;
- }
-
- void nestEnd(struct rtattr* nest) {
- if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
- }
-};
-
-} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkSocket.h b/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkSocket.h
deleted file mode 100644
index f2a38fb..0000000
--- a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkSocket.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2019 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 <android-base/macros.h>
-#include <android-base/unique_fd.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/nlbuf.h>
-
-#include <linux/netlink.h>
-
-#include <optional>
-
-namespace android::nl {
-
-/**
- * A wrapper around AF_NETLINK sockets.
- *
- * This class is not thread safe to use a single instance between multiple threads, but it's fine to
- * use multiple instances over multiple threads.
- */
-struct NetlinkSocket {
- /**
- * 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. The sequence number will be automatically incremented, and
- * the NLM_F_ACK (request ACK) flag will be set.
- *
- * \param msg Message to send.
- * \return true, if succeeded
- */
- template <class T, unsigned int BUFSIZE>
- bool send(NetlinkRequest<T, BUFSIZE>& req) {
- if (!req.isGood()) return false;
- return send(req.header(), req.totalLength);
- }
-
- /**
- * 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;
-
- uint32_t mSeq = 0;
- base::unique_fd mFd;
- bool mFailed = false;
-
- bool send(nlmsghdr* msg, size_t totalLen);
-
- DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
-};
-
-} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
new file mode 100644
index 0000000..c69523d
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2019 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 <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/Message.h>
+#include <libnl++/MessageFactory.h>
+
+#include <linux/netlink.h>
+
+#include <optional>
+#include <set>
+#include <vector>
+
+namespace android::nl {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+class Socket {
+ public:
+ static constexpr size_t defaultReceiveSize = 8192;
+
+ /**
+ * Socket 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.
+ */
+ Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
+
+ /**
+ * Send Netlink message with incremented sequence number to the Kernel.
+ *
+ * \param msg Message to send. Its sequence number will be updated.
+ * \return true, if succeeded.
+ */
+ template <typename T, unsigned BUFSIZE>
+ bool send(MessageFactory<T, BUFSIZE>& req) {
+ sockaddr_nl sa = {};
+ sa.nl_family = AF_NETLINK;
+ sa.nl_pid = 0; // Kernel
+ return send(req, sa);
+ }
+
+ /**
+ * Send Netlink message with incremented sequence number.
+ *
+ * \param msg Message to send. Its sequence number will be updated.
+ * \param sa Destination address.
+ * \return true, if succeeded.
+ */
+ template <typename T, unsigned BUFSIZE>
+ bool send(MessageFactory<T, BUFSIZE>& req, const sockaddr_nl& sa) {
+ req.header.nlmsg_seq = mSeq + 1;
+
+ const auto msg = req.build();
+ if (!msg.has_value()) return false;
+
+ return send(*msg, sa);
+ }
+
+ /**
+ * Send Netlink message.
+ *
+ * \param msg Message to send.
+ * \param sa Destination address.
+ * \return true, if succeeded.
+ */
+ bool send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa);
+
+ /**
+ * Receive one or multiple Netlink messages.
+ *
+ * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+ * call to the read function or until deallocation of Socket instance.
+ *
+ * \param maxSize Maximum total size of received messages
+ * \return Buffer view with message data, std::nullopt on error.
+ */
+ std::optional<Buffer<nlmsghdr>> receive(size_t maxSize = defaultReceiveSize);
+
+ /**
+ * Receive one or multiple Netlink messages and the sender process address.
+ *
+ * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+ * call to the read function or until deallocation of Socket instance.
+ *
+ * \param maxSize Maximum total size of received messages.
+ * \return A pair (for use with structured binding) containing:
+ * - buffer view with message data, std::nullopt on error;
+ * - sender process address.
+ */
+ std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> receiveFrom(
+ size_t maxSize = defaultReceiveSize);
+
+ /**
+ * Receive matching Netlink message of a given payload type.
+ *
+ * This method should be used if the caller expects exactly one incoming message of exactly
+ * given type (such as ACK). If there is a use case to handle multiple types of messages,
+ * please use receive(size_t) directly and iterate through potential multipart messages.
+ *
+ * If this method is used in such an environment, it will only return the first matching message
+ * from multipart packet and will issue warnings on messages that do not match.
+ *
+ * \param msgtypes Expected message types (such as NLMSG_ERROR).
+ * \param maxSize Maximum total size of received messages.
+ * \return Parsed message or std::nullopt in case of error.
+ */
+ template <typename T>
+ std::optional<Message<T>> receive(const std::set<nlmsgtype_t>& msgtypes,
+ size_t maxSize = defaultReceiveSize) {
+ const auto msg = receive(msgtypes, maxSize);
+ if (!msg.has_value()) return std::nullopt;
+
+ const auto parsed = Message<T>::parse(*msg);
+ if (!parsed.has_value()) {
+ LOG(WARNING) << "Received matching Netlink message, but couldn't parse it";
+ return std::nullopt;
+ }
+
+ return parsed;
+ }
+
+ /**
+ * Receive Netlink ACK message.
+ *
+ * \param req Message to match sequence number against.
+ * \return true if received ACK message, false in case of error.
+ */
+ template <typename T, unsigned BUFSIZE>
+ bool receiveAck(MessageFactory<T, BUFSIZE>& req) {
+ return receiveAck(req.header.nlmsg_seq);
+ }
+
+ /**
+ * Receive Netlink ACK message.
+ *
+ * \param seq Sequence number of message to ACK.
+ * \return true if received ACK message, false in case of error.
+ */
+ bool receiveAck(uint32_t seq);
+
+ /**
+ * Fetches the socket PID.
+ *
+ * \return PID that socket is bound to or std::nullopt.
+ */
+ std::optional<unsigned> getPid();
+
+ /**
+ * Live iterator continuously receiving messages from Netlink socket.
+ *
+ * Iteration ends when socket fails to receive a buffer.
+ *
+ * Example:
+ * ```
+ * nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+ * for (const auto rawMsg : sock) {
+ * const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+ * if (!msg.has_value()) continue;
+ *
+ * LOG(INFO) << msg->attributes.get<std::string>(IFLA_IFNAME)
+ * << " is " << ((msg->data.ifi_flags & IFF_UP) ? "up" : "down");
+ * }
+ * LOG(FATAL) << "Failed to read from Netlink socket";
+ * ```
+ */
+ class receive_iterator {
+ public:
+ receive_iterator(Socket& socket, bool end);
+
+ receive_iterator operator++();
+ bool operator==(const receive_iterator& other) const;
+ const Buffer<nlmsghdr>& operator*() const;
+
+ private:
+ Socket& mSocket;
+ bool mIsEnd;
+ Buffer<nlmsghdr>::iterator mCurrent;
+
+ void receive();
+ };
+ receive_iterator begin();
+ receive_iterator end();
+
+ private:
+ const int mProtocol;
+ base::unique_fd mFd;
+ std::vector<uint8_t> mReceiveBuffer;
+
+ bool mFailed = false;
+ uint32_t mSeq = 0;
+
+ bool increaseReceiveBuffer(size_t maxSize);
+ std::optional<Buffer<nlmsghdr>> receive(const std::set<nlmsgtype_t>& msgtypes, size_t maxSize);
+
+ DISALLOW_COPY_AND_ASSIGN(Socket);
+};
+
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/bits.h b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
new file mode 100644
index 0000000..4c8f1aa
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
@@ -0,0 +1,54 @@
+/*
+ * 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 <linux/netlink.h>
+
+namespace android::nl::impl {
+
+// The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h.
+
+/**
+ * Equivalent to NLMSG_ALIGNTO.
+ */
+constexpr size_t alignto = NLMSG_ALIGNTO;
+static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
+
+/**
+ * Equivalent to NLMSG_ALIGN(len).
+ */
+constexpr size_t align(size_t len) {
+ return (len + alignto - 1) & ~(alignto - 1);
+}
+
+/**
+ * Equivalent to NLMSG_SPACE(len).
+ */
+template <typename H>
+constexpr size_t space(size_t len) {
+ return align(align(sizeof(H)) + len);
+}
+
+/**
+ * Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset).
+ */
+template <typename H, typename D>
+constexpr D* data(H* header, size_t offset = 0) {
+ return reinterpret_cast<D*>(uintptr_t(header) + space<H>(offset));
+}
+
+} // namespace android::nl::impl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
index 7167965..3570918 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
@@ -16,7 +16,7 @@
#pragma once
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
#include <linux/netlink.h>
@@ -32,6 +32,6 @@
* \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);
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = true);
} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/types.h b/automotive/can/1.0/default/libnl++/include/libnl++/types.h
index d2f10ff..567590b 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/types.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/types.h
@@ -16,12 +16,11 @@
#pragma once
-#include <linux/types.h>
+#include <linux/netlink.h>
namespace android::nl {
-typedef __u16 nlmsgtype_t; // nlmsghdr::nlmsg_type
-typedef __u16 nlattrtype_t; // nlattr::nla_type
-typedef unsigned short rtattrtype_t; // rtattr::rta_type
+typedef decltype(nlmsghdr::nlmsg_type) nlmsgtype_t;
+typedef decltype(nlattr::nla_type) nlattrtype_t;
} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
index c32afb3..e6cada2 100644
--- a/automotive/can/1.0/default/libnl++/printer.cpp
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -20,7 +20,7 @@
#include "protocols/all.h"
#include <android-base/logging.h>
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
#include <algorithm>
#include <iomanip>
@@ -28,10 +28,10 @@
namespace android::nl {
-static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags) {
+static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::MessageGenre genre) {
bool first = true;
auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) {
- if (!(nlmsg_flags & flag)) return;
+ if ((nlmsg_flags & flag) != flag) return;
nlmsg_flags &= ~flag;
if (first) {
@@ -42,6 +42,7 @@
ss << name;
};
+
printFlag(NLM_F_REQUEST, "REQUEST");
printFlag(NLM_F_MULTI, "MULTI");
printFlag(NLM_F_ACK, "ACK");
@@ -49,11 +50,29 @@
printFlag(NLM_F_DUMP_INTR, "DUMP_INTR");
printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
- // TODO(twasilczyk): print flags depending on request type
- printFlag(NLM_F_ROOT, "ROOT-REPLACE");
- printFlag(NLM_F_MATCH, "MATCH-EXCL");
- printFlag(NLM_F_ATOMIC, "ATOMIC-CREATE");
- printFlag(NLM_F_APPEND, "APPEND");
+ switch (genre) {
+ case protocols::MessageGenre::UNKNOWN:
+ break;
+ case protocols::MessageGenre::GET:
+ printFlag(NLM_F_DUMP, "DUMP"); // ROOT | MATCH
+ printFlag(NLM_F_ROOT, "ROOT");
+ printFlag(NLM_F_MATCH, "MATCH");
+ printFlag(NLM_F_ATOMIC, "ATOMIC");
+ break;
+ case protocols::MessageGenre::NEW:
+ printFlag(NLM_F_REPLACE, "REPLACE");
+ printFlag(NLM_F_EXCL, "EXCL");
+ printFlag(NLM_F_CREATE, "CREATE");
+ printFlag(NLM_F_APPEND, "APPEND");
+ break;
+ case protocols::MessageGenre::DELETE:
+ printFlag(NLM_F_NONREC, "NONREC");
+ break;
+ case protocols::MessageGenre::ACK:
+ printFlag(NLM_F_CAPPED, "CAPPED");
+ printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
+ break;
+ }
if (nlmsg_flags != 0) {
if (!first) ss << '|';
@@ -61,7 +80,7 @@
}
}
-static void toStream(std::stringstream& ss, const nlbuf<uint8_t> data) {
+static void toStream(std::stringstream& ss, const Buffer<uint8_t> data) {
const auto rawData = data.getRaw();
const auto dataLen = rawData.len();
ss << std::hex;
@@ -77,7 +96,7 @@
if (dataLen > 16) ss << std::endl;
}
-static void toStream(std::stringstream& ss, const nlbuf<nlattr> attr,
+static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
const protocols::AttributeMap& attrMap) {
using DataType = protocols::AttributeDefinition::DataType;
const auto attrtype = attrMap[attr->nla_type];
@@ -100,7 +119,7 @@
}
case DataType::String: {
const auto str = attr.data<char>().getRaw();
- ss << '"' << sanitize({str.ptr(), str.len()}) << '"';
+ ss << '"' << printableOnly({str.ptr(), str.len()}) << '"';
break;
}
case DataType::Uint:
@@ -115,7 +134,7 @@
}
}
-std::string toString(const nlbuf<nlmsghdr> hdr, int protocol, bool printPayload) {
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload) {
if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
std::stringstream ss;
@@ -128,27 +147,26 @@
}
protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
- auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
- const auto msgTypeName = msgDescMaybe.has_value()
- ? msgDescMaybe->get().getMessageName(hdr->nlmsg_type)
- : std::to_string(hdr->nlmsg_type);
+ const auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
+ const auto msgDetails =
+ protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
ss << "nlmsg{" << protocolDescr.getName() << " ";
ss << "hdr={";
- ss << "type=" << msgTypeName;
+ ss << "type=" << msgDetails.name;
if (hdr->nlmsg_flags != 0) {
ss << ", flags=";
- flagsToStream(ss, hdr->nlmsg_flags);
+ flagsToStream(ss, hdr->nlmsg_flags, msgDetails.genre);
}
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 << "} ";
+ ss << '}';
if (!printPayload) return ss.str();
+ ss << ' ';
if (!msgDescMaybe.has_value()) {
toStream(ss, hdr.data<uint8_t>());
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
index dc56643..c93d865 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
@@ -32,11 +32,12 @@
return find(nla_type)->second;
}
-MessageDescriptor::MessageDescriptor(const std::string& name, const MessageTypeMap&& messageTypes,
+MessageDescriptor::MessageDescriptor(const std::string& name,
+ const MessageDetailsMap&& messageDetails,
const AttributeMap&& attrTypes, size_t contentsSize)
: mName(name),
mContentsSize(contentsSize),
- mMessageTypes(messageTypes),
+ mMessageDetails(messageDetails),
mAttributeMap(attrTypes) {}
MessageDescriptor::~MessageDescriptor() {}
@@ -45,18 +46,25 @@
return mContentsSize;
}
-const MessageDescriptor::MessageTypeMap& MessageDescriptor::getMessageTypeMap() const {
- return mMessageTypes;
+const MessageDescriptor::MessageDetailsMap& MessageDescriptor::getMessageDetailsMap() const {
+ return mMessageDetails;
}
const AttributeMap& MessageDescriptor::getAttributeMap() const {
return mAttributeMap;
}
-const std::string MessageDescriptor::getMessageName(nlmsgtype_t msgtype) const {
- const auto it = mMessageTypes.find(msgtype);
- if (it == mMessageTypes.end()) return "?";
+MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(nlmsgtype_t msgtype) const {
+ const auto it = mMessageDetails.find(msgtype);
+ if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::UNKNOWN};
return it->second;
}
+MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
+ const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ nlmsgtype_t msgtype) {
+ if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
+ return {std::to_string(msgtype), protocols::MessageGenre::UNKNOWN};
+}
+
} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
index 046ef47..bd0e60f 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
@@ -16,7 +16,7 @@
#pragma once
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
#include <libnl++/types.h>
#include <map>
@@ -60,7 +60,7 @@
Uint,
Struct,
};
- using ToStream = std::function<void(std::stringstream& ss, const nlbuf<nlattr> attr)>;
+ using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>;
std::string name;
DataType dataType = DataType::Raw;
@@ -68,30 +68,53 @@
};
/**
+ * General message type's kind.
+ *
+ * For example, RTM_NEWLINK is a NEW kind. For details, please see "Flags values"
+ * section in linux/netlink.h.
+ */
+enum class MessageGenre {
+ UNKNOWN,
+ GET,
+ NEW,
+ DELETE,
+ ACK,
+};
+
+/**
* Message family descriptor.
*
* Describes the structure of all message types with the same header and attributes.
*/
class MessageDescriptor {
- protected:
- typedef std::map<nlmsgtype_t, std::string> MessageTypeMap;
-
- MessageDescriptor(const std::string& name, const MessageTypeMap&& messageTypes,
- const AttributeMap&& attrTypes, size_t contentsSize);
+ public:
+ struct MessageDetails {
+ std::string name;
+ MessageGenre genre;
+ };
+ typedef std::map<nlmsgtype_t, MessageDetails> MessageDetailsMap;
public:
virtual ~MessageDescriptor();
size_t getContentsSize() const;
- const MessageTypeMap& getMessageTypeMap() const;
+ const MessageDetailsMap& getMessageDetailsMap() const;
const AttributeMap& getAttributeMap() const;
- const std::string getMessageName(nlmsgtype_t msgtype) const;
- virtual void dataToStream(std::stringstream& ss, const nlbuf<nlmsghdr> hdr) const = 0;
+ MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
+ virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
+
+ static MessageDetails getMessageDetails(
+ const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ nlmsgtype_t msgtype);
+
+ protected:
+ MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
+ const AttributeMap&& attrTypes, size_t contentsSize);
private:
const std::string mName;
const size_t mContentsSize;
- const MessageTypeMap mMessageTypes;
+ const MessageDetailsMap mMessageDetails;
const AttributeMap mAttributeMap;
};
@@ -103,13 +126,13 @@
template <typename T>
class MessageDefinition : public MessageDescriptor {
public:
- MessageDefinition(
+ MessageDefinition( //
const std::string& name,
- const std::initializer_list<MessageDescriptor::MessageTypeMap::value_type> messageTypes,
+ const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
const std::initializer_list<AttributeMap::value_type> attrTypes = {})
- : MessageDescriptor(name, messageTypes, attrTypes, sizeof(T)) {}
+ : MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
- void dataToStream(std::stringstream& ss, const nlbuf<nlmsghdr> hdr) const override {
+ void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {
const auto& [ok, msg] = hdr.data<T>().getFirst();
if (!ok) {
ss << "{incomplete payload}";
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
index 4b795d9..cd2e8c6 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
@@ -18,7 +18,7 @@
namespace android::nl::protocols {
-NetlinkProtocol::NetlinkProtocol(int protocol, const std::string name,
+NetlinkProtocol::NetlinkProtocol(int protocol, const std::string& name,
const MessageDescriptorList&& messageDescrs)
: mProtocol(protocol), mName(name), mMessageDescrs(toMap(messageDescrs, protocol)) {}
@@ -42,7 +42,7 @@
const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
MessageDescriptorMap map;
for (const auto& descr : descrs) {
- for (const auto& [mtype, mname] : descr->getMessageTypeMap()) {
+ for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
map.emplace(mtype, descr);
}
}
@@ -53,7 +53,7 @@
};
for (const auto& descr : baseDescriptors) {
- for (const auto& [mtype, mname] : descr->getMessageTypeMap()) {
+ for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
map.emplace(mtype, descr);
}
}
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
index 81a0a65..c969547 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
@@ -46,7 +46,7 @@
protected:
typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
- NetlinkProtocol(int protocol, const std::string name,
+ NetlinkProtocol(int protocol, const std::string& name,
const MessageDescriptorList&& messageDescrs);
private:
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
index dbf10d4..8a672d3 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
@@ -20,9 +20,9 @@
// clang-format off
Empty::Empty() : MessageDefinition<char>("nlmsg", {
- {NLMSG_NOOP, "NOOP"},
- {NLMSG_DONE, "DONE"},
- {NLMSG_OVERRUN, "OVERRUN"},
+ {NLMSG_NOOP, {"NOOP", MessageGenre::UNKNOWN}},
+ {NLMSG_DONE, {"DONE", MessageGenre::UNKNOWN}},
+ {NLMSG_OVERRUN, {"OVERRUN", MessageGenre::UNKNOWN}},
}) {}
// clang-format on
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
index 1d6bd1c..44708a3 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
@@ -22,15 +22,21 @@
namespace android::nl::protocols::base {
+using DataType = AttributeDefinition::DataType;
+
// clang-format off
Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
- {NLMSG_ERROR, "ERROR"},
+ {NLMSG_ERROR, {"ERROR", MessageGenre::ACK}},
+}, {
+ {NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
+ {NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
+ {NLMSGERR_ATTR_COOKIE, {"COOKIE", DataType::Raw}},
}), mProtocol(protocol) {}
// clang-format on
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, false) << "}";
}
} // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
index 5203368..134638e 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
@@ -19,13 +19,14 @@
namespace android::nl::protocols::generic {
GenericMessageBase::GenericMessageBase(
- nlmsgtype_t msgtype, std::string msgname,
+ nlmsgtype_t msgtype, const std::string&& msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
const std::initializer_list<AttributeMap::value_type> attrTypes)
- : MessageDefinition<struct genlmsghdr>(msgname, {{msgtype, msgname}}, attrTypes),
+ : MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::UNKNOWN}}},
+ attrTypes),
mCommandNames(commandNames) {}
-void GenericMessageBase::toStream(std::stringstream& ss, const struct genlmsghdr& data) const {
+void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
ss << "genlmsghdr{";
if (mCommandNames.count(data.cmd) == 0) {
ss << "cmd=" << unsigned(data.cmd);
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
index f3b0b31..443f10c 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
@@ -22,16 +22,16 @@
namespace android::nl::protocols::generic {
-class GenericMessageBase : public MessageDefinition<struct genlmsghdr> {
+class GenericMessageBase : public MessageDefinition<genlmsghdr> {
public:
typedef std::map<uint8_t, std::string> GenericCommandNameMap;
GenericMessageBase(
- nlmsgtype_t msgtype, std::string msgname,
+ nlmsgtype_t msgtype, const std::string&& msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames = {},
const std::initializer_list<AttributeMap::value_type> attrTypes = {});
- void toStream(std::stringstream& ss, const struct genlmsghdr& data) const override;
+ void toStream(std::stringstream& ss, const genlmsghdr& data) const override;
private:
const GenericCommandNameMap mCommandNames;
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
index 26d3e3e..7db487a 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
@@ -25,10 +25,10 @@
using DataType = AttributeDefinition::DataType;
// clang-format off
-Link::Link() : MessageDefinition<struct ifinfomsg>("link", {
- {RTM_NEWLINK, "NEWLINK"},
- {RTM_DELLINK, "DELLINK"},
- {RTM_GETLINK, "GETLINK"},
+Link::Link() : MessageDefinition<ifinfomsg>("link", {
+ {RTM_NEWLINK, {"NEWLINK", MessageGenre::NEW}},
+ {RTM_DELLINK, {"DELLINK", MessageGenre::DELETE}},
+ {RTM_GETLINK, {"GETLINK", MessageGenre::GET}},
}, {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
@@ -107,7 +107,7 @@
}) {}
// clang-format off
-void Link::toStream(std::stringstream& ss, const struct ifinfomsg& data) const {
+void Link::toStream(std::stringstream& ss, const ifinfomsg& data) const {
ss << "ifinfomsg{"
<< "family=" << unsigned(data.ifi_family) << ", type=" << data.ifi_type
<< ", index=" << data.ifi_index << ", flags=" << data.ifi_flags
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.h b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
index 4ea3eba..ecfefc9 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/Link.h
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
@@ -22,10 +22,10 @@
namespace android::nl::protocols::route {
-class Link : public MessageDefinition<struct ifinfomsg> {
+class Link : public MessageDefinition<ifinfomsg> {
public:
Link();
- void toStream(std::stringstream& ss, const struct ifinfomsg& data) const override;
+ void toStream(std::stringstream& ss, const ifinfomsg& data) const override;
};
} // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
index ea923bb..b62cec3 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
@@ -18,7 +18,7 @@
namespace android::nl::protocols::route {
-void mapToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
const auto& [ok, data] = attr.data<rtnl_link_ifmap>().getFirst();
if (!ok) {
ss << "invalid structure";
@@ -33,7 +33,7 @@
<< unsigned(data.port) << '}';
}
-void ifla_cacheinfoToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
const auto& [ok, data] = attr.data<ifla_cacheinfo>().getFirst();
if (!ok) {
ss << "invalid structure";
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.h b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
index 38776fa..b9d622a 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/structs.h
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
@@ -16,7 +16,7 @@
#pragma once
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
#include <linux/rtnetlink.h>
@@ -25,13 +25,13 @@
namespace android::nl::protocols::route {
// rtnl_link_ifmap
-void mapToStream(std::stringstream& ss, const nlbuf<nlattr> attr);
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
// ifla_cacheinfo
-void ifla_cacheinfoToStream(std::stringstream& ss, const nlbuf<nlattr> attr);
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
template <typename T>
-void arrayToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
ss << '{';
for (const auto it : attr.data<T>().getRaw()) {
ss << it << ',';
@@ -42,7 +42,7 @@
// rtnl_link_stats or rtnl_link_stats64
template <typename T>
-void statsToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
const auto& [ok, data] = attr.data<T>().getFirst();
if (!ok) {
ss << "invalid structure";
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 8dfd7d6..fc77579 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -86,7 +86,7 @@
EXPECT_EQ(ICanController::Result::OK, result);
/* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
- * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+ * file -- this is a test, so we don't want to add fake services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto service = manager->get(ICanBus::descriptor, config.name);
mBus = ICanBus::castFrom(service);
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index b945978..294cd17 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -119,7 +119,7 @@
void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
/* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
- * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+ * file -- this is a test, so we don't want to add fake services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto busService = manager->get(ICanBus::descriptor, srvname);
ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
@@ -145,7 +145,7 @@
assertRegistered(name, false);
}
-TEST_P(CanControllerHalTest, DownDummy) {
+TEST_P(CanControllerHalTest, DownFake) {
const auto result = mCanController->downInterface("imnotup");
ASSERT_FALSE(result);
}
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
index e0782ec..0daea5a 100644
--- a/automotive/evs/1.0/default/EvsCamera.cpp
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -49,7 +49,7 @@
mDescription.cameraId = id;
- // Set up dummy data for testing
+ // Set up mock data for testing
if (mDescription.cameraId == kCameraName_Backup) {
mWidth = 640; // full NTSC/VGA
mHeight = 480; // full NTSC/VGA
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index 7fe7a33..ad607d8 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -369,7 +369,7 @@
TEST_P(EvsHidlTest, CameraStreamBuffering) {
ALOGI("Starting CameraStreamBuffering test");
- // Arbitrary constant (should be > 1 and less than crazy)
+ // Arbitrary constant (should be > 1 and not too big)
static const unsigned int kBuffersToHold = 6;
// Get the camera list
@@ -381,7 +381,7 @@
sp<IEvsCamera> pCam = pEnumerator->openCamera(cam.cameraId);
ASSERT_NE(pCam, nullptr);
- // Ask for a crazy number of buffers in flight to ensure it errors correctly
+ // Ask for a very large number of buffers in flight to ensure it errors correctly
Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 870af1c..b0b2670 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -76,7 +76,7 @@
}
/*
- * List of supported controls that the master client can program.
+ * List of supported controls that the primary client can program.
* Paraemters are stored with its valid range
*/
unordered_map<CameraParam,
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index 117ee7a..d066471 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -70,7 +70,7 @@
// Add ultrasonics array desc.
sUltrasonicsArrayRecordList.emplace_back(
- EvsUltrasonicsArray::GetDummyArrayDesc("front_array"));
+ EvsUltrasonicsArray::GetMockArrayDesc("front_array"));
}
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
index bc69aa4..ebd47c6 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
@@ -45,7 +45,7 @@
namespace {
-void fillDummyArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
+void fillMockArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
arrayDesc.maxReceiversCount = kMaxReceiversCount;
@@ -99,8 +99,8 @@
}
}
-// Fills dataFrameDesc with dummy data.
-bool fillDummyDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
+// Fills dataFrameDesc with mock data.
+bool fillMockDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
dataFrameDesc.timestampNs = elapsedRealtimeNano();
const std::vector<uint8_t> transmittersIdList = {0};
@@ -137,9 +137,9 @@
: mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
- // Set up dummy data for description.
+ // Set up mock data for description.
mArrayDesc.ultrasonicsArrayId = deviceName;
- fillDummyArrayDesc(mArrayDesc);
+ fillMockArrayDesc(mArrayDesc);
// Assign allocator.
mShmemAllocator = IAllocator::getService("ashmem");
@@ -182,10 +182,10 @@
mStreamState = DEAD;
}
-UltrasonicsArrayDesc EvsUltrasonicsArray::GetDummyArrayDesc(const char* deviceName) {
+UltrasonicsArrayDesc EvsUltrasonicsArray::GetMockArrayDesc(const char* deviceName) {
UltrasonicsArrayDesc ultrasonicsArrayDesc;
ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
- fillDummyArrayDesc(ultrasonicsArrayDesc);
+ fillMockArrayDesc(ultrasonicsArrayDesc);
return ultrasonicsArrayDesc;
}
@@ -497,17 +497,17 @@
if (timeForFrame) {
// Assemble the buffer description we'll transmit below
- UltrasonicsDataFrameDesc dummyDataFrameDesc;
- dummyDataFrameDesc.dataFrameId = idx;
- dummyDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
+ UltrasonicsDataFrameDesc mockDataFrameDesc;
+ mockDataFrameDesc.dataFrameId = idx;
+ mockDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
- // Fill dummy waveform data.
- fillDummyDataFrame(dummyDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
+ // Fill mock waveform data.
+ fillMockDataFrame(mockDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- auto result = mStream->deliverDataFrame(dummyDataFrameDesc);
+ auto result = mStream->deliverDataFrame(mockDataFrameDesc);
if (result.isOk()) {
- LOG(DEBUG) << "Delivered data frame id: " << dummyDataFrameDesc.dataFrameId;
+ LOG(DEBUG) << "Delivered data frame id: " << mockDataFrameDesc.dataFrameId;
} else {
// This can happen if the client dies and is likely unrecoverable.
// To avoid consuming resources generating failing calls, we stop sending
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.h b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
index 7a41012..88aa600 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.h
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
@@ -58,7 +58,7 @@
static sp<EvsUltrasonicsArray> Create(const char* deviceName);
// Returns a ultrasonics array descriptor filled with sample data.
- static UltrasonicsArrayDesc GetDummyArrayDesc(const char* id);
+ static UltrasonicsArrayDesc GetMockArrayDesc(const char* id);
DISALLOW_COPY_AND_ASSIGN(EvsUltrasonicsArray);
virtual ~EvsUltrasonicsArray() override;
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 4398fb1..638ecd5 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -500,7 +500,7 @@
TEST_P(EvsHidlTest, CameraStreamBuffering) {
LOG(INFO) << "Starting CameraStreamBuffering test";
- // Arbitrary constant (should be > 1 and less than crazy)
+ // Arbitrary constant (should be > 1 and not too big)
static const unsigned int kBuffersToHold = 6;
// Get the camera list
@@ -527,7 +527,7 @@
// Store a camera handle for a clean-up
activeCameras.push_back(pCam);
- // Ask for a crazy number of buffers in flight to ensure it errors correctly
+ // Ask for a very large number of buffers in flight to ensure it errors correctly
Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
@@ -930,12 +930,12 @@
/*
- * CameraMasterRelease
- * Verify that non-master client gets notified when the master client either
+ * CameraPrimaryClientRelease
+ * Verify that non-primary client gets notified when the primary client either
* terminates or releases a role.
*/
-TEST_P(EvsHidlTest, CameraMasterRelease) {
- LOG(INFO) << "Starting CameraMasterRelease test";
+TEST_P(EvsHidlTest, CameraPrimaryClientRelease) {
+ LOG(INFO) << "Starting CameraPrimaryClientRelease test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -961,57 +961,57 @@
}
// Create two camera clients.
- sp<IEvsCamera_1_1> pCamMaster =
+ sp<IEvsCamera_1_1> pCamPrimary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamMaster, nullptr);
+ ASSERT_NE(pCamPrimary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamMaster);
+ activeCameras.push_back(pCamPrimary);
- sp<IEvsCamera_1_1> pCamNonMaster =
+ sp<IEvsCamera_1_1> pCamSecondary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamNonMaster, nullptr);
+ ASSERT_NE(pCamSecondary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamNonMaster);
+ activeCameras.push_back(pCamSecondary);
// Set up per-client frame receiver objects which will fire up its own thread
- sp<FrameHandler> frameHandlerMaster =
- new FrameHandler(pCamMaster, cam,
+ sp<FrameHandler> frameHandlerPrimary =
+ new FrameHandler(pCamPrimary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerMaster, nullptr);
- sp<FrameHandler> frameHandlerNonMaster =
- new FrameHandler(pCamNonMaster, cam,
+ ASSERT_NE(frameHandlerPrimary, nullptr);
+ sp<FrameHandler> frameHandlerSecondary =
+ new FrameHandler(pCamSecondary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerNonMaster, nullptr);
+ ASSERT_NE(frameHandlerSecondary, nullptr);
- // Set one client as the master
- EvsResult result = pCamMaster->setMaster();
+ // Set one client as the primary client
+ EvsResult result = pCamPrimary->setMaster();
ASSERT_TRUE(result == EvsResult::OK);
- // Try to set another client as the master.
- result = pCamNonMaster->setMaster();
+ // Try to set another client as the primary client.
+ result = pCamSecondary->setMaster();
ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
- // Start the camera's video stream via a master client.
- bool startResult = frameHandlerMaster->startStream();
+ // Start the camera's video stream via a primary client client.
+ bool startResult = frameHandlerPrimary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerMaster->waitForFrameCount(1);
+ frameHandlerPrimary->waitForFrameCount(1);
// Start the camera's video stream via another client
- startResult = frameHandlerNonMaster->startStream();
+ startResult = frameHandlerSecondary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerNonMaster->waitForFrameCount(1);
+ frameHandlerSecondary->waitForFrameCount(1);
- // Non-master client expects to receive a master role relesed
+ // Non-primary client expects to receive a primary client role relesed
// notification.
EvsEventDesc aTargetEvent = {};
EvsEventDesc aNotification = {};
@@ -1020,14 +1020,14 @@
std::mutex eventLock;
std::condition_variable eventCond;
std::thread listener = std::thread(
- [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+ [&aNotification, &frameHandlerSecondary, &listening, &eventCond]() {
// Notify that a listening thread is running.
listening = true;
eventCond.notify_all();
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification, true)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
@@ -1043,8 +1043,8 @@
}
lock.unlock();
- // Release a master role.
- pCamMaster->unsetMaster();
+ // Release a primary client role.
+ pCamPrimary->unsetMaster();
// Join a listening thread.
if (listener.joinable()) {
@@ -1055,24 +1055,24 @@
ASSERT_EQ(EvsEventType::MASTER_RELEASED,
static_cast<EvsEventType>(aNotification.aType));
- // Non-master becomes a master.
- result = pCamNonMaster->setMaster();
+ // Non-primary becomes a primary client.
+ result = pCamSecondary->setMaster();
ASSERT_TRUE(result == EvsResult::OK);
- // Previous master client fails to become a master.
- result = pCamMaster->setMaster();
+ // Previous primary client fails to become a primary client.
+ result = pCamPrimary->setMaster();
ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
listening = false;
listener = std::thread(
- [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+ [&aNotification, &frameHandlerPrimary, &listening, &eventCond]() {
// Notify that a listening thread is running.
listening = true;
eventCond.notify_all();
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
- if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification, true)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
@@ -1087,8 +1087,8 @@
}
lock.unlock();
- // Closing current master client.
- frameHandlerNonMaster->shutdown();
+ // Closing current primary client.
+ frameHandlerSecondary->shutdown();
// Join a listening thread.
if (listener.joinable()) {
@@ -1100,11 +1100,11 @@
static_cast<EvsEventType>(aNotification.aType));
// Closing streams.
- frameHandlerMaster->shutdown();
+ frameHandlerPrimary->shutdown();
// Explicitly release the camera
- pEnumerator->closeCamera(pCamMaster);
- pEnumerator->closeCamera(pCamNonMaster);
+ pEnumerator->closeCamera(pCamPrimary);
+ pEnumerator->closeCamera(pCamSecondary);
activeCameras.clear();
}
}
@@ -1112,7 +1112,7 @@
/*
* MultiCameraParameter:
- * Verify that master and non-master clients behave as expected when they try to adjust
+ * Verify that primary and non-primary clients behave as expected when they try to adjust
* camera parameters.
*/
TEST_P(EvsHidlTest, MultiCameraParameter) {
@@ -1142,88 +1142,88 @@
}
// Create two camera clients.
- sp<IEvsCamera_1_1> pCamMaster =
+ sp<IEvsCamera_1_1> pCamPrimary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamMaster, nullptr);
+ ASSERT_NE(pCamPrimary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamMaster);
+ activeCameras.push_back(pCamPrimary);
- sp<IEvsCamera_1_1> pCamNonMaster =
+ sp<IEvsCamera_1_1> pCamSecondary =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCamNonMaster, nullptr);
+ ASSERT_NE(pCamSecondary, nullptr);
// Store a camera handle for a clean-up
- activeCameras.push_back(pCamNonMaster);
+ activeCameras.push_back(pCamSecondary);
// Get the parameter list
- std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
- pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
- camMasterCmds.reserve(cmdList.size());
+ std::vector<CameraParam> camPrimaryCmds, camSecondaryCmds;
+ pCamPrimary->getParameterList([&camPrimaryCmds](hidl_vec<CameraParam> cmdList) {
+ camPrimaryCmds.reserve(cmdList.size());
for (auto &&cmd : cmdList) {
- camMasterCmds.push_back(cmd);
+ camPrimaryCmds.push_back(cmd);
}
}
);
- pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
- camNonMasterCmds.reserve(cmdList.size());
+ pCamSecondary->getParameterList([&camSecondaryCmds](hidl_vec<CameraParam> cmdList) {
+ camSecondaryCmds.reserve(cmdList.size());
for (auto &&cmd : cmdList) {
- camNonMasterCmds.push_back(cmd);
+ camSecondaryCmds.push_back(cmd);
}
}
);
- if (camMasterCmds.size() < 1 ||
- camNonMasterCmds.size() < 1) {
+ if (camPrimaryCmds.size() < 1 ||
+ camSecondaryCmds.size() < 1) {
// Skip a camera device if it does not support any parameter.
continue;
}
// Set up per-client frame receiver objects which will fire up its own thread
- sp<FrameHandler> frameHandlerMaster =
- new FrameHandler(pCamMaster, cam,
+ sp<FrameHandler> frameHandlerPrimary =
+ new FrameHandler(pCamPrimary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerMaster, nullptr);
- sp<FrameHandler> frameHandlerNonMaster =
- new FrameHandler(pCamNonMaster, cam,
+ ASSERT_NE(frameHandlerPrimary, nullptr);
+ sp<FrameHandler> frameHandlerSecondary =
+ new FrameHandler(pCamSecondary, cam,
nullptr,
FrameHandler::eAutoReturn);
- ASSERT_NE(frameHandlerNonMaster, nullptr);
+ ASSERT_NE(frameHandlerSecondary, nullptr);
- // Set one client as the master
- EvsResult result = pCamMaster->setMaster();
+ // Set one client as the primary client.
+ EvsResult result = pCamPrimary->setMaster();
ASSERT_EQ(EvsResult::OK, result);
- // Try to set another client as the master.
- result = pCamNonMaster->setMaster();
+ // Try to set another client as the primary client.
+ result = pCamSecondary->setMaster();
ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
- // Start the camera's video stream via a master client.
- bool startResult = frameHandlerMaster->startStream();
+ // Start the camera's video stream via a primary client client.
+ bool startResult = frameHandlerPrimary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerMaster->waitForFrameCount(1);
+ frameHandlerPrimary->waitForFrameCount(1);
// Start the camera's video stream via another client
- startResult = frameHandlerNonMaster->startStream();
+ startResult = frameHandlerSecondary->startStream();
ASSERT_TRUE(startResult);
// Ensure the stream starts
- frameHandlerNonMaster->waitForFrameCount(1);
+ frameHandlerSecondary->waitForFrameCount(1);
int32_t val0 = 0;
std::vector<int32_t> values;
EvsEventDesc aNotification0 = {};
EvsEventDesc aNotification1 = {};
- for (auto &cmd : camMasterCmds) {
+ for (auto &cmd : camPrimaryCmds) {
// Get a valid parameter value range
int32_t minVal, maxVal, step;
- pCamMaster->getIntParameterRange(
+ pCamPrimary->getIntParameterRange(
cmd,
[&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
minVal = val0;
@@ -1236,7 +1236,7 @@
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
values.clear();
- pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ pCamPrimary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1261,7 +1261,7 @@
std::condition_variable eventCond;
std::thread listener0 = std::thread(
[cmd, val0,
- &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ &aNotification0, &frameHandlerPrimary, &listening0, &listening1, &eventCond]() {
listening0 = true;
if (listening1) {
eventCond.notify_all();
@@ -1271,14 +1271,14 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
std::thread listener1 = std::thread(
[cmd, val0,
- &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ &aNotification1, &frameHandlerSecondary, &listening0, &listening1, &eventCond]() {
listening1 = true;
if (listening0) {
eventCond.notify_all();
@@ -1288,7 +1288,7 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1305,7 +1305,7 @@
// Try to program a parameter
values.clear();
- pCamMaster->setIntParameter(cmd, val0,
+ pCamPrimary->setIntParameter(cmd, val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1345,9 +1345,9 @@
}
// Clients expects to receive a parameter change notification
- // whenever a master client adjusts it.
+ // whenever a primary client client adjusts it.
values.clear();
- pCamMaster->getIntParameter(cmd,
+ pCamPrimary->getIntParameter(cmd,
[&result, &values](auto status, auto readValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1362,9 +1362,9 @@
}
}
- // Try to adjust a parameter via non-master client
+ // Try to adjust a parameter via non-primary client
values.clear();
- pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
+ pCamSecondary->setIntParameter(camSecondaryCmds[0], val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1375,21 +1375,21 @@
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
- // Non-master client attemps to be a master
- result = pCamNonMaster->setMaster();
+ // Non-primary client attempts to be a primary client
+ result = pCamSecondary->setMaster();
ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
- // Master client retires from a master role
+ // Primary client retires from a primary client role
bool listening = false;
std::condition_variable eventCond;
std::thread listener = std::thread(
- [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+ [&aNotification0, &frameHandlerSecondary, &listening, &eventCond]() {
listening = true;
eventCond.notify_all();
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification0, true)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1403,7 +1403,7 @@
}
lock.unlock();
- result = pCamMaster->unsetMaster();
+ result = pCamPrimary->unsetMaster();
ASSERT_EQ(EvsResult::OK, result);
if (listener.joinable()) {
@@ -1414,7 +1414,7 @@
// Try to adjust a parameter after being retired
values.clear();
- pCamMaster->setIntParameter(camMasterCmds[0], val0,
+ pCamPrimary->setIntParameter(camPrimaryCmds[0], val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1425,15 +1425,15 @@
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
- // Non-master client becomes a master
- result = pCamNonMaster->setMaster();
+ // Non-primary client becomes a primary client
+ result = pCamSecondary->setMaster();
ASSERT_EQ(EvsResult::OK, result);
- // Try to adjust a parameter via new master client
- for (auto &cmd : camNonMasterCmds) {
+ // Try to adjust a parameter via new primary client
+ for (auto &cmd : camSecondaryCmds) {
// Get a valid parameter value range
int32_t minVal, maxVal, step;
- pCamNonMaster->getIntParameterRange(
+ pCamSecondary->getIntParameterRange(
cmd,
[&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
minVal = val0;
@@ -1447,7 +1447,7 @@
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
values.clear();
- pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ pCamSecondary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1471,7 +1471,7 @@
bool listening1 = false;
std::condition_variable eventCond;
std::thread listener0 = std::thread(
- [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ [&]() {
listening0 = true;
if (listening1) {
eventCond.notify_all();
@@ -1481,13 +1481,13 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
std::thread listener1 = std::thread(
- [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ [&]() {
listening1 = true;
if (listening0) {
eventCond.notify_all();
@@ -1497,7 +1497,7 @@
aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
- if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1514,7 +1514,7 @@
// Try to program a parameter
values.clear();
- pCamNonMaster->setIntParameter(cmd, val0,
+ pCamSecondary->setIntParameter(cmd, val0,
[&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1526,9 +1526,9 @@
ASSERT_EQ(EvsResult::OK, result);
// Clients expects to receive a parameter change notification
- // whenever a master client adjusts it.
+ // whenever a primary client client adjusts it.
values.clear();
- pCamNonMaster->getIntParameter(cmd,
+ pCamSecondary->getIntParameter(cmd,
[&result, &values](auto status, auto readValues) {
result = status;
if (status == EvsResult::OK) {
@@ -1567,17 +1567,17 @@
}
}
- // New master retires from a master role
- result = pCamNonMaster->unsetMaster();
+ // New primary client retires from the role
+ result = pCamSecondary->unsetMaster();
ASSERT_EQ(EvsResult::OK, result);
// Shutdown
- frameHandlerMaster->shutdown();
- frameHandlerNonMaster->shutdown();
+ frameHandlerPrimary->shutdown();
+ frameHandlerSecondary->shutdown();
// Explicitly release the camera
- pEnumerator->closeCamera(pCamMaster);
- pEnumerator->closeCamera(pCamNonMaster);
+ pEnumerator->closeCamera(pCamPrimary);
+ pEnumerator->closeCamera(pCamSecondary);
activeCameras.clear();
}
}
@@ -1586,7 +1586,7 @@
/*
* HighPriorityCameraClient:
* EVS client, which owns the display, is priortized and therefore can take over
- * a master role from other EVS clients without the display.
+ * a primary client role from other EVS clients without the display.
*/
TEST_P(EvsHidlTest, HighPriorityCameraClient) {
LOG(INFO) << "Starting HighPriorityCameraClient test";
@@ -1668,7 +1668,7 @@
frameHandler0->waitForFrameCount(1);
frameHandler1->waitForFrameCount(1);
- // Client 1 becomes a master and programs a parameter.
+ // Client 1 becomes a primary client and programs a parameter.
EvsResult result = EvsResult::OK;
// Get a valid parameter value range
int32_t minVal, maxVal, step;
@@ -1681,7 +1681,7 @@
}
);
- // Client1 becomes a master
+ // Client1 becomes a primary client
result = pCam1->setMaster();
ASSERT_EQ(EvsResult::OK, result);
@@ -1820,7 +1820,7 @@
}
lock.unlock();
- // Client 0 steals a master role
+ // Client 0 steals a primary client role
ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
// Join a listener
@@ -2241,7 +2241,7 @@
TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
LOG(INFO) << "Starting CameraStreamExternalBuffering test";
- // Arbitrary constant (should be > 1 and less than crazy)
+ // Arbitrary constant (should be > 1 and not too big)
static const unsigned int kBuffersToHold = 6;
// Get the camera list
diff --git a/automotive/vehicle/2.0/utils/Android.bp b/automotive/vehicle/2.0/utils/Android.bp
new file mode 100644
index 0000000..e354634
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/Android.bp
@@ -0,0 +1,41 @@
+// 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.
+
+// User HAL helper library.
+cc_library_static {
+ name: "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
+ defaults: ["vhal_v2_0_defaults"],
+ vendor: true,
+ host_supported: true,
+ srcs: [
+ "UserHalHelper.cpp",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+}
+
+cc_test {
+ name: "android.hardware.automotive.vehicle@2.0-utils-unit-tests",
+ defaults: ["vhal_v2_0_defaults"],
+ vendor: true,
+ srcs: [
+ "tests/UserHalHelper_test.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
+ "libgmock",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.cpp b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
new file mode 100644
index 0000000..33b3948
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "UserHalHelper"
+
+#include "UserHalHelper.h"
+
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace user_hal_helper {
+namespace {
+
+using android::base::Error;
+using android::base::Result;
+
+static constexpr const char* kSeparator = "||";
+static const size_t kNumFieldsPerUserInfo = 2;
+static const size_t kNumFieldsPerSetAssociation = 2;
+
+template <typename T>
+Result<T> verifyAndCast(int32_t value) {
+ T castValue = static_cast<T>(value);
+ const auto iter = hidl_enum_range<T>();
+ if (castValue < *iter.begin() || castValue > *std::prev(iter.end())) {
+ return Error() << "Value " << value << " not in range [" << toString(*iter.begin()) << ", "
+ << toString(*std::prev(iter.end())) << "]";
+ }
+ for (const auto& v : hidl_enum_range<T>()) {
+ if (castValue == v) {
+ return castValue;
+ }
+ }
+ return Error() << "Value " << value << " not in enum values";
+}
+
+Result<void> verifyPropValue(const VehiclePropValue& propValue, VehicleProperty vehicleProperty,
+ size_t minInt32Values) {
+ auto prop = verifyAndCast<VehicleProperty>(propValue.prop);
+ if (!prop.ok()) {
+ return Error() << "Invalid vehicle property: " << prop.error();
+ }
+ if (*prop != vehicleProperty) {
+ return Error() << "Mismatching " << toString(vehicleProperty) << " request, received "
+ << toString(*prop) << " property";
+ }
+ if (propValue.value.int32Values.size() < minInt32Values) {
+ return Error() << "Int32Values must have at least " << minInt32Values
+ << " values, received " << propValue.value.int32Values.size();
+ }
+ return {};
+}
+
+Result<void> parseUserInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
+ UserInfo* userInfo) {
+ if (int32Values.size() < startPos + kNumFieldsPerUserInfo) {
+ return Error() << "Int32Values must have at least " << startPos + 2 << " values, received "
+ << int32Values.size();
+ }
+ userInfo->userId = int32Values[startPos];
+ auto userFlags = verifyAndCast<UserFlags>(int32Values[startPos + 1]);
+ if (!userFlags.ok()) {
+ return Error() << "Invalid user flags: " << userFlags.error();
+ }
+ userInfo->flags = *userFlags;
+ return {};
+}
+
+Result<void> parseUsersInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
+ UsersInfo* usersInfo) {
+ if (int32Values.size() < startPos + 3) {
+ return Error() << "Int32Values must have at least " << startPos + 3 << " values, received "
+ << int32Values.size();
+ }
+ auto ret = parseUserInfo(int32Values, startPos, &usersInfo->currentUser);
+ if (!ret.ok()) {
+ return ret;
+ }
+ usersInfo->numberUsers = int32Values[startPos + 2];
+ usersInfo->existingUsers.resize(usersInfo->numberUsers);
+ for (size_t i = 0; i < static_cast<size_t>(usersInfo->numberUsers); ++i) {
+ ret = parseUserInfo(int32Values, startPos + 3 + (kNumFieldsPerUserInfo * i),
+ &usersInfo->existingUsers[i]);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse existing user '" << i << "' info: " << ret.error();
+ }
+ }
+ return {};
+}
+
+Result<void> parseUserAssociationTypes(
+ const hidl_vec<int32_t>& int32Values, size_t startPos, size_t numberAssociationTypes,
+ hidl_vec<UserIdentificationAssociationType>* associationTypes) {
+ size_t minInt32Values = startPos + numberAssociationTypes;
+ if (int32Values.size() < minInt32Values) {
+ return Error() << "Int32Values must have at least " << minInt32Values
+ << " values, received " << int32Values.size();
+ }
+ associationTypes->resize(numberAssociationTypes);
+ for (size_t i = 0; i < static_cast<size_t>(numberAssociationTypes); ++i) {
+ size_t pos = startPos + i;
+ auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
+ if (!type.ok()) {
+ return Error() << "Invalid association type in query '" << i << "': " << type.error();
+ }
+ (*associationTypes)[i] = *type;
+ }
+ return {};
+}
+
+Result<void> parseUserAssociations(const hidl_vec<int32_t>& int32Values, size_t startPos,
+ size_t numberAssociations,
+ hidl_vec<UserIdentificationSetAssociation>* associations) {
+ size_t minInt32Values = startPos + (numberAssociations * kNumFieldsPerSetAssociation);
+ if (int32Values.size() < minInt32Values) {
+ return Error() << "Int32Values must have at least " << minInt32Values
+ << " values, received " << int32Values.size();
+ }
+ associations->resize(numberAssociations);
+ for (size_t i = 0; i < static_cast<size_t>(numberAssociations); ++i) {
+ size_t pos = startPos + (kNumFieldsPerSetAssociation * i);
+ auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
+ if (!type.ok()) {
+ return Error() << "Invalid association type in request '" << i << "': " << type.error();
+ }
+ (*associations)[i].type = *type;
+ auto value = verifyAndCast<UserIdentificationAssociationSetValue>(int32Values[pos + 1]);
+ if (!value.ok()) {
+ return Error() << "Invalid association set value in request '" << i
+ << "': " << value.error();
+ }
+ (*associations)[i].value = *value;
+ }
+ return {};
+}
+
+} // namespace
+
+Result<InitialUserInfoRequest> toInitialUserInfoRequest(const VehiclePropValue& propValue) {
+ auto ret = verifyPropValue(propValue, VehicleProperty::INITIAL_USER_INFO, 2);
+ if (!ret.ok()) {
+ return ret.error();
+ }
+ InitialUserInfoRequest request;
+ request.requestId = propValue.value.int32Values[0];
+ auto requestType = verifyAndCast<InitialUserInfoRequestType>(propValue.value.int32Values[1]);
+ if (!requestType.ok()) {
+ return Error() << "Invalid InitialUserInfoRequestType: " << requestType.error();
+ }
+ request.requestType = *requestType;
+ ret = parseUsersInfo(propValue.value.int32Values, 2, &request.usersInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse users info: " << ret.error();
+ }
+ return request;
+}
+
+Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue) {
+ auto ret = verifyPropValue(propValue, VehicleProperty::SWITCH_USER, 2);
+ if (!ret.ok()) {
+ return ret.error();
+ }
+ SwitchUserRequest request;
+ auto messageType = verifyAndCast<SwitchUserMessageType>(propValue.value.int32Values[1]);
+ if (!messageType.ok()) {
+ return Error() << "Invalid SwitchUserMessageType: " << messageType.error();
+ }
+ if (*messageType != SwitchUserMessageType::LEGACY_ANDROID_SWITCH &&
+ *messageType != SwitchUserMessageType::ANDROID_SWITCH &&
+ *messageType != SwitchUserMessageType::ANDROID_POST_SWITCH) {
+ return Error() << "Invalid " << toString(*messageType) << " from Android System";
+ }
+ request.requestId = propValue.value.int32Values[0];
+ request.messageType = *messageType;
+ ret = parseUserInfo(propValue.value.int32Values, 2, &request.targetUser);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse target user info: " << ret.error();
+ }
+ ret = parseUsersInfo(propValue.value.int32Values, 4, &request.usersInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse users info: " << ret.error();
+ }
+ return request;
+}
+
+Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue) {
+ auto ret = verifyPropValue(propValue, VehicleProperty::CREATE_USER, 1);
+ if (!ret.ok()) {
+ return ret.error();
+ }
+ CreateUserRequest request;
+ request.requestId = propValue.value.int32Values[0];
+ ret = parseUserInfo(propValue.value.int32Values, 1, &request.newUserInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse new user info: " << ret.error();
+ }
+ request.newUserName = propValue.value.stringValue;
+ ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse users info: " << ret.error();
+ }
+ return request;
+}
+
+Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue) {
+ auto ret = verifyPropValue(propValue, VehicleProperty::REMOVE_USER, 1);
+ if (!ret.ok()) {
+ return ret.error();
+ }
+ RemoveUserRequest request;
+ request.requestId = propValue.value.int32Values[0];
+ ret = parseUserInfo(propValue.value.int32Values, 1, &request.removedUserInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse removed user info: " << ret.error();
+ }
+ ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse users info: " << ret.error();
+ }
+ return request;
+}
+
+Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
+ const VehiclePropValue& propValue) {
+ auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
+ if (!ret.ok()) {
+ return ret.error();
+ }
+ UserIdentificationGetRequest request;
+ request.requestId = propValue.value.int32Values[0];
+ ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse user info: " << ret.error();
+ }
+ request.numberAssociationTypes = propValue.value.int32Values[3];
+ ret = parseUserAssociationTypes(propValue.value.int32Values, 4, request.numberAssociationTypes,
+ &request.associationTypes);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse UserIdentificationAssociationType: " << ret.error();
+ }
+ return request;
+}
+
+Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
+ const VehiclePropValue& propValue) {
+ auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
+ if (!ret.ok()) {
+ return ret.error();
+ }
+ UserIdentificationSetRequest request;
+ request.requestId = propValue.value.int32Values[0];
+ ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse user info: " << ret.error();
+ }
+ request.numberAssociations = propValue.value.int32Values[3];
+ ret = parseUserAssociations(propValue.value.int32Values, 4, request.numberAssociations,
+ &request.associations);
+ if (!ret.ok()) {
+ return Error() << "Failed to parse UserIdentificationSetAssociation: " << ret.error();
+ }
+ return request;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request) {
+ if (request.messageType != SwitchUserMessageType::VEHICLE_REQUEST) {
+ ALOGE("Invalid %s message type %s from HAL", toString(VehicleProperty::SWITCH_USER).c_str(),
+ toString(request.messageType).c_str());
+ return nullptr;
+ }
+ auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+ propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+ propValue->timestamp = elapsedRealtimeNano();
+ propValue->value.int32Values.resize(3);
+ propValue->value.int32Values[0] = static_cast<int32_t>(request.requestId);
+ propValue->value.int32Values[1] = static_cast<int32_t>(request.messageType);
+ propValue->value.int32Values[2] = static_cast<int32_t>(request.targetUser.userId);
+ return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response) {
+ auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+ propValue->prop = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
+ propValue->timestamp = elapsedRealtimeNano();
+ propValue->value.int32Values.resize(4);
+ propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+ propValue->value.int32Values[1] = static_cast<int32_t>(response.action);
+ propValue->value.int32Values[2] = static_cast<int32_t>(response.userToSwitchOrCreate.userId);
+ propValue->value.int32Values[3] = static_cast<int32_t>(response.userToSwitchOrCreate.flags);
+ propValue->value.stringValue = std::string(response.userLocales) + std::string(kSeparator) +
+ std::string(response.userNameToCreate);
+ return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response) {
+ auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+ propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+ propValue->timestamp = elapsedRealtimeNano();
+ propValue->value.int32Values.resize(3);
+ propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+ propValue->value.int32Values[1] = static_cast<int32_t>(response.messageType);
+ propValue->value.int32Values[2] = static_cast<int32_t>(response.status);
+ if (response.status == SwitchUserStatus::FAILURE) {
+ propValue->value.stringValue = response.errorMessage;
+ }
+ return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response) {
+ auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+ propValue->prop = static_cast<int32_t>(VehicleProperty::CREATE_USER);
+ propValue->timestamp = elapsedRealtimeNano();
+ propValue->value.int32Values.resize(2);
+ propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+ propValue->value.int32Values[1] = static_cast<int32_t>(response.status);
+ if (response.status == CreateUserStatus::FAILURE) {
+ propValue->value.stringValue = response.errorMessage;
+ }
+ return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response) {
+ auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+ propValue->prop = static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+ propValue->timestamp = elapsedRealtimeNano();
+ propValue->value.int32Values.resize(2 + (response.numberAssociation * 2));
+ propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+ propValue->value.int32Values[1] = static_cast<int32_t>(response.numberAssociation);
+ for (size_t i = 0; i < static_cast<size_t>(response.numberAssociation); ++i) {
+ size_t int32ValuesPos = 2 + (2 * i);
+ propValue->value.int32Values[int32ValuesPos] =
+ static_cast<int32_t>(response.associations[i].type);
+ propValue->value.int32Values[int32ValuesPos + 1] =
+ static_cast<int32_t>(response.associations[i].value);
+ }
+ if (!response.errorMessage.empty()) {
+ propValue->value.stringValue = response.errorMessage;
+ }
+ return propValue;
+}
+
+} // namespace user_hal_helper
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.h b/automotive/vehicle/2.0/utils/UserHalHelper.h
new file mode 100644
index 0000000..bee34cf
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
+
+#include <android-base/result.h>
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include <functional>
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace user_hal_helper {
+
+// Below functions parse VehiclePropValues to the respective User HAL request structs. On success,
+// these functions return the User HAL struct. Otherwise, they return the error.
+android::base::Result<InitialUserInfoRequest> toInitialUserInfoRequest(
+ const VehiclePropValue& propValue);
+android::base::Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue);
+android::base::Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue);
+android::base::Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue);
+android::base::Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
+ const VehiclePropValue& propValue);
+android::base::Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
+ const VehiclePropValue& propValue);
+
+// Below functions convert the User HAL structs to VehiclePropValues. On success, these functions
+// return the pointer to VehiclePropValue. Otherwise, they return nullptr.
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response);
+
+} // namespace user_hal_helper
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
diff --git a/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
new file mode 100644
index 0000000..7da87a2
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
@@ -0,0 +1,666 @@
+/*
+ * 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 "UserHalHelper.h"
+
+#include <gtest/gtest.h>
+
+#include <cstdint>
+
+#include "gmock/gmock.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace user_hal_helper {
+
+namespace {
+
+using testing::Eq;
+using testing::Gt;
+using testing::IsNull;
+using testing::NotNull;
+using testing::Pointee;
+
+constexpr int32_t INITIAL_USER_INFO = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
+constexpr int32_t SWITCH_USER = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+constexpr int32_t CREATE_USER = static_cast<int32_t>(VehicleProperty::CREATE_USER);
+constexpr int32_t REMOVE_USER = static_cast<int32_t>(VehicleProperty::REMOVE_USER);
+constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
+ static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+
+constexpr int32_t FIRST_BOOT_AFTER_OTA =
+ static_cast<int32_t>(InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA);
+constexpr int32_t LEGACY_ANDROID_SWITCH =
+ static_cast<int32_t>(SwitchUserMessageType::LEGACY_ANDROID_SWITCH);
+constexpr int32_t VEHICLE_REQUEST = static_cast<int32_t>(SwitchUserMessageType::VEHICLE_REQUEST);
+
+constexpr int32_t GUEST_USER = static_cast<int32_t>(UserFlags::GUEST);
+constexpr int32_t NONE_USER = static_cast<int32_t>(UserFlags::NONE);
+constexpr int32_t SYSTEM_USER = static_cast<int32_t>(UserFlags::SYSTEM);
+
+constexpr int32_t USER_ID_ASSOC_KEY_FOB =
+ static_cast<int32_t>(UserIdentificationAssociationType::KEY_FOB);
+constexpr int32_t USER_ID_ASSOC_CUSTOM_1 =
+ static_cast<int32_t>(UserIdentificationAssociationType::CUSTOM_1);
+
+constexpr int32_t USER_ID_ASSOC_SET_CURRENT_USER =
+ static_cast<int32_t>(UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER);
+constexpr int32_t USER_ID_ASSOC_UNSET_CURRENT_USER =
+ static_cast<int32_t>(UserIdentificationAssociationSetValue::DISASSOCIATE_CURRENT_USER);
+
+constexpr int32_t USER_ID_ASSOC_CURRENT_USER =
+ static_cast<int32_t>(UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER);
+constexpr int32_t USER_ID_ASSOC_NO_USER =
+ static_cast<int32_t>(UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER);
+
+} // namespace
+
+TEST(UserHalHelperTest, TestToInitialUserInfoRequest) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
+ 10, NONE_USER}},
+ };
+ InitialUserInfoRequest expected{
+ .requestId = 23,
+ .requestType = InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA,
+ .usersInfo = {{10, UserFlags::NONE},
+ 2,
+ {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithMismatchingPropType) {
+ VehiclePropValue propValue{
+ .prop = INT32_MAX,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
+ 10, NONE_USER}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithInvalidRequestType) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, INT32_MAX, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+ NONE_USER}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on invalid request type";
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithInvalidUserFlag) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
+ 10, INT32_MAX}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on invalid user flags";
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithIncompleteUsersInfo) {
+ VehiclePropValue propValueMissingSecondUserInfo{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0,
+ SYSTEM_USER /*Missing 2nd UserInfo*/}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValueMissingSecondUserInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+ VehiclePropValue propValueMissingUsersInfo{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, /*Missing UsersInfo*/}},
+ };
+
+ actual = toInitialUserInfoRequest(propValueMissingUsersInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+}
+
+TEST(UserHalHelperTest, TestToSwitchUserRequest) {
+ VehiclePropValue propValue{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER, 10, NONE_USER, 2,
+ 0, SYSTEM_USER, 10, NONE_USER}},
+ };
+ SwitchUserRequest expected{
+ .requestId = 23,
+ .messageType = SwitchUserMessageType::LEGACY_ANDROID_SWITCH,
+ .targetUser = {0, UserFlags::SYSTEM},
+ .usersInfo = {{10, UserFlags::NONE},
+ 2,
+ {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+ };
+
+ auto actual = toSwitchUserRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToSwitchUserRequestWithMismatchingPropType) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER, 10, NONE_USER, 2,
+ 0, SYSTEM_USER, 10, NONE_USER}},
+ };
+
+ auto actual = toSwitchUserRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToSwitchUserRequestWithInvalidMessageType) {
+ VehiclePropValue propValueIncompatibleMessageType{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23, VEHICLE_REQUEST, 0, SYSTEM_USER, 10, NONE_USER, 2, 0,
+ SYSTEM_USER, 10, NONE_USER}},
+ };
+
+ auto actual = toSwitchUserRequest(propValueIncompatibleMessageType);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on incompatible message type";
+
+ VehiclePropValue propValueInvalidMessageType{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23, INT32_MAX, 0, SYSTEM_USER, 10, NONE_USER, 2, 0,
+ SYSTEM_USER, 10, NONE_USER}},
+ };
+
+ actual = toSwitchUserRequest(propValueInvalidMessageType);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on invalid message type";
+}
+
+TEST(UserHalHelperTest, TestFailsToSwitchUserRequestWithIncompleteUsersInfo) {
+ VehiclePropValue propValueMissingSecondUserInfo{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER, 10, NONE_USER, 2,
+ 0, SYSTEM_USER,
+ /*Missing 2nd UserInfo*/}},
+ };
+
+ auto actual = toSwitchUserRequest(propValueMissingSecondUserInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+ VehiclePropValue propValueMissingUsersInfo{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER,
+ /*Missing UsersInfo*/}},
+ };
+
+ actual = toSwitchUserRequest(propValueMissingUsersInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+
+ VehiclePropValue propValueMissingTargetUser{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, /*Missing target UserInfo*/}},
+ };
+
+ actual = toSwitchUserRequest(propValueMissingTargetUser);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing target user info";
+}
+
+TEST(UserHalHelperTest, TestToCreateUserRequest) {
+ VehiclePropValue propValue{
+ .prop = CREATE_USER,
+ .value = {.int32Values = {23, 11, GUEST_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+ NONE_USER},
+ .stringValue = "Guest11"},
+ };
+ CreateUserRequest expected{
+ .requestId = 23,
+ .newUserInfo = {11, UserFlags::GUEST},
+ .newUserName = "Guest11",
+ .usersInfo = {{10, UserFlags::NONE},
+ 2,
+ {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+ };
+
+ auto actual = toCreateUserRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToCreateUserRequestWithMismatchingPropType) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, 11, GUEST_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+ NONE_USER},
+ .stringValue = "Guest11"},
+ };
+
+ auto actual = toCreateUserRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToCreateUserRequestWithIncompleteUsersInfo) {
+ VehiclePropValue propValueMissingSecondUserInfo{
+ .prop = CREATE_USER,
+ .value = {.int32Values = {23, 11, GUEST_USER, 10, NONE_USER, 2, 0,
+ SYSTEM_USER /*Missing 2nd UserInfo*/},
+ .stringValue = "Guest11"},
+ };
+
+ auto actual = toCreateUserRequest(propValueMissingSecondUserInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+ VehiclePropValue propValueMissingUsersInfo{
+ .prop = CREATE_USER,
+ .value = {.int32Values = {23, 11, GUEST_USER, /*Missing UsersInfo*/},
+ .stringValue = "Guest11"},
+ };
+
+ actual = toCreateUserRequest(propValueMissingUsersInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+
+ VehiclePropValue propValueMissingCreateUserInfo{
+ .prop = CREATE_USER,
+ .value = {.int32Values = {23, /*Missing create UserInfo*/}, .stringValue = "Guest11"},
+ };
+
+ actual = toCreateUserRequest(propValueMissingCreateUserInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing create user info";
+}
+
+TEST(UserHalHelperTest, TestToRemoveUserRequest) {
+ VehiclePropValue propValue{
+ .prop = REMOVE_USER,
+ .value = {.int32Values = {23, 10, NONE_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+ NONE_USER}},
+ };
+ RemoveUserRequest expected{
+ .requestId = 23,
+ .removedUserInfo = {10, UserFlags::NONE},
+ .usersInfo = {{10, UserFlags::NONE},
+ 2,
+ {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+ };
+
+ auto actual = toRemoveUserRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToRemoveUserRequestWithMismatchingPropType) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, 10, NONE_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+ NONE_USER}},
+ };
+
+ auto actual = toRemoveUserRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToRemoveUserRequestWithIncompleteUsersInfo) {
+ VehiclePropValue propValueMissingSecondUserInfo{
+ .prop = REMOVE_USER,
+ .value = {.int32Values = {23, 10, NONE_USER, 10, NONE_USER, 2, 0,
+ SYSTEM_USER /*Missing 2nd UserInfo*/}},
+ };
+
+ auto actual = toRemoveUserRequest(propValueMissingSecondUserInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+ VehiclePropValue propValueMissingUsersInfo{
+ .prop = REMOVE_USER,
+ .value = {.int32Values = {23, 10, NONE_USER, /*Missing UsersInfo*/}},
+ };
+
+ actual = toRemoveUserRequest(propValueMissingUsersInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+
+ VehiclePropValue propValueMissingRemoveUserInfo{
+ .prop = REMOVE_USER,
+ .value = {.int32Values = {23, /*Missing remove UserInfo*/}},
+ };
+
+ actual = toRemoveUserRequest(propValueMissingRemoveUserInfo);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing remove user info";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequest) {
+ VehiclePropValue propValue{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+ USER_ID_ASSOC_CUSTOM_1}},
+ };
+ UserIdentificationGetRequest expected{
+ .requestId = 23,
+ .userInfo = {10, UserFlags::NONE},
+ .numberAssociationTypes = 2,
+ .associationTypes = {UserIdentificationAssociationType::KEY_FOB,
+ UserIdentificationAssociationType::CUSTOM_1},
+ };
+
+ auto actual = toUserIdentificationGetRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithMismatchingPropType) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+ USER_ID_ASSOC_CUSTOM_1}},
+ };
+
+ auto actual = toUserIdentificationGetRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithInvalidAssociationTypes) {
+ VehiclePropValue propValue{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, 1, INT32_MAX}},
+ };
+
+ auto actual = toUserIdentificationGetRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on invalid association type";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithIncompleteAssociationTypes) {
+ VehiclePropValue propValueMissingSecondAssociationType{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, 2,
+ USER_ID_ASSOC_KEY_FOB /*Missing 2nd association type*/}},
+ };
+
+ auto actual = toUserIdentificationGetRequest(propValueMissingSecondAssociationType);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing second association type";
+
+ VehiclePropValue propValueMissingNumberAssociationTypes{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, /*Missing number association types*/}},
+ };
+
+ actual = toUserIdentificationGetRequest(propValueMissingNumberAssociationTypes);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing number association types";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithMissingUserInfo) {
+ VehiclePropValue propValue{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, /*Missing user info*/}},
+ };
+
+ auto actual = toUserIdentificationGetRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing UserInfo";
+}
+
+TEST(UserHalHelperTest, TestToUserIdentificationSetRequest) {
+ VehiclePropValue propValue{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+ USER_ID_ASSOC_SET_CURRENT_USER, USER_ID_ASSOC_CUSTOM_1,
+ USER_ID_ASSOC_UNSET_CURRENT_USER}},
+ };
+ UserIdentificationSetRequest expected{
+ .requestId = 23,
+ .userInfo = {10, UserFlags::NONE},
+ .numberAssociations = 2,
+ .associations = {{UserIdentificationAssociationType::KEY_FOB,
+ UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER},
+ {UserIdentificationAssociationType::CUSTOM_1,
+ UserIdentificationAssociationSetValue::DISASSOCIATE_CURRENT_USER}},
+ };
+
+ auto actual = toUserIdentificationSetRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithMismatchingPropType) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+ USER_ID_ASSOC_SET_CURRENT_USER, USER_ID_ASSOC_CUSTOM_1,
+ USER_ID_ASSOC_UNSET_CURRENT_USER}},
+ };
+
+ auto actual = toUserIdentificationSetRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithInvalidAssociations) {
+ VehiclePropValue propValueInvalidAssociationType{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, 1, INT32_MAX,
+ USER_ID_ASSOC_SET_CURRENT_USER}},
+ };
+
+ auto actual = toUserIdentificationSetRequest(propValueInvalidAssociationType);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on invalid association type";
+
+ VehiclePropValue propValueInvalidAssociationValue{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, USER_ID_ASSOC_KEY_FOB, INT32_MAX}},
+ };
+
+ actual = toUserIdentificationSetRequest(propValueInvalidAssociationValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing number association types";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithIncompleteAssociations) {
+ VehiclePropValue propValueMissingSecondAssociationType{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+ USER_ID_ASSOC_SET_CURRENT_USER,
+ /*Missing 2nd association*/}},
+ };
+
+ auto actual = toUserIdentificationSetRequest(propValueMissingSecondAssociationType);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing second association type";
+
+ VehiclePropValue propValueMissingNumberAssociationTypes{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 10, NONE_USER, /*Missing number associations*/}},
+ };
+
+ actual = toUserIdentificationSetRequest(propValueMissingNumberAssociationTypes);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing number association types";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithMissingUserInfo) {
+ VehiclePropValue propValue{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, /*Missing user info*/}},
+ };
+
+ auto actual = toUserIdentificationSetRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on missing UserInfo";
+}
+
+TEST(UserHalHelperTest, TestSwitchUserRequestToVehiclePropValue) {
+ SwitchUserRequest request{
+ .requestId = 23,
+ .messageType = SwitchUserMessageType::VEHICLE_REQUEST,
+ .targetUser = {11, UserFlags::GUEST},
+ };
+ VehiclePropValue expected{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23,
+ static_cast<int32_t>(SwitchUserMessageType::VEHICLE_REQUEST),
+ 11}},
+ };
+
+ auto actual = toVehiclePropValue(request);
+
+ ASSERT_THAT(actual, NotNull());
+ EXPECT_THAT(actual->timestamp, Gt(0));
+ // Don't rely on real timestamp in tests as the expected and actual objects won't have the same
+ // timestamps. Thus remove the timestamps before comparing them.
+ actual->timestamp = 0;
+ EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestFailsSwitchUserRequestToVehiclePropValueWithIncompatibleMessageType) {
+ SwitchUserRequest request{
+ .requestId = 23,
+ .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
+ .targetUser = {11, UserFlags::GUEST},
+ };
+
+ auto actual = toVehiclePropValue(request);
+
+ EXPECT_THAT(actual, IsNull());
+}
+
+TEST(UserHalHelperTest, TestInitialUserInfoResponseToVehiclePropValue) {
+ InitialUserInfoResponse response{
+ .requestId = 23,
+ .action = InitialUserInfoResponseAction::CREATE,
+ .userToSwitchOrCreate = {11, UserFlags::GUEST},
+ .userLocales = "en-US,pt-BR",
+ .userNameToCreate = "Owner",
+ };
+ VehiclePropValue expected{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23,
+ static_cast<int32_t>(InitialUserInfoResponseAction::CREATE),
+ 11, GUEST_USER},
+ .stringValue = "en-US,pt-BR||Owner"},
+ };
+
+ auto actual = toVehiclePropValue(response);
+
+ ASSERT_THAT(actual, NotNull());
+ EXPECT_THAT(actual->timestamp, Gt(0));
+ actual->timestamp = 0;
+ EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestSwitchUserResponseToVehiclePropValue) {
+ SwitchUserResponse response{
+ .requestId = 23,
+ .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
+ .status = SwitchUserStatus::FAILURE,
+ .errorMessage = "random error",
+ };
+ VehiclePropValue expected{
+ .prop = SWITCH_USER,
+ .value = {.int32Values = {23,
+ static_cast<int32_t>(SwitchUserMessageType::VEHICLE_RESPONSE),
+ static_cast<int32_t>(SwitchUserStatus::FAILURE)},
+ .stringValue = "random error"},
+ };
+
+ auto actual = toVehiclePropValue(response);
+
+ ASSERT_THAT(actual, NotNull());
+ EXPECT_THAT(actual->timestamp, Gt(0));
+ actual->timestamp = 0;
+ EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestCreateUserResponseToVehiclePropValue) {
+ CreateUserResponse response{
+ .requestId = 23,
+ .status = CreateUserStatus::FAILURE,
+ .errorMessage = "random error",
+ };
+ VehiclePropValue expected{
+ .prop = CREATE_USER,
+ .value = {.int32Values = {23, static_cast<int32_t>(CreateUserStatus::FAILURE)},
+ .stringValue = "random error"},
+ };
+
+ auto actual = toVehiclePropValue(response);
+
+ ASSERT_THAT(actual, NotNull());
+ EXPECT_THAT(actual->timestamp, Gt(0));
+ actual->timestamp = 0;
+ EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestUserIdentificationResponseToVehiclePropValue) {
+ UserIdentificationResponse response{
+ .requestId = 23,
+ .numberAssociation = 2,
+ .associations = {{UserIdentificationAssociationType::KEY_FOB,
+ UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER},
+ {UserIdentificationAssociationType::CUSTOM_1,
+ UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER}},
+ .errorMessage = "random error",
+ };
+ VehiclePropValue expected{
+ .prop = USER_IDENTIFICATION_ASSOCIATION,
+ .value = {.int32Values = {23, 2, USER_ID_ASSOC_KEY_FOB, USER_ID_ASSOC_CURRENT_USER,
+ USER_ID_ASSOC_CUSTOM_1, USER_ID_ASSOC_NO_USER},
+ .stringValue = "random error"},
+ };
+
+ auto actual = toVehiclePropValue(response);
+
+ ASSERT_THAT(actual, NotNull());
+ EXPECT_THAT(actual->timestamp, Gt(0));
+ actual->timestamp = 0;
+ EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+} // namespace user_hal_helper
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 384edf3..832c419 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -4453,9 +4453,12 @@
nullptr};
} else {
allocateGraphicBuffer(testStream.width, testStream.height,
- android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
- halStreamConfig.streams[0].consumerUsage),
- halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+ /* We don't look at halStreamConfig.streams[0].consumerUsage
+ * since that is 0 for output streams
+ */
+ android_convertGralloc1To0Usage(
+ halStreamConfig.streams[0].producerUsage, bufferUsage),
+ halStreamConfig.streams[0].overrideFormat, &buffer_handle);
outputBuffer = {halStreamConfig.streams[0].id,
bufferId,
buffer_handle,
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index d0b08a9..44fbc64 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -545,7 +545,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
- <version>1.0-3</version>
+ <version>1.0-4</version>
<interface>
<name>ISupplicant</name>
<instance>default</instance>
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp
index 5f83a22..a08c520 100644
--- a/contexthub/1.0/default/Contexthub.cpp
+++ b/contexthub/1.0/default/Contexthub.cpp
@@ -155,10 +155,10 @@
.message = static_cast<const uint8_t *>(msg.msg.data()),
};
- // Use a dummy to prevent send_message with empty message from failing prematurely
- static uint8_t dummy;
+ // Use a placeholder to prevent send_message with empty message from failing prematurely
+ static uint8_t placeholder;
if (txMsg.message_len == 0 && txMsg.message == nullptr) {
- txMsg.message = &dummy;
+ txMsg.message = &placeholder;
}
ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
@@ -255,7 +255,7 @@
memcpy(rsp, msg, sizeof(*rsp));
- // No sanity checks on return values
+ // No validations on return values
return true;
}
diff --git a/current.txt b/current.txt
index 6f5e559..594ceb6 100644
--- a/current.txt
+++ b/current.txt
@@ -770,6 +770,7 @@
cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardware.neuralnetworks@1.2::IDevice
9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
+7da2707d4cf93818eaf8038eb65e2180116a399c310e594a00935c5c981aa340 android.hardware.radio@1.0::types
38d65fb20c60a5b823298560fc0825457ecdc49603a4b4e94bf81511790737da android.hardware.radio@1.4::types
954c334efd80e8869b66d1ce5fe2755712d96ba4b3c38d415739c330af5fb4cb android.hardware.radio@1.5::types
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index d16a67b..1fe6c3e 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/hardware/gnss/2.1/IGnss.h>
+#include <errno.h>
#include <fcntl.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
@@ -158,14 +159,16 @@
template <class T_IGnss>
std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
char inputBuffer[INPUT_BUFFER_SIZE];
- mHardwareModeOn = false;
if (mGnssFd == -1) {
mGnssFd = open(GNSS_PATH, O_RDWR | O_NONBLOCK);
}
+
if (mGnssFd == -1) {
+ ALOGW("Failed to open /dev/gnss0 errno: %d", errno);
return nullptr;
}
- // Send control message to device
+ // Indicates it is a hardwareMode, don't report the default location.
+ mHardwareModeOn = true;
int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION));
if (bytes_write <= 0) {
return nullptr;
@@ -179,8 +182,7 @@
int bytes_read = -1;
std::string inputStr = "";
int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs);
- // Indicates it is a hardwareMode, don't need to wait outside.
- mHardwareModeOn = true;
+
if (epoll_ret == -1) {
return nullptr;
}
@@ -206,10 +208,12 @@
while (mIsActive == true) {
auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
this->reportSvStatus(svStatus);
-
auto currentLocation = getLocationFromHW();
- if (currentLocation != nullptr) {
- this->reportLocation(*currentLocation);
+ if (mHardwareModeOn) {
+ if (currentLocation != nullptr) {
+ // Only report location if the return from hardware is valid
+ this->reportLocation(*currentLocation);
+ }
} else {
if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
const auto location = Utils::getMockLocationV2_0();
@@ -218,13 +222,8 @@
const auto location = Utils::getMockLocationV1_0();
this->reportLocation(location);
}
-
- // Only need do the sleep in the static location mode, which mocks the "wait
- // for" hardware behavior.
- if (!mHardwareModeOn) {
- std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
- }
}
+ std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
}
});
return true;
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
index 91de3e9..fbcdb32 100644
--- a/light/aidl/Android.bp
+++ b/light/aidl/Android.bp
@@ -7,7 +7,7 @@
stability: "vintf",
backend: {
java: {
- platform_apis: true,
+ sdk_version: "module_current",
},
ndk: {
vndk: {
diff --git a/media/omx/1.0/vts/functional/README.md b/media/omx/1.0/vts/functional/README.md
index c5a6867..67f4aa5 100644
--- a/media/omx/1.0/vts/functional/README.md
+++ b/media/omx/1.0/vts/functional/README.md
@@ -1,12 +1,12 @@
## Omx Hal @ 1.0 tests ##
---
## Overview :
-The scope of the tests presented here is not restricted solely to testing omx hal @ 1.0 API but also test to omx core functionality and to an extent omx components as well. The current directory contains the following folders: audio, common, component, master and video. Besides common all other folders contain test fixtures for testing AV decoder, encoder components. Common constitutes files that are used across by these test applications.
+The scope of the tests presented here is not restricted solely to testing omx hal @ 1.0 API but also test to omx core functionality and to an extent omx components as well. The current directory contains the following folders: audio, common, component, store and video. Besides common all other folders contain test fixtures for testing AV decoder, encoder components. Common constitutes files that are used across by these test applications.
-#### master :
-Functionality of master is to enumerate all the omx components (and the roles it supports) available in android media framework.
+#### store :
+Functionality of store is to enumerate all the omx components (and the roles it supports) available in android media framework.
-usage: atest VtsHalMediaOmxV1\_0TargetMasterTest
+usage: atest VtsHalMediaOmxV1\_0TargetStoreTest
#### component :
This folder includes test fixtures that tests aspects common to all omx compatible components. For instance, port enabling/disabling, enumerating port formats, state transitions, flush, ..., stay common to all components irrespective of the service they offer. Test fixtures here are directed towards testing these (omx core). Every standard OMX compatible component is expected to pass these tests.
diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp
index 3845b9f..89df4ff 100644
--- a/media/omx/1.0/vts/functional/common/Android.bp
+++ b/media/omx/1.0/vts/functional/common/Android.bp
@@ -22,28 +22,24 @@
export_header_lib_headers: ["media_plugin_headers"],
export_include_dirs: ["."],
+ shared_libs: [
+ "libui",
+ ],
+
static_libs: [
"libgtest",
"libhidlmemory",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"android.hardware.media.omx@1.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
],
export_static_lib_headers: [
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
],
}
@@ -54,15 +50,10 @@
// Link to these statically as they are not guaranteed to be on the device.
static_libs: [
"VtsHalMediaOmxV1_0CommonUtil",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.common@1.0",
"android.hardware.media.omx@1.0",
"android.hardware.media@1.0",
"android.hidl.allocator@1.0",
@@ -73,6 +64,7 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
"libnativehelper",
+ "libui",
"libstagefright_foundation",
"libstagefright_omx_utils",
],
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
index d9d1157..9184c56 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
@@ -21,12 +21,6 @@
#include <android-base/logging.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.0/types.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/types.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -199,42 +193,6 @@
BufferInfo* buffer, uint32_t nFrameWidth,
uint32_t nFrameHeight, int32_t* nStride,
int format) {
- struct AllocatorV2 : public GrallocV2 {
- sp<IAllocator> mAllocator;
- sp<IMapper> mMapper;
- AllocatorV2(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
- : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
- AllocatorV2() = default;
- };
- struct AllocatorV3 : public GrallocV3 {
- sp<IAllocator> mAllocator;
- sp<IMapper> mMapper;
- AllocatorV3(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
- : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
- AllocatorV3() = default;
- };
- std::variant<AllocatorV2, AllocatorV3> grallocVar;
-
- sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2{};
- sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3{};
- sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator2{};
- sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocator3 =
- android::hardware::graphics::allocator::V3_0::IAllocator::getService();
- if (allocator3) {
- mapper3 =
- android::hardware::graphics::mapper::V3_0::IMapper::getService();
- ASSERT_NE(nullptr, mapper3.get());
- grallocVar.emplace<AllocatorV3>(std::move(allocator3), std::move(mapper3));
- } else {
- allocator2 =
- android::hardware::graphics::allocator::V2_0::IAllocator::getService();
- ASSERT_NE(nullptr, allocator2.get());
- mapper2 =
- android::hardware::graphics::mapper::V2_0::IMapper::getService();
- ASSERT_NE(nullptr, allocator2.get());
- grallocVar.emplace<AllocatorV2>(std::move(allocator2), std::move(mapper2));
- }
-
android::hardware::media::omx::V1_0::Status status{};
uint64_t usage{};
ASSERT_TRUE(omxNode->getGraphicBufferUsage(
@@ -246,57 +204,27 @@
}).isOk());
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ uint32_t stride;
+ buffer_handle_t handle = nullptr;
+ android::GraphicBufferAllocator& allocator = android::GraphicBufferAllocator::get();
+ android::status_t error = allocator.allocate(
+ nFrameWidth, nFrameHeight, static_cast<android::PixelFormat>(format), 1,
+ usage | BufferUsage::CPU_READ_OFTEN, &handle, &stride, "omx_vts_common");
+
+ ASSERT_EQ(error, android::NO_ERROR);
+ ASSERT_NE(handle, nullptr);
+
+ *nStride = static_cast<int32_t>(stride);
+ buffer->omxBuffer.nativeHandle = handle;
+ buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
+ buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
+ buffer->omxBuffer.attr.anwBuffer.stride = stride;
+ buffer->omxBuffer.attr.anwBuffer.format = static_cast<PixelFormat>(format);
+ buffer->omxBuffer.attr.anwBuffer.usage = usage | BufferUsage::CPU_READ_OFTEN;
+ buffer->omxBuffer.attr.anwBuffer.layerCount = 1;
static std::atomic_int32_t bufferIdCounter{0};
-
- std::visit([buffer, nFrameWidth, nFrameHeight, format, usage, nStride](auto&& gralloc) {
- using Gralloc = std::remove_reference_t<decltype(gralloc)>;
- using Descriptor = typename Gralloc::Descriptor;
- using DescriptorInfo = typename Gralloc::DescriptorInfo;
- using Error = typename Gralloc::Error;
- using Format = typename Gralloc::Format;
- using Usage = typename Gralloc::Usage;
-
- Error error{};
- Descriptor descriptor{};
-
- DescriptorInfo descriptorInfo{};
- descriptorInfo.width = nFrameWidth;
- descriptorInfo.height = nFrameHeight;
- descriptorInfo.layerCount = 1;
- descriptorInfo.format = static_cast<Format>(format);
- descriptorInfo.usage = usage | Usage(BufferUsage::CPU_READ_OFTEN);
-
- gralloc.mMapper->createDescriptor(descriptorInfo,
- [&error, &descriptor](
- Error _s,
- const Descriptor& _n1) {
- error = _s;
- descriptor = _n1;
- });
- ASSERT_EQ(error, Error::NONE);
-
- gralloc.mAllocator->allocate(
- descriptor, 1,
- [&](Error _s, uint32_t _n1,
- const ::android::hardware::hidl_vec<
- ::android::hardware::hidl_handle>& _n2) {
- ASSERT_EQ(Error::NONE, _s);
- *nStride = _n1;
- buffer->omxBuffer.nativeHandle = _n2[0];
- buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
- buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
- buffer->omxBuffer.attr.anwBuffer.stride = _n1;
- buffer->omxBuffer.attr.anwBuffer.format =
- static_cast<PixelFormat>(descriptorInfo.format);
- buffer->omxBuffer.attr.anwBuffer.usage =
- static_cast<uint32_t>(descriptorInfo.usage);
- buffer->omxBuffer.attr.anwBuffer.layerCount =
- descriptorInfo.layerCount;
- buffer->omxBuffer.attr.anwBuffer.id =
- (static_cast<uint64_t>(getpid()) << 32) |
- bufferIdCounter.fetch_add(1, std::memory_order_relaxed);
- });
- }, grallocVar);
+ buffer->omxBuffer.attr.anwBuffer.id = (static_cast<uint64_t>(getpid()) << 32) |
+ bufferIdCounter.fetch_add(1, std::memory_order_relaxed);
}
// allocate buffers needed on a component port
@@ -785,8 +713,8 @@
for (IOmx::ComponentInfo info : componentInfos) {
for (std::string role : info.mRoles) {
if (filter.empty()) {
- if (kWhiteListRoles.find(role.c_str()) == kWhiteListRoles.end()) {
- // This is for component test and the role is not in the white list.
+ if (kKnownRoles.find(role.c_str()) == kKnownRoles.end()) {
+ // This is for component test and the role is not supported.
continue;
}
} else if (role.find(filter) == std::string::npos) {
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index bb03dd0..b16c772 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -22,16 +22,6 @@
#endif
#include <getopt.h>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/common/1.2/types.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.0/types.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/types.h>
#include <gtest/gtest.h>
#include <hidl/ServiceManagement.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -46,6 +36,9 @@
#include <media/openmax/OMX_AudioExt.h>
#include <media/openmax/OMX_VideoExt.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
/* TIME OUTS (Wait time in dequeueMessage()) */
/* As component is switching states (loaded<->idle<->execute), dequeueMessage()
@@ -78,8 +71,8 @@
unknown,
};
-// White list audio/video roles to be tested.
-static std::set<std::string> kWhiteListRoles{
+// List known and thus tested audio/video roles.
+static std::set<std::string> kKnownRoles{
"audio_encoder.aac", "audio_encoder.amrnb", "audio_encoder.amrwb",
"audio_encoder.flac", "audio_decoder.aac", "audio_decoder.amrnb",
"audio_decoder.amrwb", "audio_decoder.flac", "audio_decoder.g711alaw",
@@ -312,35 +305,6 @@
/*
* common functions declarations
*/
-struct GrallocV2 {
- using Format = android::hardware::graphics::common::V1_0::PixelFormat;
- using Usage = android::hardware::hidl_bitfield<
- android::hardware::graphics::common::V1_0::BufferUsage>;
-
- using IAllocator = android::hardware::graphics::allocator::V2_0::IAllocator;
-
- using IMapper = android::hardware::graphics::mapper::V2_0::IMapper;
- using Error = android::hardware::graphics::mapper::V2_0::Error;
- using Descriptor = android::hardware::graphics::mapper::V2_0::BufferDescriptor;
- using YCbCrLayout = android::hardware::graphics::mapper::V2_0::YCbCrLayout;
- using DescriptorInfo = IMapper::BufferDescriptorInfo;
- using Rect = IMapper::Rect;
-};
-
-struct GrallocV3 {
- using Format = android::hardware::graphics::common::V1_2::PixelFormat;
- using Usage = android::hardware::hidl_bitfield<
- android::hardware::graphics::common::V1_2::BufferUsage>;
-
- using IAllocator = android::hardware::graphics::allocator::V3_0::IAllocator;
-
- using IMapper = android::hardware::graphics::mapper::V3_0::IMapper;
- using Error = android::hardware::graphics::mapper::V3_0::Error;
- using Descriptor = android::hardware::graphics::mapper::V3_0::BufferDescriptor;
- using YCbCrLayout = android::hardware::graphics::mapper::V3_0::YCbCrLayout;
- using DescriptorInfo = IMapper::BufferDescriptorInfo;
- using Rect = IMapper::Rect;
-};
Return<android::hardware::media::omx::V1_0::Status> setRole(sp<IOmxNode> omxNode,
const std::string& role);
diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/store/Android.bp
similarity index 87%
rename from media/omx/1.0/vts/functional/master/Android.bp
rename to media/omx/1.0/vts/functional/store/Android.bp
index 5953eb5..28d12ff 100644
--- a/media/omx/1.0/vts/functional/master/Android.bp
+++ b/media/omx/1.0/vts/functional/store/Android.bp
@@ -15,9 +15,9 @@
//
cc_test {
- name: "VtsHalMediaOmxV1_0TargetMasterTest",
+ name: "VtsHalMediaOmxV1_0TargetStoreTest",
defaults: ["VtsHalMediaOmxV1_0Defaults"],
- srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"],
+ srcs: ["VtsHalMediaOmxV1_0TargetStoreTest.cpp"],
test_suites: [
"general-tests",
"vts",
diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
similarity index 97%
rename from media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
rename to media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
index 68ee900..8c36347 100644
--- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
+++ b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "media_omx_hidl_master_test"
+#define LOG_TAG "media_omx_hidl_store_test"
#ifdef __LP64__
#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
#endif
@@ -55,7 +55,7 @@
#include <getopt.h>
#include <media_hidl_test_common.h>
-class MasterHidlTest : public ::testing::TestWithParam<std::string> {
+class StoreHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
omxStore = IOmxStore::getService(GetParam());
@@ -127,7 +127,7 @@
}
// Make sure IOmx and IOmxStore have the same set of instances.
-TEST(MasterHidlTest, instanceMatchValidation) {
+TEST(StoreHidlTest, instanceMatchValidation) {
auto omxInstances = android::hardware::getAllHalInstanceNames(IOmx::descriptor);
auto omxStoreInstances = android::hardware::getAllHalInstanceNames(IOmxStore::descriptor);
ASSERT_EQ(omxInstances.size(), omxInstances.size());
@@ -138,7 +138,7 @@
}
// list service attributes and verify expected formats
-TEST_P(MasterHidlTest, ListServiceAttr) {
+TEST_P(StoreHidlTest, ListServiceAttr) {
description("list service attributes");
android::hardware::media::omx::V1_0::Status status;
hidl_vec<IOmxStore::Attribute> attributes;
@@ -184,7 +184,7 @@
}
// get node prefix
-TEST_P(MasterHidlTest, getNodePrefix) {
+TEST_P(StoreHidlTest, getNodePrefix) {
description("get node prefix");
hidl_string prefix;
omxStore->getNodePrefix(
@@ -193,7 +193,7 @@
}
// list roles and validate all RoleInfo objects
-TEST_P(MasterHidlTest, ListRoles) {
+TEST_P(StoreHidlTest, ListRoles) {
description("list roles");
hidl_vec<IOmxStore::RoleInfo> roleList;
omxStore->listRoles([&roleList](hidl_vec<IOmxStore::RoleInfo> const& _nl) {
@@ -370,7 +370,7 @@
}
// list components and roles.
-TEST_P(MasterHidlTest, ListNodes) {
+TEST_P(StoreHidlTest, ListNodes) {
description("enumerate component and roles");
android::hardware::media::omx::V1_0::Status status;
hidl_vec<IOmx::ComponentInfo> nodeList;
@@ -419,6 +419,6 @@
}
INSTANTIATE_TEST_CASE_P(
- PerInstance, MasterHidlTest,
+ PerInstance, StoreHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IOmxStore::descriptor)),
android::hardware::PrintInstanceNameToString);
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
index 397bee6..3c0734e 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
@@ -23,8 +23,6 @@
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.0/types.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
@@ -289,11 +287,11 @@
};
// Mock IOmxBufferSource class. GraphicBufferSource.cpp in libstagefright/omx/
-// implements this class. Below is dummy class introduced to test if callback
+// implements this class. Below class is introduced to test if callback
// functions are actually being called or not
-struct DummyBufferSource : public IOmxBufferSource {
+struct MockBufferSource : public IOmxBufferSource {
public:
- DummyBufferSource(sp<IOmxNode> node) {
+ MockBufferSource(sp<IOmxNode> node) {
callback = 0;
executing = false;
omxNode = node;
@@ -311,7 +309,7 @@
android::Vector<BufferInfo> iBuffer, oBuffer;
};
-Return<void> DummyBufferSource::onOmxExecuting() {
+Return<void> MockBufferSource::onOmxExecuting() {
executing = true;
callback |= 0x1;
size_t index;
@@ -332,25 +330,25 @@
return Void();
};
-Return<void> DummyBufferSource::onOmxIdle() {
+Return<void> MockBufferSource::onOmxIdle() {
callback |= 0x2;
executing = false;
return Void();
};
-Return<void> DummyBufferSource::onOmxLoaded() {
+Return<void> MockBufferSource::onOmxLoaded() {
callback |= 0x4;
return Void();
};
-Return<void> DummyBufferSource::onInputBufferAdded(uint32_t buffer) {
+Return<void> MockBufferSource::onInputBufferAdded(uint32_t buffer) {
(void)buffer;
EXPECT_EQ(executing, false);
callback |= 0x8;
return Void();
};
-Return<void> DummyBufferSource::onInputBufferEmptied(
+Return<void> MockBufferSource::onInputBufferEmptied(
uint32_t buffer, const ::android::hardware::hidl_handle& fence) {
(void)fence;
callback |= 0x10;
@@ -364,61 +362,6 @@
return Void();
};
-// Variant of mappers
-struct MapperV2 : public GrallocV2 {
- sp<IMapper> mMapper;
- MapperV2(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
- MapperV2() = default;
- android::hardware::Return<void> lock(
- void* buffer,
- Usage usage,
- const Rect& rect,
- const android::hardware::hidl_handle& handle,
- Error* error,
- void** data) {
- return mMapper->lock(buffer, usage, rect, handle,
- [error, data](Error e, void* d) {
- *error = e;
- *data = d;
- });
- }
-};
-struct MapperV3 : public GrallocV3 {
- sp<IMapper> mMapper;
- MapperV3(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
- MapperV3() = default;
- android::hardware::Return<void> lock(
- void* buffer,
- Usage usage,
- const Rect& rect,
- const android::hardware::hidl_handle& handle,
- Error* error,
- void** data) {
- return mMapper->lock(buffer, usage, rect, handle,
- [error, data](Error e, void* d, int32_t, int32_t) {
- *error = e;
- *data = d;
- });
- }
-};
-using MapperVar = std::variant<MapperV2, MapperV3>;
-// Initializes the MapperVar by trying services of different versions.
-bool initialize(MapperVar& mapperVar) {
- sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3 =
- android::hardware::graphics::mapper::V3_0::IMapper::getService();
- if (mapper3) {
- mapperVar.emplace<MapperV3>(std::move(mapper3));
- return true;
- }
- sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2 =
- android::hardware::graphics::mapper::V2_0::IMapper::getService();
- if (mapper2) {
- mapperVar.emplace<MapperV2>(std::move(mapper2));
- return true;
- }
- return false;
-}
-
// request VOP refresh
void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) {
android::hardware::media::omx::V1_0::Status status;
@@ -627,168 +570,113 @@
}
}
-int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format,
+int colorFormatConversion(BufferInfo* buffer, buffer_handle_t buff, PixelFormat format,
std::ifstream& eleStream) {
- MapperVar mapperVar;
- if (!initialize(mapperVar)) {
- EXPECT_TRUE(false) << "failed to obtain mapper service";
- return 1;
+ android::GraphicBufferMapper& gbmapper = android::GraphicBufferMapper::get();
+
+ android::Rect rect(0, 0, buffer->omxBuffer.attr.anwBuffer.width,
+ buffer->omxBuffer.attr.anwBuffer.height);
+ android_ycbcr ycbcrLayout;
+ android::status_t error = android::NO_ERROR;
+
+ if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
+ format == PixelFormat::YCBCR_420_888) {
+ error = gbmapper.lockYCbCr(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect,
+ &ycbcrLayout);
+ EXPECT_EQ(error, android::NO_ERROR);
+ if (error != android::NO_ERROR) return 1;
+
+ int size = ((rect.getWidth() * rect.getHeight() * 3) >> 1);
+ char* img = new char[size];
+ if (img == nullptr) return 1;
+ eleStream.read(img, size);
+ if (eleStream.gcount() != size) {
+ delete[] img;
+ return 1;
+ }
+
+ char* imgTmp = img;
+ char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
+ for (size_t y = rect.getHeight(); y > 0; --y) {
+ memcpy(ipBuffer, imgTmp, rect.getWidth());
+ ipBuffer += ycbcrLayout.ystride;
+ imgTmp += rect.getWidth();
+ }
+
+ if (format == PixelFormat::YV12)
+ EXPECT_EQ(ycbcrLayout.chroma_step, 1U);
+ else if (format == PixelFormat::YCRCB_420_SP)
+ EXPECT_EQ(ycbcrLayout.chroma_step, 2U);
+
+ ipBuffer = static_cast<char*>(ycbcrLayout.cb);
+ for (size_t y = rect.getHeight() >> 1; y > 0; --y) {
+ for (int32_t x = 0; x < (rect.getWidth() >> 1); ++x) {
+ ipBuffer[ycbcrLayout.chroma_step * x] = *imgTmp++;
+ }
+ ipBuffer += ycbcrLayout.cstride;
+ }
+ ipBuffer = static_cast<char*>(ycbcrLayout.cr);
+ for (size_t y = rect.getHeight() >> 1; y > 0; --y) {
+ for (int32_t x = 0; x < (rect.getWidth() >> 1); ++x) {
+ ipBuffer[ycbcrLayout.chroma_step * x] = *imgTmp++;
+ }
+ ipBuffer += ycbcrLayout.cstride;
+ }
+
+ delete[] img;
+
+ error = gbmapper.unlock(buff);
+ EXPECT_EQ(error, android::NO_ERROR);
+ if (error != android::NO_ERROR) return 1;
+ } else {
+ void* data;
+ int32_t outBytesPerPixel;
+ int32_t outBytesPerStride;
+ error = gbmapper.lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, &data,
+ &outBytesPerPixel, &outBytesPerStride);
+ EXPECT_EQ(error, android::NO_ERROR);
+ if (error != android::NO_ERROR) return 1;
+
+ if (format == PixelFormat::BGRA_8888) {
+ char* ipBuffer = static_cast<char*>(data);
+ for (size_t y = rect.getHeight(); y > 0; --y) {
+ eleStream.read(ipBuffer, rect.getWidth() * 4);
+ if (eleStream.gcount() != rect.getWidth() * 4) return 1;
+ ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
+ }
+ } else {
+ EXPECT_TRUE(false) << "un expected pixel format";
+ return 1;
+ }
+
+ error = gbmapper.unlock(buff);
+ EXPECT_EQ(error, android::NO_ERROR);
+ if (error != android::NO_ERROR) return 1;
}
- return std::visit([buffer, buff, format, &eleStream](auto&& mapper) -> int {
- using Gralloc = std::remove_reference_t<decltype(mapper)>;
- using Error = typename Gralloc::Error;
- using Rect = typename Gralloc::Rect;
- using Usage = typename Gralloc::Usage;
- using YCbCrLayout = typename Gralloc::YCbCrLayout;
-
- android::hardware::hidl_handle fence;
- Rect rect;
- YCbCrLayout ycbcrLayout;
- Error error;
- rect.left = 0;
- rect.top = 0;
- rect.width = buffer->omxBuffer.attr.anwBuffer.width;
- rect.height = buffer->omxBuffer.attr.anwBuffer.height;
-
- if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
- format == PixelFormat::YCBCR_420_888) {
- mapper.mMapper->lockYCbCr(
- buff,
- static_cast<Usage>(
- buffer->omxBuffer.attr.anwBuffer.usage),
- rect,
- fence,
- [&](Error _e,
- const YCbCrLayout& _n1) {
- error = _e;
- ycbcrLayout = _n1;
- });
- EXPECT_EQ(error, Error::NONE);
- if (error != Error::NONE)
- return 1;
-
- int size = ((rect.width * rect.height * 3) >> 1);
- char* img = new char[size];
- if (img == nullptr) return 1;
- eleStream.read(img, size);
- if (eleStream.gcount() != size) {
- delete[] img;
- return 1;
- }
-
- char* imgTmp = img;
- char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
- for (size_t y = rect.height; y > 0; --y) {
- memcpy(ipBuffer, imgTmp, rect.width);
- ipBuffer += ycbcrLayout.yStride;
- imgTmp += rect.width;
- }
-
- if (format == PixelFormat::YV12)
- EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
- else if (format == PixelFormat::YCRCB_420_SP)
- EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
-
- ipBuffer = static_cast<char*>(ycbcrLayout.cb);
- for (size_t y = rect.height >> 1; y > 0; --y) {
- for (int32_t x = 0; x < (rect.width >> 1); ++x) {
- ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
- }
- ipBuffer += ycbcrLayout.cStride;
- }
- ipBuffer = static_cast<char*>(ycbcrLayout.cr);
- for (size_t y = rect.height >> 1; y > 0; --y) {
- for (int32_t x = 0; x < (rect.width >> 1); ++x) {
- ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
- }
- ipBuffer += ycbcrLayout.cStride;
- }
-
- delete[] img;
-
- mapper.mMapper->unlock(buff,
- [&](Error _e,
- const android::hardware::hidl_handle& _n1) {
- error = _e;
- fence = _n1;
- });
- EXPECT_EQ(error, Error::NONE);
- if (error != Error::NONE)
- return 1;
- } else {
- void* data;
- mapper.lock(
- buff,
- buffer->omxBuffer.attr.anwBuffer.usage,
- rect,
- fence,
- &error,
- &data);
- EXPECT_EQ(error, Error::NONE);
- if (error != Error::NONE)
- return 1;
-
- if (format == PixelFormat::BGRA_8888) {
- char* ipBuffer = static_cast<char*>(data);
- for (size_t y = rect.height; y > 0; --y) {
- eleStream.read(ipBuffer, rect.width * 4);
- if (eleStream.gcount() != rect.width * 4) return 1;
- ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
- }
- } else {
- EXPECT_TRUE(false) << "un expected pixel format";
- return 1;
- }
-
- mapper.mMapper->unlock(
- buff,
- [&](Error _e, const android::hardware::hidl_handle& _n1) {
- error = _e;
- fence = _n1;
- });
- EXPECT_EQ(error, Error::NONE);
- if (error != Error::NONE)
- return 1;
- }
-
- return 0;
- }, mapperVar);
+ return 0;
}
int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format,
std::ifstream& eleStream) {
- MapperVar mapperVar;
- if (!initialize(mapperVar)) {
- EXPECT_TRUE(false) << "failed to obtain mapper service";
- return 1;
- }
+ android::GraphicBufferMapper& gbmapper = android::GraphicBufferMapper::get();
+ buffer_handle_t buff;
+ android::status_t error = android::NO_ERROR;
+ gbmapper.importBuffer(
+ buffer->omxBuffer.nativeHandle, buffer->omxBuffer.attr.anwBuffer.width,
+ buffer->omxBuffer.attr.anwBuffer.height, buffer->omxBuffer.attr.anwBuffer.layerCount,
+ static_cast<android::PixelFormat>(format), buffer->omxBuffer.attr.anwBuffer.usage,
+ buffer->omxBuffer.attr.anwBuffer.stride, &buff);
+ EXPECT_EQ(error, android::NO_ERROR);
+ if (error != android::NO_ERROR) return 1;
- return std::visit([buffer, format, &eleStream](auto&& mapper) -> int {
- using Gralloc = std::remove_reference_t<decltype(mapper)>;
- using Error = typename Gralloc::Error;
+ if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
- void* buff = nullptr;
- Error error;
- mapper.mMapper->importBuffer(
- buffer->omxBuffer.nativeHandle,
- [&](Error _e, void* _n1) {
- error = _e;
- buff = _n1;
- });
- EXPECT_EQ(error, Error::NONE);
- if (error != Error::NONE)
- return 1;
+ error = gbmapper.freeBuffer(buff);
+ EXPECT_EQ(error, android::NO_ERROR);
+ if (error != android::NO_ERROR) return 1;
- if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
-
- error = mapper.mMapper->freeBuffer(buff);
- EXPECT_EQ(error, Error::NONE);
- if (error != Error::NONE)
- return 1;
-
- return 0;
- }, mapperVar);
+ return 0;
}
int dispatchGraphicBuffer(sp<IOmxNode> omxNode,
@@ -1143,7 +1031,7 @@
setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
xFramerate, eColorFormat);
- sp<DummyBufferSource> buffersource = new DummyBufferSource(omxNode);
+ sp<MockBufferSource> buffersource = new MockBufferSource(omxNode);
ASSERT_NE(buffersource, nullptr);
status = omxNode->setInputSurface(buffersource);
ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 8393cf5..025aa7c 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -1890,8 +1890,8 @@
};
struct CarrierRestrictions {
- vec<Carrier> allowedCarriers; // whitelist for allowed carriers
- vec<Carrier> excludedCarriers; // blacklist for explicitly excluded carriers
+ vec<Carrier> allowedCarriers; // Allowed carriers
+ vec<Carrier> excludedCarriers; // Explicitly excluded carriers
// which match allowed_carriers. Eg. allowedCarriers
// match mcc/mnc, excludedCarriers has same mcc/mnc and
// gid1 is ABCD. It means except the carrier whose gid1
diff --git a/radio/1.2/default/Radio.cpp b/radio/1.2/default/Radio.cpp
index 73512e4..28a815f 100644
--- a/radio/1.2/default/Radio.cpp
+++ b/radio/1.2/default/Radio.cpp
@@ -52,16 +52,16 @@
/**
* IRadio-defined request is called from the client and talk to the radio to get
* IRadioResponse-defined response or/and IRadioIndication-defined indication back to the
- * client. This dummy implementation omits and replaces the design and implementation of vendor
+ * client. This implementation omits and replaces the design and implementation of vendor
* codes that needs to handle the receipt of the request and the return of the response from the
- * radio; this just directly returns a dummy response back to the client.
+ * radio; this just directly returns a fake response back to the client.
*/
ALOGD("Radio Request: getIccCardStatus is entering");
if (mRadioResponse != nullptr || mRadioResponseV1_1 != nullptr ||
mRadioResponseV1_2 != nullptr) {
- // Dummy RadioResponseInfo as part of response to return in 1.0, 1.1 and 1.2
+ // Fake RadioResponseInfo as part of response to return in 1.0, 1.1 and 1.2
::android::hardware::radio::V1_0::RadioResponseInfo info;
info.serial = serial;
info.type = ::android::hardware::radio::V1_0::RadioResponseType::SOLICITED;
@@ -72,7 +72,7 @@
* return getIccCardStatusResponse.
*/
if (mRadioResponseV1_2 != nullptr) {
- // Dummy CardStatus as part of getIccCardStatusResponse_1_2 response to return
+ // Fake CardStatus as part of getIccCardStatusResponse_1_2 response to return
::android::hardware::radio::V1_2::CardStatus card_status;
card_status.base.cardState = ::android::hardware::radio::V1_0::CardState::ABSENT;
card_status.base.gsmUmtsSubscriptionAppIndex = 0;
@@ -80,7 +80,7 @@
mRadioResponseV1_2->getIccCardStatusResponse_1_2(info, card_status);
ALOGD("Radio Response: getIccCardStatusResponse_1_2 is sent");
} else if (mRadioResponseV1_1 != nullptr) {
- // Dummy CardStatus as part of getIccCardStatusResponse response to return
+ // Fake CardStatus as part of getIccCardStatusResponse response to return
::android::hardware::radio::V1_0::CardStatus card_status_V1_0;
card_status_V1_0.cardState = ::android::hardware::radio::V1_0::CardState::ABSENT;
card_status_V1_0.gsmUmtsSubscriptionAppIndex = 0;
@@ -88,7 +88,7 @@
mRadioResponseV1_1->getIccCardStatusResponse(info, card_status_V1_0);
ALOGD("Radio Response: getIccCardStatusResponse is sent");
} else {
- // Dummy CardStatus as part of getIccCardStatusResponse response to return
+ // Fake CardStatus as part of getIccCardStatusResponse response to return
::android::hardware::radio::V1_0::CardStatus card_status_V1_0;
card_status_V1_0.cardState = ::android::hardware::radio::V1_0::CardState::ABSENT;
card_status_V1_0.gsmUmtsSubscriptionAppIndex = 0;
diff --git a/radio/1.5/.hidl_for_system_ext b/radio/1.5/.hidl_for_system_ext
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/radio/1.5/.hidl_for_system_ext
diff --git a/radio/1.5/Android.bp b/radio/1.5/Android.bp
index 0542924..74de0fd 100644
--- a/radio/1.5/Android.bp
+++ b/radio/1.5/Android.bp
@@ -19,4 +19,5 @@
"android.hidl.safe_union@1.0",
],
gen_java: true,
+ system_ext_specific: true,
}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 24b7fd5..ca1593f 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -1265,7 +1265,7 @@
info.serviceType <= BarringInfo::ServiceType::OPERATOR_32));
reportedServices.insert(info.serviceType);
- // Any type that is "conditional" must have sane values for conditional barring
+ // Any type that is "conditional" must have valid values for conditional barring
// factor and time.
switch (info.barringType) {
case BarringInfo::BarringType::NONE: // fall through
@@ -1284,7 +1284,7 @@
// Certain types of barring are relevant for certain RANs. Ensure that only the right
// types are reported. Note that no types are required, simply that for a given technology
- // only certain types are valid. This is one way to sanity check that implementations are
+ // only certain types are valid. This is one way to check that implementations are
// not providing information that they don't have.
static const std::set<BarringInfo::ServiceType> UTRA_SERVICES{
BarringInfo::ServiceType::CS_SERVICE, BarringInfo::ServiceType::PS_SERVICE,
diff --git a/radio/config/1.1/.hidl_for_system_ext b/radio/config/1.1/.hidl_for_system_ext
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/radio/config/1.1/.hidl_for_system_ext
diff --git a/radio/config/1.1/Android.bp b/radio/config/1.1/Android.bp
index a5c3114..69d9a83 100644
--- a/radio/config/1.1/Android.bp
+++ b/radio/config/1.1/Android.bp
@@ -15,4 +15,5 @@
"android.hidl.base@1.0",
],
gen_java: true,
+ system_ext_specific: true,
}
diff --git a/radio/config/1.2/.hidl_for_system_ext b/radio/config/1.2/.hidl_for_system_ext
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/radio/config/1.2/.hidl_for_system_ext
diff --git a/radio/config/1.2/Android.bp b/radio/config/1.2/Android.bp
index 39d55ff..f751868 100644
--- a/radio/config/1.2/Android.bp
+++ b/radio/config/1.2/Android.bp
@@ -15,4 +15,5 @@
"android.hidl.base@1.0",
],
gen_java: true,
+ system_ext_specific: true,
}
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 4521824..078f5df 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -628,14 +628,4 @@
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/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
index 6804f3c..5a23ca5 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
@@ -67,6 +67,9 @@
FrontendTests mFrontendTests;
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
+
class TunerLnbHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -86,6 +89,9 @@
LnbTests mLnbTests;
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerLnbHidlTest);
+
class TunerDemuxHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -109,6 +115,9 @@
FilterTests mFilterTests;
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDemuxHidlTest);
+
class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -135,6 +144,9 @@
FilterTests mFilterTests;
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFilterHidlTest);
+
class TunerBroadcastHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -171,6 +183,9 @@
uint32_t* mLnbId = nullptr;
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest);
+
class TunerPlaybackHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -200,6 +215,9 @@
void playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf);
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerPlaybackHidlTest);
+
class TunerRecordHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -237,6 +255,9 @@
uint32_t* mLnbId = nullptr;
};
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerRecordHidlTest);
+
class TunerDescramblerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -270,4 +291,7 @@
DescramblerTests mDescramblerTests;
DvrTests mDvrTests;
};
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDescramblerHidlTest);
} // namespace
diff --git a/tv/tuner/1.1/Android.bp b/tv/tuner/1.1/Android.bp
index 2019050..032232d 100644
--- a/tv/tuner/1.1/Android.bp
+++ b/tv/tuner/1.1/Android.bp
@@ -16,4 +16,5 @@
"android.hardware.tv.tuner@1.0",
],
gen_java: false,
+ gen_java_constants: true,
}
diff --git a/tv/tuner/1.1/default/Dvr.cpp b/tv/tuner/1.1/default/Dvr.cpp
index bf4c77e..3a4ef1b 100644
--- a/tv/tuner/1.1/default/Dvr.cpp
+++ b/tv/tuner/1.1/default/Dvr.cpp
@@ -395,6 +395,7 @@
mDemux->sendFrontendInputToRecord(frameData, pid, static_cast<uint64_t>(esMeta[i].pts));
}
startFilterDispatcher(isVirtualFrontend, isRecording);
+ frameData.clear();
}
return true;
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
index 2d6214d..4d08afe 100644
--- a/tv/tuner/1.1/default/Filter.cpp
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -500,7 +500,12 @@
}
if (mPts) {
- return createMediaFilterEventWithIon(mFilterOutput);
+ Result result;
+ result = createMediaFilterEventWithIon(mFilterOutput);
+ if (result == Result::SUCCESS) {
+ mFilterOutput.clear();
+ }
+ return result;
}
for (int i = 0; i < mFilterOutput.size(); i += 188) {
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
index 21c7021..5c02b85 100644
--- a/tv/tuner/1.1/types.hal
+++ b/tv/tuner/1.1/types.hal
@@ -16,6 +16,7 @@
package android.hardware.tv.tuner@1.1;
+import @1.0::Constant;
import @1.0::DemuxFilterDownloadEvent;
import @1.0::DemuxFilterIpPayloadEvent;
import @1.0::DemuxFilterMediaEvent;
@@ -26,6 +27,30 @@
import @1.0::DemuxFilterTsRecordEvent;
import android.hidl.safe_union@1.0;
+@export
+enum Constant : @1.0::Constant {
+ /**
+ * An invalid mpuSequenceNumber in DemuxFilterMmtpRecordEvent.
+ */
+ INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = 0xFFFFFFFF,
+};
+
+@export
+enum Constant64Bit : uint64_t {
+ /**
+ * An invalid 64-bit Filter ID.
+ */
+ INVALID_FILTER_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+ /**
+ * An invalid 64-bit AV sync hardware ID.
+ */
+ INVALID_AV_SYNC_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+ /**
+ * An invalid pts in the DemuxFilterTsRecordEvent or DemuxFilterMmtpRecordEvent.
+ */
+ INVALID_PRESENTATION_TIME_STAMP = 0xFFFFFFFFFFFFFFFF,
+};
+
/**
* Filter Event for TS Record data.
*/
@@ -56,6 +81,13 @@
* MPU sequence number of the filtered data. This is only used for MMTP.
*/
uint32_t mpuSequenceNumber;
+
+ /**
+ * The Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
+ * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
+ * the SC_HEVC.
+ */
+ uint64_t pts;
};
/**
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
index 3ddb2b3..75d6252 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -17,7 +17,6 @@
#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <android/hidl/manager/1.0/IServiceNotification.h>
#include <hidl/HidlTransportSupport.h>
#include <wifi_system/hostapd_manager.h>
@@ -39,7 +38,6 @@
using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
using ::android::hardware::wifi::V1_0::ChipModeId;
using ::android::hardware::wifi::V1_0::IWifiChip;
-using ::android::hidl::manager::V1_0::IServiceNotification;
using ::android::wifi_system::HostapdManager;
using ::android::wifi_system::SupplicantManager;
@@ -68,55 +66,6 @@
}
} // namespace
-// Utility class to wait for wpa_hostapd's HIDL service registration.
-class ServiceNotificationListener : public IServiceNotification {
- public:
- Return<void> onRegistration(const hidl_string& fully_qualified_name,
- const hidl_string& instance_name,
- bool pre_existing) override {
- if (pre_existing) {
- return Void();
- }
- std::unique_lock<std::mutex> lock(mutex_);
- registered_.push_back(std::string(fully_qualified_name.c_str()) + "/" +
- instance_name.c_str());
- lock.unlock();
- condition_.notify_one();
- return Void();
- }
-
- bool registerForHidlServiceNotifications(const std::string& instance_name) {
- if (!IHostapd::registerForNotifications(instance_name, this)) {
- return false;
- }
- configureRpcThreadpool(2, false);
- return true;
- }
-
- bool waitForHidlService(uint32_t timeout_in_millis,
- const std::string& instance_name) {
- std::unique_lock<std::mutex> lock(mutex_);
- condition_.wait_for(lock, std::chrono::milliseconds(timeout_in_millis),
- [&]() { return registered_.size() >= 1; });
- if (registered_.size() != 1) {
- return false;
- }
- std::string expected_registered =
- std::string(IHostapd::descriptor) + "/" + instance_name;
- if (registered_[0] != expected_registered) {
- LOG(ERROR) << "Expected: " << expected_registered
- << ", Got: " << registered_[0];
- return false;
- }
- return true;
- }
-
- private:
- std::vector<std::string> registered_{};
- std::mutex mutex_;
- std::condition_variable condition_;
-};
-
void stopSupplicantIfNeeded(const std::string& instance_name) {
SupplicantManager supplicant_manager;
if (supplicant_manager.IsSupplicantRunning()) {
@@ -139,16 +88,11 @@
const std::string& hostapd_instance_name) {
initilializeDriverAndFirmware(wifi_instance_name);
- android::sp<ServiceNotificationListener> notification_listener =
- new ServiceNotificationListener();
- ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
- hostapd_instance_name));
-
HostapdManager hostapd_manager;
ASSERT_TRUE(hostapd_manager.StartHostapd());
- ASSERT_TRUE(
- notification_listener->waitForHidlService(500, hostapd_instance_name));
+ // Wait for hostapd service to come up.
+ IHostapd::getService(hostapd_instance_name);
}
bool is_1_1(const sp<IHostapd>& hostapd) {
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index addf066..5e7a371 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -18,7 +18,6 @@
#include <cutils/properties.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <android/hidl/manager/1.0/IServiceNotification.h>
#include <hidl/HidlTransportSupport.h>
#include <wifi_system/interface_tool.h>
@@ -45,7 +44,6 @@
using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using ::android::hidl::manager::V1_0::IServiceNotification;
using ::android::wifi_system::InterfaceTool;
using ::android::wifi_system::SupplicantManager;
@@ -120,55 +118,6 @@
}
} // namespace
-// Utility class to wait for wpa_supplicant's HIDL service registration.
-class ServiceNotificationListener : public IServiceNotification {
- public:
- Return<void> onRegistration(const hidl_string& fully_qualified_name,
- const hidl_string& instance_name,
- bool pre_existing) override {
- if (pre_existing) {
- return Void();
- }
- std::unique_lock<std::mutex> lock(mutex_);
- registered_.push_back(std::string(fully_qualified_name.c_str()) + "/" +
- instance_name.c_str());
- lock.unlock();
- condition_.notify_one();
- return Void();
- }
-
- bool registerForHidlServiceNotifications(const std::string& instance_name) {
- if (!ISupplicant::registerForNotifications(instance_name, this)) {
- return false;
- }
- configureRpcThreadpool(2, false);
- return true;
- }
-
- bool waitForHidlService(uint32_t timeout_in_millis,
- const std::string& instance_name) {
- std::unique_lock<std::mutex> lock(mutex_);
- condition_.wait_for(lock, std::chrono::milliseconds(timeout_in_millis),
- [&]() { return registered_.size() >= 1; });
- if (registered_.size() != 1) {
- return false;
- }
- std::string exptected_registered =
- std::string(ISupplicant::descriptor) + "/" + instance_name;
- if (registered_[0] != exptected_registered) {
- LOG(ERROR) << "Expected: " << exptected_registered
- << ", Got: " << registered_[0];
- return false;
- }
- return true;
- }
-
- private:
- std::vector<std::string> registered_{};
- std::mutex mutex_;
- std::condition_variable condition_;
-};
-
void stopSupplicant() { stopSupplicant(""); }
void stopSupplicant(const std::string& wifi_instance_name) {
@@ -184,17 +133,12 @@
const std::string& supplicant_instance_name) {
initilializeDriverAndFirmware(wifi_instance_name);
- android::sp<ServiceNotificationListener> notification_listener =
- new ServiceNotificationListener();
- ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
- supplicant_instance_name));
-
SupplicantManager supplicant_manager;
ASSERT_TRUE(supplicant_manager.StartSupplicant());
ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
- ASSERT_TRUE(notification_listener->waitForHidlService(
- 500, supplicant_instance_name));
+ // Wait for supplicant service to come up.
+ ISupplicant::getService(supplicant_instance_name);
}
bool is_1_1(const sp<ISupplicant>& supplicant) {
diff --git a/wifi/supplicant/1.4/Android.bp b/wifi/supplicant/1.4/Android.bp
new file mode 100644
index 0000000..ff2a8bc
--- /dev/null
+++ b/wifi/supplicant/1.4/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.supplicant@1.4",
+ root: "android.hardware",
+ srcs: [
+ "ISupplicant.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi.supplicant@1.3",
+ "android.hardware.wifi@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+ apex_available: [
+ "com.android.wifi",
+ ],
+}
diff --git a/wifi/supplicant/1.4/ISupplicant.hal b/wifi/supplicant/1.4/ISupplicant.hal
new file mode 100644
index 0000000..9cb88ba
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicant.hal
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi.supplicant@1.4;
+
+import @1.3::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.4 features you must cast specific interfaces returned from the
+ * 1.1 HAL. For example V1_1::ISupplicant::addIface() adds V1_0::ISupplicantIface,
+ * which can be cast to V1_4::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.3::ISupplicant {};