353 lines
12 KiB
C++
353 lines
12 KiB
C++
/*
|
|
* 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 <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/bus-enumerator.h>
|
|
#include <can-vts-utils/can-hal-printers.h>
|
|
#include <gmock/gmock.h>
|
|
#include <hidl-utils/hidl-utils.h>
|
|
#include <hidl/GtestPrinter.h>
|
|
#include <hidl/ServiceManagement.h>
|
|
|
|
namespace android::hardware::automotive::can::V1_0::vts {
|
|
|
|
using hardware::hidl_vec;
|
|
using InterfaceType = ICanController::InterfaceType;
|
|
using IfId = ICanController::BusConfig::InterfaceId;
|
|
|
|
struct Bus {
|
|
DISALLOW_COPY_AND_ASSIGN(Bus);
|
|
|
|
Bus(sp<ICanController> controller, const ICanController::BusConfig& config)
|
|
: mIfname(config.name), mController(controller) {
|
|
// Don't bring up the bus, we just need a wrapper for the ICanBus object
|
|
/* 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 fake services to a device manifest. */
|
|
auto manager = hidl::manager::V1_2::IServiceManager::getService();
|
|
auto service = manager->get(ICanBus::descriptor, config.name);
|
|
mBus = ICanBus::castFrom(service);
|
|
}
|
|
|
|
ICanBus* operator->() const { return mBus.get(); }
|
|
sp<ICanBus> get() { return mBus; }
|
|
|
|
Return<Result> send(const CanMessage& msg) { return mBus->send(msg); }
|
|
|
|
private:
|
|
const std::string mIfname;
|
|
sp<ICanController> mController;
|
|
sp<ICanBus> mBus;
|
|
};
|
|
|
|
class CanControllerHalTest : public ::testing::TestWithParam<std::string> {
|
|
protected:
|
|
virtual void SetUp() override;
|
|
virtual void TearDown() override;
|
|
static void SetUpTestCase();
|
|
|
|
Bus makeBus(const std::string ifaceName);
|
|
|
|
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, const std::string ifaceName,
|
|
bool expectRegistered);
|
|
|
|
sp<ICanController> mCanController;
|
|
static hidl_vec<hidl_string> mBusNames;
|
|
|
|
private:
|
|
static bool mTestCaseInitialized;
|
|
};
|
|
|
|
hidl_vec<hidl_string> CanControllerHalTest::mBusNames;
|
|
bool CanControllerHalTest::mTestCaseInitialized = false;
|
|
|
|
void CanControllerHalTest::SetUp() {
|
|
ASSERT_TRUE(mTestCaseInitialized);
|
|
|
|
mCanController = ICanController::getService(GetParam());
|
|
ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << GetParam();
|
|
}
|
|
|
|
void CanControllerHalTest::TearDown() {
|
|
mCanController.clear();
|
|
}
|
|
|
|
void CanControllerHalTest::SetUpTestCase() {
|
|
mBusNames = utils::getBusNames();
|
|
ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
|
|
|
|
mTestCaseInitialized = true;
|
|
}
|
|
|
|
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::BusConfig config = {};
|
|
config.name = srvname;
|
|
|
|
// TODO(b/146214370): move interfaceId constructors to a library
|
|
if (iftype == InterfaceType::SOCKETCAN) {
|
|
IfId::Socketcan socketcan = {};
|
|
socketcan.ifname(ifname);
|
|
config.interfaceId.socketcan(socketcan);
|
|
} else if (iftype == InterfaceType::SLCAN) {
|
|
IfId::Slcan slcan = {};
|
|
slcan.ttyname(ifname);
|
|
config.interfaceId.slcan(slcan);
|
|
} else if (iftype == InterfaceType::VIRTUAL) {
|
|
config.interfaceId.virtualif({ifname});
|
|
} else {
|
|
EXPECT_TRUE(false) << "Unexpected iftype: " << toString(iftype);
|
|
}
|
|
|
|
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(const std::string srvname, const std::string ifaceName,
|
|
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 fake services to a device manifest. */
|
|
auto manager = hidl::manager::V1_2::IServiceManager::getService();
|
|
auto busService = manager->get(ICanBus::descriptor, srvname);
|
|
if (!expectRegistered) {
|
|
/* We can't unregister a HIDL interface defined in the manifest, so we'll just check to make
|
|
* sure that the interface behind it is down */
|
|
auto bus = makeBus(ifaceName);
|
|
const auto result = bus->send({});
|
|
ASSERT_EQ(Result::INTERFACE_DOWN, result);
|
|
return;
|
|
}
|
|
ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
|
|
<< "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered"
|
|
<< " (should be otherwise)";
|
|
}
|
|
|
|
Bus CanControllerHalTest::makeBus(const std::string ifaceName) {
|
|
ICanController::BusConfig config = {};
|
|
config.name = mBusNames[0];
|
|
config.interfaceId.virtualif({ifaceName});
|
|
|
|
return Bus(mCanController, config);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, SupportsSomething) {
|
|
const auto supported = getSupportedInterfaceTypes();
|
|
ASSERT_GT(supported.size(), 0u);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, BringUpDown) {
|
|
const std::string name = mBusNames[0];
|
|
const std::string iface = "vcan57";
|
|
mCanController->downInterface(name);
|
|
|
|
assertRegistered(name, iface, false);
|
|
|
|
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::OK)) GTEST_SKIP();
|
|
assertRegistered(name, iface, true);
|
|
|
|
const auto dnresult = mCanController->downInterface(name);
|
|
ASSERT_TRUE(dnresult);
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, DownFake) {
|
|
const auto result = mCanController->downInterface("imnotup");
|
|
ASSERT_FALSE(result);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, UpTwice) {
|
|
const std::string name = mBusNames[0];
|
|
const std::string iface = "vcan72";
|
|
|
|
assertRegistered(name, iface, false);
|
|
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::OK)) GTEST_SKIP();
|
|
assertRegistered(name, iface, true);
|
|
if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) {
|
|
GTEST_SKIP();
|
|
}
|
|
assertRegistered(name, iface, true);
|
|
|
|
const auto result = mCanController->downInterface(name);
|
|
ASSERT_TRUE(result);
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, ConfigCompatibility) {
|
|
// using random-ish addresses, which may not be valid - we can't test the success case
|
|
// TODO(b/146214370): move interfaceId constructors to a library
|
|
IfId virtualCfg = {};
|
|
virtualCfg.virtualif({"vcan70"});
|
|
|
|
IfId::Socketcan socketcanIfname = {};
|
|
socketcanIfname.ifname("can0");
|
|
IfId socketcanIfnameCfg = {};
|
|
socketcanIfnameCfg.socketcan(socketcanIfname);
|
|
|
|
IfId::Socketcan socketcanSerial = {};
|
|
socketcanSerial.serialno({"1234", "2345"});
|
|
IfId socketcanSerialCfg = {};
|
|
socketcanSerialCfg.socketcan(socketcanSerial);
|
|
|
|
IfId::Slcan slcanTtyname = {};
|
|
slcanTtyname.ttyname("/dev/ttyUSB0");
|
|
IfId slcanTtynameCfg = {};
|
|
slcanTtynameCfg.slcan(slcanTtyname);
|
|
|
|
IfId::Slcan slcanSerial = {};
|
|
slcanSerial.serialno({"dead", "beef"});
|
|
IfId slcanSerialCfg = {};
|
|
slcanSerialCfg.slcan(slcanSerial);
|
|
|
|
IfId indexedCfg = {};
|
|
indexedCfg.indexed({0});
|
|
|
|
static const std::vector<std::pair<InterfaceType, IfId>> compatMatrix = {
|
|
{InterfaceType::VIRTUAL, virtualCfg},
|
|
{InterfaceType::SOCKETCAN, socketcanIfnameCfg},
|
|
{InterfaceType::SOCKETCAN, socketcanSerialCfg},
|
|
{InterfaceType::SLCAN, slcanTtynameCfg},
|
|
{InterfaceType::SLCAN, slcanSerialCfg},
|
|
{InterfaceType::INDEXED, indexedCfg},
|
|
};
|
|
|
|
for (const auto [iftype, cfg] : compatMatrix) {
|
|
LOG(INFO) << "Compatibility testing: " << iftype << " / " << cfg;
|
|
|
|
ICanController::BusConfig config = {};
|
|
config.name = "compattestsrv";
|
|
config.bitrate = 125000;
|
|
config.interfaceId = cfg;
|
|
|
|
const auto upresult = mCanController->upInterface(config);
|
|
|
|
if (!isSupported(iftype)) {
|
|
ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
|
|
continue;
|
|
}
|
|
ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
|
|
|
|
if (upresult == ICanController::Result::OK) {
|
|
const auto dnresult = mCanController->downInterface(config.name);
|
|
ASSERT_TRUE(dnresult);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, FailEmptyName) {
|
|
const std::string name = "";
|
|
const std::string iface = "vcan57";
|
|
|
|
assertRegistered(name, iface, false);
|
|
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::BAD_SERVICE_NAME)) {
|
|
GTEST_SKIP();
|
|
}
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, FailBadName) {
|
|
// 33 characters (name can be at most 32 characters long)
|
|
const std::string name = "ab012345678901234567890123456789c";
|
|
const std::string iface = "vcan57";
|
|
|
|
assertRegistered(name, iface, false);
|
|
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::BAD_SERVICE_NAME)) {
|
|
GTEST_SKIP();
|
|
}
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, FailBadVirtualAddress) {
|
|
const std::string name = mBusNames[0];
|
|
const std::string iface = "";
|
|
|
|
assertRegistered(name, iface, false);
|
|
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::BAD_INTERFACE_ID)) {
|
|
GTEST_SKIP();
|
|
}
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, FailBadSocketcanAddress) {
|
|
const std::string name = mBusNames[0];
|
|
const std::string iface = "can87";
|
|
|
|
assertRegistered(name, iface, false);
|
|
if (!up(InterfaceType::SOCKETCAN, name, iface, ICanController::Result::BAD_INTERFACE_ID)) {
|
|
GTEST_SKIP();
|
|
}
|
|
assertRegistered(name, iface, false);
|
|
|
|
auto supported =
|
|
up(InterfaceType::SOCKETCAN, name, "", ICanController::Result::BAD_INTERFACE_ID);
|
|
ASSERT_TRUE(supported);
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
TEST_P(CanControllerHalTest, FailBadSlcanAddress) {
|
|
const std::string name = mBusNames[0];
|
|
const std::string iface = "/dev/shouldnotexist123";
|
|
|
|
assertRegistered(name, iface, false);
|
|
if (!up(InterfaceType::SLCAN, name, iface, ICanController::Result::BAD_INTERFACE_ID)) {
|
|
GTEST_SKIP();
|
|
}
|
|
assertRegistered(name, iface, false);
|
|
|
|
auto supported = up(InterfaceType::SLCAN, name, "", ICanController::Result::BAD_INTERFACE_ID);
|
|
ASSERT_TRUE(supported);
|
|
assertRegistered(name, iface, false);
|
|
}
|
|
|
|
/**
|
|
* Example manual invocation:
|
|
* adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest
|
|
*/
|
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerHalTest);
|
|
INSTANTIATE_TEST_SUITE_P(PerInstance, CanControllerHalTest,
|
|
testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
|
|
PrintInstanceNameToString);
|
|
|
|
} // namespace android::hardware::automotive::can::V1_0::vts
|