Test CAN bus HAL
Bug: 135918744
Test: VTS
Change-Id: I7b45a24b6a1142cf74c1d215658792835553d169
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..b4d9132
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+ name: "android.hardware.automotive.can@vts-defaults",
+ defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ "android.hardware.automotive.can@vts-utils-lib",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libgmock",
+ ],
+ test_suites: ["general-tests"],
+}
+
+cc_test {
+ name: "VtsHalCanControllerV1_0TargetTest",
+ defaults: ["android.hardware.automotive.can@vts-defaults"],
+ srcs: ["VtsHalCanControllerV1_0TargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalCanBusV1_0TargetTest",
+ defaults: ["android.hardware.automotive.can@vts-defaults"],
+ srcs: ["VtsHalCanBusV1_0TargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalCanBusVirtualV1_0TargetTest",
+ defaults: ["android.hardware.automotive.can@vts-defaults"],
+ srcs: ["VtsHalCanBusVirtualV1_0TargetTest.cpp"],
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
new file mode 100644
index 0000000..215328e
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using hardware::hidl_vec;
+
+static utils::SimpleHidlEnvironment<ICanBus>* gEnv = nullptr;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+ virtual Return<void> onReceive(const can::V1_0::CanMessage&) { return {}; }
+ virtual Return<void> onError(can::V1_0::ErrorEvent) { return {}; }
+};
+
+class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ std::tuple<Result, sp<ICloseHandle>> listen(const hidl_vec<CanMessageFilter>& filter,
+ const sp<ICanMessageListener>& listener);
+
+ sp<ICanBus> mCanBus;
+};
+
+void CanBusHalTest::SetUp() {
+ const auto serviceName = gEnv->getServiceName<ICanBus>();
+ mCanBus = getService<ICanBus>(serviceName);
+ ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << serviceName;
+}
+
+void CanBusHalTest::TearDown() {
+ mCanBus.clear();
+}
+
+std::tuple<Result, sp<ICloseHandle>> CanBusHalTest::listen(
+ const hidl_vec<CanMessageFilter>& filter, const sp<ICanMessageListener>& listener) {
+ Result halResult;
+ sp<ICloseHandle> closeHandle;
+ mCanBus->listen(filter, listener, hidl_utils::fill(&halResult, &closeHandle)).assertOk();
+
+ return {halResult, closeHandle};
+}
+
+TEST_F(CanBusHalTest, SendNoPayload) {
+ CanMessage msg = {};
+ msg.id = 0x123;
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, Send8B) {
+ CanMessage msg = {};
+ msg.id = 0x234;
+ msg.payload = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, SendZeroId) {
+ CanMessage msg = {};
+ msg.payload = {1, 2, 3};
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, SendTooLong) {
+ CanMessage msg = {};
+ msg.id = 0x123;
+ msg.payload = hidl_vec<uint8_t>(102400); // 100kiB
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::PAYLOAD_TOO_LONG, result);
+}
+
+TEST_F(CanBusHalTest, ListenNoFilter) {
+ const auto [result, closeHandle] = listen({}, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenSomeFilter) {
+ hidl_vec<CanMessageFilter> filters = {
+ {0x123, 0x1FF, false},
+ {0x001, 0x00F, true},
+ {0x200, 0x100, false},
+ };
+
+ const auto [result, closeHandle] = listen(filters, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenNull) {
+ const auto [result, closeHandle] = listen({}, nullptr);
+ ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+TEST_F(CanBusHalTest, DoubleCloseListen) {
+ const auto [result, closeHandle] = listen({}, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+
+ closeHandle->close().assertOk();
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseListen) {
+ const auto [result, closeHandle] = listen({}, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+}
+
+} // namespace vts
+} // namespace V1_0
+} // namespace can
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test
+ */
+int main(int argc, char** argv) {
+ using android::hardware::automotive::can::V1_0::ICanBus;
+ using android::hardware::automotive::can::V1_0::vts::gEnv;
+ using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ android::base::SetDefaultTag("CanBusVts");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ gEnv = new SimpleHidlEnvironment<ICanBus>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
new file mode 100644
index 0000000..699c138
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using namespace std::chrono_literals;
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+ DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+ CanMessageListener() {}
+
+ virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) {
+ std::unique_lock<std::mutex> lk(mMessagesGuard);
+ mMessages.push_back(msg);
+ mMessagesUpdated.notify_one();
+ return {};
+ }
+
+ virtual Return<void> onError(can::V1_0::ErrorEvent event) {
+ EXPECT_TRUE(false) << "Got error: " << event;
+ return {};
+ }
+
+ virtual ~CanMessageListener() { mCloseHandle->close(); }
+
+ void assignCloseHandle(sp<ICloseHandle> closeHandle) {
+ EXPECT_TRUE(closeHandle);
+ EXPECT_FALSE(mCloseHandle);
+ mCloseHandle = closeHandle;
+ }
+
+ std::vector<can::V1_0::CanMessage> fetchMessages(std::chrono::milliseconds timeout,
+ unsigned atLeast = 1) {
+ std::unique_lock<std::mutex> lk(mMessagesGuard);
+ mMessagesUpdated.wait_for(lk, timeout, [&] { return mMessages.size() >= atLeast; });
+ const auto messages = mMessages;
+ mMessages.clear();
+ return messages;
+ }
+
+ private:
+ sp<ICloseHandle> mCloseHandle;
+
+ std::mutex mMessagesGuard;
+ std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+ std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+ DISALLOW_COPY_AND_ASSIGN(Bus);
+
+ Bus(sp<ICanController> controller, const ICanController::BusConfiguration& config)
+ : mIfname(config.name), mController(controller) {
+ const auto result = controller->upInterface(config);
+ EXPECT_EQ(ICanController::Result::OK, result);
+
+ /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
+ * file -- this is a test, so we don't want to add dummy services to a device manifest.
+ */
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ auto service = manager->get(ICanBus::descriptor, config.name);
+ mBus = ICanBus::castFrom(service);
+ EXPECT_TRUE(mBus) << "ICanBus/" << config.name << " failed to register";
+ }
+
+ virtual ~Bus() { reset(); }
+
+ void reset() {
+ mBus.clear();
+ if (mController) {
+ const auto res = mController->downInterface(mIfname);
+ EXPECT_TRUE(res);
+ mController.clear();
+ }
+ }
+
+ ICanBus* operator->() const { return mBus.get(); }
+ sp<ICanBus> get() { return mBus; }
+
+ sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+ sp<CanMessageListener> listener = new CanMessageListener();
+
+ Result result;
+ sp<ICloseHandle> closeHandle;
+ mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+ EXPECT_EQ(Result::OK, result);
+ listener->assignCloseHandle(closeHandle);
+
+ return listener;
+ }
+
+ void send(const CanMessage& msg) {
+ const auto result = mBus->send(msg);
+ EXPECT_EQ(Result::OK, result);
+ }
+
+ private:
+ const std::string mIfname;
+ sp<ICanController> mController;
+ sp<ICanBus> mBus;
+};
+
+class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ Bus makeBus();
+
+ private:
+ unsigned mLastIface = 0;
+ static sp<ICanController> mCanController;
+ static bool mVirtualSupported;
+};
+
+sp<ICanController> CanBusVirtualHalTest::mCanController = nullptr;
+bool CanBusVirtualHalTest::mVirtualSupported;
+
+static CanMessage makeMessage(CanMessageId id) {
+ CanMessage msg = {};
+ msg.id = id;
+ return msg;
+}
+
+static void clearTimestamps(std::vector<CanMessage>& messages) {
+ std::for_each(messages.begin(), messages.end(), [](auto& msg) { msg.timestamp = 0; });
+}
+
+void CanBusVirtualHalTest::SetUp() {
+ if (!mVirtualSupported) GTEST_SKIP();
+}
+
+void CanBusVirtualHalTest::SetUpTestCase() {
+ const auto serviceName = gEnv->getServiceName<ICanController>();
+ mCanController = getService<ICanController>(serviceName);
+ ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+
+ hidl_vec<InterfaceType> supported;
+ mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
+ mVirtualSupported = supported.contains(InterfaceType::VIRTUAL);
+}
+
+void CanBusVirtualHalTest::TearDownTestCase() {
+ mCanController.clear();
+}
+
+Bus CanBusVirtualHalTest::makeBus() {
+ const auto idx = ++mLastIface;
+
+ ICanController::BusConfiguration config = {};
+ config.name = "test" + std::to_string(idx);
+ config.iftype = InterfaceType::VIRTUAL;
+ config.interfaceId.address("vcan50");
+
+ return Bus(mCanController, config);
+}
+
+TEST_F(CanBusVirtualHalTest, Send) {
+ auto bus = makeBus();
+
+ CanMessage msg = {};
+ msg.id = 0x123;
+ msg.payload = {1, 2, 3};
+
+ bus.send(msg);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAfterClose) {
+ auto bus = makeBus();
+ auto zombie = bus.get();
+ bus.reset();
+
+ const auto result = zombie->send({});
+ ASSERT_EQ(Result::INTERFACE_DOWN, result);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ auto listener = bus2.listen({});
+
+ CanMessage msg = {};
+ msg.id = 0x123;
+ msg.payload = {1, 2, 3};
+ bus1.send(msg);
+
+ auto messages = listener->fetchMessages(100ms);
+ ASSERT_EQ(1u, messages.size());
+ ASSERT_NEAR(uint64_t(elapsedRealtimeNano()), messages[0].timestamp,
+ std::chrono::nanoseconds(100ms).count());
+ clearTimestamps(messages);
+ ASSERT_EQ(msg, messages[0]);
+}
+
+TEST_F(CanBusVirtualHalTest, DownOneOfTwo) {
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ bus2.reset();
+
+ bus1.send({});
+}
+
+TEST_F(CanBusVirtualHalTest, Filter) {
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ hidl_vec<CanMessageFilter> filterPositive = {
+ {0x101, 0x100, false},
+ {0x010, 0x0F0, false},
+ };
+ auto listenerPositive = bus2.listen(filterPositive);
+
+ hidl_vec<CanMessageFilter> filterNegative = {
+ {0x123, 0x0FF, true},
+ {0x004, 0x00F, true},
+ };
+ auto listenerNegative = bus2.listen(filterNegative);
+
+ bus1.send(makeMessage(0));
+ bus1.send(makeMessage(0x1A0));
+ bus1.send(makeMessage(0x1A1));
+ bus1.send(makeMessage(0x2A0));
+ bus1.send(makeMessage(0x3A0));
+ bus1.send(makeMessage(0x010));
+ bus1.send(makeMessage(0x123));
+ bus1.send(makeMessage(0x023));
+ bus1.send(makeMessage(0x124));
+
+ std::vector<can::V1_0::CanMessage> expectedPositive{
+ makeMessage(0x1A0), //
+ makeMessage(0x1A1), //
+ makeMessage(0x3A0), //
+ makeMessage(0x010), //
+ makeMessage(0x123), //
+ makeMessage(0x124), //
+ };
+ std::vector<can::V1_0::CanMessage> expectedNegative{
+ makeMessage(0), //
+ makeMessage(0x1A0), //
+ makeMessage(0x1A1), //
+ makeMessage(0x2A0), //
+ makeMessage(0x3A0), //
+ makeMessage(0x010), //
+ };
+
+ auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
+ auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
+ clearTimestamps(messagesNegative);
+ clearTimestamps(messagesPositive);
+ ASSERT_EQ(expectedNegative, messagesNegative);
+ ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+} // namespace vts
+} // namespace V1_0
+} // namespace can
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest\
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+ using android::hardware::automotive::can::V1_0::ICanController;
+ using android::hardware::automotive::can::V1_0::vts::gEnv;
+ using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ android::base::SetDefaultTag("CanBusVirtualVts");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ gEnv = new SimpleHidlEnvironment<ICanController>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
new file mode 100644
index 0000000..70f9fe4
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ hidl_vec<InterfaceType> getSupportedInterfaceTypes();
+ bool isSupported(InterfaceType iftype);
+
+ bool up(InterfaceType iftype, const std::string srvname, std::string ifname,
+ ICanController::Result expected);
+ void assertRegistered(const std::string srvname, bool expectRegistered);
+
+ sp<ICanController> mCanController;
+};
+
+void CanControllerHalTest::SetUp() {
+ const auto serviceName = gEnv->getServiceName<ICanController>();
+ mCanController = getService<ICanController>(serviceName);
+ ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+}
+
+void CanControllerHalTest::TearDown() {
+ mCanController.clear();
+}
+
+hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
+ hidl_vec<InterfaceType> iftypesResult;
+ mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
+ return iftypesResult;
+}
+
+bool CanControllerHalTest::isSupported(InterfaceType iftype) {
+ const auto supported = getSupportedInterfaceTypes();
+ return std::find(supported.begin(), supported.end(), iftype) != supported.end();
+}
+
+bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname,
+ ICanController::Result expected) {
+ ICanController::BusConfiguration config = {};
+ config.name = srvname;
+ config.iftype = iftype;
+ config.interfaceId.address(ifname);
+
+ const auto upresult = mCanController->upInterface(config);
+
+ if (!isSupported(iftype)) {
+ LOG(INFO) << iftype << " interfaces not supported";
+ EXPECT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+ return false;
+ }
+
+ EXPECT_EQ(expected, upresult);
+ return true;
+}
+
+void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
+ /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
+ * file -- this is a test, so we don't want to add dummy services to a device manifest.
+ */
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ auto busService = manager->get(ICanBus::descriptor, srvname);
+ ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
+ << "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered"
+ << " (should be otherwise)";
+}
+
+TEST_F(CanControllerHalTest, SupportsSomething) {
+ const auto supported = getSupportedInterfaceTypes();
+ ASSERT_GT(supported.size(), 0u);
+}
+
+TEST_F(CanControllerHalTest, BringUpDown) {
+ const std::string name = "dummy";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
+ assertRegistered(name, true);
+
+ const auto dnresult = mCanController->downInterface(name);
+ ASSERT_TRUE(dnresult);
+
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, DownDummy) {
+ const auto result = mCanController->downInterface("imnotup");
+ ASSERT_FALSE(result);
+}
+
+TEST_F(CanControllerHalTest, UpTwice) {
+ const std::string name = "dummy";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
+ assertRegistered(name, true);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, true);
+
+ const auto result = mCanController->downInterface(name);
+ ASSERT_TRUE(result);
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, IdentifierCompatibility) {
+ using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+ static const std::map<InterfaceType, std::vector<IdDisc>> compatMatrix = {
+ {InterfaceType::VIRTUAL, {IdDisc::address}},
+ {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}},
+ {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}},
+ {InterfaceType::INDEXED, {IdDisc::index}},
+ };
+ static const std::vector<IdDisc> allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno};
+
+ for (const auto [iftype, supported] : compatMatrix) {
+ for (const auto iddisc : allDisc) {
+ LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc;
+
+ ICanController::BusConfiguration config = {};
+ config.name = "compattestsrv";
+ config.iftype = iftype;
+ config.baudrate = 125000;
+
+ // using random-ish addresses, which may not be valid - we can't test the success case
+ if (iddisc == IdDisc::address) {
+ config.interfaceId.address("can0");
+ } else if (iddisc == IdDisc::index) {
+ config.interfaceId.index(0);
+ } else if (iddisc == IdDisc::serialno) {
+ config.interfaceId.serialno({"dummy", "dummier"});
+ }
+
+ const auto upresult = mCanController->upInterface(config);
+
+ if (!isSupported(iftype)) {
+ ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+ continue;
+ }
+ ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
+
+ bool isSupportedDisc =
+ std::find(supported.begin(), supported.end(), iddisc) != supported.end();
+ if (!isSupportedDisc) {
+ ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult);
+ continue;
+ }
+
+ if (upresult == ICanController::Result::OK) {
+ const auto dnresult = mCanController->downInterface(config.name);
+ ASSERT_TRUE(dnresult);
+ continue;
+ }
+ }
+ }
+}
+
+TEST_F(CanControllerHalTest, FailEmptyName) {
+ const std::string name = "";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadName) {
+ // 33 characters (name can be at most 32 characters long)
+ const std::string name = "ab012345678901234567890123456789c";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
+ const std::string name = "dummy";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
+ const std::string name = "dummy";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, false);
+}
+
+} // namespace vts
+} // namespace V1_0
+} // namespace can
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest\
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+ using android::hardware::automotive::can::V1_0::ICanController;
+ using android::hardware::automotive::can::V1_0::vts::gEnv;
+ using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ android::base::SetDefaultTag("CanControllerVts");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ gEnv = new SimpleHidlEnvironment<ICanController>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}