Merge "Change 'blacklist' to 'disallow'"
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
index 6e2c782..928ad13 100644
--- a/automotive/can/1.0/default/libnetdevice/Android.bp
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -20,11 +20,25 @@
vendor_available: true,
relative_install_path: "hw",
srcs: [
+ "protocols/common/Empty.cpp",
+ "protocols/common/Error.cpp",
+ "protocols/generic/Ctrl.cpp",
+ "protocols/generic/Generic.cpp",
+ "protocols/generic/GenericMessageBase.cpp",
+ "protocols/generic/Unknown.cpp",
+ "protocols/route/Link.cpp",
+ "protocols/route/Route.cpp",
+ "protocols/MessageDefinition.cpp",
+ "protocols/NetlinkProtocol.cpp",
+ "protocols/all.cpp",
"NetlinkRequest.cpp",
"NetlinkSocket.cpp",
"can.cpp",
"common.cpp",
+ "ethtool.cpp",
+ "ifreqs.cpp",
"libnetdevice.cpp",
+ "printer.cpp",
"vlan.cpp",
],
export_include_dirs: ["include"],
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
index 3e28d78..5bea333 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -16,6 +16,8 @@
#pragma once
+#include "types.h"
+
#include <android-base/macros.h>
#include <linux/rtnetlink.h>
@@ -23,12 +25,10 @@
namespace android::netdevice {
-typedef unsigned short rtattrtype_t; // as in rtnetlink.h
-typedef __u16 nlmsgtype_t; // as in netlink.h
-
/** 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);
@@ -36,6 +36,7 @@
} // namespace impl
+// TODO(twasilczyk): rename to NetlinkMessage
/**
* Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
*
@@ -44,6 +45,14 @@
*/
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.
*
@@ -131,12 +140,7 @@
private:
bool mIsGood = true;
-
- struct {
- struct nlmsghdr nlmsg;
- T data;
- char buf[BUFSIZE];
- } mRequest = {};
+ RequestData mRequest = {};
struct rtattr* nestStart(rtattrtype_t type) {
if (!mIsGood) return nullptr;
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
index 7817169..15c0f9b 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -16,11 +16,18 @@
#include "NetlinkSocket.h"
+#include <libnetdevice/printer.h>
+
#include <android-base/logging.h>
namespace android::netdevice {
-NetlinkSocket::NetlinkSocket(int protocol) {
+/**
+ * Print all outbound/inbound Netlink messages.
+ */
+static constexpr bool kSuperVerbose = false;
+
+NetlinkSocket::NetlinkSocket(int protocol) : mProtocol(protocol) {
mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
if (!mFd.ok()) {
PLOG(ERROR) << "Can't open Netlink socket";
@@ -38,7 +45,13 @@
}
}
-bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
+bool NetlinkSocket::send(struct 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
@@ -91,6 +104,11 @@
for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
+ if constexpr (kSuperVerbose) {
+ LOG(VERBOSE) << "received Netlink response: "
+ << toString(nlmsg, sizeof(buf), 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;
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
index 2b40ea2..595c31a 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -43,7 +43,7 @@
template <class T, unsigned int BUFSIZE>
bool send(NetlinkRequest<T, BUFSIZE>& req) {
if (!req.isGood()) return false;
- return send(req.header());
+ return send(req.header(), req.totalLength);
}
/**
@@ -54,11 +54,13 @@
bool receiveAck();
private:
+ const int mProtocol;
+
uint32_t mSeq = 0;
base::unique_fd mFd;
bool mFailed = false;
- bool send(struct nlmsghdr* msg);
+ bool send(struct nlmsghdr* msg, size_t totalLen);
DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
};
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 5c62443..103cf53 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -22,6 +22,8 @@
namespace android::netdevice {
+socketparams::Params socketparams::current = general;
+
unsigned int nametoindex(const std::string& ifname) {
const auto ifidx = if_nametoindex(ifname.c_str());
if (ifidx != 0) return ifidx;
@@ -33,4 +35,27 @@
return 0;
}
+std::string sanitize(std::string str) {
+ str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
+
+ 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) {
+ for (const auto byte : data.getRaw()) {
+ crc ^= byte;
+ for (unsigned i = 0; i < 8; i++) {
+ if (crc & 1) {
+ crc = (crc >> 1) ^ 0xA001;
+ } else {
+ crc >>= 1;
+ }
+ }
+ }
+ return crc;
+}
+
} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 8097f37..1e04d41 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -16,10 +16,30 @@
#pragma once
+#include "nlbuf.h"
+
+#include <linux/can.h>
+#include <net/if.h>
+
#include <string>
namespace android::netdevice {
+namespace socketparams {
+
+struct Params {
+ int domain;
+ int type;
+ int protocol;
+};
+
+constexpr Params general = {AF_INET, SOCK_DGRAM, 0};
+constexpr Params can = {PF_CAN, SOCK_RAW, CAN_RAW};
+
+extern Params current;
+
+} // namespace socketparams
+
/**
* Returns the index of a given network interface.
*
@@ -31,4 +51,24 @@
*/
unsigned int nametoindex(const std::string& ifname);
+/**
+ * Sanitize a string of unknown contents.
+ *
+ * Trims the string to the first '\0' character and replaces all non-printable characters with '?'.
+ */
+std::string sanitize(std::string str);
+
+/**
+ * Calculates a (optionally running) CRC16 checksum.
+ *
+ * CRC16 isn't a strong checksum, but is good for quick comparison purposes.
+ * One benefit (and also a drawback too) is that all-zero payloads with any length will
+ * always have a checksum of 0x0000.
+ *
+ * \param data Buffer to calculate checksum for
+ * \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);
+
} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/ethtool.cpp b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
new file mode 100644
index 0000000..762ef5c
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 <libnetdevice/ethtool.h>
+
+#include "ifreqs.h"
+
+#include <linux/ethtool.h>
+
+namespace android::netdevice::ethtool {
+
+std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command) {
+ struct ethtool_value valueop = {};
+ valueop.cmd = command;
+
+ auto ifr = ifreqs::fromName(ifname);
+ ifr.ifr_data = &valueop;
+
+ if (!ifreqs::send(SIOCETHTOOL, ifr)) return std::nullopt;
+ return valueop.data;
+}
+
+bool setValue(const std::string& ifname, uint32_t command, uint32_t value) {
+ struct ethtool_value valueop = {};
+ valueop.cmd = command;
+ valueop.data = value;
+
+ auto ifr = ifreqs::fromName(ifname);
+ ifr.ifr_data = &valueop;
+
+ return ifreqs::send(SIOCETHTOOL, ifr);
+}
+
+} // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
new file mode 100644
index 0000000..9335021
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "ifreqs.h"
+
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android::netdevice::ifreqs {
+
+bool send(unsigned long request, struct ifreq& ifr) {
+ base::unique_fd sock(socket(socketparams::current.domain, socketparams::current.type,
+ socketparams::current.protocol));
+ if (!sock.ok()) {
+ LOG(ERROR) << "Can't create socket";
+ return false;
+ }
+
+ if (ioctl(sock.get(), request, &ifr) < 0) {
+ PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
+ return false;
+ }
+
+ return true;
+}
+
+struct ifreq fromName(const std::string& ifname) {
+ struct ifreq ifr = {};
+ strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+ return ifr;
+}
+
+} // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.h b/automotive/can/1.0/default/libnetdevice/ifreqs.h
new file mode 100644
index 0000000..25a40a6
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.h
@@ -0,0 +1,42 @@
+/*
+ * 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 <net/if.h>
+
+#include <string>
+
+namespace android::netdevice::ifreqs {
+
+/**
+ * Sends ioctl interface request.
+ *
+ * \param request Request type (such as SIOCGIFFLAGS)
+ * \param ifr Request data (both input and output)
+ * \return true if the call succeeded, false otherwise
+ */
+bool send(unsigned long request, struct ifreq& ifr);
+
+/**
+ * Initializes interface request with interface name.
+ *
+ * \param ifname Interface to initialize request with
+ * \return Interface request with ifr_name field set to ifname
+ */
+struct ifreq fromName(const std::string& ifname);
+
+} // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
new file mode 100644
index 0000000..26bfdce
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
@@ -0,0 +1,45 @@
+/*
+ * 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 <optional>
+#include <string>
+
+namespace android::netdevice::ethtool {
+
+/**
+ * Fetch a single value with ethtool_value.
+ *
+ * \see linux/ethtool.h
+ * \param ifname Interface to fetch data for
+ * \param command Fetch command (ETHTOOL_G*)
+ * \return value, or nullopt if fetch failed
+ */
+std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command);
+
+/**
+ * Set a single value with ethtool_value.
+ *
+ * \see linux/ethtool.h
+ * \param ifname Interface to set data for
+ * \param command Set command (ETHTOOL_S*)
+ * \param value New value
+ * \return true if succeeded, false otherwise
+ */
+bool setValue(const std::string& ifname, uint32_t command, uint32_t value);
+
+} // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h
new file mode 100644
index 0000000..efeb6b1
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/printer.h
@@ -0,0 +1,27 @@
+/*
+ * 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>
+
+#include <string>
+
+namespace android::netdevice {
+
+std::string toString(const nlmsghdr* hdr, size_t bufLen, int protocol);
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index 827f8f3..73b91d0 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -19,6 +19,7 @@
#include "NetlinkRequest.h"
#include "NetlinkSocket.h"
#include "common.h"
+#include "ifreqs.h"
#include <android-base/logging.h>
@@ -27,21 +28,6 @@
namespace android::netdevice {
-namespace socketparams {
-
-struct Params {
- int domain;
- int type;
- int protocol;
-};
-
-static constexpr Params general = {AF_INET, SOCK_DGRAM, 0};
-static constexpr Params can = {PF_CAN, SOCK_RAW, CAN_RAW};
-
-static Params current = general;
-
-} // namespace socketparams
-
void useCanSockets(bool yes) {
socketparams::current = yes ? socketparams::can : socketparams::general;
}
@@ -50,31 +36,9 @@
return nametoindex(ifname) != 0;
}
-static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
- base::unique_fd sock(socket(socketparams::current.domain, socketparams::current.type,
- socketparams::current.protocol));
- if (!sock.ok()) {
- LOG(ERROR) << "Can't create socket";
- return false;
- }
-
- if (ioctl(sock.get(), request, &ifr) < 0) {
- PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
- return false;
- }
-
- return true;
-}
-
-static struct ifreq ifreqFromName(const std::string& ifname) {
- struct ifreq ifr = {};
- strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
- return ifr;
-}
-
std::optional<bool> isUp(std::string ifname) {
- struct ifreq ifr = ifreqFromName(ifname);
- if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
return ifr.ifr_flags & IFF_UP;
}
@@ -83,17 +47,17 @@
}
bool up(std::string ifname) {
- struct ifreq ifr = ifreqFromName(ifname);
- if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
ifr.ifr_flags |= IFF_UP;
- return sendIfreq(SIOCSIFFLAGS, ifr);
+ return ifreqs::send(SIOCSIFFLAGS, ifr);
}
bool down(std::string ifname) {
- struct ifreq ifr = ifreqFromName(ifname);
- if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+ auto ifr = ifreqs::fromName(ifname);
+ if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
ifr.ifr_flags &= ~IFF_UP;
- return sendIfreq(SIOCSIFFLAGS, ifr);
+ return ifreqs::send(SIOCSIFFLAGS, ifr);
}
bool add(std::string dev, std::string type) {
diff --git a/automotive/can/1.0/default/libnetdevice/nlbuf.h b/automotive/can/1.0/default/libnetdevice/nlbuf.h
new file mode 100644
index 0000000..f7e53be
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/nlbuf.h
@@ -0,0 +1,189 @@
+/*
+ * 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 <linux/netlink.h>
+
+#include <optional>
+
+namespace android::netdevice {
+
+/**
+ * Buffer containing netlink structure (e.g. struct nlmsghdr, struct nlattr).
+ *
+ * This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
+ *
+ * While netlink structures contain information about their total length (with payload), they can
+ * 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):
+ * - 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
+ *
+ * In most cases buffer length would be larger than declared length (or equal - modulo alignment -
+ * for continuous data). If that's not the case, there is a potential of ouf-of-bounds read which
+ * 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));
+
+ public:
+ nlbuf(const T* data, size_t bufferLen) : mData(data), mBufferEnd(pointerAdd(data, bufferLen)) {}
+
+ const T* operator->() const {
+ CHECK(firstOk()) << "buffer can't fit the first element's header";
+ return mData;
+ }
+
+ std::optional<std::reference_wrapper<const T>> getFirst() const {
+ if (!ok()) return std::nullopt;
+ return *mData;
+ }
+
+ /**
+ * 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.
+ */
+ T copyFirst() const {
+ T val = {};
+ memcpy(&val, mData, std::min(sizeof(val), remainingLength()));
+ return val;
+ }
+
+ 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()};
+ }
+
+ class iterator {
+ public:
+ iterator() : mCurrent(nullptr, size_t(0)) {
+ CHECK(!mCurrent.ok()) << "end() iterator should indicate it's beyond end";
+ }
+ iterator(const nlbuf<T>& buf) : mCurrent(buf) {}
+
+ iterator operator++() {
+ // mBufferEnd stays the same
+ mCurrent.mData = reinterpret_cast<const T*>( //
+ uintptr_t(mCurrent.mData) + 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;
+
+ return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
+ }
+
+ const nlbuf<T>& operator*() const { return mCurrent; }
+
+ protected:
+ nlbuf<T> mCurrent;
+ };
+ iterator begin() const { return {*this}; }
+ iterator end() const { return {}; }
+
+ class raw_iterator : public iterator {
+ public:
+ iterator operator++() {
+ this->mCurrent.mData++; // ignore alignment
+ return *this;
+ }
+ const T& operator*() const { return *this->mCurrent.mData; }
+ };
+
+ class raw_view {
+ public:
+ raw_view(const nlbuf<T>& buffer) : mBuffer(buffer) {}
+ raw_iterator begin() const { return {mBuffer}; }
+ raw_iterator end() const { return {}; }
+
+ const T* ptr() const { return mBuffer.mData; }
+ size_t len() const { return mBuffer.remainingLength(); }
+
+ private:
+ const nlbuf<T>& mBuffer;
+ };
+
+ raw_view getRaw() const { return {*this}; }
+
+ private:
+ const T* mData;
+ const void* mBufferEnd;
+
+ nlbuf(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
+
+ bool ok() const { return declaredLength() <= remainingLength(); }
+
+ // to be specialized individually for each T with payload after a header
+ inline size_t declaredLengthImpl() const { return sizeof(T); }
+
+ size_t declaredLength() const {
+ // We can't even fit a header, so let's return some absurd high value to trip off
+ // buffer overflow checks.
+ if (sizeof(T) > remainingLength()) return std::numeric_limits<size_t>::max() / 2;
+ return declaredLengthImpl();
+ }
+
+ size_t remainingLength() const {
+ auto len = intptr_t(mBufferEnd) - intptr_t(mData);
+ return (len >= 0) ? len : 0;
+ }
+
+ const void* dataEnd() const {
+ auto declaredEnd = pointerAdd(mData, declaredLength());
+ return std::min(declaredEnd, mBufferEnd);
+ }
+
+ static const void* pointerAdd(const void* ptr, size_t len) {
+ return reinterpret_cast<const void*>(uintptr_t(ptr) + len);
+ }
+
+ template <typename D>
+ friend class nlbuf; // calling private constructor of data buffers
+};
+
+template <>
+inline size_t nlbuf<nlmsghdr>::declaredLengthImpl() const {
+ return mData->nlmsg_len;
+}
+
+template <>
+inline size_t nlbuf<nlattr>::declaredLengthImpl() const {
+ return mData->nla_len;
+}
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/printer.cpp b/automotive/can/1.0/default/libnetdevice/printer.cpp
new file mode 100644
index 0000000..8e17e7f
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/printer.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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 <libnetdevice/printer.h>
+
+#include "common.h"
+#include "nlbuf.h"
+#include "protocols/all.h"
+
+#include <android-base/logging.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+
+namespace android::netdevice {
+
+static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags) {
+ bool first = true;
+ auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) {
+ if (!(nlmsg_flags & flag)) return;
+ nlmsg_flags &= ~flag;
+
+ if (first) {
+ first = false;
+ } else {
+ ss << '|';
+ }
+
+ ss << name;
+ };
+ printFlag(NLM_F_REQUEST, "REQUEST");
+ printFlag(NLM_F_MULTI, "MULTI");
+ printFlag(NLM_F_ACK, "ACK");
+ printFlag(NLM_F_ECHO, "ECHO");
+ 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");
+
+ if (nlmsg_flags != 0) {
+ if (!first) ss << '|';
+ ss << std::hex << nlmsg_flags << std::dec;
+ }
+}
+
+static void toStream(std::stringstream& ss, const nlbuf<uint8_t> data) {
+ ss << std::hex;
+ int i = 0;
+ for (const auto byte : data.getRaw()) {
+ if (i++ > 0) ss << ' ';
+ ss << std::setw(2) << unsigned(byte);
+ }
+ ss << std::dec;
+}
+
+static void toStream(std::stringstream& ss, const nlbuf<nlattr> attr,
+ const protocols::AttributeMap& attrMap) {
+ using DataType = protocols::AttributeDefinition::DataType;
+ const auto attrtype = attrMap[attr->nla_type];
+
+ ss << attrtype.name << ": ";
+ switch (attrtype.dataType) {
+ case DataType::Raw: {
+ toStream(ss, attr.data<uint8_t>());
+ break;
+ }
+ case DataType::Nested: {
+ ss << '{';
+ bool first = true;
+ for (auto childattr : attr.data<nlattr>()) {
+ if (!first) ss << ", ";
+ first = false;
+ toStream(ss, childattr, attrtype.subTypes);
+ }
+ ss << '}';
+ break;
+ }
+ case DataType::String: {
+ const auto str = attr.data<char>().getRaw();
+ ss << '"' << sanitize({str.ptr(), str.len()}) << '"';
+ break;
+ }
+ case DataType::Uint: {
+ ss << attr.data<uint32_t>().copyFirst();
+ break;
+ }
+ }
+}
+
+static std::string toString(const nlbuf<nlmsghdr> hdr, int protocol) {
+ if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
+
+ std::stringstream ss;
+ ss << std::setfill('0');
+
+ auto protocolMaybe = protocols::get(protocol);
+ if (!protocolMaybe.has_value()) {
+ ss << "nlmsg{protocol=" << protocol << "}";
+ return ss.str();
+ }
+ 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);
+
+ ss << "nlmsg{" << protocolDescr.getName() << " ";
+
+ ss << "hdr={";
+ ss << "type=" << msgTypeName;
+ if (hdr->nlmsg_flags != 0) {
+ ss << ", flags=";
+ flagsToStream(ss, hdr->nlmsg_flags);
+ }
+ if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq;
+ if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid;
+
+ ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec;
+ ss << "} ";
+
+ if (!msgDescMaybe.has_value()) {
+ toStream(ss, hdr.data<uint8_t>());
+ } else {
+ const protocols::MessageDescriptor& msgDesc = *msgDescMaybe;
+ msgDesc.dataToStream(ss, hdr);
+
+ bool first = true;
+ for (auto attr : hdr.data<nlattr>(msgDesc.getContentsSize())) {
+ if (first) {
+ ss << " attributes: {";
+ first = false;
+ } else {
+ ss << ", ";
+ }
+ toStream(ss, attr, msgDesc.getAttributeMap());
+ }
+ if (!first) ss << '}';
+ }
+
+ ss << "}";
+
+ return ss.str();
+}
+
+std::string toString(const nlmsghdr* hdr, size_t bufLen, int protocol) {
+ return toString({hdr, bufLen}, protocol);
+}
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.cpp b/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.cpp
new file mode 100644
index 0000000..cb42896
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.cpp
@@ -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.
+ */
+
+#include "MessageDefinition.h"
+
+namespace android::netdevice::protocols {
+
+AttributeMap::AttributeMap(const std::initializer_list<value_type> attrTypes)
+ : std::map<std::optional<nlattrtype_t>, AttributeDefinition>(attrTypes) {}
+
+const AttributeDefinition AttributeMap::operator[](nlattrtype_t nla_type) const {
+ if (count(nla_type) == 0) {
+ if (count(std::nullopt) == 0) return {std::to_string(nla_type)};
+
+ auto definition = find(std::nullopt)->second;
+ definition.name += std::to_string(nla_type);
+ return definition;
+ }
+ return find(nla_type)->second;
+}
+
+MessageDescriptor::MessageDescriptor(const std::string& name, const MessageTypeMap&& messageTypes,
+ const AttributeMap&& attrTypes, size_t contentsSize)
+ : mName(name),
+ mContentsSize(contentsSize),
+ mMessageTypes(messageTypes),
+ mAttributeMap(attrTypes) {}
+
+MessageDescriptor::~MessageDescriptor() {}
+
+size_t MessageDescriptor::getContentsSize() const {
+ return mContentsSize;
+}
+
+const MessageDescriptor::MessageTypeMap& MessageDescriptor::getMessageTypeMap() const {
+ return mMessageTypes;
+}
+
+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 "?";
+ return it->second;
+}
+
+} // namespace android::netdevice::protocols
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h
new file mode 100644
index 0000000..9764f8d
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/MessageDefinition.h
@@ -0,0 +1,123 @@
+/*
+ * 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 "nlbuf.h"
+#include "types.h"
+
+#include <map>
+#include <sstream>
+
+namespace android::netdevice::protocols {
+
+struct AttributeDefinition;
+
+/**
+ * Mapping between nlattrtype_t identifier and attribute definition.
+ *
+ * The map contains values for all nlattrtype_t identifiers - if some is missing, a generic
+ * definition with a identifier as its name will be generated.
+ *
+ * It's possible to define a default attribute to return instead of to_string of its identifier
+ * (useful for nested attribute lists). In such case, an entry with id=std::nullopt needs to be
+ * present in the map.
+ */
+class AttributeMap : private std::map<std::optional<nlattrtype_t>, AttributeDefinition> {
+ public:
+ using std::map<std::optional<nlattrtype_t>, AttributeDefinition>::value_type;
+
+ AttributeMap(const std::initializer_list<value_type> attrTypes);
+
+ const AttributeDefinition operator[](nlattrtype_t nla_type) const;
+};
+
+/**
+ * Attribute definition.
+ *
+ * Describes the name and type (optionally sub types, in case of Nested attribute)
+ * for a given message attribute.
+ */
+struct AttributeDefinition {
+ enum class DataType : uint8_t {
+ Raw,
+ Nested,
+ String,
+ Uint,
+ };
+
+ std::string name;
+ DataType dataType = DataType::Raw;
+ AttributeMap subTypes = {};
+};
+
+/**
+ * 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:
+ virtual ~MessageDescriptor();
+
+ size_t getContentsSize() const;
+ const MessageTypeMap& getMessageTypeMap() 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;
+
+ private:
+ const std::string mName;
+ const size_t mContentsSize;
+ const MessageTypeMap mMessageTypes;
+ const AttributeMap mAttributeMap;
+};
+
+/**
+ * Message definition template.
+ *
+ * A convenience initialization helper of a message descriptor.
+ */
+template <typename T>
+class MessageDefinition : public MessageDescriptor {
+ public:
+ MessageDefinition(
+ const std::string& name,
+ const std::initializer_list<MessageDescriptor::MessageTypeMap::value_type> messageTypes,
+ const std::initializer_list<AttributeMap::value_type> attrTypes = {})
+ : MessageDescriptor(name, messageTypes, attrTypes, sizeof(T)) {}
+
+ void dataToStream(std::stringstream& ss, const nlbuf<nlmsghdr> hdr) const override {
+ const auto msg = hdr.data<T>().getFirst();
+ if (!msg.has_value()) {
+ ss << "{incomplete payload}";
+ return;
+ }
+
+ toStream(ss, *msg);
+ }
+
+ protected:
+ virtual void toStream(std::stringstream& ss, const T& data) const = 0;
+};
+
+} // namespace android::netdevice::protocols
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnetdevice/protocols/NetlinkProtocol.cpp
new file mode 100644
index 0000000..4b6cefb
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/NetlinkProtocol.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 "NetlinkProtocol.h"
+
+namespace android::netdevice::protocols {
+
+NetlinkProtocol::NetlinkProtocol(int protocol, const std::string name,
+ const MessageDescriptorList&& messageDescrs)
+ : mProtocol(protocol), mName(name), mMessageDescrs(toMap(messageDescrs, protocol)) {}
+
+NetlinkProtocol::~NetlinkProtocol() {}
+
+int NetlinkProtocol::getProtocol() const {
+ return mProtocol;
+}
+
+const std::string& NetlinkProtocol::getName() const {
+ return mName;
+}
+
+const std::optional<std::reference_wrapper<const MessageDescriptor>>
+NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
+ if (mMessageDescrs.count(nlmsg_type) == 0) return std::nullopt;
+ return *mMessageDescrs.find(nlmsg_type)->second;
+}
+
+NetlinkProtocol::MessageDescriptorMap NetlinkProtocol::toMap(
+ const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
+ MessageDescriptorMap map;
+ for (const auto& descr : descrs) {
+ for (const auto& [mtype, mname] : descr->getMessageTypeMap()) {
+ map.emplace(mtype, descr);
+ }
+ }
+
+ const MessageDescriptorList baseDescriptors = {
+ std::make_shared<base::Empty>(),
+ std::make_shared<base::Error>(protocol),
+ };
+
+ for (const auto& descr : baseDescriptors) {
+ for (const auto& [mtype, mname] : descr->getMessageTypeMap()) {
+ map.emplace(mtype, descr);
+ }
+ }
+
+ return map;
+}
+
+} // namespace android::netdevice::protocols
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/NetlinkProtocol.h b/automotive/can/1.0/default/libnetdevice/protocols/NetlinkProtocol.h
new file mode 100644
index 0000000..0e1878d
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/NetlinkProtocol.h
@@ -0,0 +1,61 @@
+/*
+ * 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 "MessageDefinition.h"
+#include "common/Empty.h"
+#include "common/Error.h"
+#include "types.h"
+
+#include <string>
+#include <vector>
+
+namespace android::netdevice::protocols {
+
+/**
+ * Netlink-based protocol definition.
+ *
+ * Usually it's just an id/name and a list of supported messages.
+ */
+class NetlinkProtocol {
+ public:
+ virtual ~NetlinkProtocol();
+
+ int getProtocol() const;
+
+ const std::string& getName() const;
+
+ virtual const std::optional<std::reference_wrapper<const MessageDescriptor>>
+ getMessageDescriptor(nlmsgtype_t nlmsg_type);
+
+ protected:
+ typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
+
+ NetlinkProtocol(int protocol, const std::string name,
+ const MessageDescriptorList&& messageDescrs);
+
+ private:
+ typedef std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> MessageDescriptorMap;
+
+ const int mProtocol;
+ const std::string mName;
+ const MessageDescriptorMap mMessageDescrs;
+
+ static MessageDescriptorMap toMap(const MessageDescriptorList& descrs, int protocol);
+};
+
+} // namespace android::netdevice::protocols
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/README b/automotive/can/1.0/default/libnetdevice/protocols/README
new file mode 100644
index 0000000..45c95c4
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/README
@@ -0,0 +1,8 @@
+This folder contains message definitions for various protocols based on Netlink.
+
+The structure is as follows:
+protocols/*.(cpp|h) - base definition classes and protocol definition lookup
+protocols/common/ - common message types that apply to all protocols
+protocols/<proto>/<proto>.(cpp|h) - protocol definition (usually just a list of message types)
+protocols/<proto>/*.(cpp|h) - message definition that covers all message types with the same
+ header (T type in MessageDefinition template) and attributes
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/all.cpp b/automotive/can/1.0/default/libnetdevice/protocols/all.cpp
new file mode 100644
index 0000000..980e3d0
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/all.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "all.h"
+
+#include "generic/Generic.h"
+#include "route/Route.h"
+
+#include <map>
+
+namespace android::netdevice::protocols {
+
+// This should be a map of unique_ptr, but it's not trivial to uniformly initialize such a map
+static std::map<int, std::shared_ptr<NetlinkProtocol>> toMap(
+ std::initializer_list<std::shared_ptr<NetlinkProtocol>> l) {
+ std::map<int, std::shared_ptr<NetlinkProtocol>> map;
+ for (auto p : l) {
+ map[p->getProtocol()] = p;
+ }
+ return map;
+}
+
+static auto all = toMap({
+ std::make_unique<generic::Generic>(),
+ std::make_unique<route::Route>(),
+});
+
+std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol) {
+ if (all.count(protocol) == 0) return std::nullopt;
+ return *all.find(protocol)->second.get();
+}
+
+} // namespace android::netdevice::protocols
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/all.h b/automotive/can/1.0/default/libnetdevice/protocols/all.h
new file mode 100644
index 0000000..2180ebb
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/all.h
@@ -0,0 +1,31 @@
+/*
+ * 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 "NetlinkProtocol.h"
+
+namespace android::netdevice::protocols {
+
+/**
+ * Protocol definition lookup.
+ *
+ * \param protocol Protocol identifier from linux/netlink.h
+ * \return Protocol definition or nullopt if it's not implemented
+ */
+std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol);
+
+} // namespace android::netdevice::protocols
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/common/Empty.cpp b/automotive/can/1.0/default/libnetdevice/protocols/common/Empty.cpp
new file mode 100644
index 0000000..9f25203
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/common/Empty.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 "Empty.h"
+
+namespace android::netdevice::protocols::base {
+
+// clang-format off
+Empty::Empty() : MessageDefinition<char>("nlmsg", {
+ {NLMSG_NOOP, "NOOP"},
+ {NLMSG_DONE, "DONE"},
+ {NLMSG_OVERRUN, "OVERRUN"},
+}) {}
+// clang-format on
+
+void Empty::toStream(std::stringstream&, const char&) const {}
+
+} // namespace android::netdevice::protocols::base
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/common/Empty.h b/automotive/can/1.0/default/libnetdevice/protocols/common/Empty.h
new file mode 100644
index 0000000..b5b317f
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/common/Empty.h
@@ -0,0 +1,32 @@
+/*
+ * 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 "../MessageDefinition.h"
+
+#include <libnetdevice/printer.h>
+
+namespace android::netdevice::protocols::base {
+
+// no-payload (like NLMSG_NOOP) messages can't be defined with T=void, so let's use char
+class Empty : public MessageDefinition<char> {
+ public:
+ Empty();
+ void toStream(std::stringstream&, const char&) const override;
+};
+
+} // namespace android::netdevice::protocols::base
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp b/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp
new file mode 100644
index 0000000..d42a50a
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/common/Error.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Error.h"
+
+#include "../MessageDefinition.h"
+
+#include <libnetdevice/printer.h>
+
+namespace android::netdevice::protocols::base {
+
+// clang-format off
+Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
+ {NLMSG_ERROR, "ERROR"},
+}), 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) << "}";
+}
+
+} // namespace android::netdevice::protocols::base
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/common/Error.h b/automotive/can/1.0/default/libnetdevice/protocols/common/Error.h
new file mode 100644
index 0000000..1f3c1dd
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/common/Error.h
@@ -0,0 +1,32 @@
+/*
+ * 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 "../MessageDefinition.h"
+
+namespace android::netdevice::protocols::base {
+
+class Error : public MessageDefinition<nlmsgerr> {
+ public:
+ Error(int protocol);
+ void toStream(std::stringstream& ss, const nlmsgerr& data) const override;
+
+ private:
+ const int mProtocol;
+};
+
+} // namespace android::netdevice::protocols::base
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp b/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp
new file mode 100644
index 0000000..08b2be7
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 "Ctrl.h"
+
+namespace android::netdevice::protocols::generic {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
+ {CTRL_CMD_NEWFAMILY, "NEWFAMILY"},
+ {CTRL_CMD_DELFAMILY, "DELFAMILY"},
+ {CTRL_CMD_GETFAMILY, "GETFAMILY"},
+ {CTRL_CMD_NEWOPS, "NEWOPS"},
+ {CTRL_CMD_DELOPS, "DELOPS"},
+ {CTRL_CMD_GETOPS, "GETOPS"},
+ {CTRL_CMD_NEWMCAST_GRP, "NEWMCAST_GRP"},
+ {CTRL_CMD_DELMCAST_GRP, "DELMCAST_GRP"},
+ {CTRL_CMD_GETMCAST_GRP, "GETMCAST_GRP"},
+}, {
+ {CTRL_ATTR_FAMILY_ID, {"FAMILY_ID", DataType::Uint}},
+ {CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::String}},
+ {CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
+ {CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
+ {CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
+ {CTRL_ATTR_OPS, {"OPS", DataType::Nested, {
+ {std::nullopt, {"OP", DataType::Nested, {
+ {CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
+ {CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
+ }}},
+ }}},
+ {CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, {
+ {std::nullopt, {"GRP", DataType::Nested, {
+ {CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::String}},
+ {CTRL_ATTR_MCAST_GRP_ID, {"ID", DataType::Uint}},
+ }}},
+ }}},
+}) {}
+// clang-format on
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.h b/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.h
new file mode 100644
index 0000000..804ed2c
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Ctrl.h
@@ -0,0 +1,28 @@
+/*
+ * 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 "GenericMessageBase.h"
+
+namespace android::netdevice::protocols::generic {
+
+class Ctrl : public GenericMessageBase {
+ public:
+ Ctrl();
+};
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Generic.cpp b/automotive/can/1.0/default/libnetdevice/protocols/generic/Generic.cpp
new file mode 100644
index 0000000..633ef3c
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Generic.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Generic.h"
+
+#include "Ctrl.h"
+#include "Unknown.h"
+
+namespace android::netdevice::protocols::generic {
+
+Generic::Generic() : NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>()}) {}
+
+const std::optional<std::reference_wrapper<const MessageDescriptor>> Generic::getMessageDescriptor(
+ nlmsgtype_t nlmsg_type) {
+ const auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
+ if (desc.has_value()) return desc;
+
+ auto it = mFamilyRegister.find(nlmsg_type);
+ if (it != mFamilyRegister.end()) return *it->second;
+ return *(mFamilyRegister[nlmsg_type] = std::make_shared<Unknown>(nlmsg_type));
+}
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Generic.h b/automotive/can/1.0/default/libnetdevice/protocols/generic/Generic.h
new file mode 100644
index 0000000..b4352f6
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Generic.h
@@ -0,0 +1,37 @@
+/*
+ * 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 "../NetlinkProtocol.h"
+
+namespace android::netdevice::protocols::generic {
+
+/**
+ * Definition of NETLINK_GENERIC protocol.
+ */
+class Generic : public NetlinkProtocol {
+ public:
+ Generic();
+
+ const std::optional<std::reference_wrapper<const MessageDescriptor>> getMessageDescriptor(
+ nlmsgtype_t nlmsg_type);
+
+ private:
+ std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> mFamilyRegister;
+};
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/GenericMessageBase.cpp b/automotive/can/1.0/default/libnetdevice/protocols/generic/GenericMessageBase.cpp
new file mode 100644
index 0000000..c9f0813
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/GenericMessageBase.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "GenericMessageBase.h"
+
+namespace android::netdevice::protocols::generic {
+
+GenericMessageBase::GenericMessageBase(
+ nlmsgtype_t msgtype, 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),
+ mCommandNames(commandNames) {}
+
+void GenericMessageBase::toStream(std::stringstream& ss, const struct genlmsghdr& data) const {
+ ss << "genlmsghdr{";
+ if (mCommandNames.count(data.cmd) == 0) {
+ ss << "cmd=" << unsigned(data.cmd);
+ } else {
+ ss << "cmd=" << mCommandNames.find(data.cmd)->second;
+ }
+ ss << ", version=" << unsigned(data.version);
+ if (data.reserved != 0) ss << ", reserved=" << data.reserved;
+ ss << "}";
+}
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/GenericMessageBase.h b/automotive/can/1.0/default/libnetdevice/protocols/generic/GenericMessageBase.h
new file mode 100644
index 0000000..2a19034
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/GenericMessageBase.h
@@ -0,0 +1,40 @@
+/*
+ * 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 "../MessageDefinition.h"
+
+#include <linux/genetlink.h>
+
+namespace android::netdevice::protocols::generic {
+
+class GenericMessageBase : public MessageDefinition<struct genlmsghdr> {
+ public:
+ typedef std::map<uint8_t, std::string> GenericCommandNameMap;
+
+ GenericMessageBase(
+ nlmsgtype_t msgtype, 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;
+
+ private:
+ const GenericCommandNameMap mCommandNames;
+};
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Unknown.cpp b/automotive/can/1.0/default/libnetdevice/protocols/generic/Unknown.cpp
new file mode 100644
index 0000000..9a71d89
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Unknown.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 "Unknown.h"
+
+namespace android::netdevice::protocols::generic {
+
+Unknown::Unknown(nlmsgtype_t msgtype)
+ : GenericMessageBase(msgtype, "Unknown(" + std::to_string(msgtype) + ")") {}
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/generic/Unknown.h b/automotive/can/1.0/default/libnetdevice/protocols/generic/Unknown.h
new file mode 100644
index 0000000..82a5501
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/generic/Unknown.h
@@ -0,0 +1,28 @@
+/*
+ * 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 "GenericMessageBase.h"
+
+namespace android::netdevice::protocols::generic {
+
+class Unknown : public GenericMessageBase {
+ public:
+ Unknown(nlmsgtype_t msgtype);
+};
+
+} // namespace android::netdevice::protocols::generic
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp b/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp
new file mode 100644
index 0000000..4617d92
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/Link.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "Link.h"
+
+namespace android::netdevice::protocols::route {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Link::Link() : MessageDefinition<struct ifinfomsg>("link", {
+ {RTM_NEWLINK, "NEWLINK"},
+ {RTM_DELLINK, "DELLINK"},
+ {RTM_GETLINK, "GETLINK"},
+}, {
+ {IFLA_ADDRESS, {"ADDRESS"}},
+ {IFLA_BROADCAST, {"BROADCAST"}},
+ {IFLA_IFNAME, {"IFNAME", DataType::String}},
+ {IFLA_MTU, {"MTU"}},
+ {IFLA_LINK, {"LINK", DataType::Uint}},
+ {IFLA_QDISC, {"QDISC"}},
+ {IFLA_STATS, {"STATS"}},
+ {IFLA_COST, {"COST"}},
+ {IFLA_PRIORITY, {"PRIORITY"}},
+ {IFLA_MASTER, {"MASTER"}},
+ {IFLA_WIRELESS, {"WIRELESS"}},
+ {IFLA_PROTINFO, {"PROTINFO"}},
+ {IFLA_TXQLEN, {"TXQLEN"}},
+ {IFLA_MAP, {"MAP"}},
+ {IFLA_WEIGHT, {"WEIGHT"}},
+ {IFLA_OPERSTATE, {"OPERSTATE"}},
+ {IFLA_LINKMODE, {"LINKMODE"}},
+ {IFLA_LINKINFO, {"LINKINFO", DataType::Nested, {
+ {IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
+ {IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
+ {IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
+ {IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND"}},
+ {IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
+ }}},
+ {IFLA_NET_NS_PID, {"NET_NS_PID"}},
+ {IFLA_IFALIAS, {"IFALIAS"}},
+ {IFLA_NUM_VF, {"NUM_VF"}},
+ {IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
+ {IFLA_STATS64, {"STATS64"}},
+ {IFLA_VF_PORTS, {"VF_PORTS"}},
+ {IFLA_PORT_SELF, {"PORT_SELF"}},
+ {IFLA_AF_SPEC, {"AF_SPEC"}},
+ {IFLA_GROUP, {"GROUP"}},
+ {IFLA_NET_NS_FD, {"NET_NS_FD"}},
+ {IFLA_EXT_MASK, {"EXT_MASK"}},
+ {IFLA_PROMISCUITY, {"PROMISCUITY"}},
+ {IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES"}},
+ {IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES"}},
+ {IFLA_CARRIER, {"CARRIER"}},
+ {IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
+ {IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES"}},
+ {IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
+ {IFLA_LINK_NETNSID, {"LINK_NETNSID"}},
+ {IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME"}},
+ {IFLA_PROTO_DOWN, {"PROTO_DOWN"}},
+ {IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS"}},
+ {IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE"}},
+ {IFLA_PAD, {"PAD"}},
+ {IFLA_XDP, {"XDP"}},
+ {IFLA_EVENT, {"EVENT"}},
+ {IFLA_NEW_NETNSID, {"NEW_NETNSID"}},
+ {IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}},
+ {IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT"}},
+ {IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT"}},
+ {IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}},
+ {IFLA_MIN_MTU, {"MIN_MTU"}},
+ {IFLA_MAX_MTU, {"MAX_MTU"}},
+ {IFLA_PROP_LIST, {"PROP_LIST"}},
+ {IFLA_ALT_IFNAME, {"ALT_IFNAME"}},
+ {IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
+}) {}
+// clang-format off
+
+void Link::toStream(std::stringstream& ss, const struct ifinfomsg& data) const {
+ ss << "ifinfomsg{"
+ << "family=" << unsigned(data.ifi_family) << ", type=" << data.ifi_type
+ << ", index=" << data.ifi_index << ", flags=" << data.ifi_flags
+ << ", change=" << data.ifi_change << "}";
+}
+
+} // namespace android::netdevice::protocols::route
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/Link.h b/automotive/can/1.0/default/libnetdevice/protocols/route/Link.h
new file mode 100644
index 0000000..bcfce19
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/Link.h
@@ -0,0 +1,31 @@
+/*
+ * 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 "../MessageDefinition.h"
+
+#include <linux/rtnetlink.h>
+
+namespace android::netdevice::protocols::route {
+
+class Link : public MessageDefinition<struct ifinfomsg> {
+ public:
+ Link();
+ void toStream(std::stringstream& ss, const struct ifinfomsg& data) const override;
+};
+
+} // namespace android::netdevice::protocols::route
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/Route.cpp b/automotive/can/1.0/default/libnetdevice/protocols/route/Route.cpp
new file mode 100644
index 0000000..456072b
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/Route.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 "Route.h"
+
+#include "Link.h"
+
+namespace android::netdevice::protocols::route {
+
+Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {std::make_shared<Link>()}) {}
+
+} // namespace android::netdevice::protocols::route
diff --git a/automotive/can/1.0/default/libnetdevice/protocols/route/Route.h b/automotive/can/1.0/default/libnetdevice/protocols/route/Route.h
new file mode 100644
index 0000000..3051cf9
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/protocols/route/Route.h
@@ -0,0 +1,31 @@
+/*
+ * 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 "../NetlinkProtocol.h"
+
+namespace android::netdevice::protocols::route {
+
+/**
+ * Definition of NETLINK_ROUTE protocol.
+ */
+class Route : public NetlinkProtocol {
+ public:
+ Route();
+};
+
+} // namespace android::netdevice::protocols::route
diff --git a/automotive/can/1.0/default/libnetdevice/types.h b/automotive/can/1.0/default/libnetdevice/types.h
new file mode 100644
index 0000000..9d90c8a
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/types.h
@@ -0,0 +1,27 @@
+/*
+ * 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/types.h>
+
+namespace android::netdevice {
+
+typedef __u16 nlmsgtype_t; // nlmsghdr::nlmsg_type
+typedef __u16 nlattrtype_t; // nlattr::nla_type
+typedef unsigned short rtattrtype_t; // rtattr::rta_type
+
+} // namespace android::netdevice
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index 1f69f09..e699fd0 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -105,6 +105,10 @@
* Master role has become available
*/
MASTER_RELEASED,
+ /**
+ * Any other erroneous streaming events
+ */
+ STREAM_ERROR,
};
/**
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index a4fd641..d9ac239 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -15,12 +15,10 @@
cc_defaults {
name: "vhal_v2_0_defaults",
shared_libs: [
- "libbinder_ndk",
"libhidlbase",
"liblog",
"libutils",
"android.hardware.automotive.vehicle@2.0",
- "carwatchdog_aidl_interface-ndk_platform",
],
cflags: [
"-Wall",
@@ -29,6 +27,15 @@
],
}
+cc_defaults {
+ name: "vhal_v2_0_target_defaults",
+ defaults: ["vhal_v2_0_defaults"],
+ shared_libs: [
+ "libbinder_ndk",
+ "carwatchdog_aidl_interface-ndk_platform",
+ ],
+}
+
cc_library_headers {
name: "vhal_v2_0_common_headers",
vendor: true,
@@ -39,7 +46,7 @@
cc_library {
name: "android.hardware.automotive.vehicle@2.0-manager-lib",
vendor: true,
- defaults: ["vhal_v2_0_defaults"],
+ defaults: ["vhal_v2_0_target_defaults"],
srcs: [
"common/src/Obd2SensorStore.cpp",
"common/src/SubscriptionManager.cpp",
@@ -61,7 +68,7 @@
cc_library_static {
name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
vendor: true,
- defaults: ["vhal_v2_0_defaults"],
+ defaults: ["vhal_v2_0_target_defaults"],
srcs: [
"impl/vhal_v2_0/CommConn.cpp",
"impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
@@ -97,16 +104,59 @@
cc_library_static {
name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
vendor: true,
- defaults: ["vhal_v2_0_defaults"],
+ defaults: ["vhal_v2_0_target_defaults"],
srcs: [
"impl/vhal_v2_0/EmulatedUserHal.cpp",
],
}
+// Vehicle HAL Server reference impl lib
+cc_library_static {
+ name: "android.hardware.automotive.vehicle@2.0-server-common-lib",
+ vendor: true,
+ host_supported: true,
+ defaults: ["vhal_v2_0_defaults"],
+ local_include_dirs: ["common/include/vhal_v2_0"],
+ export_include_dirs: ["common/include"],
+ srcs: [
+ "common/src/Obd2SensorStore.cpp",
+ "common/src/VehicleObjectPool.cpp",
+ "common/src/VehicleUtils.cpp",
+ ],
+}
+
+// Vehicle HAL Server default implementation
+cc_library_static {
+ name: "android.hardware.automotive.vehicle@2.0-server-impl-lib",
+ vendor: true,
+ host_supported: true,
+ defaults: ["vhal_v2_0_defaults"],
+ local_include_dirs: ["common/include/vhal_v2_0"],
+ export_include_dirs: ["impl"],
+ srcs: [
+ "impl/vhal_v2_0/EmulatedUserHal.cpp",
+ "impl/vhal_v2_0/GeneratorHub.cpp",
+ "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
+ "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
+ "impl/vhal_v2_0/ProtoMessageConverter.cpp",
+ "impl/vhal_v2_0/VehicleHalServer.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.automotive.vehicle@2.0-server-common-lib",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-libproto-native",
+ ],
+ shared_libs: [
+ "libbase",
+ "libjsoncpp",
+ ],
+}
+
cc_test {
name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
vendor: true,
- defaults: ["vhal_v2_0_defaults"],
+ defaults: ["vhal_v2_0_target_defaults"],
whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
srcs: [
"tests/RecurrentTimer_test.cpp",
@@ -126,7 +176,7 @@
cc_test {
name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
vendor: true,
- defaults: ["vhal_v2_0_defaults"],
+ defaults: ["vhal_v2_0_target_defaults"],
srcs: [
"impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
],
@@ -140,7 +190,7 @@
cc_binary {
name: "android.hardware.automotive.vehicle@2.0-service",
- defaults: ["vhal_v2_0_defaults"],
+ defaults: ["vhal_v2_0_target_defaults"],
vintf_fragments: [
"android.hardware.automotive.vehicle@2.0-service.xml",
],
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
index 31ba8ab..c5b9ed6 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
@@ -16,6 +16,7 @@
cc_library_static {
name: "android.hardware.automotive.vehicle@2.0-libproto-native",
vendor: true,
+ host_supported: true,
proto: {
export_proto_headers: true,
type: "lite",
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index acdea8a..b4aa11d 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -4280,6 +4280,16 @@
* Admin users have additional privileges such as permission to create other users.
*/
ADMIN = 0x08,
+
+ /**
+ * Disabled users are marked for deletion.
+ */
+ DISABLED = 0x10,
+
+ /**
+ * Profile user is a profile of another user.
+ */
+ PROFILE = 0x20,
};
/**
@@ -4294,10 +4304,16 @@
/** The current foreground user. */
UserInfo currentUser;
- /** Number of existing users (includes the current user). */
+ /**
+ * Number of existing users; includes the current user, recently removed users (with DISABLED
+ * flag), and profile users (with PROFILE flag).
+ */
int32_t numberUsers;
- /** List of existing users (includes the current user). */
+ /**
+ * List of existing users; includes the current user, recently removed users (with DISABLED
+ * flag), and profile users (with PROFILE flag).
+ */
vec<UserInfo> existingUsers;
};
diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal
index 607502e..206a649 100644
--- a/camera/device/3.2/ICameraDeviceCallback.hal
+++ b/camera/device/3.2/ICameraDeviceCallback.hal
@@ -87,8 +87,11 @@
* ERROR_RESULT message.
*
* If an output buffer cannot be filled, its status field must be set to
- * STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER
- * message.
+ * STATUS_ERROR. In this case, notify() isn't required to be called with
+ * an ERROR_BUFFER message. The framework will simply treat the notify()
+ * call with ERROR_BUFFER as a no-op, and derive whether and when to notify
+ * the application of buffer loss based on the buffer status and whether or not
+ * the entire capture has failed.
*
* If the entire capture has failed, then this method still needs to be
* called to return the output buffers to the framework. All the buffer
diff --git a/current.txt b/current.txt
index eb3594b..05da000 100644
--- a/current.txt
+++ b/current.txt
@@ -588,7 +588,7 @@
578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay
f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
-d123013165a19b6353cdc46a57b2ff4a17179619d36dbd595dfcf15dcd099af6 android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799
+2924c3e43858190ee3e2da4c2fb93bba8ae065fe314451f035a7ec52cb80c94a android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
5cf81b1001296fbb3c5b3d275a859244f61cec5fa858d7be9cca46c5b7dfa733 android.hardware.camera.metadata@3.2::types # b/150331548
@@ -658,7 +658,7 @@
87958d728d7c0ee9b9391ab4a072b097914921a7b38f7dc3df427f933a5b528e android.hardware.automotive.evs@1.1::IEvsEnumerator
f53b4e8de6209c6d0fa9036005671b34a2f98328b51423d3a5137a43bf42c84d android.hardware.automotive.evs@1.1::IEvsUltrasonicsArray
0460bacbde906a846a3d71b2b7b33d6927cac3ff072e523ffac7853577464406 android.hardware.automotive.evs@1.1::IEvsUltrasonicsArrayStream
-3e374b5c4777f959f62a320abb3b9edca8874e24e383dbb19c66d224f151b363 android.hardware.automotive.evs@1.1::types
+f27cf8283e7b953d33dd258734749d2fca9cc63502ea41353060ffa78d8ce9f6 android.hardware.automotive.evs@1.1::types
4e4904c4067dadae974ddf90351f362331dcd04bba1d890d313cc8ba91f68c15 android.hardware.automotive.sv@1.0::ISurroundView2dSession
63336e9d03f545020ff2982ff76d9d8c44fa76ad476293b5ef6732cbbd71e61b android.hardware.automotive.sv@1.0::ISurroundView3dSession
b7015428cd52ce8192d13bfcbf2c4455cda3727d57f2aac80d65a1747104f5ac android.hardware.automotive.sv@1.0::ISurroundViewService
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 6df7f8d..db06c66 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -587,8 +587,8 @@
static_cast<int32_t>(info.height)};
unique_fd fence;
uint8_t* data;
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
// RGBA_8888
fillRGBA8888(data, info.height, stride * 4, info.width * 4);
@@ -596,8 +596,8 @@
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
// lock again for reading
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
ASSERT_NO_FATAL_FAILURE(
verifyRGBA8888(bufferHandle, data, info.height, stride * 4, info.width * 4));
@@ -627,8 +627,8 @@
unique_fd fence;
uint8_t* data;
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
android_ycbcr yCbCr;
int64_t hSubsampling = 0;
@@ -650,8 +650,8 @@
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
// lock again for reading
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
ASSERT_NO_FATAL_FAILURE(
getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
@@ -676,8 +676,8 @@
unique_fd fence;
uint8_t* data;
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
android_ycbcr yCbCr;
int64_t hSubsampling = 0;
@@ -699,8 +699,8 @@
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
// lock again for reading
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
ASSERT_NO_FATAL_FAILURE(
getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
@@ -725,8 +725,8 @@
unique_fd fence;
uint8_t* data;
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
android_ycbcr yCbCr;
int64_t hSubsampling = 0;
@@ -743,8 +743,8 @@
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
// lock again for reading
- ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
- mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
ASSERT_NO_FATAL_FAILURE(
getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
@@ -771,7 +771,7 @@
static_cast<int32_t>(info.height)};
unique_fd fence;
- ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.get()));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
@@ -813,7 +813,7 @@
static_cast<int32_t>(info.height)};
unique_fd fence;
- ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.get()));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
diff --git a/health/1.0/default/Android.bp b/health/1.0/default/Android.bp
index 7581335..b815eae 100644
--- a/health/1.0/default/Android.bp
+++ b/health/1.0/default/Android.bp
@@ -51,6 +51,12 @@
"android.hardware.health@1.0-convert",
"libhealthd.default",
],
+
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "android.hardware.health@1.0",
+ ],
}
cc_binary {
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index cd6f9b0..c1f44e7 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -14,19 +14,19 @@
"ReaderAuthTests.cpp",
],
shared_libs: [
- "android.hardware.keymaster@4.0",
"libbinder",
"libcrypto",
- "android.hardware.keymaster-ndk_platform",
],
static_libs: [
"libcppbor",
"libkeymaster_portable",
"libsoft_attestation_cert",
"libpuresoftkeymasterdevice",
+ "android.hardware.keymaster@4.0",
"android.hardware.identity-support-lib",
"android.hardware.identity-cpp",
"android.hardware.keymaster-cpp",
+ "android.hardware.keymaster-ndk_platform",
],
test_suites: [
"general-tests",
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 0f27a72..f7ec7c5 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -33,6 +33,7 @@
using ::std::string;
using ::std::tuple;
using ::std::vector;
+using ::std::pair;
// ---------------------------------------------------------------------------
// Miscellaneous utilities.
@@ -119,6 +120,12 @@
optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
+// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
+//
+optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
+ const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
+ const vector<uint8_t>& applicationId);
+
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
// PKCS#8 encoded key-pair.
//
@@ -155,6 +162,12 @@
//
optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data);
+// Like signEcDsa() but instead of taking the data to be signed, takes a digest
+// of it instead.
+//
+optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
+ const vector<uint8_t>& dataDigest);
+
// Calculates the HMAC with SHA-256 for |data| using |key|. The calculated HMAC
// is returned and will be 32 bytes.
//
@@ -175,6 +188,27 @@
//
optional<vector<uint8_t>> certificateChainGetTopMostKey(const vector<uint8_t>& certificateChain);
+// Extracts the public-key from the top-most certificate in |certificateChain|
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Return offset and size of the public-key
+//
+optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate);
+
+// Extracts the TbsCertificate from the top-most certificate in |certificateChain|
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Return offset and size of the TbsCertificate
+//
+optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate);
+
+// Extracts the Signature from the top-most certificate in |certificateChain|
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Return offset and size of the Signature
+//
+optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
+
// Generates a X.509 certificate for |publicKey| (which must be in the format
// returned by ecKeyPairGetPublicKey()).
//
@@ -231,6 +265,11 @@
//
bool certificateChainValidate(const vector<uint8_t>& certificateChain);
+// Returns true if |certificate| is signed by |publicKey|.
+//
+bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
+ const vector<uint8_t>& publicKey);
+
// Signs |data| and |detachedContent| with |key| (which must be in the format
// returned by ecKeyPairGetPrivateKey()).
//
@@ -243,6 +282,21 @@
const vector<uint8_t>& detachedContent,
const vector<uint8_t>& certificateChain);
+// Creates a COSE_Signature1 where |signatureToBeSigned| is the ECDSA signature
+// of the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process".
+//
+// The |signatureToBeSigned| is expected to be 64 bytes and contain the R value,
+// then the S value.
+//
+// The |data| parameter will be included in the COSE_Sign1 CBOR.
+//
+// If |certificateChain| is non-empty it's included in the 'x5chain'
+// protected header element (as as described in'draft-ietf-cose-x509-04').
+//
+optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
+ const vector<uint8_t>& data,
+ const vector<uint8_t>& certificateChain);
+
// Checks that |signatureCoseSign1| (in COSE_Sign1 format) is a valid signature
// made with |public_key| (which must be in the format returned by
// ecKeyPairGetPublicKey()) where |detachedContent| is the detached content.
@@ -251,9 +305,23 @@
const vector<uint8_t>& detachedContent,
const vector<uint8_t>& publicKey);
+// Converts a DER-encoded signature to the format used in 'signature' bstr in COSE_Sign1.
+bool ecdsaSignatureDerToCose(const vector<uint8_t>& ecdsaDerSignature,
+ vector<uint8_t>& ecdsaCoseSignature);
+
+// Converts from the format in in 'signature' bstr in COSE_Sign1 to DER encoding.
+bool ecdsaSignatureCoseToDer(const vector<uint8_t>& ecdsaCoseSignature,
+ vector<uint8_t>& ecdsaDerSignature);
+
// Extracts the payload from a COSE_Sign1.
optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1);
+// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
+optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1);
+
+// Extracts the signature algorithm from a COSE_Sign1.
+optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1);
+
// Extracts the X.509 certificate chain, if present. Returns the data as a
// concatenated chain of DER-encoded X.509 certificates
//
@@ -269,6 +337,16 @@
optional<vector<uint8_t>> coseMac0(const vector<uint8_t>& key, const vector<uint8_t>& data,
const vector<uint8_t>& detachedContent);
+// Creates a COSE_Mac0 where |digestToBeMaced| is the HMAC-SHA256
+// of the ToBeMaced CBOR from RFC 8051 "6.3. How to Compute and Verify a MAC".
+//
+// The |digestToBeMaced| is expected to be 32 bytes.
+//
+// The |data| parameter will be included in the COSE_Mac0 CBOR.
+//
+optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
+ const vector<uint8_t>& data);
+
// ---------------------------------------------------------------------------
// Utility functions specific to IdentityCredential.
// ---------------------------------------------------------------------------
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index e9d5d6c..8e099e7 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -24,6 +24,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
+#include <chrono>
#include <iomanip>
#include <openssl/aes.h>
@@ -684,6 +685,48 @@
return true;
}
+bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
+ const vector<uint8_t>& publicKey) {
+ const unsigned char* p = certificate.data();
+ auto x509 = X509_Ptr(d2i_X509(nullptr, &p, certificate.size()));
+ if (x509 == nullptr) {
+ LOG(ERROR) << "Error parsing X509 certificate";
+ return false;
+ }
+
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+ if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
+ 1) {
+ LOG(ERROR) << "Error decoding publicKey";
+ return false;
+ }
+ auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+ auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
+ if (ecKey.get() == nullptr || pkey.get() == nullptr) {
+ LOG(ERROR) << "Memory allocation failed";
+ return false;
+ }
+ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
+ LOG(ERROR) << "Error setting group";
+ return false;
+ }
+ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
+ LOG(ERROR) << "Error setting point";
+ return false;
+ }
+ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
+ LOG(ERROR) << "Error setting key";
+ return false;
+ }
+
+ if (X509_verify(x509.get(), pkey.get()) != 1) {
+ return false;
+ }
+
+ return true;
+}
+
// TODO: Right now the only check we perform is to check that each certificate
// is signed by its successor. We should - but currently don't - also check
// things like valid dates etc.
@@ -770,7 +813,8 @@
return ret;
}
-optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data) {
+optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
+ const vector<uint8_t>& dataDigest) {
auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr));
if (bn.get() == nullptr) {
LOG(ERROR) << "Error creating BIGNUM";
@@ -783,8 +827,7 @@
return {};
}
- auto digest = sha256(data);
- ECDSA_SIG* sig = ECDSA_do_sign(digest.data(), digest.size(), ec_key.get());
+ ECDSA_SIG* sig = ECDSA_do_sign(dataDigest.data(), dataDigest.size(), ec_key.get());
if (sig == nullptr) {
LOG(ERROR) << "Error signing digest";
return {};
@@ -798,6 +841,10 @@
return signature;
}
+optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data) {
+ return signEcDsaDigest(key, sha256(data));
+}
+
optional<vector<uint8_t>> hmacSha256(const vector<uint8_t>& key, const vector<uint8_t>& data) {
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
@@ -955,6 +1002,51 @@
return make_pair(keyPair, attestationCert.value());
}
+optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
+ const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
+ const vector<uint8_t>& applicationId) {
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+ if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
+ 1) {
+ LOG(ERROR) << "Error decoding publicKey";
+ return {};
+ }
+ auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+ auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
+ if (ecKey.get() == nullptr || pkey.get() == nullptr) {
+ LOG(ERROR) << "Memory allocation failed";
+ return {};
+ }
+ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
+ LOG(ERROR) << "Error setting group";
+ return {};
+ }
+ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
+ LOG(ERROR) << "Error setting point";
+ return {};
+ }
+ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
+ LOG(ERROR) << "Error setting key";
+ return {};
+ }
+
+ uint64_t now = (std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch()).
+ count()/ 1000000000);
+ uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
+ uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+
+ optional<vector<vector<uint8_t>>> attestationCert =
+ createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+ if (!attestationCert) {
+ LOG(ERROR) << "Error create attestation from key and challenge";
+ return {};
+ }
+
+ return attestationCert.value();
+}
+
optional<vector<uint8_t>> createEcKeyPair() {
auto ec_key = EC_KEY_Ptr(EC_KEY_new());
auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
@@ -1477,6 +1569,120 @@
return publicKey;
}
+optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate) {
+ vector<X509_Ptr> certs;
+ if (!parseX509Certificates(x509Certificate, certs)) {
+ return {};
+ }
+ if (certs.size() < 1) {
+ LOG(ERROR) << "No certificates in chain";
+ return {};
+ }
+
+ auto pkey = EVP_PKEY_Ptr(X509_get_pubkey(certs[0].get()));
+ if (pkey.get() == nullptr) {
+ LOG(ERROR) << "No public key";
+ return {};
+ }
+
+ auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pkey.get()));
+ if (ecKey.get() == nullptr) {
+ LOG(ERROR) << "Failed getting EC key";
+ return {};
+ }
+
+ auto ecGroup = EC_KEY_get0_group(ecKey.get());
+ auto ecPoint = EC_KEY_get0_public_key(ecKey.get());
+ int size = EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0,
+ nullptr);
+ if (size == 0) {
+ LOG(ERROR) << "Error generating public key encoding";
+ return {};
+ }
+ vector<uint8_t> publicKey;
+ publicKey.resize(size);
+ EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
+ publicKey.size(), nullptr);
+
+ size_t publicKeyOffset = 0;
+ size_t publicKeySize = (size_t)size;
+ void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
+ (const void*)publicKey.data(), publicKey.size());
+
+ if (location == NULL) {
+ LOG(ERROR) << "Error finding publicKey from x509Certificate";
+ return {};
+ }
+ publicKeyOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
+
+ return std::make_pair(publicKeyOffset, publicKeySize);
+}
+
+optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate) {
+ vector<X509_Ptr> certs;
+ if (!parseX509Certificates(x509Certificate, certs)) {
+ return {};
+ }
+ if (certs.size() < 1) {
+ LOG(ERROR) << "No certificates in chain";
+ return {};
+ }
+
+ unsigned char* buf = NULL;
+ int len = i2d_re_X509_tbs(certs[0].get(), &buf);
+ if ((len < 0) || (buf == NULL)) {
+ LOG(ERROR) << "fail to extract tbsCertificate in x509Certificate";
+ return {};
+ }
+
+ vector<uint8_t> tbsCertificate(len);
+ memcpy(tbsCertificate.data(), buf, len);
+
+ size_t tbsCertificateOffset = 0;
+ size_t tbsCertificateSize = (size_t)len;
+ void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
+ (const void*)tbsCertificate.data(), tbsCertificate.size());
+
+ if (location == NULL) {
+ LOG(ERROR) << "Error finding tbsCertificate from x509Certificate";
+ return {};
+ }
+ tbsCertificateOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
+
+ return std::make_pair(tbsCertificateOffset, tbsCertificateSize);
+}
+
+optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate) {
+ vector<X509_Ptr> certs;
+ if (!parseX509Certificates(x509Certificate, certs)) {
+ return {};
+ }
+ if (certs.size() < 1) {
+ LOG(ERROR) << "No certificates in chain";
+ return {};
+ }
+
+ ASN1_BIT_STRING* psig;
+ X509_ALGOR* palg;
+ X509_get0_signature((const ASN1_BIT_STRING**)&psig, (const X509_ALGOR**)&palg, certs[0].get());
+
+ vector<char> signature(psig->length);
+ memcpy(signature.data(), psig->data, psig->length);
+
+ size_t signatureOffset = 0;
+ size_t signatureSize = (size_t)psig->length;
+ void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
+ (const void*)signature.data(), signature.size());
+
+ if (location == NULL) {
+ LOG(ERROR) << "Error finding signature from x509Certificate";
+ return {};
+ }
+ signatureOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
+
+ return std::make_pair(signatureOffset, signatureSize);
+}
+
// ---------------------------------------------------------------------------
// COSE Utility Functions
// ---------------------------------------------------------------------------
@@ -1574,6 +1780,55 @@
return true;
}
+optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
+ const vector<uint8_t>& data,
+ const vector<uint8_t>& certificateChain) {
+ if (signatureToBeSigned.size() != 64) {
+ LOG(ERROR) << "Invalid size for signatureToBeSigned, expected 64 got "
+ << signatureToBeSigned.size();
+ return {};
+ }
+
+ cppbor::Map unprotectedHeaders;
+ cppbor::Map protectedHeaders;
+
+ protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_ECDSA_256);
+
+ if (certificateChain.size() != 0) {
+ optional<vector<vector<uint8_t>>> certs = support::certificateChainSplit(certificateChain);
+ if (!certs) {
+ LOG(ERROR) << "Error splitting certificate chain";
+ return {};
+ }
+ if (certs.value().size() == 1) {
+ unprotectedHeaders.add(COSE_LABEL_X5CHAIN, certs.value()[0]);
+ } else {
+ cppbor::Array certArray;
+ for (const vector<uint8_t>& cert : certs.value()) {
+ certArray.add(cert);
+ }
+ unprotectedHeaders.add(COSE_LABEL_X5CHAIN, std::move(certArray));
+ }
+ }
+
+ vector<uint8_t> encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders);
+
+ cppbor::Array coseSign1;
+ coseSign1.add(encodedProtectedHeaders);
+ coseSign1.add(std::move(unprotectedHeaders));
+ if (data.size() == 0) {
+ cppbor::Null nullValue;
+ coseSign1.add(std::move(nullValue));
+ } else {
+ coseSign1.add(data);
+ }
+ coseSign1.add(signatureToBeSigned);
+ vector<uint8_t> signatureCoseSign1;
+ signatureCoseSign1 = coseSign1.encode();
+
+ return signatureCoseSign1;
+}
+
optional<vector<uint8_t>> coseSignEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data,
const vector<uint8_t>& detachedContent,
const vector<uint8_t>& certificateChain) {
@@ -1709,6 +1964,35 @@
return true;
}
+// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
+optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1) {
+ auto [item, _, message] = cppbor::parse(signatureCoseSign1);
+ if (item == nullptr) {
+ LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message;
+ return {};
+ }
+ const cppbor::Array* array = item->asArray();
+ if (array == nullptr) {
+ LOG(ERROR) << "Value for COSE_Sign1 is not an array";
+ return {};
+ }
+ if (array->size() != 4) {
+ LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4";
+ return {};
+ }
+
+ vector<uint8_t> signature;
+ const cppbor::Bstr* signatureAsBstr = (*array)[3]->asBstr();
+ if (signatureAsBstr == nullptr) {
+ LOG(ERROR) << "Value for signature is not a bstr";
+ return {};
+ }
+ // Copy payload into |data|
+ signature = signatureAsBstr->value();
+
+ return signature;
+}
+
optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1) {
auto [item, _, message] = cppbor::parse(signatureCoseSign1);
if (item == nullptr) {
@@ -1746,6 +2030,59 @@
return data;
}
+optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1) {
+ auto [item, _, message] = cppbor::parse(signatureCoseSign1);
+ if (item == nullptr) {
+ LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message;
+ return {};
+ }
+ const cppbor::Array* array = item->asArray();
+ if (array == nullptr) {
+ LOG(ERROR) << "Value for COSE_Sign1 is not an array";
+ return {};
+ }
+ if (array->size() != 4) {
+ LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4";
+ return {};
+ }
+
+ const cppbor::Bstr* protectedHeadersBytes = (*array)[0]->asBstr();
+ if (protectedHeadersBytes == nullptr) {
+ LOG(ERROR) << "Value for protectedHeaders is not a bstr";
+ return {};
+ }
+ auto [item2, _2, message2] = cppbor::parse(protectedHeadersBytes->value());
+ if (item2 == nullptr) {
+ LOG(ERROR) << "Error parsing protectedHeaders: " << message2;
+ return {};
+ }
+ const cppbor::Map* protectedHeaders = item2->asMap();
+ if (protectedHeaders == nullptr) {
+ LOG(ERROR) << "Decoded CBOR for protectedHeaders is not a map";
+ return {};
+ }
+
+ for (size_t n = 0; n < protectedHeaders->size(); n++) {
+ auto [keyItem, valueItem] = (*protectedHeaders)[n];
+ const cppbor::Int* number = keyItem->asInt();
+ if (number == nullptr) {
+ LOG(ERROR) << "Key item in top-level map is not a number";
+ return {};
+ }
+ int label = number->value();
+ if (label == COSE_LABEL_ALG) {
+ const cppbor::Int* number = valueItem->asInt();
+ if (number != nullptr) {
+ return number->value();
+ }
+ LOG(ERROR) << "Value for COSE_LABEL_ALG label is not a number";
+ return {};
+ }
+ }
+ LOG(ERROR) << "Did not find COSE_LABEL_ALG label in protected headers";
+ return {};
+}
+
optional<vector<uint8_t>> coseSignGetX5Chain(const vector<uint8_t>& signatureCoseSign1) {
auto [item, _, message] = cppbor::parse(signatureCoseSign1);
if (item == nullptr) {
@@ -1861,6 +2198,28 @@
return array.encode();
}
+optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
+ const vector<uint8_t>& data) {
+ cppbor::Map unprotectedHeaders;
+ cppbor::Map protectedHeaders;
+
+ protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_HMAC_256_256);
+
+ vector<uint8_t> encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders);
+
+ cppbor::Array array;
+ array.add(encodedProtectedHeaders);
+ array.add(std::move(unprotectedHeaders));
+ if (data.size() == 0) {
+ cppbor::Null nullValue;
+ array.add(std::move(nullValue));
+ } else {
+ array.add(data);
+ }
+ array.add(digestToBeMaced);
+ return array.encode();
+}
+
// ---------------------------------------------------------------------------
// Utility functions specific to IdentityCredential.
// ---------------------------------------------------------------------------
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 87e8519..d802911 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -62,11 +62,12 @@
defaults: ["neuralnetworks_vts_functional_defaults"],
srcs: [
"BasicTests.cpp",
+ "GeneratedTestHarness.cpp",
"TestAssertions.cpp",
+ "TestMain.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
"VtsHalNeuralnetworks.cpp",
- "GeneratedTestHarness.cpp",
],
shared_libs: [
"libfmq",
diff --git a/neuralnetworks/1.0/vts/functional/AndroidTest.xml b/neuralnetworks/1.0/vts/functional/AndroidTest.xml
index 54e6e91..13671f9 100644
--- a/neuralnetworks/1.0/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.0/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
- <!-- b/155577050, temporarily disable the failing tests.
- Must be deleted after corresponding driver issues are fixed.
- -->
- <option name="native-test-flag" value="--gtest_filter=-*Validation*:*CycleTest*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalNeuralnetworksV1_0TargetTest" />
</test>
diff --git a/neuralnetworks/1.0/vts/functional/TestMain.cpp b/neuralnetworks/1.0/vts/functional/TestMain.cpp
new file mode 100644
index 0000000..6bf4e5f
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/TestMain.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 <gtest/gtest.h>
+#include "1.0/LogTestCaseToLogcat.h"
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ testing::UnitTest::GetInstance()->listeners().Append(
+ new android::hardware::neuralnetworks::LogTestCaseToLogcat());
+ return RUN_ALL_TESTS();
+}
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/LogTestCaseToLogcat.h b/neuralnetworks/1.0/vts/functional/include/1.0/LogTestCaseToLogcat.h
new file mode 100644
index 0000000..f1413ef
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/LogTestCaseToLogcat.h
@@ -0,0 +1,40 @@
+/*
+ * 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_NEURALNETWORKS_V1_0_LOG_TEST_CASE_TO_LOGCAT_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_LOG_TEST_CASE_TO_LOGCAT_H
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+namespace android::hardware::neuralnetworks {
+
+class LogTestCaseToLogcat : public ::testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const ::testing::TestInfo& test_info) override {
+ LOG(INFO) << "[Test Case] " << test_info.test_suite_name() << "." << test_info.name()
+ << " BEGIN";
+ }
+
+ void OnTestEnd(const ::testing::TestInfo& test_info) override {
+ LOG(INFO) << "[Test Case] " << test_info.test_suite_name() << "." << test_info.name()
+ << " END";
+ }
+};
+
+} // namespace android::hardware::neuralnetworks
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_LOG_TEST_CASE_TO_LOGCAT_H
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 9afa0af..405548f 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -20,6 +20,7 @@
srcs: [
"BasicTests.cpp",
"TestAssertions.cpp",
+ "TestMain.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
"VtsHalNeuralnetworks.cpp",
diff --git a/neuralnetworks/1.1/vts/functional/AndroidTest.xml b/neuralnetworks/1.1/vts/functional/AndroidTest.xml
index a6f812f..cfde60c 100644
--- a/neuralnetworks/1.1/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.1/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
- <!-- b/155577050, temporarily disable the failing tests.
- Must be deleted after corresponding driver issues are fixed.
- -->
- <option name="native-test-flag" value="--gtest_filter=-*Validation*:*CycleTest*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalNeuralnetworksV1_1TargetTest" />
</test>
diff --git a/neuralnetworks/1.1/vts/functional/TestMain.cpp b/neuralnetworks/1.1/vts/functional/TestMain.cpp
new file mode 100644
index 0000000..6bf4e5f
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/TestMain.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 <gtest/gtest.h>
+#include "1.0/LogTestCaseToLogcat.h"
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ testing::UnitTest::GetInstance()->listeners().Append(
+ new android::hardware::neuralnetworks::LogTestCaseToLogcat());
+ return RUN_ALL_TESTS();
+}
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 182f716..93edca6 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -40,6 +40,7 @@
"CompilationCachingTests.cpp",
"GeneratedTestHarness.cpp",
"TestAssertions.cpp",
+ "TestMain.cpp",
"ValidateBurst.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
diff --git a/neuralnetworks/1.2/vts/functional/AndroidTest.xml b/neuralnetworks/1.2/vts/functional/AndroidTest.xml
index adbdf40..3f91618 100644
--- a/neuralnetworks/1.2/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.2/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
- <!-- b/155577050, b/155674368, b/153876253, temporarily disable the test.
- Must be deleted after corresponding driver issues are fixed.
- -->
- <option name="native-test-flag" value="--gtest_filter=-*Validation*:*squeeze*_all*_inputs*:*strided_slice*_all*_inputs*:*transpose*_all*_inputs*:*l2_normalization_axis_corner_case*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalNeuralnetworksV1_2TargetTest" />
</test>
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 449b8f3..16b313a 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -315,7 +315,8 @@
void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
const hidl_vec<hidl_handle>& dataCache,
- sp<IPreparedModel>* preparedModel = nullptr) {
+ sp<IPreparedModel>* preparedModel = nullptr,
+ bool allowGeneralFailure = false) {
if (preparedModel != nullptr) *preparedModel = nullptr;
// Launch prepare model.
@@ -329,7 +330,10 @@
// Retrieve prepared model.
preparedModelCallback->wait();
- ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+ const auto prepareCallbackStatus = preparedModelCallback->getStatus();
+ if (!allowGeneralFailure || prepareCallbackStatus != ErrorStatus::GENERAL_FAILURE) {
+ ASSERT_EQ(prepareCallbackStatus, ErrorStatus::NONE);
+ }
if (preparedModel != nullptr) {
*preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
.withDefault(nullptr);
@@ -1022,7 +1026,8 @@
// Number of operations in the large test model.
constexpr uint32_t kLargeModelSize = 100;
-constexpr uint32_t kNumIterationsTOCTOU = 100;
+constexpr uint32_t kNumSuccessfulIterationsTOCTOU = 100;
+constexpr uint32_t kMaxNumFailedIterationsTOCTOU = 100;
TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
if (!mIsCachingSupported) return;
@@ -1050,18 +1055,30 @@
// Use a different token for modelAdd.
mToken[0]++;
- // This test is probabilistic, so we run it multiple times.
- for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+ // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+ // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+ // enough successful iterations to ensure the test coverage.
+ uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+ while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
// Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+ sp<IPreparedModel> preparedModel = nullptr;
// Spawn a thread to copy the cache content concurrently while saving to cache.
std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
- saveModelToCache(modelAdd, modelCache, dataCache);
+ saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+ /*allowGeneralFailure=*/true);
thread.join();
+
+ if (preparedModel == nullptr) {
+ numFailedIterations++;
+ ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+ } else {
+ numSuccessfulIterations++;
+ }
}
// Retrieve preparedModel from cache.
@@ -1112,14 +1129,26 @@
// Use a different token for modelAdd.
mToken[0]++;
- // This test is probabilistic, so we run it multiple times.
- for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+ // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+ // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+ // enough successful iterations to ensure the test coverage.
+ uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+ while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
// Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(modelAdd, modelCache, dataCache);
+ sp<IPreparedModel> preparedModel = nullptr;
+ saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+ /*allowGeneralFailure=*/true);
+
+ if (preparedModel == nullptr) {
+ numFailedIterations++;
+ ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+ } else {
+ numSuccessfulIterations++;
+ }
}
// Retrieve preparedModel from cache.
diff --git a/neuralnetworks/1.2/vts/functional/TestMain.cpp b/neuralnetworks/1.2/vts/functional/TestMain.cpp
new file mode 100644
index 0000000..6bf4e5f
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/TestMain.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 <gtest/gtest.h>
+#include "1.0/LogTestCaseToLogcat.h"
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ testing::UnitTest::GetInstance()->listeners().Append(
+ new android::hardware::neuralnetworks::LogTestCaseToLogcat());
+ return RUN_ALL_TESTS();
+}
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index d01336e..c4e2b15 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -21,6 +21,7 @@
#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
#include <android/hardware/neuralnetworks/1.2/types.h>
#include <gtest/gtest.h>
+#include <vector>
#include "1.0/Utils.h"
#include "1.2/Callbacks.h"
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 771fc54..b17d445 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -43,6 +43,7 @@
"MemoryDomainTests.cpp",
"QualityOfServiceTests.cpp",
"TestAssertions.cpp",
+ "TestMain.cpp",
"ValidateBurst.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
diff --git a/neuralnetworks/1.3/vts/functional/AndroidTest.xml b/neuralnetworks/1.3/vts/functional/AndroidTest.xml
index 30cff2e..e5acd90 100644
--- a/neuralnetworks/1.3/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.3/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
- <!-- b/156691406, b/155577050, b/155674368, b/153876253, temporarily disable the test.
- Must be deleted after corresponding driver issues are fixed.
- -->
- <option name="native-test-flag" value="--gtest_filter=-*Validation*:*DynamicOutputShapeTest*:*FencedComputeTest*:*MemoryDomain*:*QuantizationCouplingTest*:*DeadlineTest*:*resize_*_v1_3*:*squeeze*_all*_inputs*:*strided_slice*_all*_inputs*:*transpose*_all*_inputs*:*l2_normalization_axis_corner_case*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalNeuralnetworksV1_3TargetTest" />
</test>
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index ac18c8f..382fc76 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -318,7 +318,8 @@
void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
const hidl_vec<hidl_handle>& dataCache,
- sp<IPreparedModel>* preparedModel = nullptr) {
+ sp<IPreparedModel>* preparedModel = nullptr,
+ bool allowGeneralFailure = false) {
if (preparedModel != nullptr) *preparedModel = nullptr;
// Launch prepare model.
@@ -332,7 +333,10 @@
// Retrieve prepared model.
preparedModelCallback->wait();
- ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+ const auto prepareCallbackStatus = preparedModelCallback->getStatus();
+ if (!allowGeneralFailure || prepareCallbackStatus != ErrorStatus::GENERAL_FAILURE) {
+ ASSERT_EQ(prepareCallbackStatus, ErrorStatus::NONE);
+ }
if (preparedModel != nullptr) {
*preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
.withDefault(nullptr);
@@ -1013,7 +1017,8 @@
// Number of operations in the large test model.
constexpr uint32_t kLargeModelSize = 100;
-constexpr uint32_t kNumIterationsTOCTOU = 100;
+constexpr uint32_t kNumSuccessfulIterationsTOCTOU = 100;
+constexpr uint32_t kMaxNumFailedIterationsTOCTOU = 100;
TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
if (!mIsCachingSupported) return;
@@ -1041,18 +1046,30 @@
// Use a different token for modelAdd.
mToken[0]++;
- // This test is probabilistic, so we run it multiple times.
- for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+ // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+ // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+ // enough successful iterations to ensure the test coverage.
+ uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+ while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
// Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+ sp<IPreparedModel> preparedModel = nullptr;
// Spawn a thread to copy the cache content concurrently while saving to cache.
std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
- saveModelToCache(modelAdd, modelCache, dataCache);
+ saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+ /*allowGeneralFailure=*/true);
thread.join();
+
+ if (preparedModel == nullptr) {
+ numFailedIterations++;
+ ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+ } else {
+ numSuccessfulIterations++;
+ }
}
// Retrieve preparedModel from cache.
@@ -1103,14 +1120,26 @@
// Use a different token for modelAdd.
mToken[0]++;
- // This test is probabilistic, so we run it multiple times.
- for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+ // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+ // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+ // enough successful iterations to ensure the test coverage.
+ uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+ while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
// Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(modelAdd, modelCache, dataCache);
+ sp<IPreparedModel> preparedModel = nullptr;
+ saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+ /*allowGeneralFailure=*/true);
+
+ if (preparedModel == nullptr) {
+ numFailedIterations++;
+ ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+ } else {
+ numSuccessfulIterations++;
+ }
}
// Retrieve preparedModel from cache.
diff --git a/neuralnetworks/1.3/vts/functional/TestMain.cpp b/neuralnetworks/1.3/vts/functional/TestMain.cpp
new file mode 100644
index 0000000..6bf4e5f
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/TestMain.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 <gtest/gtest.h>
+#include "1.0/LogTestCaseToLogcat.h"
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ testing::UnitTest::GetInstance()->listeners().Append(
+ new android::hardware::neuralnetworks::LogTestCaseToLogcat());
+ return RUN_ALL_TESTS();
+}
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
index de082c3..a2e5071 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
@@ -21,6 +21,7 @@
#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
#include <android/hardware/neuralnetworks/1.3/types.h>
#include <gtest/gtest.h>
+#include <vector>
#include "1.0/Utils.h"
#include "1.3/Callbacks.h"
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 8cbb2d0..9b6d450 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -1017,8 +1017,10 @@
return Void();
}
-Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& /*info*/,
+Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
const SendSmsResult& /*sms*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
return Void();
}