regex-instance: Fix check deprecate test
Deprecation check should check <regex-instance> as well
as <instance>.
An instance is considered deprecated if it matches
some <instance> or <regex-instance> in "old" matrix
but a higher major version / higher minor version matchese
some <instance> or <regex-instance> in "new" matrix.
For example:
1.xml: @1.0::IFoo/legacy/[0-9]+
2.xml: @2.0::IFoo/leg[a-z]+/[0-9]+
And a device manifest provides @1.0::IFoo/legacy/1, then
this instance is deprecated.
Caveat:
VintfObject::IsInstanceInUse is changed to VintfObject::ListInstances
because the matrix no longer provides an exact list of instances
that it checks, but rather a "match rule"; hence it needs to list
all instances from IServiceManager or manifest to work. However,
this doesn't work with passthrough service manager. Hence, if a HAL
is a passthrough HAL, only <instance>s can be checked.
Bug: 73738616
Test: libvintf_test
Test: vintf_object_test
Test: vts_treble_vintf_test
Change-Id: Ibb7585b157c3c1148ba78b8fcd27a113d398297a
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 367dc17..604f7cb 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -577,10 +577,10 @@
bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal,
const CompatibilityMatrix& targetMatrix,
- const IsInstanceInUse& isInstanceInUse, std::string* error) {
+ const ListInstances& listInstances, std::string* error) {
bool isDeprecated = false;
oldMatrixHal.forEachInstance([&](const MatrixInstance& oldMatrixInstance) {
- if (isInstanceDeprecated(oldMatrixInstance, targetMatrix, isInstanceInUse, error)) {
+ if (isInstanceDeprecated(oldMatrixInstance, targetMatrix, listInstances, error)) {
isDeprecated = true;
}
return !isDeprecated; // continue if no deprecated instance is found.
@@ -588,30 +588,39 @@
return isDeprecated;
}
-// If isInstanceInUse(package@x.y::interface/instance), return true iff:
-// 1. package@x.?::interface/instance is not in targetMatrix; OR
-// 2. package@x.z::interface/instance is in targetMatrix but
-// !isInstanceInUse(package@x.z::interface/instance)
+// Let oldMatrixInstance = package@x.y-w::interface with instancePattern.
+// If any "servedInstance" in listInstances(package@x.y::interface) matches instancePattern, return
+// true iff:
+// 1. package@x.?::interface/servedInstance is not in targetMatrix; OR
+// 2. package@x.z::interface/servedInstance is in targetMatrix but
+// servedInstance is not in listInstances(package@x.z::interface)
bool VintfObject::isInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
const CompatibilityMatrix& targetMatrix,
- const IsInstanceInUse& isInstanceInUse, std::string* error) {
+ const ListInstances& listInstances, std::string* error) {
const std::string& package = oldMatrixInstance.package();
const Version& version = oldMatrixInstance.versionRange().minVer();
const std::string& interface = oldMatrixInstance.interface();
- const std::string& instance = oldMatrixInstance.instance();
- bool oldVersionIsServed;
- Version servedVersion;
- std::tie(oldVersionIsServed, servedVersion) =
- isInstanceInUse(package, version, interface, instance);
- if (oldVersionIsServed) {
+ std::vector<std::string> instanceHint;
+ if (!oldMatrixInstance.isRegex()) {
+ instanceHint.push_back(oldMatrixInstance.exactInstance());
+ }
+
+ auto list = listInstances(package, version, interface, instanceHint);
+ for (const auto& pair : list) {
+ const std::string& servedInstance = pair.first;
+ Version servedVersion = pair.second;
+ if (!oldMatrixInstance.matchInstance(servedInstance)) {
+ continue;
+ }
+
// Find any package@x.? in target matrix, and check if instance is in target matrix.
bool foundInstance = false;
Version targetMatrixMinVer;
targetMatrix.forEachInstanceOfPackage(package, [&](const auto& targetMatrixInstance) {
if (targetMatrixInstance.versionRange().majorVer == version.majorVer &&
targetMatrixInstance.interface() == interface &&
- targetMatrixInstance.instance() == instance) {
+ targetMatrixInstance.matchInstance(servedInstance)) {
targetMatrixMinVer = targetMatrixInstance.versionRange().minVer();
foundInstance = true;
}
@@ -619,7 +628,7 @@
});
if (!foundInstance) {
if (error) {
- *error = toFQNameString(package, servedVersion, interface, instance) +
+ *error = toFQNameString(package, servedVersion, interface, servedInstance) +
" is deprecated in compatibility matrix at FCM Version " +
to_string(targetMatrix.level()) + "; it should not be served.";
}
@@ -627,23 +636,29 @@
}
// Assuming that targetMatrix requires @x.u-v, require that at least @x.u is served.
- bool targetVersionServed;
- std::tie(targetVersionServed, std::ignore) =
- isInstanceInUse(package, targetMatrixMinVer, interface, instance);
+ bool targetVersionServed = false;
+ for (const auto& newPair :
+ listInstances(package, targetMatrixMinVer, interface, instanceHint)) {
+ if (newPair.first == servedInstance) {
+ targetVersionServed = true;
+ break;
+ }
+ }
if (!targetVersionServed) {
if (error) {
- *error += toFQNameString(package, servedVersion) + " is deprecated; " +
- "require at least " + to_string(targetMatrixMinVer) + "\n";
+ *error += toFQNameString(package, servedVersion, interface, servedInstance) +
+ " is deprecated; requires at least " + to_string(targetMatrixMinVer) +
+ "\n";
}
return true;
}
}
+
return false;
}
-int32_t VintfObject::CheckDeprecation(const IsInstanceInUse& isInstanceInUse,
- std::string* error) {
+int32_t VintfObject::CheckDeprecation(const ListInstances& listInstances, std::string* error) {
auto matrixFragments = GetAllFrameworkMatrixLevels(error);
if (matrixFragments.empty()) {
if (error && error->empty())
@@ -680,7 +695,7 @@
const auto& oldMatrix = namedMatrix.object;
for (const MatrixHal& hal : oldMatrix.getHals()) {
- hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, isInstanceInUse, error);
+ hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, listInstances, error);
}
}
@@ -690,22 +705,18 @@
int32_t VintfObject::CheckDeprecation(std::string* error) {
using namespace std::placeholders;
auto deviceManifest = GetDeviceHalManifest();
- IsInstanceInUse inManifest = [&deviceManifest](const std::string& package, Version version,
- const std::string& interface,
- const std::string& instance) {
- std::pair<bool, Version> ret(false, Version{});
- deviceManifest->forEachInstanceOfInterface(
- package, version, interface,
- [&instance, &ret](const ManifestInstance& manifestInstance) {
- if (manifestInstance.instance() == instance) {
- ret.first = true;
- ret.second = manifestInstance.version();
- return false;
- }
- return true;
- });
- return ret;
- };
+ ListInstances inManifest =
+ [&deviceManifest](const std::string& package, Version version, const std::string& interface,
+ const std::vector<std::string>& /* hintInstances */) {
+ std::vector<std::pair<std::string, Version>> ret;
+ deviceManifest->forEachInstanceOfInterface(
+ package, version, interface, [&ret](const ManifestInstance& manifestInstance) {
+ ret.push_back(
+ std::make_pair(manifestInstance.instance(), manifestInstance.version()));
+ return true;
+ });
+ return ret;
+ };
return CheckDeprecation(inManifest, error);
}
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 811c110..56581f8 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -110,22 +110,32 @@
std::string* error = nullptr,
DisabledChecks disabledChecks = ENABLE_ALL_CHECKS);
- using IsInstanceInUse = std::function<std::pair<bool, Version>(
+ /**
+ * A std::function that abstracts a list of "provided" instance names. Given package, version
+ * and interface, the function returns a list of instance names that matches.
+ * This function can represent a manifest, an IServiceManager, etc.
+ * If the source is passthrough service manager, a list of instance names cannot be provided.
+ * Instead, the function should call getService on each of the "hintInstances", and
+ * return those instances for which getService does not return a nullptr. This means that for
+ * passthrough HALs, the deprecation on <regex-instance>s cannot be enforced; only <instance>s
+ * can be enforced.
+ */
+ using ListInstances = std::function<std::vector<std::pair<std::string, Version>>(
const std::string& package, Version version, const std::string& interface,
- const std::string& instance)>;
+ const std::vector<std::string>& hintInstances)>;
/**
* Check deprecation on framework matrices with a provided predicate.
*
- * @param isInstanceInUse predicate that takes parameter in this format:
- * android.hardware.foo@1.0::IFoo/instance
- * and returns {true, version} if HAL is in use, where version =
+ * @param listInstances predicate that takes parameter in this format:
+ * android.hardware.foo@1.0::IFoo
+ * and returns {{"default", version}...} if HAL is in use, where version =
* first version in interfaceChain where package + major version matches.
*
* @return = 0 if success (no deprecated HALs)
* > 0 if there is at least one deprecated HAL
* < 0 if any error (mount partition fails, illformed XML, etc.)
*/
- static int32_t CheckDeprecation(const IsInstanceInUse& isInstanceInUse,
+ static int32_t CheckDeprecation(const ListInstances& listInstances,
std::string* error = nullptr);
/**
@@ -153,10 +163,10 @@
static bool isHalDeprecated(const MatrixHal& oldMatrixHal,
const CompatibilityMatrix& targetMatrix,
- const IsInstanceInUse& isInstanceInUse, std::string* error);
+ const ListInstances& listInstances, std::string* error);
static bool isInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
const CompatibilityMatrix& targetMatrix,
- const IsInstanceInUse& isInstanceInUse, std::string* error);
+ const ListInstances& listInstances, std::string* error);
};
enum : int32_t {
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 0a08b26..27c04a5 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -32,7 +32,7 @@
using namespace ::android::vintf;
using namespace ::android::vintf::details;
-using android::FQName;
+using android::FqInstance;
static bool In(const std::string& sub, const std::string& str) {
return str.find(sub) != std::string::npos;
@@ -837,23 +837,29 @@
EXPECT_TRUE(containsOdmManifest(p));
}
-struct FQInstance {
- FQName fqName;
- std::string instance;
+struct CheckedFqInstance : FqInstance {
+ CheckedFqInstance(const char* s) : CheckedFqInstance(std::string(s)) {}
+ CheckedFqInstance(const std::string& s) { CHECK(setTo(s)) << s; }
- FQInstance(const char* s) : FQInstance(std::string(s)) {}
- FQInstance(const std::string& s) {
- auto tokens = android::base::Split(s, "/");
- CHECK(2u == tokens.size());
- CHECK(FQName::parse(tokens[0], &fqName));
- instance = tokens[1];
- }
-
- Version getVersion() const {
- return Version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()};
- }
+ Version getVersion() const { return FqInstance::getVersion(); }
};
+static VintfObject::ListInstances getInstanceListFunc(
+ const std::vector<CheckedFqInstance>& instances) {
+ return [instances](const std::string& package, Version version, const std::string& interface,
+ const auto& /* instanceHint */) {
+ std::vector<std::pair<std::string, Version>> 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 {
@@ -878,24 +884,10 @@
VintfObject::GetDeviceHalManifest(true /* skipCache */);
}
- VintfObject::IsInstanceInUse getPredicate(const std::vector<FQInstance>& instances) {
- return [instances](const std::string& package, Version version,
- const std::string& interface, const std::string& instance) {
- for (auto&& existing : instances) {
- if (existing.fqName.package() == package &&
- existing.getVersion().minorAtLeast(version) &&
- existing.fqName.name() == interface && existing.instance == instance) {
- return std::make_pair(true, existing.getVersion());
- }
- }
-
- return std::make_pair(false, Version{});
- };
- }
};
TEST_F(DeprecateTest, CheckNoDeprecate) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.minor@1.1::IMinor/default",
"android.hardware.major@2.0::IMajor/default",
});
@@ -904,7 +896,7 @@
}
TEST_F(DeprecateTest, CheckRemoved) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.removed@1.0::IRemoved/default",
"android.hardware.minor@1.1::IMinor/default",
"android.hardware.major@2.0::IMajor/default",
@@ -915,7 +907,7 @@
}
TEST_F(DeprecateTest, CheckMinor) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.minor@1.0::IMinor/default",
"android.hardware.major@2.0::IMajor/default",
});
@@ -925,7 +917,7 @@
}
TEST_F(DeprecateTest, CheckMinorDeprecatedInstance1) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.minor@1.0::IMinor/legacy",
"android.hardware.minor@1.1::IMinor/default",
"android.hardware.major@2.0::IMajor/default",
@@ -936,7 +928,7 @@
}
TEST_F(DeprecateTest, CheckMinorDeprecatedInstance2) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.minor@1.1::IMinor/default",
"android.hardware.minor@1.1::IMinor/legacy",
"android.hardware.major@2.0::IMajor/default",
@@ -947,7 +939,7 @@
}
TEST_F(DeprecateTest, CheckMajor1) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.minor@1.1::IMinor/default",
"android.hardware.major@1.0::IMajor/default",
"android.hardware.major@2.0::IMajor/default",
@@ -958,7 +950,7 @@
}
TEST_F(DeprecateTest, CheckMajor2) {
- auto pred = getPredicate({
+ auto pred = getInstanceListFunc({
"android.hardware.minor@1.1::IMinor/default",
"android.hardware.major@1.0::IMajor/default",
});