Merge changes from topic "executeFenced_tests" into rvc-dev am: 3930e63791 am: e244f2de18 am: 17b62d761a am: ebe4e08de1
Change-Id: I3d55a47048697469c4241dd04698129d5fc7d79f
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 9f704c1..8b98e5e 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -226,7 +226,6 @@
* \param flag bool object from CanMessage object
*/
static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
- // TODO(b/144458917) add testing for this to VTS tests
if (filterFlag == FilterFlag::DONT_CARE) return true;
if (filterFlag == FilterFlag::SET) return flag;
if (filterFlag == FilterFlag::NOT_SET) return !flag;
@@ -302,7 +301,6 @@
if ((frame.can_id & CAN_ERR_FLAG) != 0) {
// error bit is set
LOG(WARNING) << "CAN Error frame received";
- // TODO(b/144458917) consider providing different values for isFatal, depending on error
notifyErrorListeners(parseErrorFrame(frame), false);
return;
}
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
index d15905d..f08566c 100644
--- a/automotive/can/1.0/default/CanBusSlcan.cpp
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -56,7 +56,7 @@
* that has already been configured and brought up.
*/
if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
- LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno);
+ PLOG(ERROR) << "Failed to get the name of the created device";
return ICanController::Result::UNKNOWN_ERROR;
}
@@ -80,7 +80,7 @@
* controlling terminal */
mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY));
if (!mFd.ok()) {
- LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno);
+ PLOG(ERROR) << "SLCAN Failed to open " << mUartName;
return ICanController::Result::BAD_INTERFACE_ID;
}
@@ -92,7 +92,7 @@
// blank terminal settings and pull them from the device
struct termios terminalSettings = {};
if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
- LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno);
+ PLOG(ERROR) << "Failed to read attrs of" << mUartName;
return ICanController::Result::UNKNOWN_ERROR;
}
@@ -107,42 +107,40 @@
struct serial_struct serialSettings;
// get serial settings
if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
- LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": "
- << strerror(errno);
+ PLOG(ERROR) << "Failed to read serial settings from " << mUartName;
return ICanController::Result::UNKNOWN_ERROR;
}
// set low latency mode
serialSettings.flags |= ASYNC_LOW_LATENCY;
// apply serial settings
if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
- LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno);
+ PLOG(ERROR) << "Failed to set low latency mode on " << mUartName;
return ICanController::Result::UNKNOWN_ERROR;
}
/* TCSADRAIN applies settings after we finish writing the rest of our
* changes (as opposed to TCSANOW, which changes immediately) */
if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
- LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": "
- << strerror(errno);
+ PLOG(ERROR) << "Failed to apply terminal settings to " << mUartName;
return ICanController::Result::UNKNOWN_ERROR;
}
// apply speed setting for CAN
if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) {
- LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno);
+ PLOG(ERROR) << "Failed to apply CAN bitrate";
return ICanController::Result::UNKNOWN_ERROR;
}
- // set open flag TODO: also support listen only
+ // TODO(b/144775286): set open flag & support listen only
if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(),
slcanprotocol::kOpenCommand.length()) <= 0) {
- LOG(ERROR) << "Failed to set open flag: " << strerror(errno);
+ PLOG(ERROR) << "Failed to set open flag";
return ICanController::Result::UNKNOWN_ERROR;
}
// set line discipline to slcan
if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
- LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno);
+ PLOG(ERROR) << "Failed to set line discipline to slcan";
return ICanController::Result::UNKNOWN_ERROR;
}
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
index 86ccc0e..f379d5a 100644
--- a/automotive/can/1.0/default/CanSocket.cpp
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -67,7 +67,7 @@
bool CanSocket::send(const struct canfd_frame& frame) {
const auto res = write(mSocket.get(), &frame, CAN_MTU);
if (res < 0) {
- LOG(DEBUG) << "CanSocket send failed: " << errno;
+ PLOG(DEBUG) << "CanSocket send failed";
return false;
}
if (res != CAN_MTU) {
@@ -102,7 +102,7 @@
const auto sel = selectRead(mSocket, kReadPooling);
if (sel == 0) continue; // timeout
if (sel == -1) {
- LOG(ERROR) << "Select failed: " << errno;
+ PLOG(ERROR) << "Select failed";
break;
}
@@ -130,7 +130,7 @@
if (errno == EAGAIN) continue;
errnoCopy = errno;
- LOG(ERROR) << "Failed to read CAN packet: " << strerror(errno) << " (" << errno << ")";
+ PLOG(ERROR) << "Failed to read CAN packet";
break;
}
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
index 6a7f506..7817169 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -23,7 +23,7 @@
NetlinkSocket::NetlinkSocket(int protocol) {
mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
if (!mFd.ok()) {
- LOG(ERROR) << "Can't open Netlink socket: " << errno;
+ PLOG(ERROR) << "Can't open Netlink socket";
mFailed = true;
return;
}
@@ -32,7 +32,7 @@
sa.nl_family = AF_NETLINK;
if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
- LOG(ERROR) << "Can't bind Netlink socket: " << errno;
+ PLOG(ERROR) << "Can't bind Netlink socket";
mFd.reset();
mFailed = true;
}
@@ -57,7 +57,7 @@
msg.msg_iovlen = 1;
if (sendmsg(mFd.get(), &msg, 0) < 0) {
- LOG(ERROR) << "Can't send Netlink message: " << errno;
+ PLOG(ERROR) << "Can't send Netlink message";
return false;
}
return true;
@@ -79,7 +79,7 @@
const ssize_t status = recvmsg(mFd.get(), &msg, 0);
if (status < 0) {
- LOG(ERROR) << "Failed to receive Netlink message: " << errno;
+ PLOG(ERROR) << "Failed to receive Netlink message";
return false;
}
size_t remainingLen = status;
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index 06d45d3..a2a85dc 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -48,7 +48,7 @@
}
if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) {
- LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno);
+ PLOG(ERROR) << "Can't receive error frames, CAN setsockpt failed";
return {};
}
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index aee8205..b051442 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -41,7 +41,7 @@
}
if (ioctl(sock.get(), request, &ifr) < 0) {
- LOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed: " << errno;
+ PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
return false;
}
diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp
index 21f364b..a6c40d9 100644
--- a/automotive/can/1.0/tools/Android.bp
+++ b/automotive/can/1.0/tools/Android.bp
@@ -27,6 +27,9 @@
header_libs: [
"android.hardware.automotive.can@hidl-utils-lib",
],
+ static_libs: [
+ "android.hardware.automotive.can@libcanhaltools",
+ ],
}
cc_binary {
@@ -42,6 +45,9 @@
header_libs: [
"android.hardware.automotive.can@hidl-utils-lib",
],
+ static_libs: [
+ "android.hardware.automotive.can@libcanhaltools",
+ ],
}
cc_binary {
@@ -54,4 +60,7 @@
"android.hardware.automotive.can@1.0",
"libhidlbase",
],
+ static_libs: [
+ "android.hardware.automotive.can@libcanhaltools",
+ ],
}
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
index 33755bf..bf1c3b1 100644
--- a/automotive/can/1.0/tools/canhalctrl.cpp
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -15,9 +15,11 @@
*/
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android/hardware/automotive/can/1.0/ICanController.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl-utils/hidl-utils.h>
+#include <libcanhaltools/libcanhaltools.h>
#include <iostream>
#include <string>
@@ -41,34 +43,17 @@
std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
}
-static hidl_vec<hidl_string> getControlServices() {
- auto manager = hidl::manager::V1_2::IServiceManager::getService();
- hidl_vec<hidl_string> services;
- manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
- if (services.size() == 0) {
- std::cerr << "No ICanController services registered (missing privileges?)" << std::endl;
- exit(-1);
- }
- return services;
-}
-
-static bool isSupported(sp<ICanController> ctrl, ICanController::InterfaceType iftype) {
- hidl_vec<ICanController::InterfaceType> supported;
- if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false;
- return supported.contains(iftype);
-}
-
static int up(const std::string& busName, ICanController::InterfaceType type,
const std::string& interface, uint32_t bitrate) {
bool anySupported = false;
- for (auto&& service : getControlServices()) {
+ for (auto&& service : libcanhaltools::getControlServices()) {
auto ctrl = ICanController::getService(service);
if (ctrl == nullptr) {
std::cerr << "Couldn't open ICanController/" << service;
continue;
}
- if (!isSupported(ctrl, type)) continue;
+ if (!libcanhaltools::isSupported(ctrl, type)) continue;
anySupported = true;
ICanController::BusConfig config = {};
@@ -88,8 +73,8 @@
slcan.ttyname(interface);
config.interfaceId.slcan(slcan);
} else if (type == ICanController::InterfaceType::INDEXED) {
- auto idx = std::stol(interface);
- if (idx < 0 || idx > UINT8_MAX) {
+ unsigned idx;
+ if (!android::base::ParseUint(interface, &idx, unsigned(UINT8_MAX))) {
std::cerr << "Interface index out of range: " << idx;
return -1;
}
@@ -111,7 +96,7 @@
}
static int down(const std::string& busName) {
- for (auto&& service : getControlServices()) {
+ for (auto&& service : libcanhaltools::getControlServices()) {
auto ctrl = ICanController::getService(service);
if (ctrl == nullptr) continue;
@@ -162,9 +147,11 @@
return -1;
}
- long long bitrate = 0;
- if (argc == 4) {
- bitrate = std::stoll(argv[3]);
+ uint32_t bitrate = 0;
+ if (argc == 4 && !android::base::ParseUint(argv[3], &bitrate)) {
+ std::cerr << "Invalid bitrate!" << std::endl;
+ usage();
+ return -1;
}
return up(busName, *type, interface, bitrate);
diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp
index 7e6833a..f0f9d10 100644
--- a/automotive/can/1.0/tools/canhalsend.cpp
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -15,6 +15,8 @@
*/
#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <android/hardware/automotive/can/1.0/ICanBus.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
@@ -27,13 +29,13 @@
using Result = V1_0::Result;
static void usage() {
- std::cerr << "cansend - simple command line tool to send raw CAN frames" << std::endl;
+ std::cerr << "canhalsend - simple command line tool to send raw CAN frames" << std::endl;
std::cerr << std::endl << "usage:" << std::endl << std::endl;
std::cerr << "canhalsend <bus name> <can id>#<data>" << std::endl;
std::cerr << "where:" << std::endl;
- std::cerr << " bus name - name under which ICanBus is be published" << std::endl;
- std::cerr << " can id - such as 1a5" << std::endl;
- std::cerr << " data - such as deadbeef or 010203" << std::endl;
+ std::cerr << " bus name - name under which ICanBus is published" << std::endl;
+ std::cerr << " can id - such as 1a5 or 1fab5982" << std::endl;
+ std::cerr << " data - such as deadbeef, 010203, or R for a remote frame" << std::endl;
}
// TODO(b/135918744): extract to a new library
@@ -53,18 +55,13 @@
return ICanBus::castFrom(ret);
}
-static int cansend(const std::string& busname, V1_0::CanMessageId msgid,
- std::vector<uint8_t> payload) {
+static int cansend(const std::string& busname, const V1_0::CanMessage& msg) {
auto bus = tryOpen(busname);
if (bus == nullptr) {
std::cerr << "Bus " << busname << " is not available" << std::endl;
return -1;
}
- V1_0::CanMessage msg = {};
- msg.id = msgid;
- msg.payload = payload;
-
const auto result = bus->send(msg);
if (result != Result::OK) {
std::cerr << "Send call failed: " << toString(result) << std::endl;
@@ -73,27 +70,54 @@
return 0;
}
-static std::optional<std::tuple<V1_0::CanMessageId, std::vector<uint8_t>>> parseCanMessage(
- const std::string& msg) {
+static std::optional<V1_0::CanMessage> parseCanMessage(const std::string& msg) {
const auto hashpos = msg.find("#");
if (hashpos == std::string::npos) return std::nullopt;
const std::string msgidStr = msg.substr(0, hashpos);
const std::string payloadStr = msg.substr(hashpos + 1);
- size_t idx = 0;
- V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16);
- if (msgidStr[idx] != '\0') return std::nullopt;
+ V1_0::CanMessageId msgid;
+ // "0x" must be prepended to msgidStr, since ParseUint doesn't accept a base argument.
+ if (!android::base::ParseUint("0x" + msgidStr, &msgid)) return std::nullopt;
+
+ V1_0::CanMessage canmsg = {};
+ canmsg.id = msgid;
+ if (msgid > 0x7FF) {
+ canmsg.isExtendedId = true;
+ }
+
+ if (android::base::StartsWith(payloadStr, "R")) {
+ canmsg.remoteTransmissionRequest = true;
+
+ /* The CAN bus HAL doesn't define a data length code (DLC) field, since it is inferrred
+ * from the payload size. RTR messages indicate to the receiver how many bytes they are
+ * expecting to receive back via the DLC sent with the RTR frame. */
+ if (payloadStr.size() <= 1) return canmsg;
+
+ unsigned int dlc = 0;
+
+ /* The maximum DLC for CAN-FD is 64 bytes and CAN 2.0 is 8 bytes. Limit the size of the DLC
+ * to something memory safe and let the HAL determine if the DLC is valid. */
+ if (!android::base::ParseUint(payloadStr.substr(1), &dlc, 10000u)) {
+ std::cerr << "Invalid DLC for RTR frame!" << std::endl;
+ return std::nullopt;
+ }
+ canmsg.payload.resize(dlc);
+ return canmsg;
+ }
std::vector<uint8_t> payload;
if (payloadStr.size() % 2 != 0) return std::nullopt;
for (size_t i = 0; i < payloadStr.size(); i += 2) {
std::string byteStr(payloadStr, i, 2);
- payload.emplace_back(std::stoi(byteStr, &idx, 16));
- if (byteStr[idx] != '\0') return std::nullopt;
+ uint8_t byteBuf;
+ if (!android::base::ParseUint("0x" + byteStr, &byteBuf)) return std::nullopt;
+ payload.emplace_back(byteBuf);
}
+ canmsg.payload = payload;
- return {{msgid, payload}};
+ return canmsg;
}
static int main(int argc, char* argv[]) {
@@ -117,9 +141,8 @@
std::cerr << "Failed to parse CAN message argument" << std::endl;
return -1;
}
- const auto [msgid, payload] = *canmsg;
- return cansend(busname, msgid, payload);
+ return cansend(busname, *canmsg);
}
} // namespace android::hardware::automotive::can
diff --git a/automotive/can/1.0/tools/configurator/Android.bp b/automotive/can/1.0/tools/configurator/Android.bp
new file mode 100644
index 0000000..2c4bc1d
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+cc_binary {
+ name: "canhalconfigurator",
+ init_rc: ["canhalconfigurator.rc"],
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "canhalconfigurator.cpp",
+ "canprototools.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ "libprotobuf-cpp-full",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@1.x-config-format",
+ "android.hardware.automotive.can@libcanhaltools",
+ ],
+}
diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
new file mode 100644
index 0000000..a100f06
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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 "canbus_config.pb.h"
+#include "canprototools.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <libcanhaltools/libcanhaltools.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can {
+
+using ICanController = V1_0::ICanController;
+
+/**
+ * Takes output from parsed protobuf config and uses it to configure the CAN HAL.
+ *
+ * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration.
+ * \return boolean status, true on success, false on failure.
+ */
+static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
+ for (auto const& bus : pb_cfg.buses()) {
+ if (bus.name().empty()) {
+ LOG(ERROR) << "Invalid config: Bus config must have a valid name field";
+ return false;
+ }
+
+ LOG(INFO) << "Configure " << bus.name();
+ auto bus_cfg = config::fromPbBus(bus);
+ if (!bus_cfg.has_value()) {
+ return false;
+ }
+
+ // TODO(149405589): remove this sleep and associated includes.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ if (libcanhaltools::configureIface(*bus_cfg) != ICanController::Result::OK) {
+ LOG(ERROR) << "No controller supports " << bus.name() << std::endl;
+ // TODO(149405589): add retry logic in case a bus fails to come up.
+ continue;
+ }
+ LOG(INFO) << bus.name() << " has been successfully configured!";
+ }
+ return true;
+}
+
+/**
+ * This kicks off the CAN HAL configuration process. This starts the following:
+ * 1. Reading the config file
+ * 2. Setting up CAN buses
+ * 3. Handling services
+ * \param filepath is a string specifying the absolute path of the config file
+ * \return boolean status, true on success, false on failure
+ */
+static bool configuratorStart(const std::string& filepath) {
+ base::SetDefaultTag("CanConfigurator");
+
+ auto pb_cfg = config::parseConfigFile(filepath);
+ if (!pb_cfg.has_value()) {
+ return false;
+ }
+
+ // process the rest of the config file data and configure the CAN buses.
+ if (!processPbCfg(*pb_cfg)) {
+ return false;
+ }
+ LOG(INFO) << "CAN HAL has been configured!";
+ return true;
+}
+
+} // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+ std::string config_filepath = "/etc/canbus_config.pb";
+
+ // allow for CLI specification of a config file.
+ if (argc == 2) {
+ config_filepath = argv[1];
+ } else if (argc > 2) {
+ std::cerr << "usage: " << argv[0] << " [optional config filepath]";
+ return 1;
+ }
+
+ if (!::android::hardware::automotive::can::configuratorStart(config_filepath)) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.rc b/automotive/can/1.0/tools/configurator/canhalconfigurator.rc
new file mode 100644
index 0000000..12c2465
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.rc
@@ -0,0 +1,3 @@
+service canhalconfigurator /system/bin/canhalconfigurator
+ class core
+ oneshot
diff --git a/automotive/can/1.0/tools/configurator/canprototools.cpp b/automotive/can/1.0/tools/configurator/canprototools.cpp
new file mode 100644
index 0000000..8e6b2b1
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canprototools.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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 "canprototools.h"
+
+#include <android-base/logging.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+#include <hidl/HidlTransportSupport.h>
+#include <libcanhaltools/libcanhaltools.h>
+
+#include <fstream>
+
+namespace android::hardware::automotive::can::config {
+
+using ICanController = V1_0::ICanController;
+
+/**
+ * Helper function for parseConfigFile. readString is used to get the fist n characters (n) from an
+ * istream object (s) and return it as a string object.
+ *
+ * \param s istream of the file you intend to read.
+ * \param n streamsize object of the number of characters you'd like.
+ * \return optional string containing up to n characters from the stream(s) you provided.
+ */
+static std::optional<std::string> readString(std::istream& s, std::streamsize n) {
+ char buff[n];
+ auto got = s.read(buff, n).gcount();
+ if (!s.good() && !s.eof()) return std::nullopt;
+ return std::string(buff, 0, std::min(n, got));
+}
+
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+ std::ifstream cfg_stream(filepath);
+
+ // text headers that would be present in a plaintext proto config file.
+ static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
+ auto cfg_file_snippet = readString(cfg_stream, 10);
+
+ if (!cfg_file_snippet.has_value()) {
+ LOG(ERROR) << "Can't open " << filepath << " for reading";
+ return std::nullopt;
+ }
+ cfg_stream.seekg(0);
+
+ // check if any of the textHeaders are at the start of the config file.
+ bool text_format = false;
+ for (auto const& header : text_headers) {
+ if (cfg_file_snippet->compare(0, header.length(), header) == 0) {
+ text_format = true;
+ break;
+ }
+ }
+
+ CanBusConfig config;
+ if (text_format) {
+ google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
+ if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
+ LOG(ERROR) << "Failed to parse (text format) " << filepath;
+ return std::nullopt;
+ }
+ } else if (!config.ParseFromIstream(&cfg_stream)) {
+ LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+ return std::nullopt;
+ }
+ return config;
+}
+
+std::optional<ICanController::BusConfig> fromPbBus(const Bus& pb_bus) {
+ ICanController::BusConfig bus_cfg = {};
+ bus_cfg.name = pb_bus.name();
+
+ switch (pb_bus.iface_type_case()) {
+ case Bus::kNative: {
+ const auto ifname = pb_bus.native().ifname();
+ if (ifname.empty()) {
+ LOG(ERROR) << "Invalid config: native type bus must have an iface name";
+ return std::nullopt;
+ }
+ bus_cfg.bitrate = pb_bus.bitrate();
+ ICanController::BusConfig::InterfaceId::Socketcan socketcan = {};
+ socketcan.ifname(ifname);
+ bus_cfg.interfaceId.socketcan(socketcan);
+ // TODO(b/142654031) - add support for serial number as an option instead of ifname.
+ break;
+ }
+ case Bus::kSlcan: {
+ const auto ttyname = pb_bus.slcan().ttyname();
+ if (ttyname.empty()) {
+ LOG(ERROR) << "Invalid config: slcan type bus must have a tty name";
+ return std::nullopt;
+ }
+ bus_cfg.bitrate = pb_bus.bitrate();
+ ICanController::BusConfig::InterfaceId::Slcan slcan = {};
+ slcan.ttyname(pb_bus.slcan().ttyname());
+ bus_cfg.interfaceId.slcan(slcan);
+ break;
+ }
+ case Bus::kVirtual: {
+ // Theoretically, we could just create the next available vcan iface.
+ const auto ifname = pb_bus.virtual_().ifname();
+ if (ifname.empty()) {
+ LOG(ERROR) << "Invalid config: native type bus must have an iface name";
+ return std::nullopt;
+ }
+ bus_cfg.interfaceId.virtualif({ifname});
+ break;
+ }
+ case Bus::kIndexed: {
+ const auto index = pb_bus.indexed().index();
+ if (index > UINT8_MAX) {
+ LOG(ERROR) << "Interface index out of range: " << index;
+ return std::nullopt;
+ }
+ bus_cfg.interfaceId.indexed({uint8_t(index)});
+ break;
+ }
+ default:
+ LOG(ERROR) << "Invalid config: bad interface type for " << bus_cfg.name;
+ return std::nullopt;
+ }
+ return bus_cfg;
+}
+
+std::optional<ICanController::InterfaceType> getHalIftype(const Bus& pb_bus) {
+ switch (pb_bus.iface_type_case()) {
+ case Bus::kNative:
+ return ICanController::InterfaceType::SOCKETCAN;
+ case Bus::kSlcan:
+ return ICanController::InterfaceType::SLCAN;
+ case Bus::kVirtual:
+ return ICanController::InterfaceType::VIRTUAL;
+ case Bus::kIndexed:
+ return ICanController::InterfaceType::INDEXED;
+ default:
+ return std::nullopt;
+ }
+}
+
+} // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/1.0/tools/configurator/canprototools.h b/automotive/can/1.0/tools/configurator/canprototools.h
new file mode 100644
index 0000000..b7f2b6f
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canprototools.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "canbus_config.pb.h"
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::config {
+
+/**
+ * This reads the protobuf config file into a protobuf object. Both text based protobuf files as
+ * well as binary format protobuf files are supported.
+ *
+ * \param filepath string containing the name of the config file to read.
+ * \return a CanBusConfig protobuf object constructed from the config file.
+ */
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath);
+
+/**
+ * Converts protobuf format single-bus config object to a HAL bus config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return a converted HAL bus config object.
+ */
+std::optional<V1_0::ICanController::BusConfig> fromPbBus(const Bus& pb_bus);
+
+/**
+ * Get the CAN HAL interface type specified by a given protobuf config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return the CAN HAL interface type.
+ */
+std::optional<V1_0::ICanController::InterfaceType> getHalIftype(const Bus& pb_bus);
+
+} // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/1.0/tools/configurator/proto/Android.bp b/automotive/can/1.0/tools/configurator/proto/Android.bp
new file mode 100644
index 0000000..05e1205
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/proto/Android.bp
@@ -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.
+//
+
+cc_library_static {
+ name: "android.hardware.automotive.can@1.x-config-format",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+ strip: {
+ keep_symbols: true,
+ },
+ srcs: ["canbus_config.proto"],
+}
diff --git a/automotive/can/1.0/tools/configurator/proto/canbus_config.proto b/automotive/can/1.0/tools/configurator/proto/canbus_config.proto
new file mode 100644
index 0000000..9aa33ac
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/proto/canbus_config.proto
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.can.config;
+
+message IfaceNative {
+ string ifname = 1;
+ repeated string serialno = 2;
+};
+
+message IfaceSlcan {
+ string ttyname = 1;
+ repeated string serialno = 2;
+};
+
+message IfaceVirtual {
+ string ifname = 1;
+};
+
+message IfaceIndexed {
+ uint32 index = 1;
+};
+
+message Bus {
+ string name = 1; // this is the name presented in the HAL
+ oneof iface_type {
+ IfaceNative native = 2;
+ IfaceSlcan slcan = 3;
+ IfaceVirtual virtual = 4;
+ IfaceIndexed indexed = 5;
+ }
+ uint32 bitrate = 6;
+};
+
+message CanBusConfig {
+ repeated Bus buses = 1;
+};
diff --git a/automotive/can/1.0/tools/libcanhaltools/Android.bp b/automotive/can/1.0/tools/libcanhaltools/Android.bp
new file mode 100644
index 0000000..cee9eef
--- /dev/null
+++ b/automotive/can/1.0/tools/libcanhaltools/Android.bp
@@ -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.
+//
+
+cc_library_static {
+ name: "android.hardware.automotive.can@libcanhaltools",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ vendor_available: true,
+ srcs: [
+ "libcanhaltools.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ ],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+}
diff --git a/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h b/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h
new file mode 100644
index 0000000..bbd1fe5
--- /dev/null
+++ b/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::libcanhaltools {
+
+/**
+ * Fetch the list of registered can controller services.
+ *
+ * \return list of service names identifying the registered can controllers.
+ */
+hidl_vec<hidl_string> getControlServices();
+
+/**
+ * Determine if an can controller supports a specific interface type.
+ *
+ * \param ctrl a pointer to a can controller instance to check for interface support.
+ * \param iftype the interface type we wish to check if ctrl supports.
+ * \return true if iftype is supported by ctrl, false if not supported.
+ */
+bool isSupported(sp<V1_0::ICanController> ctrl, V1_0::ICanController::InterfaceType iftype);
+
+/**
+ * Configures a CAN interface through the CAN HAL and brings it up.
+ *
+ * \param can_config this holds the parameters for configuring a CAN bus.
+ * \return status passed back from the CAN HAL, should be OK on success.
+ */
+V1_0::ICanController::Result configureIface(V1_0::ICanController::BusConfig can_config);
+
+} // namespace android::hardware::automotive::can::libcanhaltools
diff --git a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
new file mode 100644
index 0000000..9192e2f
--- /dev/null
+++ b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "libcanhaltools/libcanhaltools.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+
+#include <iostream>
+#include <string>
+
+namespace android::hardware::automotive::can::libcanhaltools {
+
+using ICanBus = V1_0::ICanBus;
+using ICanController = V1_0::ICanController;
+using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
+
+hidl_vec<hidl_string> getControlServices() {
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ hidl_vec<hidl_string> services;
+ manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
+ CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?)"
+ << std::endl;
+ return services;
+}
+
+bool isSupported(sp<ICanController> ctrl, ICanController::InterfaceType iftype) {
+ hidl_vec<ICanController::InterfaceType> supported;
+ if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false;
+ return supported.contains(iftype);
+}
+
+ICanController::InterfaceType getIftype(ICanController::BusConfig can_config) {
+ switch (can_config.interfaceId.getDiscriminator()) {
+ case IfIdDisc::socketcan:
+ return ICanController::InterfaceType::SOCKETCAN;
+ case IfIdDisc::slcan:
+ return ICanController::InterfaceType::SLCAN;
+ case IfIdDisc::virtualif:
+ return ICanController::InterfaceType::VIRTUAL;
+ case IfIdDisc::indexed:
+ return ICanController::InterfaceType::INDEXED;
+ default:
+ CHECK(false) << "HAL returned unexpected interface type!";
+ }
+}
+
+ICanController::Result configureIface(ICanController::BusConfig can_config) {
+ auto iftype = getIftype(can_config);
+ auto can_controller_list = getControlServices();
+ for (auto const& service : can_controller_list) {
+ auto ctrl = ICanController::getService(service);
+ if (ctrl == nullptr) {
+ LOG(ERROR) << "Couldn't open ICanController/" << service;
+ continue;
+ }
+
+ if (!libcanhaltools::isSupported(ctrl, iftype)) continue;
+
+ const auto up_result = ctrl->upInterface(can_config);
+ if (up_result != ICanController::Result::OK) {
+ LOG(ERROR) << "Failed to bring " << can_config.name << " up: " << toString(up_result)
+ << std::endl;
+ }
+ return up_result;
+ }
+ return ICanController::Result::NOT_SUPPORTED;
+}
+
+} // namespace android::hardware::automotive::can::libcanhaltools
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 8e57901..e529675 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -63,6 +63,8 @@
"impl/vhal_v2_0/CommConn.cpp",
"impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
"impl/vhal_v2_0/EmulatedVehicleHal.cpp",
+ "impl/vhal_v2_0/VehicleHalClient.cpp",
+ "impl/vhal_v2_0/VehicleHalServer.cpp",
"impl/vhal_v2_0/VehicleEmulator.cpp",
"impl/vhal_v2_0/PipeComm.cpp",
"impl/vhal_v2_0/ProtoMessageConverter.cpp",
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
new file mode 100644
index 0000000..5e4bf27
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android::hardware::automotive::vehicle::V2_0 {
+
+/**
+ * Vehicle HAL talks to the vehicle through a client, instead of accessing
+ * the car bus directly, to give us more flexibility on the implementation.
+ * Android OS do not need direct access to the vehicle, and the communication
+ * channel is also customizable.
+ *
+ * Client lives on the Android (HAL) side to talk to the vehicle
+ */
+class IVehicleClient {
+ public:
+ IVehicleClient() = default;
+
+ IVehicleClient(const IVehicleClient&) = delete;
+
+ IVehicleClient& operator=(const IVehicleClient&) = delete;
+
+ IVehicleClient(IVehicleClient&&) = default;
+
+ virtual ~IVehicleClient() = default;
+
+ // Get configuration of all properties from server
+ virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
+
+ // Send the set property request to server
+ // updateStatus indicate if VHal should change the status of the value
+ // it should be false except injecting values for e2e tests
+ virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0;
+
+ // Receive a new property value from server
+ // updateStatus is true if and only if the value is
+ // generated by car (ECU/fake generator/injected)
+ virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
+
+ // Dump method forwarded from HIDL's debug()
+ // If implemented, it must return whether the caller should dump its state.
+ virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+ return true;
+ }
+};
+
+} // namespace android::hardware::automotive::vehicle::V2_0
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
index 00b5afe..2908a55 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -21,6 +21,9 @@
#include <android/hardware/automotive/vehicle/2.0/types.h>
+#include "VehicleClient.h"
+#include "VehicleServer.h"
+
namespace android {
namespace hardware {
namespace automotive {
@@ -34,85 +37,6 @@
*/
/**
- * Vehicle HAL talks to the vehicle through a client, instead of accessing
- * the car bus directly, to give us more flexibility on the implementation.
- * Android OS do not need direct access to the vehicle, and the communication
- * channel is also customizable.
- *
- * Client lives on the Android (HAL) side to talk to the vehicle
- */
-class IVehicleClient {
- public:
- IVehicleClient() = default;
-
- IVehicleClient(const IVehicleClient&) = delete;
-
- IVehicleClient& operator=(const IVehicleClient&) = delete;
-
- IVehicleClient(IVehicleClient&&) = default;
-
- virtual ~IVehicleClient() = default;
-
- // Get configuration of all properties from server
- virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
-
- // Send the set property request to server
- // updateStatus indicate if VHal should change the status of the value
- // it should be false except injecting values for e2e tests
- virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0;
-
- // Receive a new property value from server
- // updateStatus is true if and only if the value is
- // generated by car (ECU/fake generator/injected)
- virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
-
- // Dump method forwarded from HIDL's debug()
- // If implemented, it must return whether the caller should dump its state.
- virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
- return true;
- }
-};
-
-/**
- * Server lives on the vehicle side to talk to Android HAL
- */
-class IVehicleServer {
- public:
- IVehicleServer() = default;
-
- IVehicleServer(const IVehicleServer&) = delete;
-
- IVehicleServer& operator=(const IVehicleServer&) = delete;
-
- IVehicleServer(IVehicleServer&&) = default;
-
- virtual ~IVehicleServer() = default;
-
- // Receive the get property configuration request from HAL.
- // Return a list of all property config
- virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() const = 0;
-
- // Receive the set property request from HAL.
- // Process the setting and return the status code
- // updateStatus indicate if VHal should change the status of the value
- // it should be false except injecting values for e2e tests
- virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0;
-
- // Receive a new property value from car (via direct connection to the car bus or the emulator)
- // and forward the value to HAL
- // updateStatus is true if and only if the value is
- // generated by car (ECU/fake generator/injected)
- virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
-
- // Dump method forwarded from HIDL's debug()
- // If implemented, it must return whether the caller should dump its state.
- virtual bool onDump(const hidl_handle& /* handle */,
- const hidl_vec<hidl_string>& /* options */) {
- return true;
- }
-};
-
-/**
* If Android has direct access to the vehicle, then the client and
* the server may act in passthrough mode to avoid extra IPC
*
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
index 946e74d..e3cbf2e 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -21,6 +21,7 @@
#include <deque>
#include <map>
#include <mutex>
+#include <memory>
#include <android/hardware/automotive/vehicle/2.0/types.h>
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
new file mode 100644
index 0000000..ba9799a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
@@ -0,0 +1,68 @@
+/*
+ * 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 <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android::hardware::automotive::vehicle::V2_0 {
+
+/**
+ * Server lives on the vehicle side to talk to Android HAL.
+ * Note that the server may not be run on Android
+ */
+class IVehicleServer {
+ public:
+ IVehicleServer() = default;
+
+ IVehicleServer(const IVehicleServer&) = delete;
+
+ IVehicleServer& operator=(const IVehicleServer&) = delete;
+
+ IVehicleServer(IVehicleServer&&) = default;
+
+ virtual ~IVehicleServer() = default;
+
+ // Receive the get property configuration request from HAL.
+ // Return a list of all property config
+ virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() const = 0;
+
+ // Receive the set property request from HAL.
+ // Process the setting and return the status code
+ // updateStatus indicate if VHal should change the status of the value
+ // it should be false except injecting values for e2e tests
+ virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0;
+
+ // Receive a new property value from car (via direct connection to the car bus or the emulator)
+ // and forward the value to HAL
+ // updateStatus is true if and only if the value is
+ // generated by car (ECU/fake generator/injected)
+ virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
+
+ // TODO (chenhaosjtuacm): fix this since there are no HIDL in non-Android OS
+#ifdef __ANDROID__
+ // Dump method forwarded from HIDL's debug()
+ // If implemented, it must return whether the caller should dump its state.
+ virtual bool onDump(const hidl_handle& /* handle */,
+ const hidl_vec<hidl_string>& /* options */) {
+ return true;
+ }
+#endif // __ANDROID__
+};
+
+} // namespace android::hardware::automotive::vehicle::V2_0
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
index f97dfa1..9553415 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
@@ -19,7 +19,9 @@
#include <memory>
+#ifdef __ANDROID__
#include <hidl/HidlSupport.h>
+#endif
#include <android/hardware/automotive/vehicle/2.0/types.h>
@@ -69,6 +71,8 @@
void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
const VehiclePropValue::RawValue& src);
+#ifdef __ANDROID__
+
template<typename T>
void shallowCopyHidlVec(hidl_vec<T>* dest, const hidl_vec<T>& src);
@@ -76,6 +80,8 @@
void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src);
+#endif // __ANDROID__
+
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
index 40dd56e..0947c9f 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -131,7 +131,7 @@
ALOGE("Discarding value for prop 0x%x because it contains "
"data that is not consistent with this pool. "
"Expected type: %d, vector size: %zu",
- o->prop, mPropType, mVectorSize);
+ o->prop, toInt(mPropType), mVectorSize);
delete o;
} else {
ObjectPool<VehiclePropValue>::recycle(o);
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index 5b6816e..c16b29a 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -52,7 +52,7 @@
case VehiclePropertyType::MIXED:
break; // Valid, but nothing to do.
default:
- ALOGE("createVehiclePropValue: unknown type: %d", type);
+ ALOGE("createVehiclePropValue: unknown type: %d", toInt(type));
val.reset(nullptr);
}
return val;
@@ -78,13 +78,6 @@
}
}
-template<typename T>
-inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
- for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
- (*dest)[i] = src[i];
- }
-}
-
void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
const VehiclePropValue::RawValue& src) {
dest->int32Values = src.int32Values;
@@ -94,6 +87,15 @@
dest->stringValue = src.stringValue;
}
+#ifdef __ANDROID__
+
+template<typename T>
+inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
+ for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
+ (*dest)[i] = src[i];
+ }
+}
+
template<typename T>
void shallowCopyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
if (src.size() > 0) {
@@ -123,6 +125,7 @@
shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue);
}
+#endif // __ANDROID__
//} // namespace utils
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 4b94800..53c9ffb 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -17,9 +17,11 @@
#ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
#define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/hardware/automotive/vehicle/2.0/types.h>
#include <vhal_v2_0/VehicleUtils.h>
+#include <map>
+
namespace android {
namespace hardware {
namespace automotive {
@@ -1017,7 +1019,6 @@
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
},
-
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
index 7f90914..9c3c95f 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -35,346 +35,16 @@
namespace impl {
-void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
- if (!mPropCallback) {
- LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
- return;
- }
- return mPropCallback(value, updateStatus);
-}
+class EmulatedPassthroughConnector : public PassthroughConnector {
+ public:
+ bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
-void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
- if (mPropCallback) {
- LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
- return;
- }
- mPropCallback = std::move(callback);
-}
+ private:
+ void dumpUserHal(int fd, std::string indent);
+};
-GeneratorHub* EmulatedVehicleServer::getGenerator() {
- return &mGeneratorHub;
-}
-
-VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const {
- if (!mValuePool) {
- LOG(WARNING) << __func__ << ": Value pool not set!";
- }
- return mValuePool;
-}
-
-void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) {
- if (!valuePool) {
- LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
- }
- mValuePool = valuePool;
-}
-
-void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
- constexpr bool updateStatus = true;
- LOG(DEBUG) << __func__ << ": " << toString(value);
- auto updatedPropValue = getValuePool()->obtain(value);
- if (updatedPropValue) {
- updatedPropValue->timestamp = value.timestamp;
- updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- }
-}
-
-std::vector<VehiclePropConfig> EmulatedVehicleServer::onGetAllPropertyConfig() const {
- std::vector<VehiclePropConfig> vehiclePropConfigs;
- constexpr size_t numOfVehiclePropConfigs =
- sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
- vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
- for (auto& it : kVehicleProperties) {
- vehiclePropConfigs.emplace_back(it.config);
- }
- return vehiclePropConfigs;
-}
-
-StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
- constexpr bool updateStatus = true;
-
- LOG(INFO) << __func__;
- const auto& v = request.value;
- if (!v.int32Values.size()) {
- LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
- return StatusCode::INVALID_ARG;
- }
-
- FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
-
- switch (command) {
- case FakeDataCommand::StartLinear: {
- LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
- if (v.int32Values.size() < 2) {
- LOG(ERROR) << __func__ << ": expected property ID in int32Values";
- return StatusCode::INVALID_ARG;
- }
- if (!v.int64Values.size()) {
- LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
- return StatusCode::INVALID_ARG;
- }
- if (v.floatValues.size() < 3) {
- LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
- << v.floatValues.size();
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = v.int32Values[1];
- getGenerator()->registerGenerator(cookie,
- std::make_unique<LinearFakeValueGenerator>(request));
- break;
- }
- case FakeDataCommand::StartJson: {
- LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
- if (v.stringValue.empty()) {
- LOG(ERROR) << __func__ << ": path to JSON file is missing";
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = std::hash<std::string>()(v.stringValue);
- getGenerator()->registerGenerator(cookie,
- std::make_unique<JsonFakeValueGenerator>(request));
- break;
- }
- case FakeDataCommand::StopLinear: {
- LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
- if (v.int32Values.size() < 2) {
- LOG(ERROR) << __func__ << ": expected property ID in int32Values";
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = v.int32Values[1];
- getGenerator()->unregisterGenerator(cookie);
- break;
- }
- case FakeDataCommand::StopJson: {
- LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
- if (v.stringValue.empty()) {
- LOG(ERROR) << __func__ << ": path to JSON file is missing";
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = std::hash<std::string>()(v.stringValue);
- getGenerator()->unregisterGenerator(cookie);
- break;
- }
- case FakeDataCommand::KeyPress: {
- LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
- int32_t keyCode = request.value.int32Values[2];
- int32_t display = request.value.int32Values[3];
- // Send back to HAL
- onPropertyValueFromCar(
- *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
- updateStatus);
- onPropertyValueFromCar(
- *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
- updateStatus);
- break;
- }
- default: {
- LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
- return StatusCode::INVALID_ARG;
- }
- }
- return StatusCode::OK;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq(
- VehicleApPowerStateReq state, int32_t param) {
- auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
- req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
- req->areaId = 0;
- req->timestamp = elapsedRealtimeNano();
- req->status = VehiclePropertyStatus::AVAILABLE;
- req->value.int32Values[0] = toInt(state);
- req->value.int32Values[1] = param;
- return req;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp(
- VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
- auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
- keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
- keyEvent->areaId = 0;
- keyEvent->timestamp = elapsedRealtimeNano();
- keyEvent->status = VehiclePropertyStatus::AVAILABLE;
- keyEvent->value.int32Values[0] = toInt(action);
- keyEvent->value.int32Values[1] = keyCode;
- keyEvent->value.int32Values[2] = targetDisplay;
- return keyEvent;
-}
-
-StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
- // Some properties need to be treated non-trivially
- switch (value.prop) {
- case kGenerateFakeDataControllingProperty:
- return handleGenerateFakeDataRequest(value);
-
- // set the value from vehicle side, used in end to end test.
- case kSetIntPropertyFromVehicleForTest: {
- auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
- updatedPropValue->prop = value.value.int32Values[0];
- updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
- updatedPropValue->timestamp = value.value.int64Values[0];
- updatedPropValue->areaId = value.areaId;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
- case kSetFloatPropertyFromVehicleForTest: {
- auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
- updatedPropValue->prop = value.value.int32Values[0];
- updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
- updatedPropValue->timestamp = value.value.int64Values[0];
- updatedPropValue->areaId = value.areaId;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
- case kSetBooleanPropertyFromVehicleForTest: {
- auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
- updatedPropValue->prop = value.value.int32Values[1];
- updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
- updatedPropValue->timestamp = value.value.int64Values[0];
- updatedPropValue->areaId = value.areaId;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
-
- case AP_POWER_STATE_REPORT:
- switch (value.value.int32Values[0]) {
- case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
- case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
- // CPMS is in WAIT_FOR_VHAL state, simply move to ON
- // Send back to HAL
- // ALWAYS update status for generated property value
- onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
- true /* updateStatus */);
- break;
- case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
- // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
- // Send back to HAL
- // ALWAYS update status for generated property value
- onPropertyValueFromCar(
- *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
- true /* updateStatus */);
- break;
- case toInt(VehicleApPowerStateReport::ON):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
- // Do nothing
- break;
- default:
- // Unknown state
- break;
- }
- break;
- case INITIAL_USER_INFO:
- return onSetInitialUserInfo(value, updateStatus);
- default:
- break;
- }
-
- // In the real vhal, the value will be sent to Car ECU.
- // We just pretend it is done here and send back to HAL
- auto updatedPropValue = getValuePool()->obtain(value);
- updatedPropValue->timestamp = elapsedRealtimeNano();
-
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
-}
-
-/**
- * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
- * indicating what the initial user should be.
- *
- * During normal circumstances, the emulator will reply right away, passing a response if
- * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
- * to boot).
- *
- * But during development / testing, the behavior can be changed using lshal dump, which must use
- * the areaId to indicate what should happen next.
- *
- * So, the behavior of set(INITIAL_USER_INFO) is:
- *
- * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
- * lshal).
- * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
- * InitialUserInfoResponseAction::DEFAULT
- * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
- * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
- * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
- * this error scenario)
- * - if it's 3, then don't send a property change (so Android can emulate a timeout)
- *
- */
-StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value,
- bool updateStatus) {
- // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
- // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
- // LOG, it's not worth investigating why...
-
- if (value.value.int32Values.size() == 0) {
- LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
- return StatusCode::INVALID_ARG;
- }
-
- if (value.areaId != 0) {
- LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
- mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
- return StatusCode::OK;
- }
- LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
-
- int32_t requestId = value.value.int32Values[0];
-
- // Create the update property and set common values
- auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
- updatedValue->prop = INITIAL_USER_INFO;
- updatedValue->timestamp = elapsedRealtimeNano();
-
- if (mInitialUserResponseFromCmd == nullptr) {
- updatedValue->value.int32Values.resize(2);
- updatedValue->value.int32Values[0] = requestId;
- updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
- LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
- << toString(*updatedValue);
- onPropertyValueFromCar(*updatedValue, updateStatus);
- return StatusCode::OK;
- }
-
- // mInitialUserResponseFromCmd is used for just one request
- std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
-
- // TODO(b/138709788): rather than populate the raw values directly, it should use the
- // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
-
- switch (response->areaId) {
- case 1:
- LOG(INFO) << "returning response with right request id";
- *updatedValue = *response;
- updatedValue->areaId = 0;
- updatedValue->value.int32Values[0] = requestId;
- break;
- case 2:
- LOG(INFO) << "returning response with wrong request id";
- *updatedValue = *response;
- updatedValue->areaId = 0;
- updatedValue->value.int32Values[0] = -requestId;
- break;
- case 3:
- LOG(INFO) << "not generating a property change event because of lshal prop: "
- << toString(*response);
- return StatusCode::OK;
- default:
- LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
- return StatusCode::INTERNAL_ERROR;
- }
-
- LOG(INFO) << "updating property to: " << toString(*updatedValue);
- onPropertyValueFromCar(*updatedValue, updateStatus);
- return StatusCode::OK;
-}
-
-bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
- const hidl_vec<hidl_string>& options) {
+bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
+ const hidl_vec<hidl_string>& options) {
int fd = handle->data[0];
if (options.size() > 0) {
@@ -401,7 +71,7 @@
return true;
}
-void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) {
+void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) {
if (mInitialUserResponseFromCmd != nullptr) {
dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
toString(*mInitialUserResponseFromCmd).c_str());
@@ -410,7 +80,7 @@
}
}
-EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
+PassthroughConnectorPtr makeEmulatedPassthroughConnector() {
return std::make_unique<EmulatedPassthroughConnector>();
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
index 4850d32..57cbb8b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -18,9 +18,9 @@
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
#include <vhal_v2_0/VehicleConnector.h>
-#include <vhal_v2_0/VehicleHal.h>
-#include "GeneratorHub.h"
+#include "VehicleHalClient.h"
+#include "VehicleHalServer.h"
namespace android {
namespace hardware {
@@ -30,69 +30,10 @@
namespace impl {
-// Extension of the client/server interfaces for emulated vehicle
+using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
+using PassthroughConnectorPtr = std::unique_ptr<PassthroughConnector>;
-class EmulatedVehicleClient : public IVehicleClient {
- public:
- // Type of callback function for handling the new property values
- using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
-
- // Method from IVehicleClient
- void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
-
- void registerPropertyValueCallback(PropertyCallBackType&& callback);
-
- private:
- PropertyCallBackType mPropCallback;
-};
-
-class EmulatedVehicleServer : public IVehicleServer {
- public:
- // Methods from IVehicleServer
-
- std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
-
- StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
-
- bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
-
- // Set the Property Value Pool used in this server
- void setValuePool(VehiclePropValuePool* valuePool);
-
- private:
- GeneratorHub* getGenerator();
-
- VehiclePropValuePool* getValuePool() const;
-
- void onFakeValueGenerated(const VehiclePropValue& value);
-
- StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
-
- VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
-
- VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
- int32_t keyCode, int32_t targetDisplay);
-
- // private data members
-
- GeneratorHub mGeneratorHub{
- std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
-
- VehiclePropValuePool* mValuePool{nullptr};
-
- // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
- std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
- StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
- void dumpUserHal(int fd, std::string indent);
-};
-
-// Helper functions
-
-using EmulatedPassthroughConnector =
- IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
-using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
-
-EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
+PassthroughConnectorPtr makeEmulatedPassthroughConnector();
} // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 692c7f7..6d5f23f 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -87,12 +87,11 @@
return sensorStore;
}
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
- EmulatedVehicleClient* client)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
: mPropStore(propStore),
mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
- mRecurrentTimer(
- std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
+ mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
+ std::placeholders::_1)),
mVehicleClient(client) {
initStaticConfig();
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index ebc405e..ebf1995 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -46,7 +46,7 @@
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
public:
EmulatedVehicleHal(VehiclePropertyStore* propStore,
- EmulatedVehicleClient* client);
+ VehicleHalClient* client);
~EmulatedVehicleHal() = default;
// Methods from VehicleHal
@@ -85,7 +85,7 @@
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;
- EmulatedVehicleClient* mVehicleClient;
+ VehicleHalClient* mVehicleClient;
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
index d6ad77d..2dc502b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
@@ -19,6 +19,8 @@
#include <android/hardware/automotive/vehicle/2.0/types.h>
+#include <chrono>
+
namespace android {
namespace hardware {
namespace automotive {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
index 7bdc97c..96aaafe 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -46,7 +46,8 @@
if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) {
mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion;
}
- VehiclePropValue event = {.prop = mGenCfg.propId};
+ // TODO: (chenhaosjtuacm) remove "{}" if AGL compiler updated
+ VehiclePropValue event = {.timestamp = {}, .areaId = {}, .prop = mGenCfg.propId};
auto& value = event.value;
switch (getPropType(event.prop)) {
case VehiclePropertyType::INT32:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp
new file mode 100644
index 0000000..25ffc6d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "VehicleHalClient.h"
+
+#include <android-base/logging.h>
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
+ if (!mPropCallback) {
+ LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
+ return;
+ }
+ return mPropCallback(value, updateStatus);
+}
+
+void VehicleHalClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
+ if (mPropCallback) {
+ LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
+ return;
+ }
+ mPropCallback = std::move(callback);
+}
+
+} // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h
new file mode 100644
index 0000000..6559e2a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <vhal_v2_0/VehicleClient.h>
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+// The common client operations that may be used by both native and
+// virtualized VHAL clients.
+class VehicleHalClient : public IVehicleClient {
+ public:
+ // Type of callback function for handling the new property values
+ using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
+
+ // Method from IVehicleClient
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
+
+ void registerPropertyValueCallback(PropertyCallBackType&& callback);
+
+ private:
+ PropertyCallBackType mPropCallback;
+};
+
+} // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
new file mode 100644
index 0000000..3f6ea5e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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 "VehicleHalServer.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "DefaultConfig.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
+#include "Obd2SensorStore.h"
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+GeneratorHub* VehicleHalServer::getGenerator() {
+ return &mGeneratorHub;
+}
+
+VehiclePropValuePool* VehicleHalServer::getValuePool() const {
+ if (!mValuePool) {
+ LOG(WARNING) << __func__ << ": Value pool not set!";
+ }
+ return mValuePool;
+}
+
+void VehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) {
+ if (!valuePool) {
+ LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
+ }
+ mValuePool = valuePool;
+}
+
+void VehicleHalServer::onFakeValueGenerated(const VehiclePropValue& value) {
+ constexpr bool updateStatus = true;
+ LOG(DEBUG) << __func__ << ": " << toString(value);
+ auto updatedPropValue = getValuePool()->obtain(value);
+ if (updatedPropValue) {
+ updatedPropValue->timestamp = value.timestamp;
+ updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ }
+}
+
+std::vector<VehiclePropConfig> VehicleHalServer::onGetAllPropertyConfig() const {
+ std::vector<VehiclePropConfig> vehiclePropConfigs;
+ constexpr size_t numOfVehiclePropConfigs =
+ sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
+ vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
+ for (auto& it : kVehicleProperties) {
+ vehiclePropConfigs.emplace_back(it.config);
+ }
+ return vehiclePropConfigs;
+}
+
+StatusCode VehicleHalServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+ constexpr bool updateStatus = true;
+
+ LOG(INFO) << __func__;
+ const auto& v = request.value;
+ if (!v.int32Values.size()) {
+ LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
+ return StatusCode::INVALID_ARG;
+ }
+
+ FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
+
+ switch (command) {
+ case FakeDataCommand::StartLinear: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
+ if (v.int32Values.size() < 2) {
+ LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+ return StatusCode::INVALID_ARG;
+ }
+ if (!v.int64Values.size()) {
+ LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
+ return StatusCode::INVALID_ARG;
+ }
+ if (v.floatValues.size() < 3) {
+ LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
+ << v.floatValues.size();
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = v.int32Values[1];
+ getGenerator()->registerGenerator(cookie,
+ std::make_unique<LinearFakeValueGenerator>(request));
+ break;
+ }
+ case FakeDataCommand::StartJson: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
+ if (v.stringValue.empty()) {
+ LOG(ERROR) << __func__ << ": path to JSON file is missing";
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = std::hash<std::string>()(v.stringValue);
+ getGenerator()->registerGenerator(cookie,
+ std::make_unique<JsonFakeValueGenerator>(request));
+ break;
+ }
+ case FakeDataCommand::StopLinear: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
+ if (v.int32Values.size() < 2) {
+ LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = v.int32Values[1];
+ getGenerator()->unregisterGenerator(cookie);
+ break;
+ }
+ case FakeDataCommand::StopJson: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
+ if (v.stringValue.empty()) {
+ LOG(ERROR) << __func__ << ": path to JSON file is missing";
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = std::hash<std::string>()(v.stringValue);
+ getGenerator()->unregisterGenerator(cookie);
+ break;
+ }
+ case FakeDataCommand::KeyPress: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
+ int32_t keyCode = request.value.int32Values[2];
+ int32_t display = request.value.int32Values[3];
+ // Send back to HAL
+ onPropertyValueFromCar(
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+ updateStatus);
+ onPropertyValueFromCar(
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+ updateStatus);
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
+ return StatusCode::INVALID_ARG;
+ }
+ }
+ return StatusCode::OK;
+}
+
+VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createApPowerStateReq(
+ VehicleApPowerStateReq state, int32_t param) {
+ auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
+ req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+ req->areaId = 0;
+ req->timestamp = elapsedRealtimeNano();
+ req->status = VehiclePropertyStatus::AVAILABLE;
+ req->value.int32Values[0] = toInt(state);
+ req->value.int32Values[1] = param;
+ return req;
+}
+
+VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createHwInputKeyProp(
+ VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
+ auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
+ keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
+ keyEvent->areaId = 0;
+ keyEvent->timestamp = elapsedRealtimeNano();
+ keyEvent->status = VehiclePropertyStatus::AVAILABLE;
+ keyEvent->value.int32Values[0] = toInt(action);
+ keyEvent->value.int32Values[1] = keyCode;
+ keyEvent->value.int32Values[2] = targetDisplay;
+ return keyEvent;
+}
+
+StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
+ // Some properties need to be treated non-trivially
+ switch (value.prop) {
+ case kGenerateFakeDataControllingProperty:
+ return handleGenerateFakeDataRequest(value);
+
+ // set the value from vehicle side, used in end to end test.
+ case kSetIntPropertyFromVehicleForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+ updatedPropValue->prop = value.value.int32Values[0];
+ updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+ case kSetFloatPropertyFromVehicleForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+ updatedPropValue->prop = value.value.int32Values[0];
+ updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+ case kSetBooleanPropertyFromVehicleForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+ updatedPropValue->prop = value.value.int32Values[1];
+ updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+
+ case AP_POWER_STATE_REPORT:
+ switch (value.value.int32Values[0]) {
+ case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+ case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+ // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+ // Send back to HAL
+ // ALWAYS update status for generated property value
+ onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
+ true /* updateStatus */);
+ break;
+ case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
+ // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
+ // Send back to HAL
+ // ALWAYS update status for generated property value
+ onPropertyValueFromCar(
+ *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
+ true /* updateStatus */);
+ break;
+ case toInt(VehicleApPowerStateReport::ON):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
+ // Do nothing
+ break;
+ default:
+ // Unknown state
+ break;
+ }
+ break;
+ case INITIAL_USER_INFO:
+ return onSetInitialUserInfo(value, updateStatus);
+ default:
+ break;
+ }
+
+ // In the real vhal, the value will be sent to Car ECU.
+ // We just pretend it is done here and send back to HAL
+ auto updatedPropValue = getValuePool()->obtain(value);
+ updatedPropValue->timestamp = elapsedRealtimeNano();
+
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+}
+
+/**
+ * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
+ * indicating what the initial user should be.
+ *
+ * During normal circumstances, the emulator will reply right away, passing a response if
+ * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
+ * to boot).
+ *
+ * But during development / testing, the behavior can be changed using lshal dump, which must use
+ * the areaId to indicate what should happen next.
+ *
+ * So, the behavior of set(INITIAL_USER_INFO) is:
+ *
+ * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
+ * lshal).
+ * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
+ * InitialUserInfoResponseAction::DEFAULT
+ * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
+ * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
+ * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
+ * this error scenario)
+ * - if it's 3, then don't send a property change (so Android can emulate a timeout)
+ *
+ */
+StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value,
+ bool updateStatus) {
+ // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
+ // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
+ // LOG, it's not worth investigating why...
+
+ if (value.value.int32Values.size() == 0) {
+ LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
+ return StatusCode::INVALID_ARG;
+ }
+
+ if (value.areaId != 0) {
+ LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
+ mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
+ return StatusCode::OK;
+ }
+ LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
+
+ int32_t requestId = value.value.int32Values[0];
+
+ // Create the update property and set common values
+ auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
+ updatedValue->prop = INITIAL_USER_INFO;
+ updatedValue->timestamp = elapsedRealtimeNano();
+
+ if (mInitialUserResponseFromCmd == nullptr) {
+ updatedValue->value.int32Values.resize(2);
+ updatedValue->value.int32Values[0] = requestId;
+ updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
+ LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
+ << toString(*updatedValue);
+ onPropertyValueFromCar(*updatedValue, updateStatus);
+ return StatusCode::OK;
+ }
+
+ // mInitialUserResponseFromCmd is used for just one request
+ std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
+
+ // TODO(b/150409377): rather than populate the raw values directly, it should use the
+ // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
+
+ switch (response->areaId) {
+ case 1:
+ LOG(INFO) << "returning response with right request id";
+ *updatedValue = *response;
+ updatedValue->areaId = 0;
+ updatedValue->value.int32Values[0] = requestId;
+ break;
+ case 2:
+ LOG(INFO) << "returning response with wrong request id";
+ *updatedValue = *response;
+ updatedValue->areaId = 0;
+ updatedValue->value.int32Values[0] = -requestId;
+ break;
+ case 3:
+ LOG(INFO) << "not generating a property change event because of lshal prop: "
+ << toString(*response);
+ return StatusCode::OK;
+ default:
+ LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
+ return StatusCode::INTERNAL_ERROR;
+ }
+
+ LOG(INFO) << "updating property to: " << toString(*updatedValue);
+ onPropertyValueFromCar(*updatedValue, updateStatus);
+ return StatusCode::OK;
+}
+
+} // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
new file mode 100644
index 0000000..4d7dbea
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
@@ -0,0 +1,71 @@
+/*
+ * 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 <vhal_v2_0/VehicleObjectPool.h>
+#include <vhal_v2_0/VehicleServer.h>
+
+#include "GeneratorHub.h"
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+// This contains the common server operations that will be used by
+// both native and virtualized VHAL server. Notice that in the virtualized
+// scenario, the server may be run on a different OS than Android.
+class VehicleHalServer : public IVehicleServer {
+ public:
+ // Methods from IVehicleServer
+
+ std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
+
+ StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
+
+ // Set the Property Value Pool used in this server
+ void setValuePool(VehiclePropValuePool* valuePool);
+
+ private:
+ using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
+
+ GeneratorHub* getGenerator();
+
+ VehiclePropValuePool* getValuePool() const;
+
+ void onFakeValueGenerated(const VehiclePropValue& value);
+
+ StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+
+ VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
+
+ VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
+ int32_t targetDisplay);
+
+ StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
+
+ // data members
+
+ protected:
+ // TODO(b/150413515): it might be clearer to move members below to an EmulatedUserHal class
+ std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
+
+ private:
+ GeneratorHub mGeneratorHub{
+ std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)};
+
+ VehiclePropValuePool* mValuePool{nullptr};
+};
+
+} // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index f518a15..677b496 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include <array>
+#include <regex>
#include <linux/videodev2.h>
#include "android-base/macros.h"
#include "CameraMetadata.h"
@@ -46,10 +47,20 @@
} // anonymous namespace
+const std::regex kDevicePathRE("/dev/video([0-9]+)");
+
ExternalCameraDevice::ExternalCameraDevice(
- const std::string& cameraId, const ExternalCameraConfig& cfg) :
- mCameraId(cameraId),
- mCfg(cfg) {}
+ const std::string& devicePath, const ExternalCameraConfig& cfg) :
+ mCameraId("-1"),
+ mDevicePath(devicePath),
+ mCfg(cfg) {
+ std::smatch sm;
+ if (std::regex_match(mDevicePath, sm, kDevicePathRE)) {
+ mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1]));
+ } else {
+ ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str());
+ }
+}
ExternalCameraDevice::~ExternalCameraDevice() {}
@@ -129,20 +140,20 @@
return Void();
}
- unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+ unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
if (fd.get() < 0) {
int numAttempt = 0;
do {
ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
- __FUNCTION__, mCameraId.c_str());
+ __FUNCTION__, mDevicePath.c_str());
usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
- fd.reset(::open(mCameraId.c_str(), O_RDWR));
+ fd.reset(::open(mDevicePath.c_str(), O_RDWR));
numAttempt++;
} while (fd.get() < 0 && numAttempt <= MAX_RETRY);
if (fd.get() < 0) {
ALOGE("%s: v4l2 device open %s failed: %s",
- __FUNCTION__, mCameraId.c_str(), strerror(errno));
+ __FUNCTION__, mDevicePath.c_str(), strerror(errno));
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
@@ -203,9 +214,9 @@
status_t ExternalCameraDevice::initCameraCharacteristics() {
if (mCameraCharacteristics.isEmpty()) {
// init camera characteristics
- unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+ unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
if (fd.get() < 0) {
- ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
+ ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
return DEAD_OBJECT;
}
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index 62a4c87..8f4626c 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -703,6 +703,7 @@
namespace common {
namespace {
+ const int kDefaultCameraIdOffset = 100;
const int kDefaultJpegBufSize = 5 << 20; // 5MB
const int kDefaultNumVideoBuffer = 4;
const int kDefaultNumStillBuffer = 2;
@@ -738,6 +739,11 @@
return ret;
}
+ XMLElement *cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset");
+ if (cameraIdOffset != nullptr) {
+ ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText());
+ }
+
XMLElement *ignore = providerCfg->FirstChildElement("ignore");
if (ignore == nullptr) {
ALOGI("%s: no internal ignored device specified", __FUNCTION__);
@@ -874,6 +880,7 @@
}
ExternalCameraConfig::ExternalCameraConfig() :
+ cameraIdOffset(kDefaultCameraIdOffset),
maxJpegBufSize(kDefaultJpegBufSize),
numVideoBuffers(kDefaultNumVideoBuffer),
numStillBuffers(kDefaultNumStillBuffer),
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index 1958fcb..88726f4 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -149,6 +149,7 @@
bool mInitialized = false;
bool mInitFailed = false;
std::string mCameraId;
+ std::string mDevicePath;
const ExternalCameraConfig& mCfg;
std::vector<SupportedV4L2Format> mSupportedFormats;
CroppingType mCroppingType;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 74f75eb..b354406 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -68,6 +68,9 @@
static const char* kDefaultCfgPath;
static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+ // CameraId base offset for numerical representation
+ uint32_t cameraIdOffset;
+
// List of internal V4L2 video nodes external camera HAL must ignore.
std::unordered_set<std::string> mInternalDevices;
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 2bfced2..64a51f6 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -44,17 +44,19 @@
const char* kDevicePath = "/dev/";
constexpr char kPrefix[] = "video";
constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
-bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
- std::string* cameraId) {
+bool matchDeviceName(int cameraIdOffset,
+ const hidl_string& deviceName, std::string* deviceVersion,
+ std::string* cameraDevicePath) {
std::string deviceNameStd(deviceName.c_str());
std::smatch sm;
if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
if (deviceVersion != nullptr) {
*deviceVersion = sm[1];
}
- if (cameraId != nullptr) {
- *cameraId = sm[2];
+ if (cameraDevicePath != nullptr) {
+ *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
}
return true;
}
@@ -146,8 +148,9 @@
const hidl_string& cameraDeviceName,
ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) {
- std::string cameraId, deviceVersion;
- bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
+ std::string cameraDevicePath, deviceVersion;
+ bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName,
+ &deviceVersion, &cameraDevicePath);
if (!match) {
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
@@ -164,19 +167,19 @@
case 4: {
ALOGV("Constructing v3.4 external camera device");
deviceImpl = new device::V3_4::implementation::ExternalCameraDevice(
- cameraId, mCfg);
+ cameraDevicePath, mCfg);
break;
}
case 5: {
ALOGV("Constructing v3.5 external camera device");
deviceImpl = new device::V3_5::implementation::ExternalCameraDevice(
- cameraId, mCfg);
+ cameraDevicePath, mCfg);
break;
}
case 6: {
ALOGV("Constructing v3.6 external camera device");
deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
- cameraId, mCfg);
+ cameraDevicePath, mCfg);
break;
}
default:
@@ -186,7 +189,7 @@
}
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
- ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
@@ -210,12 +213,14 @@
ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
Mutex::Autolock _l(mLock);
std::string deviceName;
+ std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+ std::atoi(devName + kDevicePrefixLen));
if (mPreferredHal3MinorVersion == 6) {
- deviceName = std::string("device@3.6/external/") + devName;
+ deviceName = std::string("device@3.6/external/") + cameraId;
} else if (mPreferredHal3MinorVersion == 5) {
- deviceName = std::string("device@3.5/external/") + devName;
+ deviceName = std::string("device@3.5/external/") + cameraId;
} else {
- deviceName = std::string("device@3.4/external/") + devName;
+ deviceName = std::string("device@3.4/external/") + cameraId;
}
mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
if (mCallbacks != nullptr) {
@@ -259,12 +264,14 @@
void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
Mutex::Autolock _l(mLock);
std::string deviceName;
+ std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+ std::atoi(devName + kDevicePrefixLen));
if (mPreferredHal3MinorVersion == 6) {
- deviceName = std::string("device@3.6/external/") + devName;
+ deviceName = std::string("device@3.6/external/") + cameraId;
} else if (mPreferredHal3MinorVersion == 5) {
- deviceName = std::string("device@3.5/external/") + devName;
+ deviceName = std::string("device@3.5/external/") + cameraId;
} else {
- deviceName = std::string("device@3.4/external/") + devName;
+ deviceName = std::string("device@3.4/external/") + cameraId;
}
if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
mCameraStatusMap.erase(deviceName);
diff --git a/drm/1.3/vts/functional/AndroidTest.xml b/drm/1.3/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..338430f
--- /dev/null
+++ b/drm/1.3/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalDrmV1_3TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="VtsHalDrmV1_3TargetTest" value="/data/local/tmp/VtsHalDrmV1_3TargetTest" />
+ <option name="push-file" key="libvtswidevine64.so" value="/data/local/tmp/64/lib/libvtswidevine.so" />
+ <option name="push-file" key="libvtswidevine32.so" value="/data/local/tmp/32/lib/libvtswidevine.so" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalDrmV1_3TargetTest" />
+ </test>
+</configuration>
diff --git a/graphics/allocator/2.0/default/OWNERS b/graphics/allocator/2.0/default/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/allocator/2.0/default/OWNERS
+++ b/graphics/allocator/2.0/default/OWNERS
@@ -1,4 +1,4 @@
# Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/allocator/2.0/utils/OWNERS
+++ b/graphics/allocator/2.0/utils/OWNERS
@@ -1,4 +1,4 @@
# Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index c78c358..3becace 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -69,9 +69,8 @@
[](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
return &settings;
});
- mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
- mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
- &readyFence);
+ mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers, mGraphicBuffer, true,
+ std::move(bufferFence), &readyFence);
int fd = readyFence.release();
if (fd != -1) {
ASSERT_EQ(0, sync_wait(fd, -1));
diff --git a/graphics/mapper/2.0/default/OWNERS b/graphics/mapper/2.0/default/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.0/default/OWNERS
+++ b/graphics/mapper/2.0/default/OWNERS
@@ -1,4 +1,4 @@
# Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.0/utils/OWNERS b/graphics/mapper/2.0/utils/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.0/utils/OWNERS
+++ b/graphics/mapper/2.0/utils/OWNERS
@@ -1,4 +1,4 @@
# Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
index 8e86f64..11b7d21 100644
--- a/graphics/mapper/2.0/vts/OWNERS
+++ b/graphics/mapper/2.0/vts/OWNERS
@@ -1,5 +1,7 @@
# Graphics team
-marissaw@google.com
+chrisforbes@google.com
+stoza@google.com
+vhau@google.com
# VTS team
yim@google.com
diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.1/default/OWNERS
+++ b/graphics/mapper/2.1/default/OWNERS
@@ -1,4 +1,4 @@
# Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.1/utils/OWNERS
+++ b/graphics/mapper/2.1/utils/OWNERS
@@ -1,4 +1,4 @@
# Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
index 8e86f64..11b7d21 100644
--- a/graphics/mapper/2.1/vts/OWNERS
+++ b/graphics/mapper/2.1/vts/OWNERS
@@ -1,5 +1,7 @@
# Graphics team
-marissaw@google.com
+chrisforbes@google.com
+stoza@google.com
+vhau@google.com
# VTS team
yim@google.com
diff --git a/graphics/mapper/3.0/utils/OWNERS b/graphics/mapper/3.0/utils/OWNERS
index 96f6d51..2a56b38 100644
--- a/graphics/mapper/3.0/utils/OWNERS
+++ b/graphics/mapper/3.0/utils/OWNERS
@@ -1,3 +1,4 @@
# Graphics team
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS
index 96f6d51..2a56b38 100644
--- a/graphics/mapper/3.0/vts/OWNERS
+++ b/graphics/mapper/3.0/vts/OWNERS
@@ -1,3 +1,4 @@
# Graphics team
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS
index 96f6d51..2a56b38 100644
--- a/graphics/mapper/4.0/utils/OWNERS
+++ b/graphics/mapper/4.0/utils/OWNERS
@@ -1,3 +1,4 @@
# Graphics team
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
index 96f6d51..2a56b38 100644
--- a/graphics/mapper/4.0/vts/OWNERS
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -1,3 +1,4 @@
# Graphics team
-marissaw@google.com
+chrisforbes@google.com
stoza@google.com
+vhau@google.com
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
index 2317bac..64a51b0 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
@@ -2,6 +2,8 @@
interface android.hardware.wifi@1.0::IWifi default
interface android.hardware.wifi@1.1::IWifi default
interface android.hardware.wifi@1.2::IWifi default
+ interface android.hardware.wifi@1.3::IWifi default
+ interface android.hardware.wifi@1.4::IWifi default
class hal
capabilities NET_ADMIN NET_RAW SYS_MODULE
user wifi