/* * Copyright (C) 2017 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. */ // This needs to be on top of the file to work. #include "gmock-logging-compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "constants-private.h" #include "parse_xml_internal.h" #include "test_constants.h" #include "utils-fake.h" using namespace ::testing; using namespace std::literals; using android::FqInstance; static AssertionResult In(const std::string& sub, const std::string& str) { return (str.find(sub) != std::string::npos ? AssertionSuccess() : AssertionFailure()) << "Value is " << str; } #define EXPECT_IN(sub, str) EXPECT_TRUE(In((sub), (str))) #define EXPECT_NOT_IN(sub, str) EXPECT_FALSE(In((sub), (str))) namespace android { namespace vintf { namespace testing { using namespace ::android::vintf::details; // clang-format off // // Set of Xml1 metadata compatible with each other. // const std::string systemMatrixXml1 = "\n" " \n" " android.hardware.camera\n" " 2.0-5\n" " 3.4-16\n" " \n" " \n" " android.hardware.nfc\n" " 1.0\n" " 2.0\n" " \n" " \n" " android.hardware.foo\n" " 1.0\n" " \n" " \n" " \n" " 30\n" " 25.5\n" " 26.0-3\n" " \n" " \n" " 0.0\n" " \n" "\n"; const std::string vendorManifestXml1 = "\n" " \n" " android.hardware.camera\n" " hwbinder\n" " 3.5\n" " \n" " IBetterCamera\n" " camera\n" " \n" " \n" " ICamera\n" " default\n" " legacy/0\n" " \n" " \n" " \n" " android.hardware.nfc\n" " hwbinder\n" " 1.0\n" " \n" " INfc\n" " nfc_nci\n" " \n" " \n" " \n" " android.hardware.nfc\n" " hwbinder\n" " 2.0\n" " \n" " INfc\n" " default\n" " nfc_nci\n" " \n" " \n" " \n" " 25.5\n" " \n" "\n"; const std::string systemManifestXml1 = "\n" " \n" " android.hidl.manager\n" " hwbinder\n" " 1.0\n" " \n" " IServiceManager\n" " default\n" " \n" " \n" " \n" " 25.0.5\n" " libbase.so\n" " libjpeg.so\n" " \n" "\n"; const std::string vendorMatrixXml1 = "\n" " \n" " android.hidl.manager\n" " 1.0\n" " \n" " \n" " 25.0.1-5\n" " libbase.so\n" " libjpeg.so\n" " \n" "\n"; // // Set of Xml2 metadata compatible with each other. // const std::string systemMatrixXml2 = "\n" " \n" " android.hardware.foo\n" " 1.0\n" " \n" " \n" " \n" " 30\n" " 25.5\n" " 26.0-3\n" " \n" " \n" " 0.0\n" " \n" "\n"; const std::string vendorManifestXml2 = "" " " " android.hardware.foo" " hwbinder" " 1.0" " " " \n" " 25.5\n" " \n" ""; // // Set of framework matrices of different FCM version. // const std::string systemMatrixLevel1 = "\n" " \n" " android.hardware.major\n" " 1.0\n" " \n" " IMajor\n" " default\n" " \n" " \n" " \n" " android.hardware.removed\n" " 1.0\n" " \n" " IRemoved\n" " default\n" " \n" " \n" " \n" " android.hardware.minor\n" " 1.0\n" " \n" " IMinor\n" " default\n" " legacy\n" " \n" " \n" "\n"; const std::string systemMatrixLevel2 = "\n" " \n" " android.hardware.major\n" " 2.0\n" " \n" " IMajor\n" " default\n" " \n" " \n" " \n" " android.hardware.minor\n" " 1.1\n" " \n" " IMinor\n" " default\n" " \n" " \n" "\n"; // // Smaller product FCMs at different levels to test that framework and product // FCMs are combined when checking deprecation. // const std::string productMatrixLevel1 = "\n" " \n" " product.removed\n" " 1.0\n" " \n" " IRemoved\n" " default\n" " \n" " \n" " \n" " product.minor\n" " 1.0\n" " \n" " IMinor\n" " default\n" " \n" " \n" "\n"; const std::string productMatrixLevel2 = "\n" " \n" " product.minor\n" " 1.1\n" " \n" " IMinor\n" " default\n" " \n" " \n" "\n"; // // Set of framework matrices of different FCM version with regex. // const static std::vector systemMatrixRegexXmls = { // 1.xml "\n" " \n" " android.hardware.regex\n" " 1.0-1\n" " \n" " IRegex\n" " default\n" " special/1.0\n" " regex/1.0/[0-9]+\n" " regex_common/[0-9]+\n" " \n" " \n" "\n", // 2.xml "\n" " \n" " android.hardware.regex\n" " 1.1-2\n" " \n" " IRegex\n" " default\n" " special/1.1\n" " regex/1.1/[0-9]+\n" " [a-z]+_[a-z]+/[0-9]+\n" " \n" " \n" "\n", // 3.xml "\n" " \n" " android.hardware.regex\n" " 2.0\n" " \n" " IRegex\n" " default\n" " special/2.0\n" " regex/2.0/[0-9]+\n" " regex_[a-z]+/[0-9]+\n" " \n" " \n" "\n"}; // // Set of metadata at different FCM version that has requirements // const std::vector systemMatrixRequire = { // 1.xml "\n" " \n" " android.hardware.foo\n" " 1.0\n" " \n" " IFoo\n" " default\n" " \n" " \n" "\n", // 2.xml "\n" " \n" " android.hardware.bar\n" " 1.0\n" " \n" " IBar\n" " default\n" " \n" " \n" "\n"}; const std::string vendorManifestRequire1 = "\n" " \n" " android.hardware.foo\n" " hwbinder\n" " @1.0::IFoo/default\n" " \n" "\n"; const std::string vendorManifestRequire2 = "\n" " \n" " android.hardware.bar\n" " hwbinder\n" " @1.0::IBar/default\n" " \n" "\n"; // // Set of metadata for kernel requirements // const std::string vendorManifestKernel318 = "\n" " \n" " \n" " 25.5\n" " \n" "\n"; const std::string systemMatrixKernel318 = "\n" " \n" " \n" " 30\n" " 25.5\n" " \n" "\n"; class VintfObjectTestBase : public ::testing::Test { protected: MockFileSystem& fetcher() { return static_cast(*vintfObject->getFileSystem()); } MockPropertyFetcher& propertyFetcher() { return static_cast(*vintfObject->getPropertyFetcher()); } void useEmptyFileSystem() { // By default, no files exist in the file system. // Use EXPECT_CALL because more specific expectation of fetch and listFiles will come along. EXPECT_CALL(fetcher(), listFiles(_, _, _)).Times(AnyNumber()) .WillRepeatedly(Return(::android::NAME_NOT_FOUND)); EXPECT_CALL(fetcher(), fetch(_, _)).Times(AnyNumber()) .WillRepeatedly(Return(::android::NAME_NOT_FOUND)); } // Setup the MockFileSystem used by the fetchAllInformation template // so it returns the given metadata info instead of fetching from device. void setupMockFetcher(const std::string& vendorManifestXml, const std::string& systemMatrixXml, const std::string& systemManifestXml, const std::string& vendorMatrixXml) { useEmptyFileSystem(); ON_CALL(fetcher(), fetch(StrEq(kVendorLegacyManifest), _)) .WillByDefault( Invoke([vendorManifestXml](const std::string& path, std::string& fetched) { (void)path; fetched = vendorManifestXml; return 0; })); ON_CALL(fetcher(), fetch(StrEq(kSystemManifest), _)) .WillByDefault( Invoke([systemManifestXml](const std::string& path, std::string& fetched) { (void)path; fetched = systemManifestXml; return 0; })); ON_CALL(fetcher(), fetch(StrEq(kVendorLegacyMatrix), _)) .WillByDefault(Invoke([vendorMatrixXml](const std::string& path, std::string& fetched) { (void)path; fetched = vendorMatrixXml; return 0; })); ON_CALL(fetcher(), fetch(StrEq(kSystemLegacyMatrix), _)) .WillByDefault(Invoke([systemMatrixXml](const std::string& path, std::string& fetched) { (void)path; fetched = systemMatrixXml; return 0; })); } virtual void SetUp() { vintfObject = VintfObject::Builder() .setFileSystem(std::make_unique>()) .setRuntimeInfoFactory(std::make_unique>( std::make_shared>())) .setPropertyFetcher(std::make_unique>()) .build(); } virtual void TearDown() { Mock::VerifyAndClear(&fetcher()); } void expectVendorManifest(size_t times = 1) { EXPECT_CALL(fetcher(), fetch(StrEq(kVendorLegacyManifest), _)).Times(times); } void expectSystemManifest(size_t times = 1) { EXPECT_CALL(fetcher(), fetch(StrEq(kSystemManifest), _)).Times(times); } void expectVendorMatrix(size_t times = 1) { EXPECT_CALL(fetcher(), fetch(StrEq(kVendorLegacyMatrix), _)).Times(times); } void expectSystemMatrix(size_t times = 1) { EXPECT_CALL(fetcher(), fetch(StrEq(kSystemLegacyMatrix), _)).Times(times); } // Expect that a file exist and should be fetched once. void expectFetch(const std::string& path, const std::string& content) { EXPECT_CALL(fetcher(), fetch(StrEq(path), _)) .WillOnce(Invoke([content](const auto&, auto& out) { out = content; return ::android::OK; })); } // Expect that a file exist and can be fetched 0 or more times. void expectFetchRepeatedly(const std::string& path, const std::string& content) { EXPECT_CALL(fetcher(), fetch(StrEq(path), _)) .Times(AnyNumber()) .WillRepeatedly(Invoke([content](const auto&, auto& out) { out = content; return ::android::OK; })); } // Expect that the file should never be fetched (whether it exists or not). void expectNeverFetch(const std::string& path) { EXPECT_CALL(fetcher(), fetch(StrEq(path), _)).Times(0); } // Expect that the file does not exist, and can be fetched 0 or more times. template void expectFileNotExist(const Matcher& matcher) { EXPECT_CALL(fetcher(), fetch(matcher, _)) .Times(AnyNumber()) .WillRepeatedly(Return(::android::NAME_NOT_FOUND)); } MockRuntimeInfoFactory& runtimeInfoFactory() { return static_cast(*vintfObject->getRuntimeInfoFactory()); } std::unique_ptr vintfObject; }; // Test fixture that provides compatible metadata from the mock device. class VintfObjectCompatibleTest : public VintfObjectTestBase { protected: virtual void SetUp() { VintfObjectTestBase::SetUp(); setupMockFetcher(vendorManifestXml1, systemMatrixXml1, systemManifestXml1, vendorMatrixXml1); } }; // Tests that local info is checked. TEST_F(VintfObjectCompatibleTest, TestDeviceCompatibility) { std::string error; expectVendorManifest(); expectSystemManifest(); expectVendorMatrix(); expectSystemMatrix(); int result = vintfObject->checkCompatibility(&error); ASSERT_EQ(result, 0) << "Fail message:" << error.c_str(); // Check that nothing was ignored. ASSERT_STREQ(error.c_str(), ""); } // Test fixture that provides incompatible metadata from the mock device. class VintfObjectIncompatibleTest : public VintfObjectTestBase { protected: virtual void SetUp() { VintfObjectTestBase::SetUp(); setupMockFetcher(vendorManifestXml1, systemMatrixXml2, systemManifestXml1, vendorMatrixXml1); } }; // Fetch all metadata from device and ensure that it fails. TEST_F(VintfObjectIncompatibleTest, TestDeviceCompatibility) { std::string error; expectVendorManifest(); expectSystemManifest(); expectVendorMatrix(); expectSystemMatrix(); int result = vintfObject->checkCompatibility(&error); ASSERT_EQ(result, 1) << "Should have failed:" << error.c_str(); } const std::string vendorManifestKernelFcm = "\n" " \n" "\n"; // Test fixture that provides compatible metadata from the mock device. class VintfObjectRuntimeInfoTest : public VintfObjectTestBase { protected: virtual void SetUp() { VintfObjectTestBase::SetUp(); } virtual void TearDown() { Mock::VerifyAndClear(&runtimeInfoFactory()); Mock::VerifyAndClear(runtimeInfoFactory().getInfo().get()); } }; TEST_F(VintfObjectRuntimeInfoTest, GetRuntimeInfo) { setupMockFetcher(vendorManifestKernelFcm, "", "", ""); expectVendorManifest(); InSequence s; EXPECT_CALL(*runtimeInfoFactory().getInfo(), fetchAllInformation(RuntimeInfo::FetchFlag::CPU_VERSION)); EXPECT_CALL(*runtimeInfoFactory().getInfo(), fetchAllInformation(RuntimeInfo::FetchFlag::NONE)); EXPECT_CALL( *runtimeInfoFactory().getInfo(), fetchAllInformation(RuntimeInfo::FetchFlag::ALL & ~RuntimeInfo::FetchFlag::CPU_VERSION)); EXPECT_CALL(*runtimeInfoFactory().getInfo(), fetchAllInformation(RuntimeInfo::FetchFlag::NONE)); EXPECT_NE(nullptr, vintfObject->getRuntimeInfo( RuntimeInfo::FetchFlag::CPU_VERSION)); EXPECT_NE(nullptr, vintfObject->getRuntimeInfo( RuntimeInfo::FetchFlag::CPU_VERSION)); EXPECT_NE(nullptr, vintfObject->getRuntimeInfo( RuntimeInfo::FetchFlag::ALL)); EXPECT_NE(nullptr, vintfObject->getRuntimeInfo( RuntimeInfo::FetchFlag::ALL)); } TEST_F(VintfObjectRuntimeInfoTest, GetRuntimeInfoHost) { runtimeInfoFactory().getInfo()->failNextFetch(); EXPECT_EQ(nullptr, vintfObject->getRuntimeInfo(RuntimeInfo::FetchFlag::ALL)); } class VintfObjectKernelFcmTest : public VintfObjectTestBase, public WithParamInterface> { protected: virtual void SetUp() { VintfObjectTestBase::SetUp(); auto [isHost, hasDeviceManifest] = GetParam(); if (hasDeviceManifest) { setupMockFetcher(vendorManifestKernelFcm, "", "", ""); expectVendorManifest(); } if (isHost) { runtimeInfoFactory().getInfo()->failNextFetch(); } else { runtimeInfoFactory().getInfo()->setNextFetchKernelLevel(Level{92}); } } Level expectedKernelFcm() { auto [isHost, hasDeviceManifest] = GetParam(); return !isHost || hasDeviceManifest ? Level{92} : Level::UNSPECIFIED; } }; TEST_P(VintfObjectKernelFcmTest, GetKernelLevel) { ASSERT_EQ(expectedKernelFcm(), vintfObject->getKernelLevel()); } INSTANTIATE_TEST_SUITE_P(KernelFcm, VintfObjectKernelFcmTest, ::testing::Combine(::testing::Bool(), ::testing::Bool())); // Test fixture that provides incompatible metadata from the mock device. class VintfObjectTest : public VintfObjectTestBase { protected: virtual void SetUp() { VintfObjectTestBase::SetUp(); useEmptyFileSystem(); } }; // Test framework compatibility matrix is combined at runtime TEST_F(VintfObjectTest, FrameworkCompatibilityMatrixCombine) { EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _)) .WillOnce(Invoke([](const auto&, auto* out, auto*) { *out = { "compatibility_matrix.1.xml", "compatibility_matrix.empty.xml", }; return ::android::OK; })); expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml"s, ""); expectFetch(kSystemVintfDir + "compatibility_matrix.empty.xml"s, ""); expectFileNotExist(StrEq(kProductMatrix)); expectFetch(kVendorManifest, "\n"); expectNeverFetch(kSystemLegacyMatrix); EXPECT_NE(nullptr, vintfObject->getFrameworkCompatibilityMatrix()); } // Test product compatibility matrix is fetched TEST_F(VintfObjectTest, ProductCompatibilityMatrix) { EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _)) .WillOnce(Invoke([](const auto&, auto* out, auto*) { *out = { "compatibility_matrix.1.xml", "compatibility_matrix.empty.xml", }; return ::android::OK; })); EXPECT_CALL(fetcher(), listFiles(StrEq(kProductVintfDir), _, _)) .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { *out = {android::base::Basename(kProductMatrix)}; return ::android::OK; })); expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml"s, ""); expectFetch(kSystemVintfDir + "compatibility_matrix.empty.xml"s, ""); expectFetch(kProductMatrix, "\n" " \n" " android.hardware.foo\n" " 1.0\n" " \n" " IFoo\n" " default\n" " \n" " \n" "\n"); expectFetch(kVendorManifest, "\n"); expectNeverFetch(kSystemLegacyMatrix); auto fcm = vintfObject->getFrameworkCompatibilityMatrix(); ASSERT_NE(nullptr, fcm); FqInstance expectInstance; EXPECT_TRUE(expectInstance.setTo("android.hardware.foo@1.0::IFoo/default")); bool found = false; fcm->forEachHidlInstance([&found, &expectInstance](const auto& matrixInstance) { found |= matrixInstance.isSatisfiedBy(expectInstance); return !found; // continue if not found }); EXPECT_TRUE(found) << "android.hardware.foo@1.0::IFoo/default should be found in matrix:\n" << toXml(*fcm); } const std::string vendorEtcManifest = "\n" " \n" " android.hardware.foo\n" " hwbinder\n" " 1.0\n" " 2.0\n" " \n" " IVendorEtc\n" " default\n" " \n" " \n" "\n"; const std::string vendorManifest = "\n" " \n" " android.hardware.foo\n" " hwbinder\n" " 1.0\n" " \n" " IVendor\n" " default\n" " \n" " \n" "\n"; const std::string odmProductManifest = "\n" " \n" " android.hardware.foo\n" " hwbinder\n" " 1.1\n" " \n" " IOdmProduct\n" " default\n" " \n" " \n" "\n"; const std::string odmManifest = "\n" " \n" " android.hardware.foo\n" " hwbinder\n" " 1.1\n" " \n" " IOdm\n" " default\n" " \n" " \n" "\n"; bool containsVendorManifest(const std::shared_ptr& p) { return !p->getHidlInstances("android.hardware.foo", {1, 0}, "IVendor").empty(); } bool containsVendorEtcManifest(const std::shared_ptr& p) { return !p->getHidlInstances("android.hardware.foo", {2, 0}, "IVendorEtc").empty(); } bool vendorEtcManifestOverridden(const std::shared_ptr& p) { return p->getHidlInstances("android.hardware.foo", {1, 0}, "IVendorEtc").empty(); } bool containsOdmManifest(const std::shared_ptr& p) { return !p->getHidlInstances("android.hardware.foo", {1, 1}, "IOdm").empty(); } bool containsOdmProductManifest(const std::shared_ptr& p) { return !p->getHidlInstances("android.hardware.foo", {1, 1}, "IOdmProduct").empty(); } class DeviceManifestTest : public VintfObjectTestBase { protected: // Expect that /vendor/etc/vintf/manifest.xml is fetched. void expectVendorManifest() { expectFetch(kVendorManifest, vendorEtcManifest); } // /vendor/etc/vintf/manifest.xml does not exist. void noVendorManifest() { expectFileNotExist(StrEq(kVendorManifest)); } // Expect some ODM manifest is fetched. void expectOdmManifest() { expectFetch(kOdmManifest, odmManifest); } void noOdmManifest() { expectFileNotExist(StartsWith("/odm/")); } std::shared_ptr get() { return vintfObject->getDeviceHalManifest(); } }; // Test /vendor/etc/vintf/manifest.xml + ODM manifest TEST_F(DeviceManifestTest, Combine1) { expectVendorManifest(); expectOdmManifest(); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_TRUE(containsVendorEtcManifest(p)); EXPECT_TRUE(vendorEtcManifestOverridden(p)); EXPECT_TRUE(containsOdmManifest(p)); EXPECT_FALSE(containsVendorManifest(p)); } // Test /vendor/etc/vintf/manifest.xml TEST_F(DeviceManifestTest, Combine2) { expectVendorManifest(); noOdmManifest(); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_TRUE(containsVendorEtcManifest(p)); EXPECT_FALSE(vendorEtcManifestOverridden(p)); EXPECT_FALSE(containsOdmManifest(p)); EXPECT_FALSE(containsVendorManifest(p)); } // Test ODM manifest TEST_F(DeviceManifestTest, Combine3) { noVendorManifest(); expectOdmManifest(); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_FALSE(containsVendorEtcManifest(p)); EXPECT_TRUE(vendorEtcManifestOverridden(p)); EXPECT_TRUE(containsOdmManifest(p)); EXPECT_FALSE(containsVendorManifest(p)); } // Test /vendor/manifest.xml TEST_F(DeviceManifestTest, Combine4) { noVendorManifest(); noOdmManifest(); expectFetch(kVendorLegacyManifest, vendorManifest); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_FALSE(containsVendorEtcManifest(p)); EXPECT_TRUE(vendorEtcManifestOverridden(p)); EXPECT_FALSE(containsOdmManifest(p)); EXPECT_TRUE(containsVendorManifest(p)); } class OdmManifestTest : public VintfObjectTestBase, public ::testing::WithParamInterface { protected: virtual void SetUp() override { VintfObjectTestBase::SetUp(); // Assume /vendor/etc/vintf/manifest.xml does not exist to simplify // testing logic. expectFileNotExist(StrEq(kVendorManifest)); // Expect that the legacy /vendor/manifest.xml is never fetched. expectNeverFetch(kVendorLegacyManifest); // Assume no files exist under /odm/ unless otherwise specified. expectFileNotExist(StartsWith("/odm/")); // set SKU productModel = GetParam(); ON_CALL(propertyFetcher(), getProperty("ro.boot.product.hardware.sku", _)) .WillByDefault(Return(productModel)); } std::shared_ptr get() { return vintfObject->getDeviceHalManifest(); } std::string productModel; }; TEST_P(OdmManifestTest, OdmProductManifest) { if (productModel.empty()) return; expectFetch(kOdmVintfDir + "manifest_"s + productModel + ".xml", odmProductManifest); // /odm/etc/vintf/manifest.xml should not be fetched when the product variant exists. expectNeverFetch(kOdmManifest); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_TRUE(containsOdmProductManifest(p)); } TEST_P(OdmManifestTest, OdmManifest) { expectFetch(kOdmManifest, odmManifest); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_TRUE(containsOdmManifest(p)); } TEST_P(OdmManifestTest, OdmLegacyProductManifest) { if (productModel.empty()) return; expectFetch(kOdmLegacyVintfDir + "manifest_"s + productModel + ".xml", odmProductManifest); // /odm/manifest.xml should not be fetched when the product variant exists. expectNeverFetch(kOdmLegacyManifest); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_TRUE(containsOdmProductManifest(p)); } TEST_P(OdmManifestTest, OdmLegacyManifest) { expectFetch(kOdmLegacyManifest, odmManifest); auto p = get(); ASSERT_NE(nullptr, p); EXPECT_TRUE(containsOdmManifest(p)); } INSTANTIATE_TEST_SUITE_P(OdmManifest, OdmManifestTest, ::testing::Values("", "fake_sku")); struct CheckedFqInstance : FqInstance { CheckedFqInstance(const char* s) : CheckedFqInstance(std::string(s)) {} CheckedFqInstance(const std::string& s) { CHECK(setTo(s)) << s; } Version getVersion() const { return FqInstance::getVersion(); } }; static VintfObject::ListInstances getInstanceListFunc( const std::vector& instances) { return [instances](const std::string& package, Version version, const std::string& interface, const auto& /* instanceHint */) { std::vector> ret; for (auto&& existing : instances) { if (existing.getPackage() == package && existing.getVersion().minorAtLeast(version) && existing.getInterface() == interface) { ret.push_back(std::make_pair(existing.getInstance(), existing.getVersion())); } } return ret; }; } class DeprecateTest : public VintfObjectTestBase { protected: virtual void SetUp() override { VintfObjectTestBase::SetUp(); useEmptyFileSystem(); EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _)) .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { *out = { "compatibility_matrix.1.xml", "compatibility_matrix.2.xml", }; return ::android::OK; })); expectFetchRepeatedly(kSystemVintfDir + "compatibility_matrix.1.xml"s, systemMatrixLevel1); expectFetchRepeatedly(kSystemVintfDir + "compatibility_matrix.2.xml"s, systemMatrixLevel2); EXPECT_CALL(fetcher(), listFiles(StrEq(kProductVintfDir), _, _)) .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { *out = { "compatibility_matrix.1.xml", "compatibility_matrix.2.xml", }; return ::android::OK; })); expectFetchRepeatedly(kProductVintfDir + "compatibility_matrix.1.xml"s, productMatrixLevel1); expectFetchRepeatedly(kProductVintfDir + "compatibility_matrix.2.xml"s, productMatrixLevel2); expectFileNotExist(StrEq(kProductMatrix)); expectNeverFetch(kSystemLegacyMatrix); expectFetchRepeatedly(kVendorManifest, ""); expectFileNotExist(StartsWith("/odm/")); // Update the device manifest cache because CheckDeprecate does not fetch // device manifest again if cache exist. vintfObject->getDeviceHalManifest(); } }; TEST_F(DeprecateTest, CheckNoDeprecate) { auto pred = getInstanceListFunc({ "android.hardware.minor@1.1::IMinor/default", "android.hardware.major@2.0::IMajor/default", "product.minor@1.1::IMinor/default", }); std::string error; EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, {}, &error)) << error; } TEST_F(DeprecateTest, CheckRemovedSystem) { auto pred = getInstanceListFunc({ "android.hardware.removed@1.0::IRemoved/default", "android.hardware.minor@1.1::IMinor/default", "android.hardware.major@2.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "removed@1.0 should be deprecated. " << error; } TEST_F(DeprecateTest, CheckRemovedProduct) { auto pred = getInstanceListFunc({ "product.removed@1.0::IRemoved/default", "product.minor@1.1::IMinor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "removed@1.0 should be deprecated. " << error; } TEST_F(DeprecateTest, CheckMinorSystem) { auto pred = getInstanceListFunc({ "android.hardware.minor@1.0::IMinor/default", "android.hardware.major@2.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "minor@1.0 should be deprecated. " << error; } TEST_F(DeprecateTest, CheckMinorProduct) { auto pred = getInstanceListFunc({ "product.minor@1.0::IMinor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "minor@1.0 should be deprecated. " << error; } TEST_F(DeprecateTest, CheckMinorDeprecatedInstance1) { auto pred = getInstanceListFunc({ "android.hardware.minor@1.0::IMinor/legacy", "android.hardware.minor@1.1::IMinor/default", "android.hardware.major@2.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "minor@1.0::IMinor/legacy should be deprecated. " << error; } TEST_F(DeprecateTest, CheckMinorDeprecatedInstance2) { auto pred = getInstanceListFunc({ "android.hardware.minor@1.1::IMinor/default", "android.hardware.minor@1.1::IMinor/legacy", "android.hardware.major@2.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "minor@1.1::IMinor/legacy should be deprecated. " << error; } TEST_F(DeprecateTest, CheckMajor1) { auto pred = getInstanceListFunc({ "android.hardware.minor@1.1::IMinor/default", "android.hardware.major@1.0::IMajor/default", "android.hardware.major@2.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "major@1.0 should be deprecated. " << error; } TEST_F(DeprecateTest, CheckMajor2) { auto pred = getInstanceListFunc({ "android.hardware.minor@1.1::IMinor/default", "android.hardware.major@1.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "major@1.0 should be deprecated. " << error; } TEST_F(DeprecateTest, HidlMetadataNotDeprecate) { auto pred = getInstanceListFunc({ "android.hardware.major@1.0::IMajor/default", "android.hardware.major@2.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "major@1.0 should be deprecated. " << error; std::vector hidlMetadata{ {"android.hardware.major@2.0::IMajor", {"android.hardware.major@1.0::IMajor"}}, }; EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, hidlMetadata, &error)) << "major@1.0 should not be deprecated because it extends from 2.0: " << error; } TEST_F(DeprecateTest, HidlMetadataDeprecate) { auto pred = getInstanceListFunc({ "android.hardware.major@1.0::IMajor/default", }); std::string error; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << "major@1.0 should be deprecated. " << error; std::vector hidlMetadata{ {"android.hardware.major@2.0::IMajor", {"android.hardware.major@1.0::IMajor"}}, }; EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, hidlMetadata, &error)) << "major@1.0 should be deprecated. " << error; } class MultiMatrixTest : public VintfObjectTestBase { protected: void SetUp() override { VintfObjectTestBase::SetUp(); useEmptyFileSystem(); } static std::string getFileName(size_t i) { return "compatibility_matrix." + std::to_string(static_cast(i)) + ".xml"; } void SetUpMockSystemMatrices(const std::vector& xmls) { SetUpMockMatrices(kSystemVintfDir, xmls); } void SetUpMockMatrices(const std::string& dir, const std::vector& xmls) { EXPECT_CALL(fetcher(), listFiles(StrEq(dir), _, _)) .WillRepeatedly(Invoke([=](const auto&, auto* out, auto*) { size_t i = 1; for (const auto& content : xmls) { (void)content; out->push_back(getFileName(i)); ++i; } return ::android::OK; })); size_t i = 1; for (const auto& content : xmls) { expectFetchRepeatedly(dir + getFileName(i), content); ++i; } } void expectTargetFcmVersion(size_t level) { expectFetch(kVendorManifest, "(level)) + "\"/>"); vintfObject->getDeviceHalManifest(); } }; class RegexTest : public MultiMatrixTest { protected: virtual void SetUp() { MultiMatrixTest::SetUp(); SetUpMockSystemMatrices(systemMatrixRegexXmls); } }; TEST_F(RegexTest, CombineLevel1) { expectTargetFcmVersion(1); auto matrix = vintfObject->getFrameworkCompatibilityMatrix(); ASSERT_NE(nullptr, matrix); std::string xml = toXml(*matrix); EXPECT_IN( " \n" " android.hardware.regex\n" " 1.0-2\n" " 2.0\n" " \n" " IRegex\n" " default\n" " \n" " \n", xml); EXPECT_IN( " \n" " android.hardware.regex\n" " 1.0-1\n" " \n" " IRegex\n" " special/1.0\n" " regex/1.0/[0-9]+\n" " regex_common/[0-9]+\n" " \n" " \n", xml); EXPECT_IN( " \n" " android.hardware.regex\n" " 1.1-2\n" " \n" " IRegex\n" " special/1.1\n" " [a-z]+_[a-z]+/[0-9]+\n" " regex/1.1/[0-9]+\n" " \n" " \n", xml); EXPECT_IN( " \n" " android.hardware.regex\n" " 2.0\n" " \n" " IRegex\n" " special/2.0\n" " regex/2.0/[0-9]+\n" " regex_[a-z]+/[0-9]+\n" " \n" " \n", xml); } TEST_F(RegexTest, CombineLevel2) { expectTargetFcmVersion(2); auto matrix = vintfObject->getFrameworkCompatibilityMatrix(); ASSERT_NE(nullptr, matrix); std::string xml = toXml(*matrix); EXPECT_IN( " \n" " android.hardware.regex\n" " 1.1-2\n" " 2.0\n" " \n" " IRegex\n" " default\n" " \n" " \n", xml); EXPECT_IN( " \n" " android.hardware.regex\n" " 1.1-2\n" " \n" " IRegex\n" " special/1.1\n" " [a-z]+_[a-z]+/[0-9]+\n" " regex/1.1/[0-9]+\n" " \n" " \n", xml); EXPECT_IN( " \n" " android.hardware.regex\n" " 2.0\n" " \n" " IRegex\n" " special/2.0\n" " regex/2.0/[0-9]+\n" " regex_[a-z]+/[0-9]+\n" " \n" " \n", xml); } TEST_F(RegexTest, DeprecateLevel2) { std::string error; expectTargetFcmVersion(2); auto pred = getInstanceListFunc({ "android.hardware.regex@1.1::IRegex/default", "android.hardware.regex@1.1::IRegex/special/1.1", "android.hardware.regex@1.1::IRegex/regex/1.1/1", "android.hardware.regex@1.1::IRegex/regex_common/0", "android.hardware.regex@2.0::IRegex/default", }); EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, {}, &error)) << error; for (const auto& deprecated : { "android.hardware.regex@1.0::IRegex/default", "android.hardware.regex@1.0::IRegex/special/1.0", "android.hardware.regex@1.0::IRegex/regex/1.0/1", "android.hardware.regex@1.0::IRegex/regex_common/0", "android.hardware.regex@1.1::IRegex/special/1.0", "android.hardware.regex@1.1::IRegex/regex/1.0/1", }) { // 2.0/default ensures compatibility. pred = getInstanceListFunc({ deprecated, "android.hardware.regex@2.0::IRegex/default", }); error.clear(); EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << deprecated << " should be deprecated. " << error; } } TEST_F(RegexTest, DeprecateLevel3) { std::string error; expectTargetFcmVersion(3); auto pred = getInstanceListFunc({ "android.hardware.regex@2.0::IRegex/special/2.0", "android.hardware.regex@2.0::IRegex/regex/2.0/1", "android.hardware.regex@2.0::IRegex/default", }); EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, {}, &error)) << error; for (const auto& deprecated : { "android.hardware.regex@1.0::IRegex/default", "android.hardware.regex@1.0::IRegex/special/1.0", "android.hardware.regex@1.0::IRegex/regex/1.0/1", "android.hardware.regex@1.0::IRegex/regex_common/0", "android.hardware.regex@1.1::IRegex/special/1.0", "android.hardware.regex@1.1::IRegex/regex/1.0/1", "android.hardware.regex@1.1::IRegex/special/1.1", "android.hardware.regex@1.1::IRegex/regex/1.1/1", "android.hardware.regex@1.1::IRegex/regex_common/0", }) { // 2.0/default ensures compatibility. pred = getInstanceListFunc({ deprecated, "android.hardware.regex@2.0::IRegex/default", }); error.clear(); EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, {}, &error)) << deprecated << " should be deprecated."; } } // // Set of framework matrices of different FCM version with . // #define FAKE_KERNEL(__version__, __key__, __level__) \ " \n" \ " \n" \ " CONFIG_" __key__ "\n" \ " y\n" \ " \n" \ " \n" const static std::vector systemMatrixKernelXmls = { // 1.xml "\n" FAKE_KERNEL("1.0.0", "A1", 1) FAKE_KERNEL("2.0.0", "B1", 1) "\n", // 2.xml "\n" FAKE_KERNEL("2.0.0", "B2", 2) FAKE_KERNEL("3.0.0", "C2", 2) FAKE_KERNEL("4.0.0", "D2", 2) "\n", // 3.xml "\n" FAKE_KERNEL("4.0.0", "D3", 3) FAKE_KERNEL("5.0.0", "E3", 3) "\n", // 4.xml "\n" FAKE_KERNEL("5.0.0", "E4", 4) FAKE_KERNEL("6.0.0", "F4", 4) "\n", // 5.xml "\n" FAKE_KERNEL("6.0.0", "F5", 5) FAKE_KERNEL("7.0.0", "G5", 5) "\n", }; class KernelTest : public MultiMatrixTest { public: void expectKernelFcmVersion(size_t targetFcm, Level kernelFcm) { std::string xml = "(targetFcm)) + "\">\n"; if (kernelFcm != Level::UNSPECIFIED) { xml += " \n"; } xml += ""; expectFetch(kVendorManifest, xml); } }; // Assume that we are developing level 2. Test that old requirements should // not change and new versions are added. TEST_F(KernelTest, Level1AndLevel2) { SetUpMockSystemMatrices({systemMatrixKernelXmls[0], systemMatrixKernelXmls[1]}); expectTargetFcmVersion(1); auto matrix = vintfObject->getFrameworkCompatibilityMatrix(); ASSERT_NE(nullptr, matrix); std::string xml = toXml(*matrix); EXPECT_IN(FAKE_KERNEL("1.0.0", "A1", 1), xml) << "\nOld requirements must not change."; EXPECT_IN(FAKE_KERNEL("2.0.0", "B1", 1), xml) << "\nOld requirements must not change."; EXPECT_IN(FAKE_KERNEL("3.0.0", "C2", 2), xml) << "\nShould see from new matrices"; EXPECT_IN(FAKE_KERNEL("4.0.0", "D2", 2), xml) << "\nShould see from new matrices"; EXPECT_IN(FAKE_KERNEL("2.0.0", "B2", 2), xml) << "\nShould see from new matrices"; } // Assume that we are developing level 3. Test that old requirements should // not change and new versions are added. TEST_F(KernelTest, Level1AndMore) { SetUpMockSystemMatrices({systemMatrixKernelXmls}); expectTargetFcmVersion(1); auto matrix = vintfObject->getFrameworkCompatibilityMatrix(); ASSERT_NE(nullptr, matrix); std::string xml = toXml(*matrix); EXPECT_IN(FAKE_KERNEL("1.0.0", "A1", 1), xml) << "\nOld requirements must not change."; EXPECT_IN(FAKE_KERNEL("2.0.0", "B1", 1), xml) << "\nOld requirements must not change."; EXPECT_IN(FAKE_KERNEL("3.0.0", "C2", 2), xml) << "\nOld requirements must not change."; EXPECT_IN(FAKE_KERNEL("4.0.0", "D2", 2), xml) << "\nOld requirements must not change."; EXPECT_IN(FAKE_KERNEL("5.0.0", "E3", 3), xml) << "\nShould see from new matrices"; EXPECT_IN(FAKE_KERNEL("2.0.0", "B2", 2), xml) << "\nShould see from new matrices"; EXPECT_IN(FAKE_KERNEL("4.0.0", "D3", 3), xml) << "\nShould see from new matrices"; } KernelInfo MakeKernelInfo(const std::string& version, const std::string& key) { KernelInfo info; CHECK(fromXml(&info, " \n" " \n" " CONFIG_" + key + "\n" " y\n" " \n" " \n")); return info; } TEST_F(KernelTest, Compatible) { setupMockFetcher(vendorManifestXml1, systemMatrixXml1, systemManifestXml1, vendorMatrixXml1); SetUpMockSystemMatrices({ "\n" FAKE_KERNEL("1.0.0", "A1", 1) FAKE_KERNEL("2.0.0", "B1", 1) " \n" " 0\n" " 0.0\n" " \n" "\n"}); expectKernelFcmVersion(Level{1}, Level{1}); expectSystemManifest(); expectVendorMatrix(); auto info = MakeKernelInfo("1.0.0", "A1"); runtimeInfoFactory().getInfo()->setNextFetchKernelInfo(info.version(), info.configs()); std::string error; ASSERT_EQ(COMPATIBLE, vintfObject->checkCompatibility(&error)) << error; } TEST_F(KernelTest, Level) { expectKernelFcmVersion(1, Level{10}); EXPECT_EQ(Level{10}, vintfObject->getKernelLevel()); } TEST_F(KernelTest, LevelUnspecified) { expectKernelFcmVersion(1, Level::UNSPECIFIED); EXPECT_EQ(Level::UNSPECIFIED, vintfObject->getKernelLevel()); } class KernelTestP : public KernelTest, public WithParamInterface< std::tuple, KernelInfo, Level, Level, bool>> {}; // Assume that we are developing level 2. Test that old requirements should // not change and new versions are added. TEST_P(KernelTestP, Test) { auto&& [matrices, info, targetFcm, kernelFcm, pass] = GetParam(); SetUpMockSystemMatrices(matrices); expectKernelFcmVersion(targetFcm, kernelFcm); runtimeInfoFactory().getInfo()->setNextFetchKernelInfo(info.version(), info.configs()); auto matrix = vintfObject->getFrameworkCompatibilityMatrix(); auto runtime = vintfObject->getRuntimeInfo(); ASSERT_NE(nullptr, matrix); ASSERT_NE(nullptr, runtime); std::string fallbackError = kernelFcm == Level::UNSPECIFIED ? "\nOld requirements must not change" : "\nMust not pull unnecessary requirements from new matrices"; std::string error; ASSERT_EQ(pass, runtime->checkCompatibility(*matrix, &error)) << (pass ? error : fallbackError); } std::vector KernelTestParamValues() { std::vector ret; std::vector matrices = {systemMatrixKernelXmls[0], systemMatrixKernelXmls[1]}; ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C2"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D2"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{1}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{1}, Level{1}, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{1}, Level{1}, true); ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C2"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D2"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{1}, Level{1}, true); matrices = systemMatrixKernelXmls; ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C2"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D2"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("5.0.0", "E3"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{1}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{1}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D3"), Level{1}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("5.0.0", "E4"), Level{1}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F5"), Level{1}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{2}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{3}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{4}, Level::UNSPECIFIED, true); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{5}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{1}, Level{1}, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{1}, Level{1}, true); ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{1}, Level{1}, true); ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C2"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C3"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D2"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D3"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("5.0.0", "E3"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("5.0.0", "E4"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F5"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{1}, Level{1}, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{2}, Level{2}, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{3}, Level{3}, false); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{4}, Level{4}, true); ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{5}, Level{5}, false); return ret; } std::vector RKernelTestParamValues() { std::vector ret; std::vector matrices = systemMatrixKernelXmls; // Devices launching O~Q: Must not use *-r+ kernels without specifying kernel FCM version ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{1}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{2}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{3}, Level::UNSPECIFIED, false); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{4}, Level::UNSPECIFIED, false); // Devices launching R: may use r kernel without specifying kernel FCM version because // assemble_vintf does not insert tags to device manifest any more. ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{5}, Level::UNSPECIFIED, true); // May use *-r+ kernels with kernel FCM version ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{1}, Level{5}, true); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{2}, Level{5}, true); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{3}, Level{5}, true); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{4}, Level{5}, true); ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{5}, Level{5}, true); return ret; } std::string PrintKernelTestParam(const TestParamInfo& info) { const auto& [matrices, kernelInfo, targetFcm, kernelFcm, pass] = info.param; return (matrices.size() == 2 ? "Level1AndLevel2_" : "Level1AndMore_") + android::base::StringReplace(to_string(kernelInfo.version()), ".", "_", true) + "_" + android::base::StringReplace(kernelInfo.configs().begin()->first, "CONFIG_", "", false) + "_TargetFcm" + (targetFcm == Level::UNSPECIFIED ? "Unspecified" : to_string(targetFcm)) + "_KernelFcm" + (kernelFcm == Level::UNSPECIFIED ? "Unspecified" : to_string(kernelFcm)) + "_Should" + (pass ? "Pass" : "Fail"); } INSTANTIATE_TEST_SUITE_P(KernelTest, KernelTestP, ValuesIn(KernelTestParamValues()), &PrintKernelTestParam); INSTANTIATE_TEST_SUITE_P(NoRKernelWithoutFcm, KernelTestP, ValuesIn(RKernelTestParamValues()), &PrintKernelTestParam); class VintfObjectPartialUpdateTest : public MultiMatrixTest { protected: void SetUp() override { MultiMatrixTest::SetUp(); } }; TEST_F(VintfObjectPartialUpdateTest, DeviceCompatibility) { setupMockFetcher(vendorManifestRequire1, "", systemManifestXml1, vendorMatrixXml1); SetUpMockSystemMatrices(systemMatrixRequire); expectSystemManifest(); expectVendorMatrix(); expectVendorManifest(); std::string error; EXPECT_TRUE(vintfObject->checkCompatibility(&error)) << error; } std::string CreateFrameworkManifestFrag(const std::string& interface) { return "\n" " \n" " android.hardware.foo\n" " hwbinder\n" " @1.0::" + interface + "/default\n" " \n" "\n"; } using FrameworkManifestTestParam = std::tuple; class FrameworkManifestTest : public VintfObjectTestBase, public ::testing::WithParamInterface { protected: // Set the existence of |path|. void expectManifest(const std::string& path, const std::string& interface, bool exists) { if (exists) { expectFetchRepeatedly(path, CreateFrameworkManifestFrag(interface)); } else { expectFileNotExist(StrEq(path)); } } // Set the existence of |path| as a fragment dir void expectFragment(const std::string& path, const std::string& interface, bool exists) { if (exists) { EXPECT_CALL(fetcher(), listFiles(StrEq(path), _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { *out = {"fragment.xml"}; return ::android::OK; })); expectFetchRepeatedly(path + "fragment.xml", CreateFrameworkManifestFrag(interface)); } else { EXPECT_CALL(fetcher(), listFiles(StrEq(path), _, _)) .Times(AnyNumber()) .WillRepeatedly(Return(::android::OK)); expectFileNotExist(path + "fragment.xml"); } } void expectContainsInterface(const std::string& interface, bool contains = true) { auto manifest = vintfObject->getFrameworkHalManifest(); ASSERT_NE(nullptr, manifest); EXPECT_NE(manifest->getHidlInstances("android.hardware.foo", {1, 0}, interface).empty(), contains) << interface << " should " << (contains ? "" : "not ") << "exist."; } }; TEST_P(FrameworkManifestTest, Existence) { useEmptyFileSystem(); expectFileNotExist(StrEq(kSystemLegacyManifest)); expectManifest(kSystemManifest, "ISystemEtc", std::get<0>(GetParam())); expectFragment(kSystemManifestFragmentDir, "ISystemEtcFragment", std::get<1>(GetParam())); expectManifest(kProductManifest, "IProductEtc", std::get<2>(GetParam())); expectFragment(kProductManifestFragmentDir, "IProductEtcFragment", std::get<3>(GetParam())); expectManifest(kSystemExtManifest, "ISystemExtEtc", std::get<4>(GetParam())); expectFragment(kSystemExtManifestFragmentDir, "ISystemExtEtcFragment", std::get<5>(GetParam())); if (!std::get<0>(GetParam())) { EXPECT_EQ(nullptr, vintfObject->getFrameworkHalManifest()) << "getFrameworkHalManifest must return nullptr if " << kSystemManifest << " does not exist"; } else { expectContainsInterface("ISystemEtc", std::get<0>(GetParam())); expectContainsInterface("ISystemEtcFragment", std::get<1>(GetParam())); expectContainsInterface("IProductEtc", std::get<2>(GetParam())); expectContainsInterface("IProductEtcFragment", std::get<3>(GetParam())); expectContainsInterface("ISystemExtEtc", std::get<4>(GetParam())); expectContainsInterface("ISystemExtEtcFragment", std::get<5>(GetParam())); } } INSTANTIATE_TEST_SUITE_P(Vintf, FrameworkManifestTest, ::testing::Combine(Bool(), Bool(), Bool(), Bool(), Bool(), Bool())); // clang-format on class FrameworkManifestLevelTest : public VintfObjectTestBase { protected: void SetUp() override { VintfObjectTestBase::SetUp(); useEmptyFileSystem(); auto head = ")"; auto tail = ""; auto systemManifest = head + getFragment(HalFormat::HIDL, 13, "@3.0::ISystemEtc") + getFragment(HalFormat::AIDL, 14, "ISystemEtc4") + tail; expectFetch(kSystemManifest, systemManifest); auto hidlFragment = head + getFragment(HalFormat::HIDL, 14, "@4.0::ISystemEtcFragment") + tail; expectFetch(kSystemManifestFragmentDir + "hidl.xml"s, hidlFragment); auto aidlFragment = head + getFragment(HalFormat::AIDL, 13, "ISystemEtcFragment3") + tail; expectFetch(kSystemManifestFragmentDir + "aidl.xml"s, aidlFragment); EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemManifestFragmentDir), _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { *out = {"hidl.xml", "aidl.xml"}; return ::android::OK; })); } void expectTargetFcmVersion(size_t level) { std::string xml = android::base::StringPrintf( R"()", kMetaVersionStr.c_str(), to_string(static_cast(level)).c_str()); expectFetch(kVendorManifest, xml); (void)vintfObject->getDeviceHalManifest(); } void expectContainsHidl(const Version& version, const std::string& interfaceName, bool exists = true) { auto manifest = vintfObject->getFrameworkHalManifest(); ASSERT_NE(nullptr, manifest); EXPECT_NE( manifest->getHidlInstances("android.frameworks.foo", version, interfaceName).empty(), exists) << "@" << version << "::" << interfaceName << " should " << (exists ? "" : "not ") << "exist."; } void expectContainsAidl(const std::string& interfaceName, bool exists = true) { auto manifest = vintfObject->getFrameworkHalManifest(); ASSERT_NE(nullptr, manifest); EXPECT_NE(manifest->getAidlInstances("android.frameworks.foo", interfaceName).empty(), exists) << interfaceName << " should " << (exists ? "" : "not ") << "exist."; } private: std::string getFragment(HalFormat halFormat, size_t maxLevel, const char* versionedInterface) { auto format = R"( android.frameworks.foo %s %s/default )"; std::string level = to_string(static_cast(maxLevel)); const char* transport = ""; if (halFormat == HalFormat::HIDL) { transport = "hwbinder"; } return android::base::StringPrintf(format, to_string(halFormat).c_str(), level.c_str(), transport, versionedInterface); } }; TEST_F(FrameworkManifestLevelTest, NoTargetFcmVersion) { auto xml = android::base::StringPrintf(R"( )", kMetaVersionStr.c_str()); expectFetch(kVendorManifest, xml); expectContainsHidl({3, 0}, "ISystemEtc"); expectContainsHidl({4, 0}, "ISystemEtcFragment"); expectContainsAidl("ISystemEtcFragment3"); expectContainsAidl("ISystemEtc4"); } TEST_F(FrameworkManifestLevelTest, TargetFcmVersion13) { expectTargetFcmVersion(13); expectContainsHidl({3, 0}, "ISystemEtc"); expectContainsHidl({4, 0}, "ISystemEtcFragment"); expectContainsAidl("ISystemEtcFragment3"); expectContainsAidl("ISystemEtc4"); } TEST_F(FrameworkManifestLevelTest, TargetFcmVersion14) { expectTargetFcmVersion(14); expectContainsHidl({3, 0}, "ISystemEtc", false); expectContainsHidl({4, 0}, "ISystemEtcFragment"); expectContainsAidl("ISystemEtcFragment3", false); expectContainsAidl("ISystemEtc4"); } TEST_F(FrameworkManifestLevelTest, TargetFcmVersion15) { expectTargetFcmVersion(15); expectContainsHidl({3, 0}, "ISystemEtc", false); expectContainsHidl({4, 0}, "ISystemEtcFragment", false); expectContainsAidl("ISystemEtcFragment3", false); expectContainsAidl("ISystemEtc4", false); } // clang-format off // // Set of OEM FCM matrices at different FCM version. // std::vector GetOemFcmMatrixLevels(const std::string& name) { return { // 1.xml "\n" " \n" " vendor.foo." + name + "\n" " 1.0\n" " \n" " IExtra\n" " default\n" " \n" " \n" "\n", // 2.xml "\n" " \n" " vendor.foo." + name + "\n" " 2.0\n" " \n" " IExtra\n" " default\n" " \n" " \n" "\n", }; } class OemFcmLevelTest : public MultiMatrixTest, public WithParamInterface> { protected: virtual void SetUp() override { MultiMatrixTest::SetUp(); SetUpMockSystemMatrices({systemMatrixLevel1, systemMatrixLevel2}); } using Instances = std::set; Instances GetInstances(const CompatibilityMatrix* fcm) { Instances instances; fcm->forEachHidlInstance([&instances](const auto& matrixInstance) { instances.insert(matrixInstance.description(matrixInstance.versionRange().minVer())); return true; // continue }); return instances; } }; TEST_P(OemFcmLevelTest, Test) { auto&& [level, hasProduct, hasSystemExt] = GetParam(); expectTargetFcmVersion(level); if (hasProduct) { SetUpMockMatrices(kProductVintfDir, GetOemFcmMatrixLevels("product")); } if (hasSystemExt) { SetUpMockMatrices(kSystemExtVintfDir, GetOemFcmMatrixLevels("systemext")); } auto fcm = vintfObject->getFrameworkCompatibilityMatrix(); ASSERT_NE(nullptr, fcm); auto instances = GetInstances(fcm.get()); auto containsOrNot = [](bool contains, const std::string& e) { return contains ? SafeMatcherCast(Contains(e)) : SafeMatcherCast(Not(Contains(e))); }; EXPECT_THAT(instances, containsOrNot(level == 1, "android.hardware.major@1.0::IMajor/default")); EXPECT_THAT(instances, containsOrNot(level == 1 && hasProduct, "vendor.foo.product@1.0::IExtra/default")); EXPECT_THAT(instances, containsOrNot(level == 1 && hasSystemExt, "vendor.foo.systemext@1.0::IExtra/default")); EXPECT_THAT(instances, Contains("android.hardware.major@2.0::IMajor/default")); EXPECT_THAT(instances, containsOrNot(hasProduct, "vendor.foo.product@2.0::IExtra/default")); EXPECT_THAT(instances, containsOrNot(hasSystemExt, "vendor.foo.systemext@2.0::IExtra/default")); } static std::string OemFcmLevelTestParamToString( const TestParamInfo& info) { auto&& [level, hasProduct, hasSystemExt] = info.param; auto name = "Level" + std::to_string(level); name += "With"s + (hasProduct ? "" : "out") + "Product"; name += "With"s + (hasSystemExt ? "" : "out") + "SystemExt"; return name; } INSTANTIATE_TEST_SUITE_P(OemFcmLevel, OemFcmLevelTest, Combine(Values(1, 2), Bool(), Bool()), OemFcmLevelTestParamToString); // clang-format on // A matcher that checks if a Result object contains an error message, and the error message // contains the given substring. class ErrorMessageMatcher { public: ErrorMessageMatcher(const std::string& message) : mMessage(message) {} template bool MatchAndExplain(const android::base::Result& result, MatchResultListener* listener) const { if (result.ok()) { *listener << "result is ok"; return false; } *listener << "result has error message \"" << result.error().message() << "\""; return result.error().message().find(mMessage) != std::string::npos; } void DescribeTo(std::ostream* os) const { *os << "error message contains \"" << mMessage << "\""; } void DescribeNegationTo(std::ostream* os) const { *os << "error message does not contain \"" << mMessage << "\""; } private: std::string mMessage; }; PolymorphicMatcher HasErrorMessage(const std::string& message) { return MakePolymorphicMatcher(ErrorMessageMatcher(message)); } // Common test set up for checking matrices against lib*idlmetadata. class CheckMatricesWithHalDefTestBase : public MultiMatrixTest { void SetUp() override { MultiMatrixTest::SetUp(); // clang-format off std::vector matrices{ "\n" " \n" " android.hardware.hidl\n" " 1.0\n" " \n" " IHidl\n" " default\n" " \n" " \n" " \n" " android.hardware.aidl\n" " \n" " IAidl\n" " default\n" " \n" " \n" "\n", }; // clang-format on SetUpMockSystemMatrices(matrices); } }; // A set of tests on VintfObject::checkMissingHalsInMatrices class CheckMissingHalsTest : public CheckMatricesWithHalDefTestBase {}; TEST_F(CheckMissingHalsTest, Empty) { EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices({}, {})); } TEST_F(CheckMissingHalsTest, Pass) { std::vector hidl{{.name = "android.hardware.hidl@1.0::IHidl"}}; std::vector aidl{{.types = {"android.hardware.aidl.IAidl"}}}; EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, {})); EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices({}, aidl)); EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, aidl)); } TEST_F(CheckMissingHalsTest, FailVendor) { std::vector hidl{{.name = "vendor.foo.hidl@1.0"}}; std::vector aidl{{.types = {"vendor.foo.aidl.IAidl"}}}; auto res = vintfObject->checkMissingHalsInMatrices(hidl, {}); EXPECT_THAT(res, HasErrorMessage("vendor.foo.hidl@1.0")); res = vintfObject->checkMissingHalsInMatrices({}, aidl); EXPECT_THAT(res, HasErrorMessage("vendor.foo.aidl")); res = vintfObject->checkMissingHalsInMatrices(hidl, aidl); EXPECT_THAT(res, HasErrorMessage("vendor.foo.hidl@1.0")); EXPECT_THAT(res, HasErrorMessage("vendor.foo.aidl")); auto predicate = [](const auto& interfaceName) { return android::base::StartsWith(interfaceName, "android.hardware"); }; EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, {}, predicate)); EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices({}, aidl, predicate)); EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, aidl, predicate)); } TEST_F(CheckMissingHalsTest, FailVersion) { std::vector hidl{{.name = "android.hardware.hidl@2.0"}}; std::vector aidl{{.types = {"android.hardware.aidl2.IAidl"}}}; auto res = vintfObject->checkMissingHalsInMatrices(hidl, {}); EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0")); res = vintfObject->checkMissingHalsInMatrices({}, aidl); EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2")); res = vintfObject->checkMissingHalsInMatrices(hidl, aidl); EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0")); EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2")); auto predicate = [](const auto& interfaceName) { return android::base::StartsWith(interfaceName, "android.hardware"); }; res = vintfObject->checkMissingHalsInMatrices(hidl, {}, predicate); EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0")); res = vintfObject->checkMissingHalsInMatrices({}, aidl, predicate); EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2")); res = vintfObject->checkMissingHalsInMatrices(hidl, aidl, predicate); EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0")); EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2")); } // A set of tests on VintfObject::checkMatrixHalsHasDefinition class CheckMatrixHalsHasDefinitionTest : public CheckMatricesWithHalDefTestBase {}; TEST_F(CheckMatrixHalsHasDefinitionTest, Pass) { std::vector hidl{{.name = "android.hardware.hidl@1.0::IHidl"}}; std::vector aidl{{.types = {"android.hardware.aidl.IAidl"}}}; EXPECT_RESULT_OK(vintfObject->checkMatrixHalsHasDefinition(hidl, aidl)); } TEST_F(CheckMatrixHalsHasDefinitionTest, FailMissingHidl) { std::vector aidl{{.types = {"android.hardware.aidl.IAidl"}}}; auto res = vintfObject->checkMatrixHalsHasDefinition({}, aidl); EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@1.0::IHidl")); } TEST_F(CheckMatrixHalsHasDefinitionTest, FailMissingAidl) { std::vector hidl{{.name = "android.hardware.hidl@1.0::IHidl"}}; auto res = vintfObject->checkMatrixHalsHasDefinition(hidl, {}); EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl.IAidl")); } TEST_F(CheckMatrixHalsHasDefinitionTest, FailMissingBoth) { auto res = vintfObject->checkMatrixHalsHasDefinition({}, {}); EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@1.0::IHidl")); EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl.IAidl")); } } // namespace testing } // namespace vintf } // namespace android int main(int argc, char** argv) { #ifndef LIBVINTF_TARGET // Silence logs on host because they pollute the gtest output. Negative tests writes a lot // of warning and error logs. android::base::SetMinimumLogSeverity(android::base::LogSeverity::FATAL); #endif ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); }