diff options
author | android-build-team Robot | 2018-03-25 02:24:57 -0500 |
---|---|---|
committer | android-build-team Robot | 2018-03-25 02:24:57 -0500 |
commit | 804cfa5802b89600b204ff194d879ec03ce2a26f (patch) | |
tree | ff549f243107bf2a6b6c0c5246131d763b153a91 | |
parent | 106ff9b2fb1fdc39190c995312f9341efd5f0cb9 (diff) | |
parent | bb86f253002a9c3d3ff3bd55f1c219c0f7a53738 (diff) | |
download | platform-system-libvintf-804cfa5802b89600b204ff194d879ec03ce2a26f.tar.gz platform-system-libvintf-804cfa5802b89600b204ff194d879ec03ce2a26f.tar.xz platform-system-libvintf-804cfa5802b89600b204ff194d879ec03ce2a26f.zip |
Snap for 4677756 from bb86f253002a9c3d3ff3bd55f1c219c0f7a53738 to pi-release
Change-Id: I5483e61588a71e7cd1734b39313c3af1a6ff70c0
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | CompatibilityMatrix.cpp | 61 | ||||
-rw-r--r-- | HalInterface.cpp | 47 | ||||
-rw-r--r-- | HalManifest.cpp | 27 | ||||
-rw-r--r-- | ManifestHal.cpp | 16 | ||||
-rw-r--r-- | MatrixHal.cpp | 93 | ||||
-rw-r--r-- | MatrixInstance.cpp | 45 | ||||
-rw-r--r-- | Regex.cpp | 51 | ||||
-rw-r--r-- | VintfObject.cpp | 111 | ||||
-rw-r--r-- | include/vintf/CompatibilityMatrix.h | 7 | ||||
-rw-r--r-- | include/vintf/HalGroup.h | 23 | ||||
-rw-r--r-- | include/vintf/HalInterface.h | 33 | ||||
-rw-r--r-- | include/vintf/HalManifest.h | 8 | ||||
-rw-r--r-- | include/vintf/ManifestHal.h | 2 | ||||
-rw-r--r-- | include/vintf/MatrixHal.h | 19 | ||||
-rw-r--r-- | include/vintf/MatrixInstance.h | 22 | ||||
-rw-r--r-- | include/vintf/Regex.h | 57 | ||||
-rw-r--r-- | include/vintf/VintfObject.h | 29 | ||||
-rw-r--r-- | main.cpp | 4 | ||||
-rw-r--r-- | parse_string.cpp | 23 | ||||
-rw-r--r-- | parse_xml.cpp | 44 | ||||
-rw-r--r-- | test/LibVintfTest.cpp | 150 | ||||
-rw-r--r-- | test/vintf_object_tests.cpp | 318 |
23 files changed, 935 insertions, 256 deletions
@@ -42,6 +42,7 @@ cc_library_static { | |||
42 | "MatrixHal.cpp", | 42 | "MatrixHal.cpp", |
43 | "MatrixInstance.cpp", | 43 | "MatrixInstance.cpp", |
44 | "MatrixKernel.cpp", | 44 | "MatrixKernel.cpp", |
45 | "Regex.cpp", | ||
45 | "SystemSdk.cpp", | 46 | "SystemSdk.cpp", |
46 | "TransportArch.cpp", | 47 | "TransportArch.cpp", |
47 | "VintfObject.cpp", | 48 | "VintfObject.cpp", |
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp index 5b216f7..88ecd26 100644 --- a/CompatibilityMatrix.cpp +++ b/CompatibilityMatrix.cpp | |||
@@ -82,19 +82,38 @@ std::string CompatibilityMatrix::getXmlSchemaPath(const std::string& xmlFileName | |||
82 | // - Remove interface/instance from existingHal, and return a new MatrixHal (that is added | 82 | // - Remove interface/instance from existingHal, and return a new MatrixHal (that is added |
83 | // to "this") that contains only interface/instance. | 83 | // to "this") that contains only interface/instance. |
84 | MatrixHal* CompatibilityMatrix::splitInstance(MatrixHal* existingHal, const std::string& interface, | 84 | MatrixHal* CompatibilityMatrix::splitInstance(MatrixHal* existingHal, const std::string& interface, |
85 | const std::string& instance) { | 85 | const std::string& instanceOrPattern, bool isRegex) { |
86 | if (!existingHal->hasInstance(interface, instance)) { | 86 | bool found = false; |
87 | bool foundOthers = false; | ||
88 | existingHal->forEachInstance([&](const auto& matrixInstance) { | ||
89 | bool interfaceMatch = matrixInstance.interface() == interface; | ||
90 | bool instanceMatch = false; | ||
91 | if (matrixInstance.isRegex() && isRegex) { | ||
92 | instanceMatch = (matrixInstance.regexPattern() == instanceOrPattern); | ||
93 | } else if (!matrixInstance.isRegex() && !isRegex) { | ||
94 | instanceMatch = (matrixInstance.exactInstance() == instanceOrPattern); | ||
95 | } | ||
96 | |||
97 | bool match = interfaceMatch && instanceMatch; | ||
98 | |||
99 | found |= match; | ||
100 | foundOthers |= (!match); | ||
101 | |||
102 | return !found || !foundOthers; | ||
103 | }); | ||
104 | |||
105 | if (!found) { | ||
87 | return nullptr; | 106 | return nullptr; |
88 | } | 107 | } |
89 | 108 | ||
90 | if (existingHal->hasOnlyInstance(interface, instance)) { | 109 | if (!foundOthers) { |
91 | return existingHal; | 110 | return existingHal; |
92 | } | 111 | } |
93 | 112 | ||
94 | existingHal->removeInstance(interface, instance); | 113 | existingHal->removeInstance(interface, instanceOrPattern, isRegex); |
95 | MatrixHal copy = *existingHal; | 114 | MatrixHal copy = *existingHal; |
96 | copy.clearInstances(); | 115 | copy.clearInstances(); |
97 | copy.insertInstance(interface, instance); | 116 | copy.insertInstance(interface, instanceOrPattern, isRegex); |
98 | 117 | ||
99 | return addInternal(std::move(copy)); | 118 | return addInternal(std::move(copy)); |
100 | } | 119 | } |
@@ -114,15 +133,22 @@ bool CompatibilityMatrix::addAllHalsAsOptional(CompatibilityMatrix* other, std:: | |||
114 | MatrixHal& halToAdd = pair.second; | 133 | MatrixHal& halToAdd = pair.second; |
115 | 134 | ||
116 | std::set<std::pair<std::string, std::string>> insertedInstances; | 135 | std::set<std::pair<std::string, std::string>> insertedInstances; |
136 | std::set<std::pair<std::string, std::string>> insertedRegex; | ||
117 | auto existingHals = getHals(name); | 137 | auto existingHals = getHals(name); |
118 | 138 | ||
119 | halToAdd.forEachInstance([&](const std::vector<VersionRange>& versionRanges, | 139 | halToAdd.forEachInstance([&](const std::vector<VersionRange>& versionRanges, |
120 | const std::string& interface, const std::string& instance) { | 140 | const std::string& interface, |
141 | const std::string& instanceOrPattern, bool isRegex) { | ||
121 | for (auto* existingHal : existingHals) { | 142 | for (auto* existingHal : existingHals) { |
122 | MatrixHal* splitInstance = this->splitInstance(existingHal, interface, instance); | 143 | MatrixHal* splitInstance = |
144 | this->splitInstance(existingHal, interface, instanceOrPattern, isRegex); | ||
123 | if (splitInstance != nullptr) { | 145 | if (splitInstance != nullptr) { |
124 | splitInstance->insertVersionRanges(versionRanges); | 146 | splitInstance->insertVersionRanges(versionRanges); |
125 | insertedInstances.insert(std::make_pair(interface, instance)); | 147 | if (isRegex) { |
148 | insertedRegex.insert(std::make_pair(interface, instanceOrPattern)); | ||
149 | } else { | ||
150 | insertedInstances.insert(std::make_pair(interface, instanceOrPattern)); | ||
151 | } | ||
126 | } | 152 | } |
127 | } | 153 | } |
128 | return true; | 154 | return true; |
@@ -130,10 +156,13 @@ bool CompatibilityMatrix::addAllHalsAsOptional(CompatibilityMatrix* other, std:: | |||
130 | 156 | ||
131 | // Add the remaining instances. | 157 | // Add the remaining instances. |
132 | for (const auto& pair : insertedInstances) { | 158 | for (const auto& pair : insertedInstances) { |
133 | halToAdd.removeInstance(pair.first, pair.second); | 159 | halToAdd.removeInstance(pair.first, pair.second, false /* isRegex */); |
160 | } | ||
161 | for (const auto& pair : insertedRegex) { | ||
162 | halToAdd.removeInstance(pair.first, pair.second, true /* isRegex */); | ||
134 | } | 163 | } |
135 | 164 | ||
136 | if (halToAdd.hasAnyInstance()) { | 165 | if (halToAdd.instancesCount() > 0) { |
137 | halToAdd.setOptional(true); | 166 | halToAdd.setOptional(true); |
138 | if (!add(std::move(halToAdd))) { | 167 | if (!add(std::move(halToAdd))) { |
139 | if (error) { | 168 | if (error) { |
@@ -330,5 +359,17 @@ bool CompatibilityMatrix::forEachInstanceOfVersion( | |||
330 | return true; | 359 | return true; |
331 | } | 360 | } |
332 | 361 | ||
362 | bool CompatibilityMatrix::matchInstance(const std::string& halName, const Version& version, | ||
363 | const std::string& interfaceName, | ||
364 | const std::string& instance) const { | ||
365 | bool found = false; | ||
366 | (void)forEachInstanceOfInterface(halName, version, interfaceName, | ||
367 | [&found, &instance](const auto& e) { | ||
368 | found |= (e.matchInstance(instance)); | ||
369 | return !found; // if not found, continue | ||
370 | }); | ||
371 | return found; | ||
372 | } | ||
373 | |||
333 | } // namespace vintf | 374 | } // namespace vintf |
334 | } // namespace android | 375 | } // namespace android |
diff --git a/HalInterface.cpp b/HalInterface.cpp index 2dbf57c..b5cbd6b 100644 --- a/HalInterface.cpp +++ b/HalInterface.cpp | |||
@@ -23,13 +23,50 @@ namespace android { | |||
23 | namespace vintf { | 23 | namespace vintf { |
24 | 24 | ||
25 | bool operator==(const HalInterface& lft, const HalInterface& rgt) { | 25 | bool operator==(const HalInterface& lft, const HalInterface& rgt) { |
26 | if (lft.name != rgt.name) | 26 | if (lft.mName != rgt.mName) return false; |
27 | return false; | 27 | if (lft.mInstances != rgt.mInstances) return false; |
28 | if (lft.instances != rgt.instances) | ||
29 | return false; | ||
30 | return true; | 28 | return true; |
31 | } | 29 | } |
32 | 30 | ||
31 | bool HalInterface::forEachInstance( | ||
32 | const std::function<bool(const std::string&, const std::string&, bool isRegex)>& func) const { | ||
33 | for (const auto& instance : mInstances) { | ||
34 | if (!func(mName, instance, false /* isRegex */)) { | ||
35 | return false; | ||
36 | } | ||
37 | } | ||
38 | for (const auto& instance : mRegexes) { | ||
39 | if (!func(mName, instance, true /* isRegex */)) { | ||
40 | return false; | ||
41 | } | ||
42 | } | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | bool HalInterface::hasAnyInstance() const { | ||
47 | bool found = false; | ||
48 | forEachInstance([&found](const auto&, const auto&, bool) { | ||
49 | found = true; | ||
50 | return false; // break; | ||
51 | }); | ||
52 | return found; | ||
53 | } | ||
54 | |||
55 | bool HalInterface::insertInstance(const std::string& instanceOrPattern, bool isRegex) { | ||
56 | if (isRegex) { | ||
57 | return mRegexes.insert(instanceOrPattern).second; | ||
58 | } else { | ||
59 | return mInstances.insert(instanceOrPattern).second; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | bool HalInterface::removeInstance(const std::string& instanceOrPattern, bool isRegex) { | ||
64 | if (isRegex) { | ||
65 | return mRegexes.erase(instanceOrPattern) > 0; | ||
66 | } else { | ||
67 | return mInstances.erase(instanceOrPattern) > 0; | ||
68 | } | ||
69 | } | ||
70 | |||
33 | } // namespace vintf | 71 | } // namespace vintf |
34 | } // namespace android | 72 | } // namespace android |
35 | |||
diff --git a/HalManifest.cpp b/HalManifest.cpp index a884b1f..d1230cb 100644 --- a/HalManifest.cpp +++ b/HalManifest.cpp | |||
@@ -218,8 +218,8 @@ std::set<std::string> HalManifest::checkUnusedHals(const CompatibilityMatrix& ma | |||
218 | 218 | ||
219 | forEachInstance([&ret, &mat](const auto& manifestInstance) { | 219 | forEachInstance([&ret, &mat](const auto& manifestInstance) { |
220 | const auto& fqInstance = manifestInstance.getFqInstance(); | 220 | const auto& fqInstance = manifestInstance.getFqInstance(); |
221 | if (!mat.hasInstance(fqInstance.getPackage(), fqInstance.getVersion(), | 221 | if (!mat.matchInstance(fqInstance.getPackage(), fqInstance.getVersion(), |
222 | fqInstance.getInterface(), fqInstance.getInstance())) { | 222 | fqInstance.getInterface(), fqInstance.getInstance())) { |
223 | ret.insert(fqInstance.string()); | 223 | ret.insert(fqInstance.string()); |
224 | } | 224 | } |
225 | return true; | 225 | return true; |
@@ -423,5 +423,28 @@ bool operator==(const HalManifest &lft, const HalManifest &rgt) { | |||
423 | lft.framework.mSystemSdk == rgt.framework.mSystemSdk)); | 423 | lft.framework.mSystemSdk == rgt.framework.mSystemSdk)); |
424 | } | 424 | } |
425 | 425 | ||
426 | // Alternative to forEachInstance if you just need a set of instance names instead. | ||
427 | std::set<std::string> HalManifest::getInstances(const std::string& halName, const Version& version, | ||
428 | const std::string& interfaceName) const { | ||
429 | std::set<std::string> ret; | ||
430 | (void)forEachInstanceOfInterface(halName, version, interfaceName, [&ret](const auto& e) { | ||
431 | ret.insert(e.instance()); | ||
432 | return true; | ||
433 | }); | ||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | // Return whether instance is in getInstances(...). | ||
438 | bool HalManifest::hasInstance(const std::string& halName, const Version& version, | ||
439 | const std::string& interfaceName, const std::string& instance) const { | ||
440 | bool found = false; | ||
441 | (void)forEachInstanceOfInterface(halName, version, interfaceName, | ||
442 | [&found, &instance](const auto& e) { | ||
443 | found |= (instance == e.instance()); | ||
444 | return !found; // if not found, continue | ||
445 | }); | ||
446 | return found; | ||
447 | } | ||
448 | |||
426 | } // namespace vintf | 449 | } // namespace vintf |
427 | } // namespace android | 450 | } // namespace android |
diff --git a/ManifestHal.cpp b/ManifestHal.cpp index c0f4c8e..2d0e246 100644 --- a/ManifestHal.cpp +++ b/ManifestHal.cpp | |||
@@ -51,15 +51,20 @@ bool ManifestHal::operator==(const ManifestHal &other) const { | |||
51 | bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const { | 51 | bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const { |
52 | for (const auto& v : versions) { | 52 | for (const auto& v : versions) { |
53 | for (const auto& intf : iterateValues(interfaces)) { | 53 | for (const auto& intf : iterateValues(interfaces)) { |
54 | for (const auto& instance : intf.instances) { | 54 | bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance, |
55 | bool /* isRegex */) { | ||
55 | // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps | 56 | // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps |
56 | FqInstance fqInstance; | 57 | FqInstance fqInstance; |
57 | if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, intf.name, instance)) { | 58 | if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, interface, instance)) { |
58 | if (!func(ManifestInstance(std::move(fqInstance), TransportArch{transportArch}, | 59 | if (!func(ManifestInstance(std::move(fqInstance), TransportArch{transportArch}, |
59 | format))) { | 60 | format))) { |
60 | return false; | 61 | return false; |
61 | } | 62 | } |
62 | } | 63 | } |
64 | return true; | ||
65 | }); | ||
66 | if (!cont) { | ||
67 | return false; | ||
63 | } | 68 | } |
64 | } | 69 | } |
65 | } | 70 | } |
@@ -135,5 +140,12 @@ bool ManifestHal::insertInstances(const std::set<FqInstance>& fqInstances, std:: | |||
135 | return true; | 140 | return true; |
136 | } | 141 | } |
137 | 142 | ||
143 | void ManifestHal::insertLegacyInstance(const std::string& interface, const std::string& instance) { | ||
144 | auto it = interfaces.find(interface); | ||
145 | if (it == interfaces.end()) | ||
146 | it = interfaces.emplace(interface, HalInterface{interface, {}}).first; | ||
147 | it->second.insertInstance(instance, false /* isRegex */); | ||
148 | } | ||
149 | |||
138 | } // namespace vintf | 150 | } // namespace vintf |
139 | } // namespace android | 151 | } // namespace android |
diff --git a/MatrixHal.cpp b/MatrixHal.cpp index 62e0cd8..86118b5 100644 --- a/MatrixHal.cpp +++ b/MatrixHal.cpp | |||
@@ -43,15 +43,6 @@ bool MatrixHal::containsVersion(const Version& version) const { | |||
43 | return false; | 43 | return false; |
44 | } | 44 | } |
45 | 45 | ||
46 | std::set<std::string> MatrixHal::getInstances(const std::string& interfaceName) const { | ||
47 | std::set<std::string> ret; | ||
48 | auto it = interfaces.find(interfaceName); | ||
49 | if (it != interfaces.end()) { | ||
50 | ret.insert(it->second.instances.begin(), it->second.instances.end()); | ||
51 | } | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const { | 46 | bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const { |
56 | for (const auto& vr : versionRanges) { | 47 | for (const auto& vr : versionRanges) { |
57 | if (!forEachInstance(vr, func)) { | 48 | if (!forEachInstance(vr, func)) { |
@@ -64,14 +55,20 @@ bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)> | |||
64 | bool MatrixHal::forEachInstance(const VersionRange& vr, | 55 | bool MatrixHal::forEachInstance(const VersionRange& vr, |
65 | const std::function<bool(const MatrixInstance&)>& func) const { | 56 | const std::function<bool(const MatrixInstance&)>& func) const { |
66 | for (const auto& intf : iterateValues(interfaces)) { | 57 | for (const auto& intf : iterateValues(interfaces)) { |
67 | for (const auto& instance : intf.instances) { | 58 | bool cont = |
68 | // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps | 59 | intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) { |
69 | FqInstance fqInstance; | 60 | // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps |
70 | if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, intf.name, instance)) { | 61 | FqInstance fqInstance; |
71 | if (!func(MatrixInstance(std::move(fqInstance), VersionRange(vr), optional))) { | 62 | if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, interface, instance)) { |
72 | return false; | 63 | if (!func(MatrixInstance(std::move(fqInstance), VersionRange(vr), optional, |
64 | isRegex))) { | ||
65 | return false; | ||
66 | } | ||
73 | } | 67 | } |
74 | } | 68 | return true; |
69 | }); | ||
70 | if (!cont) { | ||
71 | return false; | ||
75 | } | 72 | } |
76 | } | 73 | } |
77 | return true; | 74 | return true; |
@@ -79,12 +76,14 @@ bool MatrixHal::forEachInstance(const VersionRange& vr, | |||
79 | 76 | ||
80 | bool MatrixHal::forEachInstance( | 77 | bool MatrixHal::forEachInstance( |
81 | const std::function<bool(const std::vector<VersionRange>&, const std::string&, | 78 | const std::function<bool(const std::vector<VersionRange>&, const std::string&, |
82 | const std::string&)>& func) const { | 79 | const std::string&, bool isRegex)>& func) const { |
83 | for (const auto& intf : iterateValues(interfaces)) { | 80 | for (const auto& intf : iterateValues(interfaces)) { |
84 | for (const auto& instance : intf.instances) { | 81 | bool cont = |
85 | if (!func(versionRanges, intf.name, instance)) { | 82 | intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) { |
86 | return false; | 83 | return func(this->versionRanges, interface, instance, isRegex); |
87 | } | 84 | }); |
85 | if (!cont) { | ||
86 | return false; | ||
88 | } | 87 | } |
89 | } | 88 | } |
90 | return true; | 89 | return true; |
@@ -145,54 +144,30 @@ void MatrixHal::insertVersionRanges(const std::vector<VersionRange>& other) { | |||
145 | } | 144 | } |
146 | } | 145 | } |
147 | 146 | ||
148 | void MatrixHal::insertInstance(const std::string& interface, const std::string& instance) { | 147 | void MatrixHal::insertInstance(const std::string& interface, const std::string& instance, |
148 | bool isRegex) { | ||
149 | auto it = interfaces.find(interface); | 149 | auto it = interfaces.find(interface); |
150 | if (it == interfaces.end()) | 150 | if (it == interfaces.end()) |
151 | it = interfaces.emplace(interface, HalInterface{interface, {}}).first; | 151 | it = interfaces.emplace(interface, HalInterface{interface, {}}).first; |
152 | it->second.instances.insert(instance); | 152 | it->second.insertInstance(instance, isRegex); |
153 | } | ||
154 | |||
155 | bool MatrixHal::hasAnyInstance() const { | ||
156 | bool found = false; | ||
157 | forEachInstance([&](const auto&) { | ||
158 | found = true; | ||
159 | return false; // break if any instance | ||
160 | }); | ||
161 | return found; | ||
162 | } | 153 | } |
163 | 154 | ||
164 | bool MatrixHal::hasInstance(const std::string& interface, const std::string& instance) const { | 155 | size_t MatrixHal::instancesCount() const { |
165 | bool found = false; | 156 | size_t count = 0; |
166 | forEachInstance([&](const auto& matrixInstance) { | 157 | forEachInstance([&](const MatrixInstance&) { |
167 | found |= matrixInstance.interface() == interface && matrixInstance.instance() == instance; | 158 | ++count; |
168 | return !found; // continue if not match | 159 | return true; // continue; |
169 | }); | 160 | }); |
170 | return found; | 161 | return count; |
171 | } | 162 | } |
172 | 163 | ||
173 | bool MatrixHal::hasOnlyInstance(const std::string& interface, const std::string& instance) const { | 164 | bool MatrixHal::removeInstance(const std::string& interface, const std::string& instance, |
174 | bool found = false; | 165 | bool isRegex) { |
175 | bool foundOthers = false; | ||
176 | |||
177 | forEachInstance([&](const auto& matrixInstance) { | ||
178 | bool match = | ||
179 | matrixInstance.interface() == interface && matrixInstance.instance() == instance; | ||
180 | |||
181 | found |= match; | ||
182 | foundOthers |= (!match); | ||
183 | |||
184 | return !foundOthers; | ||
185 | }); | ||
186 | |||
187 | return found && !foundOthers; | ||
188 | } | ||
189 | |||
190 | bool MatrixHal::removeInstance(const std::string& interface, const std::string& instance) { | ||
191 | auto it = interfaces.find(interface); | 166 | auto it = interfaces.find(interface); |
192 | if (it == interfaces.end()) return false; | 167 | if (it == interfaces.end()) return false; |
193 | it->second.instances.erase(instance); | 168 | bool removed = it->second.removeInstance(instance, isRegex); |
194 | if (it->second.instances.empty()) interfaces.erase(it); | 169 | if (!it->second.hasAnyInstance()) interfaces.erase(it); |
195 | return true; | 170 | return removed; |
196 | } | 171 | } |
197 | 172 | ||
198 | void MatrixHal::clearInstances() { | 173 | void MatrixHal::clearInstances() { |
diff --git a/MatrixInstance.cpp b/MatrixInstance.cpp index 0ac3681..e4e731e 100644 --- a/MatrixInstance.cpp +++ b/MatrixInstance.cpp | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #include <utility> | 19 | #include <utility> |
20 | 20 | ||
21 | #include "Regex.h" | ||
22 | |||
21 | namespace android { | 23 | namespace android { |
22 | namespace vintf { | 24 | namespace vintf { |
23 | 25 | ||
@@ -31,12 +33,16 @@ MatrixInstance& MatrixInstance::operator=(const MatrixInstance&) = default; | |||
31 | 33 | ||
32 | MatrixInstance& MatrixInstance::operator=(MatrixInstance&&) = default; | 34 | MatrixInstance& MatrixInstance::operator=(MatrixInstance&&) = default; |
33 | 35 | ||
34 | MatrixInstance::MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional) | 36 | MatrixInstance::MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional, |
35 | : mFqInstance(std::move(fqInstance)), mRange(std::move(range)), mOptional(optional) {} | 37 | bool isRegex) |
38 | : mFqInstance(std::move(fqInstance)), | ||
39 | mRange(std::move(range)), | ||
40 | mOptional(optional), | ||
41 | mIsRegex(isRegex) {} | ||
36 | 42 | ||
37 | MatrixInstance::MatrixInstance(const FqInstance fqInstance, const VersionRange& range, | 43 | MatrixInstance::MatrixInstance(const FqInstance fqInstance, const VersionRange& range, |
38 | bool optional) | 44 | bool optional, bool isRegex) |
39 | : mFqInstance(fqInstance), mRange(range), mOptional(optional) {} | 45 | : mFqInstance(fqInstance), mRange(range), mOptional(optional), mIsRegex(isRegex) {} |
40 | 46 | ||
41 | const std::string& MatrixInstance::package() const { | 47 | const std::string& MatrixInstance::package() const { |
42 | return mFqInstance.getPackage(); | 48 | return mFqInstance.getPackage(); |
@@ -50,10 +56,6 @@ const std::string& MatrixInstance::interface() const { | |||
50 | return mFqInstance.getInterface(); | 56 | return mFqInstance.getInterface(); |
51 | } | 57 | } |
52 | 58 | ||
53 | const std::string& MatrixInstance::instance() const { | ||
54 | return mFqInstance.getInstance(); | ||
55 | } | ||
56 | |||
57 | bool MatrixInstance::optional() const { | 59 | bool MatrixInstance::optional() const { |
58 | return mOptional; | 60 | return mOptional; |
59 | } | 61 | } |
@@ -61,7 +63,32 @@ bool MatrixInstance::optional() const { | |||
61 | bool MatrixInstance::isSatisfiedBy(const FqInstance& provided) const { | 63 | bool MatrixInstance::isSatisfiedBy(const FqInstance& provided) const { |
62 | return package() == provided.getPackage() && | 64 | return package() == provided.getPackage() && |
63 | versionRange().supportedBy(provided.getVersion()) && | 65 | versionRange().supportedBy(provided.getVersion()) && |
64 | interface() == provided.getInterface() && instance() == provided.getInstance(); | 66 | interface() == provided.getInterface() && matchInstance(provided.getInstance()); |
67 | } | ||
68 | |||
69 | bool MatrixInstance::matchInstance(const std::string& e) const { | ||
70 | if (!isRegex()) { | ||
71 | return exactInstance() == e; | ||
72 | } | ||
73 | details::Regex regex; | ||
74 | if (!regex.compile(regexPattern())) { | ||
75 | return false; | ||
76 | } | ||
77 | return regex.matches(e); | ||
78 | } | ||
79 | |||
80 | const std::string& MatrixInstance::regexPattern() const { | ||
81 | static const std::string kEmptyString; | ||
82 | return isRegex() ? mFqInstance.getInstance() : kEmptyString; | ||
83 | } | ||
84 | |||
85 | const std::string& MatrixInstance::exactInstance() const { | ||
86 | static const std::string kEmptyString; | ||
87 | return isRegex() ? kEmptyString : mFqInstance.getInstance(); | ||
88 | } | ||
89 | |||
90 | bool MatrixInstance::isRegex() const { | ||
91 | return mIsRegex; | ||
65 | } | 92 | } |
66 | 93 | ||
67 | } // namespace vintf | 94 | } // namespace vintf |
diff --git a/Regex.cpp b/Regex.cpp new file mode 100644 index 0000000..c343398 --- /dev/null +++ b/Regex.cpp | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "Regex.h" | ||
18 | |||
19 | namespace android { | ||
20 | namespace vintf { | ||
21 | namespace details { | ||
22 | |||
23 | Regex::~Regex() { | ||
24 | clear(); | ||
25 | } | ||
26 | |||
27 | void Regex::clear() { | ||
28 | if (mImpl != nullptr) { | ||
29 | regfree(mImpl.get()); | ||
30 | mImpl = nullptr; | ||
31 | } | ||
32 | } | ||
33 | |||
34 | bool Regex::compile(const std::string& pattern) { | ||
35 | clear(); | ||
36 | mImpl = std::make_unique<regex_t>(); | ||
37 | int status = regcomp(mImpl.get(), pattern.c_str(), REG_EXTENDED | REG_NEWLINE); | ||
38 | return status == 0; | ||
39 | } | ||
40 | |||
41 | bool Regex::matches(const std::string& s) const { | ||
42 | regmatch_t match; | ||
43 | int status = | ||
44 | regexec(mImpl.get(), s.c_str(), 1 /* nmatch */, &match /* pmatch */, 0 /* flags */); | ||
45 | return status == 0 && match.rm_so == 0 && match.rm_eo >= 0 && | ||
46 | static_cast<size_t>(match.rm_eo) == s.length(); | ||
47 | } | ||
48 | |||
49 | } // namespace details | ||
50 | } // namespace vintf | ||
51 | } // namespace android | ||
diff --git a/VintfObject.cpp b/VintfObject.cpp index 88bcce2..604f7cb 100644 --- a/VintfObject.cpp +++ b/VintfObject.cpp | |||
@@ -577,41 +577,50 @@ int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, st | |||
577 | 577 | ||
578 | bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal, | 578 | bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal, |
579 | const CompatibilityMatrix& targetMatrix, | 579 | const CompatibilityMatrix& targetMatrix, |
580 | const IsInstanceInUse& isInstanceInUse, std::string* error) { | 580 | const ListInstances& listInstances, std::string* error) { |
581 | for (const VersionRange& range : oldMatrixHal.versionRanges) { | 581 | bool isDeprecated = false; |
582 | for (const HalInterface& interface : iterateValues(oldMatrixHal.interfaces)) { | 582 | oldMatrixHal.forEachInstance([&](const MatrixInstance& oldMatrixInstance) { |
583 | for (const std::string& instance : interface.instances) { | 583 | if (isInstanceDeprecated(oldMatrixInstance, targetMatrix, listInstances, error)) { |
584 | if (isInstanceDeprecated(oldMatrixHal.name, range.minVer(), interface.name, | 584 | isDeprecated = true; |
585 | instance, targetMatrix, isInstanceInUse, error)) { | ||
586 | return true; | ||
587 | } | ||
588 | } | ||
589 | } | 585 | } |
590 | } | 586 | return !isDeprecated; // continue if no deprecated instance is found. |
591 | return false; | 587 | }); |
588 | return isDeprecated; | ||
592 | } | 589 | } |
593 | 590 | ||
594 | // If isInstanceInUse(package@x.y::interface/instance), return true iff: | 591 | // Let oldMatrixInstance = package@x.y-w::interface with instancePattern. |
595 | // 1. package@x.?::interface/instance is not in targetMatrix; OR | 592 | // If any "servedInstance" in listInstances(package@x.y::interface) matches instancePattern, return |
596 | // 2. package@x.z::interface/instance is in targetMatrix but | 593 | // true iff: |
597 | // !isInstanceInUse(package@x.z::interface/instance) | 594 | // 1. package@x.?::interface/servedInstance is not in targetMatrix; OR |
598 | bool VintfObject::isInstanceDeprecated(const std::string& package, Version version, | 595 | // 2. package@x.z::interface/servedInstance is in targetMatrix but |
599 | const std::string& interface, const std::string& instance, | 596 | // servedInstance is not in listInstances(package@x.z::interface) |
597 | bool VintfObject::isInstanceDeprecated(const MatrixInstance& oldMatrixInstance, | ||
600 | const CompatibilityMatrix& targetMatrix, | 598 | const CompatibilityMatrix& targetMatrix, |
601 | const IsInstanceInUse& isInstanceInUse, | 599 | const ListInstances& listInstances, std::string* error) { |
602 | std::string* error) { | 600 | const std::string& package = oldMatrixInstance.package(); |
603 | bool oldVersionIsServed; | 601 | const Version& version = oldMatrixInstance.versionRange().minVer(); |
604 | Version servedVersion; | 602 | const std::string& interface = oldMatrixInstance.interface(); |
605 | std::tie(oldVersionIsServed, servedVersion) = | 603 | |
606 | isInstanceInUse(package, version, interface, instance); | 604 | std::vector<std::string> instanceHint; |
607 | if (oldVersionIsServed) { | 605 | if (!oldMatrixInstance.isRegex()) { |
606 | instanceHint.push_back(oldMatrixInstance.exactInstance()); | ||
607 | } | ||
608 | |||
609 | auto list = listInstances(package, version, interface, instanceHint); | ||
610 | for (const auto& pair : list) { | ||
611 | const std::string& servedInstance = pair.first; | ||
612 | Version servedVersion = pair.second; | ||
613 | if (!oldMatrixInstance.matchInstance(servedInstance)) { | ||
614 | continue; | ||
615 | } | ||
616 | |||
608 | // Find any package@x.? in target matrix, and check if instance is in target matrix. | 617 | // Find any package@x.? in target matrix, and check if instance is in target matrix. |
609 | bool foundInstance = false; | 618 | bool foundInstance = false; |
610 | Version targetMatrixMinVer; | 619 | Version targetMatrixMinVer; |
611 | targetMatrix.forEachInstanceOfPackage(package, [&](const auto& targetMatrixInstance) { | 620 | targetMatrix.forEachInstanceOfPackage(package, [&](const auto& targetMatrixInstance) { |
612 | if (targetMatrixInstance.versionRange().majorVer == version.majorVer && | 621 | if (targetMatrixInstance.versionRange().majorVer == version.majorVer && |
613 | targetMatrixInstance.interface() == interface && | 622 | targetMatrixInstance.interface() == interface && |
614 | targetMatrixInstance.instance() == instance) { | 623 | targetMatrixInstance.matchInstance(servedInstance)) { |
615 | targetMatrixMinVer = targetMatrixInstance.versionRange().minVer(); | 624 | targetMatrixMinVer = targetMatrixInstance.versionRange().minVer(); |
616 | foundInstance = true; | 625 | foundInstance = true; |
617 | } | 626 | } |
@@ -619,7 +628,7 @@ bool VintfObject::isInstanceDeprecated(const std::string& package, Version versi | |||
619 | }); | 628 | }); |
620 | if (!foundInstance) { | 629 | if (!foundInstance) { |
621 | if (error) { | 630 | if (error) { |
622 | *error = toFQNameString(package, servedVersion, interface, instance) + | 631 | *error = toFQNameString(package, servedVersion, interface, servedInstance) + |
623 | " is deprecated in compatibility matrix at FCM Version " + | 632 | " is deprecated in compatibility matrix at FCM Version " + |
624 | to_string(targetMatrix.level()) + "; it should not be served."; | 633 | to_string(targetMatrix.level()) + "; it should not be served."; |
625 | } | 634 | } |
@@ -627,23 +636,29 @@ bool VintfObject::isInstanceDeprecated(const std::string& package, Version versi | |||
627 | } | 636 | } |
628 | 637 | ||
629 | // Assuming that targetMatrix requires @x.u-v, require that at least @x.u is served. | 638 | // Assuming that targetMatrix requires @x.u-v, require that at least @x.u is served. |
630 | bool targetVersionServed; | 639 | bool targetVersionServed = false; |
631 | std::tie(targetVersionServed, std::ignore) = | 640 | for (const auto& newPair : |
632 | isInstanceInUse(package, targetMatrixMinVer, interface, instance); | 641 | listInstances(package, targetMatrixMinVer, interface, instanceHint)) { |
642 | if (newPair.first == servedInstance) { | ||
643 | targetVersionServed = true; | ||
644 | break; | ||
645 | } | ||
646 | } | ||
633 | 647 | ||
634 | if (!targetVersionServed) { | 648 | if (!targetVersionServed) { |
635 | if (error) { | 649 | if (error) { |
636 | *error += toFQNameString(package, servedVersion) + " is deprecated; " + | 650 | *error += toFQNameString(package, servedVersion, interface, servedInstance) + |
637 | "require at least " + to_string(targetMatrixMinVer) + "\n"; | 651 | " is deprecated; requires at least " + to_string(targetMatrixMinVer) + |
652 | "\n"; | ||
638 | } | 653 | } |
639 | return true; | 654 | return true; |
640 | } | 655 | } |
641 | } | 656 | } |
657 | |||
642 | return false; | 658 | return false; |
643 | } | 659 | } |
644 | 660 | ||
645 | int32_t VintfObject::CheckDeprecation(const IsInstanceInUse& isInstanceInUse, | 661 | int32_t VintfObject::CheckDeprecation(const ListInstances& listInstances, std::string* error) { |
646 | std::string* error) { | ||
647 | auto matrixFragments = GetAllFrameworkMatrixLevels(error); | 662 | auto matrixFragments = GetAllFrameworkMatrixLevels(error); |
648 | if (matrixFragments.empty()) { | 663 | if (matrixFragments.empty()) { |
649 | if (error && error->empty()) | 664 | if (error && error->empty()) |
@@ -680,7 +695,7 @@ int32_t VintfObject::CheckDeprecation(const IsInstanceInUse& isInstanceInUse, | |||
680 | 695 | ||
681 | const auto& oldMatrix = namedMatrix.object; | 696 | const auto& oldMatrix = namedMatrix.object; |
682 | for (const MatrixHal& hal : oldMatrix.getHals()) { | 697 | for (const MatrixHal& hal : oldMatrix.getHals()) { |
683 | hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, isInstanceInUse, error); | 698 | hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, listInstances, error); |
684 | } | 699 | } |
685 | } | 700 | } |
686 | 701 | ||
@@ -690,22 +705,18 @@ int32_t VintfObject::CheckDeprecation(const IsInstanceInUse& isInstanceInUse, | |||
690 | int32_t VintfObject::CheckDeprecation(std::string* error) { | 705 | int32_t VintfObject::CheckDeprecation(std::string* error) { |
691 | using namespace std::placeholders; | 706 | using namespace std::placeholders; |
692 | auto deviceManifest = GetDeviceHalManifest(); | 707 | auto deviceManifest = GetDeviceHalManifest(); |
693 | IsInstanceInUse inManifest = [&deviceManifest](const std::string& package, Version version, | 708 | ListInstances inManifest = |
694 | const std::string& interface, | 709 | [&deviceManifest](const std::string& package, Version version, const std::string& interface, |
695 | const std::string& instance) { | 710 | const std::vector<std::string>& /* hintInstances */) { |
696 | std::pair<bool, Version> ret(false, Version{}); | 711 | std::vector<std::pair<std::string, Version>> ret; |
697 | deviceManifest->forEachInstanceOfInterface( | 712 | deviceManifest->forEachInstanceOfInterface( |
698 | package, version, interface, | 713 | package, version, interface, [&ret](const ManifestInstance& manifestInstance) { |
699 | [&instance, &ret](const ManifestInstance& manifestInstance) { | 714 | ret.push_back( |
700 | if (manifestInstance.instance() == instance) { | 715 | std::make_pair(manifestInstance.instance(), manifestInstance.version())); |
701 | ret.first = true; | 716 | return true; |
702 | ret.second = manifestInstance.version(); | 717 | }); |
703 | return false; | 718 | return ret; |
704 | } | 719 | }; |
705 | return true; | ||
706 | }); | ||
707 | return ret; | ||
708 | }; | ||
709 | return CheckDeprecation(inManifest, error); | 720 | return CheckDeprecation(inManifest, error); |
710 | } | 721 | } |
711 | 722 | ||
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h index 02326ae..ff5dd24 100644 --- a/include/vintf/CompatibilityMatrix.h +++ b/include/vintf/CompatibilityMatrix.h | |||
@@ -92,7 +92,12 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat | |||
92 | std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error); | 92 | std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error); |
93 | 93 | ||
94 | MatrixHal* splitInstance(MatrixHal* existingHal, const std::string& interface, | 94 | MatrixHal* splitInstance(MatrixHal* existingHal, const std::string& interface, |
95 | const std::string& instance); | 95 | const std::string& instance, bool isRegex); |
96 | |||
97 | // Return whether instance is in "this"; that is, instance is in any <instance> tag or | ||
98 | // matches any <regex-instance> tag. | ||
99 | bool matchInstance(const std::string& halName, const Version& version, | ||
100 | const std::string& interfaceName, const std::string& instance) const; | ||
96 | 101 | ||
97 | friend struct HalManifest; | 102 | friend struct HalManifest; |
98 | friend struct RuntimeInfo; | 103 | friend struct RuntimeInfo; |
diff --git a/include/vintf/HalGroup.h b/include/vintf/HalGroup.h index 2a1e1c3..f59e495 100644 --- a/include/vintf/HalGroup.h +++ b/include/vintf/HalGroup.h | |||
@@ -135,29 +135,6 @@ struct HalGroup { | |||
135 | return v; | 135 | return v; |
136 | } | 136 | } |
137 | 137 | ||
138 | // Alternative to forEachInstance if you just need a set of instance names instead. | ||
139 | std::set<std::string> getInstances(const std::string& halName, const Version& version, | ||
140 | const std::string& interfaceName) const { | ||
141 | std::set<std::string> ret; | ||
142 | (void)forEachInstanceOfInterface(halName, version, interfaceName, [&ret](const auto& e) { | ||
143 | ret.insert(e.instance()); | ||
144 | return true; | ||
145 | }); | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | // Return whether instance is in getInstances(...). | ||
150 | bool hasInstance(const std::string& halName, const Version& version, | ||
151 | const std::string& interfaceName, const std::string& instance) const { | ||
152 | bool found = false; | ||
153 | (void)forEachInstanceOfInterface(halName, version, interfaceName, | ||
154 | [&found, &instance](const auto& e) { | ||
155 | found |= (instance == e.instance()); | ||
156 | return !found; // if not found, continue | ||
157 | }); | ||
158 | return found; | ||
159 | } | ||
160 | |||
161 | protected: | 138 | protected: |
162 | // sorted map from component name to the component. | 139 | // sorted map from component name to the component. |
163 | // The component name looks like: android.hardware.foo | 140 | // The component name looks like: android.hardware.foo |
diff --git a/include/vintf/HalInterface.h b/include/vintf/HalInterface.h index a5645d3..acbb93e 100644 --- a/include/vintf/HalInterface.h +++ b/include/vintf/HalInterface.h | |||
@@ -17,19 +17,44 @@ | |||
17 | #ifndef ANDROID_VINTF_HAL_INTERFACE_H_ | 17 | #ifndef ANDROID_VINTF_HAL_INTERFACE_H_ |
18 | #define ANDROID_VINTF_HAL_INTERFACE_H_ | 18 | #define ANDROID_VINTF_HAL_INTERFACE_H_ |
19 | 19 | ||
20 | #include <functional> | ||
20 | #include <set> | 21 | #include <set> |
21 | #include <string> | 22 | #include <string> |
22 | 23 | ||
24 | #include "Regex.h" | ||
25 | |||
23 | namespace android { | 26 | namespace android { |
24 | namespace vintf { | 27 | namespace vintf { |
25 | 28 | ||
26 | // manifest.hal.interface element / compatibility-matrix.hal.interface element | 29 | // manifest.hal.interface element / compatibility-matrix.hal.interface element |
27 | struct HalInterface { | 30 | struct HalInterface { |
28 | std::string name; | 31 | HalInterface() = default; |
29 | std::set<std::string> instances; | 32 | HalInterface(std::string&& name, std::set<std::string>&& instances) |
30 | }; | 33 | : mName(std::move(name)), mInstances(std::move(instances)) {} |
34 | HalInterface(const std::string& name, const std::set<std::string>& instances) | ||
35 | : mName(name), mInstances(instances) {} | ||
36 | |||
37 | bool forEachInstance( | ||
38 | const std::function<bool(const std::string& interface, const std::string& instance, | ||
39 | bool isRegex)>& func) const; | ||
40 | bool hasAnyInstance() const; | ||
41 | |||
42 | // Return true if inserted, false otherwise. | ||
43 | bool insertInstance(const std::string& instanceOrPattern, bool isRegex); | ||
31 | 44 | ||
32 | bool operator==(const HalInterface&, const HalInterface&); | 45 | // Return true if removed, false otherwise. |
46 | bool removeInstance(const std::string& instanceOrPattern, bool isRegex); | ||
47 | |||
48 | const std::string& name() const { return mName; } | ||
49 | |||
50 | private: | ||
51 | friend bool operator==(const HalInterface&, const HalInterface&); | ||
52 | friend struct HalInterfaceConverter; | ||
53 | |||
54 | std::string mName; | ||
55 | std::set<std::string> mInstances; | ||
56 | std::set<std::string> mRegexes; | ||
57 | }; | ||
33 | 58 | ||
34 | } // namespace vintf | 59 | } // namespace vintf |
35 | } // namespace android | 60 | } // namespace android |
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h index a5d01c8..7a436a6 100644 --- a/include/vintf/HalManifest.h +++ b/include/vintf/HalManifest.h | |||
@@ -111,6 +111,14 @@ struct HalManifest : public HalGroup<ManifestHal>, public XmlFileGroup<ManifestX | |||
111 | const std::string& package, const Version& expectVersion, | 111 | const std::string& package, const Version& expectVersion, |
112 | const std::function<bool(const ManifestInstance&)>& func) const override; | 112 | const std::function<bool(const ManifestInstance&)>& func) const override; |
113 | 113 | ||
114 | // Alternative to forEachInstance if you just need a set of instance names instead. | ||
115 | std::set<std::string> getInstances(const std::string& halName, const Version& version, | ||
116 | const std::string& interfaceName) const; | ||
117 | |||
118 | // Return whether instance is in getInstances(...). | ||
119 | bool hasInstance(const std::string& halName, const Version& version, | ||
120 | const std::string& interfaceName, const std::string& instance) const; | ||
121 | |||
114 | protected: | 122 | protected: |
115 | // Check before add() | 123 | // Check before add() |
116 | bool shouldAdd(const ManifestHal& toAdd) const override; | 124 | bool shouldAdd(const ManifestHal& toAdd) const override; |
diff --git a/include/vintf/ManifestHal.h b/include/vintf/ManifestHal.h index 026c7a5..ad7be3b 100644 --- a/include/vintf/ManifestHal.h +++ b/include/vintf/ManifestHal.h | |||
@@ -70,6 +70,8 @@ struct ManifestHal { | |||
70 | // a HAL is disabled on certain products. | 70 | // a HAL is disabled on certain products. |
71 | bool isDisabledHal() const; | 71 | bool isDisabledHal() const; |
72 | 72 | ||
73 | // insert instance to <interface> <instance>. | ||
74 | void insertLegacyInstance(const std::string& interface, const std::string& instance); | ||
73 | private: | 75 | private: |
74 | friend struct LibVintfTest; | 76 | friend struct LibVintfTest; |
75 | friend struct ManifestHalConverter; | 77 | friend struct ManifestHalConverter; |
diff --git a/include/vintf/MatrixHal.h b/include/vintf/MatrixHal.h index 595c57a..bc54ec1 100644 --- a/include/vintf/MatrixHal.h +++ b/include/vintf/MatrixHal.h | |||
@@ -37,8 +37,6 @@ struct MatrixHal { | |||
37 | bool operator==(const MatrixHal &other) const; | 37 | bool operator==(const MatrixHal &other) const; |
38 | // Check whether the MatrixHal contains the given version. | 38 | // Check whether the MatrixHal contains the given version. |
39 | bool containsVersion(const Version& version) const; | 39 | bool containsVersion(const Version& version) const; |
40 | // Get all instances of the ManifestHal with given interface name. | ||
41 | std::set<std::string> getInstances(const std::string& interfaceName) const; | ||
42 | 40 | ||
43 | HalFormat format = HalFormat::HIDL; | 41 | HalFormat format = HalFormat::HIDL; |
44 | std::string name; | 42 | std::string name; |
@@ -53,13 +51,17 @@ struct MatrixHal { | |||
53 | private: | 51 | private: |
54 | friend struct HalManifest; | 52 | friend struct HalManifest; |
55 | friend struct CompatibilityMatrix; | 53 | friend struct CompatibilityMatrix; |
54 | friend std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace); | ||
55 | friend std::vector<std::string> expandInstances(const MatrixHal& req); | ||
56 | |||
56 | // Loop over interface/instance for a specific VersionRange. | 57 | // Loop over interface/instance for a specific VersionRange. |
57 | bool forEachInstance(const VersionRange& vr, | 58 | bool forEachInstance(const VersionRange& vr, |
58 | const std::function<bool(const MatrixInstance&)>& func) const; | 59 | const std::function<bool(const MatrixInstance&)>& func) const; |
59 | // Loop over interface/instance. VersionRange is supplied to the function as a vector. | 60 | // Loop over interface/instance. VersionRange is supplied to the function as a vector. |
60 | bool forEachInstance( | 61 | bool forEachInstance( |
61 | const std::function<bool(const std::vector<VersionRange>&, const std::string&, | 62 | const std::function<bool(const std::vector<VersionRange>&, const std::string&, |
62 | const std::string&)>& func) const; | 63 | const std::string& instanceOrPattern, bool isRegex)>& func) const; |
64 | |||
63 | bool isCompatible(const std::set<FqInstance>& providedInstances, | 65 | bool isCompatible(const std::set<FqInstance>& providedInstances, |
64 | const std::set<Version>& providedVersions) const; | 66 | const std::set<Version>& providedVersions) const; |
65 | bool isCompatible(const VersionRange& vr, const std::set<FqInstance>& providedInstances, | 67 | bool isCompatible(const VersionRange& vr, const std::set<FqInstance>& providedInstances, |
@@ -67,14 +69,11 @@ struct MatrixHal { | |||
67 | 69 | ||
68 | void setOptional(bool o); | 70 | void setOptional(bool o); |
69 | void insertVersionRanges(const std::vector<VersionRange>& other); | 71 | void insertVersionRanges(const std::vector<VersionRange>& other); |
70 | void insertInstance(const std::string& interface, const std::string& instance); | 72 | // Return size of all interface/instance pairs. |
71 | // Return true if it has any interface/instance tags. | 73 | size_t instancesCount() const; |
72 | bool hasAnyInstance() const; | 74 | void insertInstance(const std::string& interface, const std::string& instance, bool isRegex); |
73 | bool hasInstance(const std::string& interface, const std::string& instance) const; | ||
74 | // Return true if it contains only interface/instance. | ||
75 | bool hasOnlyInstance(const std::string& interface, const std::string& instance) const; | ||
76 | // Remove a specific interface/instances. Return true if removed, false otherwise. | 75 | // Remove a specific interface/instances. Return true if removed, false otherwise. |
77 | bool removeInstance(const std::string& interface, const std::string& instance); | 76 | bool removeInstance(const std::string& interface, const std::string& instance, bool isRegex); |
78 | // Remove all <interface> tags. | 77 | // Remove all <interface> tags. |
79 | void clearInstances(); | 78 | void clearInstances(); |
80 | }; | 79 | }; |
diff --git a/include/vintf/MatrixInstance.h b/include/vintf/MatrixInstance.h index c3d2a0b..c34500c 100644 --- a/include/vintf/MatrixInstance.h +++ b/include/vintf/MatrixInstance.h | |||
@@ -36,20 +36,34 @@ class MatrixInstance { | |||
36 | 36 | ||
37 | using VersionType = VersionRange; | 37 | using VersionType = VersionRange; |
38 | // fqInstance.version is ignored. Version range is provided separately. | 38 | // fqInstance.version is ignored. Version range is provided separately. |
39 | MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional); | 39 | MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional, bool isRegex); |
40 | MatrixInstance(const FqInstance fqInstance, const VersionRange& range, bool optional); | 40 | MatrixInstance(const FqInstance fqInstance, const VersionRange& range, bool optional, |
41 | bool isRegex); | ||
41 | const std::string& package() const; | 42 | const std::string& package() const; |
42 | const VersionRange& versionRange() const; | 43 | const VersionRange& versionRange() const; |
43 | const std::string& interface() const; | 44 | const std::string& interface() const; |
44 | const std::string& instance() const; | ||
45 | bool optional() const; | 45 | bool optional() const; |
46 | 46 | ||
47 | bool isSatisfiedBy(const FqInstance& provided) const; | 47 | bool isSatisfiedBy(const FqInstance& provided) const; |
48 | 48 | ||
49 | // If isRegex, return true if instance matches the pattern. | ||
50 | // If !isRegex, return true if e == instance(). | ||
51 | // Follows rules of "Extended Regular Expression" (ERE). | ||
52 | bool matchInstance(const std::string& e) const; | ||
53 | |||
54 | // If isRegex, return the regex pattern. Else empty string. | ||
55 | const std::string& regexPattern() const; | ||
56 | |||
57 | // If !isRegex, return the exact instance name. Else empty string. | ||
58 | const std::string& exactInstance() const; | ||
59 | |||
60 | bool isRegex() const; | ||
61 | |||
49 | private: | 62 | private: |
50 | FqInstance mFqInstance; | 63 | FqInstance mFqInstance; |
51 | VersionRange mRange; | 64 | VersionRange mRange; |
52 | bool mOptional; | 65 | bool mOptional = false; |
66 | bool mIsRegex = false; | ||
53 | }; | 67 | }; |
54 | 68 | ||
55 | } // namespace vintf | 69 | } // namespace vintf |
diff --git a/include/vintf/Regex.h b/include/vintf/Regex.h new file mode 100644 index 0000000..86c66f2 --- /dev/null +++ b/include/vintf/Regex.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef ANDROID_VINTF_REGEX_H_ | ||
18 | #define ANDROID_VINTF_REGEX_H_ | ||
19 | |||
20 | #include <regex.h> | ||
21 | #include <string> | ||
22 | |||
23 | namespace android { | ||
24 | namespace vintf { | ||
25 | namespace details { | ||
26 | |||
27 | // A wrapper class around regex.h. This is used instead of C++ <regex> library because | ||
28 | // C++ regex library throws exceptions when an invalid regular expression is compiled. | ||
29 | // Use Extended Regular Expression (ERE) syntax. | ||
30 | class Regex { | ||
31 | public: | ||
32 | Regex() = default; | ||
33 | ~Regex(); | ||
34 | |||
35 | Regex& operator=(const Regex&) = delete; | ||
36 | Regex(const Regex&) = delete; | ||
37 | |||
38 | __attribute__((warn_unused_result)) bool compile(const std::string& pattern); | ||
39 | |||
40 | bool matches(const std::string& s) const; | ||
41 | |||
42 | /** | ||
43 | * Return nullptr if not a valid regex pattern, else the Regex object. | ||
44 | */ | ||
45 | static const Regex* Get(const std::string& pattern); | ||
46 | |||
47 | private: | ||
48 | std::unique_ptr<regex_t> mImpl; | ||
49 | |||
50 | void clear(); | ||
51 | }; | ||
52 | |||
53 | } // namespace details | ||
54 | } // namespace vintf | ||
55 | } // namespace android | ||
56 | |||
57 | #endif // ANDROID_VINTF_REGEX_H_ | ||
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h index cfa4072..56581f8 100644 --- a/include/vintf/VintfObject.h +++ b/include/vintf/VintfObject.h | |||
@@ -110,22 +110,32 @@ public: | |||
110 | std::string* error = nullptr, | 110 | std::string* error = nullptr, |
111 | DisabledChecks disabledChecks = ENABLE_ALL_CHECKS); | 111 | DisabledChecks disabledChecks = ENABLE_ALL_CHECKS); |
112 | 112 | ||
113 | using IsInstanceInUse = std::function<std::pair<bool, Version>( | 113 | /** |
114 | * A std::function that abstracts a list of "provided" instance names. Given package, version | ||
115 | * and interface, the function returns a list of instance names that matches. | ||
116 | * This function can represent a manifest, an IServiceManager, etc. | ||
117 | * If the source is passthrough service manager, a list of instance names cannot be provided. | ||
118 | * Instead, the function should call getService on each of the "hintInstances", and | ||
119 | * return those instances for which getService does not return a nullptr. This means that for | ||
120 | * passthrough HALs, the deprecation on <regex-instance>s cannot be enforced; only <instance>s | ||
121 | * can be enforced. | ||
122 | */ | ||
123 | using ListInstances = std::function<std::vector<std::pair<std::string, Version>>( | ||
114 | const std::string& package, Version version, const std::string& interface, | 124 | const std::string& package, Version version, const std::string& interface, |
115 | const std::string& instance)>; | 125 | const std::vector<std::string>& hintInstances)>; |
116 | /** | 126 | /** |
117 | * Check deprecation on framework matrices with a provided predicate. | 127 | * Check deprecation on framework matrices with a provided predicate. |
118 | * | 128 | * |
119 | * @param isInstanceInUse predicate that takes parameter in this format: | 129 | * @param listInstances predicate that takes parameter in this format: |
120 | * android.hardware.foo@1.0::IFoo/instance | 130 | * android.hardware.foo@1.0::IFoo |
121 | * and returns {true, version} if HAL is in use, where version = | 131 | * and returns {{"default", version}...} if HAL is in use, where version = |
122 | * first version in interfaceChain where package + major version matches. | 132 | * first version in interfaceChain where package + major version matches. |
123 | * | 133 | * |
124 | * @return = 0 if success (no deprecated HALs) | 134 | * @return = 0 if success (no deprecated HALs) |
125 | * > 0 if there is at least one deprecated HAL | 135 | * > 0 if there is at least one deprecated HAL |
126 | * < 0 if any error (mount partition fails, illformed XML, etc.) | 136 | * < 0 if any error (mount partition fails, illformed XML, etc.) |
127 | */ | 137 | */ |
128 | static int32_t CheckDeprecation(const IsInstanceInUse& isInstanceInUse, | 138 | static int32_t CheckDeprecation(const ListInstances& listInstances, |
129 | std::string* error = nullptr); | 139 | std::string* error = nullptr); |
130 | 140 | ||
131 | /** | 141 | /** |
@@ -153,11 +163,10 @@ public: | |||
153 | 163 | ||
154 | static bool isHalDeprecated(const MatrixHal& oldMatrixHal, | 164 | static bool isHalDeprecated(const MatrixHal& oldMatrixHal, |
155 | const CompatibilityMatrix& targetMatrix, | 165 | const CompatibilityMatrix& targetMatrix, |
156 | const IsInstanceInUse& isInstanceInUse, std::string* error); | 166 | const ListInstances& listInstances, std::string* error); |
157 | static bool isInstanceDeprecated(const std::string& package, Version version, | 167 | static bool isInstanceDeprecated(const MatrixInstance& oldMatrixInstance, |
158 | const std::string& interface, const std::string& instance, | ||
159 | const CompatibilityMatrix& targetMatrix, | 168 | const CompatibilityMatrix& targetMatrix, |
160 | const IsInstanceInUse& isInstanceInUse, std::string* error); | 169 | const ListInstances& listInstances, std::string* error); |
161 | }; | 170 | }; |
162 | 171 | ||
163 | enum : int32_t { | 172 | enum : int32_t { |
@@ -203,7 +203,9 @@ void insert(const CompatibilityMatrix* matrix, Table* table, const RowMutator& m | |||
203 | minorVer <= matrixInstance.versionRange().maxMinor; ++minorVer) { | 203 | minorVer <= matrixInstance.versionRange().maxMinor; ++minorVer) { |
204 | std::string key = toFQNameString( | 204 | std::string key = toFQNameString( |
205 | matrixInstance.package(), Version{matrixInstance.versionRange().majorVer, minorVer}, | 205 | matrixInstance.package(), Version{matrixInstance.versionRange().majorVer, minorVer}, |
206 | matrixInstance.interface(), matrixInstance.instance()); | 206 | matrixInstance.interface(), |
207 | matrixInstance.isRegex() ? matrixInstance.regexPattern() | ||
208 | : matrixInstance.exactInstance()); | ||
207 | auto it = table->find(key); | 209 | auto it = table->find(key); |
208 | if (it == table->end()) { | 210 | if (it == table->end()) { |
209 | mutate(&(*table)[key]); | 211 | mutate(&(*table)[key]); |
diff --git a/parse_string.cpp b/parse_string.cpp index 0aff5ea..b99ba61 100644 --- a/parse_string.cpp +++ b/parse_string.cpp | |||
@@ -395,16 +395,17 @@ std::ostream &operator<<(std::ostream &os, const MatrixHal &req) { | |||
395 | << (req.optional ? kOptional : kRequired); | 395 | << (req.optional ? kOptional : kRequired); |
396 | } | 396 | } |
397 | 397 | ||
398 | static std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) { | 398 | std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) { |
399 | std::string s; | 399 | std::string s; |
400 | size_t count = 0; | 400 | size_t count = 0; |
401 | for (const auto& interface : iterateValues(req.interfaces)) { | 401 | req.forEachInstance(vr, [&](const auto& matrixInstance) { |
402 | for (const auto& instance : interface.instances) { | 402 | if (count > 0) s += " AND "; |
403 | if (count > 0) s += " AND "; | 403 | s += toFQNameString(vr, matrixInstance.interface(), |
404 | s += toFQNameString(vr, interface.name, instance); | 404 | matrixInstance.isRegex() ? matrixInstance.regexPattern() |
405 | count++; | 405 | : matrixInstance.exactInstance()); |
406 | } | 406 | count++; |
407 | } | 407 | return true; |
408 | }); | ||
408 | if (count == 0) { | 409 | if (count == 0) { |
409 | s += "@" + to_string(vr); | 410 | s += "@" + to_string(vr); |
410 | } | 411 | } |
@@ -415,11 +416,11 @@ static std::string expandInstances(const MatrixHal& req, const VersionRange& vr, | |||
415 | } | 416 | } |
416 | 417 | ||
417 | std::vector<std::string> expandInstances(const MatrixHal& req) { | 418 | std::vector<std::string> expandInstances(const MatrixHal& req) { |
418 | if (req.versionRanges.empty()) { | 419 | size_t count = req.instancesCount(); |
420 | if (count == 0) { | ||
419 | return {}; | 421 | return {}; |
420 | } | 422 | } |
421 | if (req.versionRanges.size() == 1 && req.interfaces.size() == 1 && | 423 | if (count == 1) { |
422 | req.interfaces.begin()->second.instances.size() == 1) { | ||
423 | return {expandInstances(req, req.versionRanges.front(), false /* brace */)}; | 424 | return {expandInstances(req, req.versionRanges.front(), false /* brace */)}; |
424 | } | 425 | } |
425 | std::vector<std::string> ss; | 426 | std::vector<std::string> ss; |
diff --git a/parse_xml.cpp b/parse_xml.cpp index 38a09b4..27f31c9 100644 --- a/parse_xml.cpp +++ b/parse_xml.cpp | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <tinyxml2.h> | 26 | #include <tinyxml2.h> |
27 | 27 | ||
28 | #include "Regex.h" | ||
28 | #include "constants.h" | 29 | #include "constants.h" |
29 | #include "parse_string.h" | 30 | #include "parse_string.h" |
30 | 31 | ||
@@ -473,22 +474,40 @@ KernelConfigConverter kernelConfigConverter{}; | |||
473 | struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { | 474 | struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { |
474 | std::string elementName() const override { return "interface"; } | 475 | std::string elementName() const override { return "interface"; } |
475 | void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override { | 476 | void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override { |
476 | appendTextElement(root, "name", intf.name, d); | 477 | appendTextElement(root, "name", intf.name(), d); |
477 | appendTextElements(root, "instance", intf.instances, d); | 478 | appendTextElements(root, "instance", intf.mInstances, d); |
479 | appendTextElements(root, "regex-instance", intf.mRegexes, d); | ||
478 | } | 480 | } |
479 | bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override { | 481 | bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override { |
480 | std::vector<std::string> instances; | 482 | std::vector<std::string> instances; |
481 | if (!parseTextElement(root, "name", &intf->name, error) || | 483 | std::vector<std::string> regexes; |
482 | !parseTextElements(root, "instance", &instances, error)) { | 484 | if (!parseTextElement(root, "name", &intf->mName, error) || |
485 | !parseTextElements(root, "instance", &instances, error) || | ||
486 | !parseTextElements(root, "regex-instance", ®exes, error)) { | ||
483 | return false; | 487 | return false; |
484 | } | 488 | } |
485 | intf->instances.clear(); | 489 | bool success = true; |
486 | intf->instances.insert(instances.begin(), instances.end()); | 490 | for (const auto& e : instances) { |
487 | if (intf->instances.size() != instances.size()) { | 491 | if (!intf->insertInstance(e, false /* isRegex */)) { |
488 | *error = "Duplicated instances in " + intf->name; | 492 | if (!error->empty()) *error += "\n"; |
489 | return false; | 493 | *error += "Duplicated instance '" + e + "' in " + intf->name(); |
494 | success = false; | ||
495 | } | ||
490 | } | 496 | } |
491 | return true; | 497 | for (const auto& e : regexes) { |
498 | details::Regex regex; | ||
499 | if (!regex.compile(e)) { | ||
500 | if (!error->empty()) *error += "\n"; | ||
501 | *error += "Invalid regular expression '" + e + "' in " + intf->name(); | ||
502 | success = false; | ||
503 | } | ||
504 | if (!intf->insertInstance(e, true /* isRegex */)) { | ||
505 | if (!error->empty()) *error += "\n"; | ||
506 | *error += "Duplicated regex-instance '" + e + "' in " + intf->name(); | ||
507 | success = false; | ||
508 | } | ||
509 | } | ||
510 | return success; | ||
492 | } | 511 | } |
493 | }; | 512 | }; |
494 | 513 | ||
@@ -514,7 +533,7 @@ struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> { | |||
514 | return false; | 533 | return false; |
515 | } | 534 | } |
516 | for (auto&& interface : interfaces) { | 535 | for (auto&& interface : interfaces) { |
517 | std::string name{interface.name}; | 536 | std::string name{interface.name()}; |
518 | auto res = object->interfaces.emplace(std::move(name), std::move(interface)); | 537 | auto res = object->interfaces.emplace(std::move(name), std::move(interface)); |
519 | if (!res.second) { | 538 | if (!res.second) { |
520 | *error = "Duplicated interface entry \"" + res.first->first + | 539 | *error = "Duplicated interface entry \"" + res.first->first + |
@@ -663,8 +682,7 @@ struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> { | |||
663 | 682 | ||
664 | object->interfaces.clear(); | 683 | object->interfaces.clear(); |
665 | for (auto &&interface : interfaces) { | 684 | for (auto &&interface : interfaces) { |
666 | auto res = object->interfaces.emplace(interface.name, | 685 | auto res = object->interfaces.emplace(interface.name(), std::move(interface)); |
667 | std::move(interface)); | ||
668 | if (!res.second) { | 686 | if (!res.second) { |
669 | *error = "Duplicated interface entry \"" + res.first->first + | 687 | *error = "Duplicated interface entry \"" + res.first->first + |
670 | "\"; if additional instances are needed, add them to the " | 688 | "\"; if additional instances are needed, add them to the " |
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp index 7bdadcc..4c7aa23 100644 --- a/test/LibVintfTest.cpp +++ b/test/LibVintfTest.cpp | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <android-base/logging.h> | 28 | #include <android-base/logging.h> |
29 | #include <android-base/parseint.h> | 29 | #include <android-base/parseint.h> |
30 | #include <android-base/strings.h> | ||
30 | #include <gtest/gtest.h> | 31 | #include <gtest/gtest.h> |
31 | 32 | ||
32 | namespace android { | 33 | namespace android { |
@@ -111,13 +112,14 @@ public: | |||
111 | std::string* e) { | 112 | std::string* e) { |
112 | return cm1->addAllXmlFilesAsOptional(cm2, e); | 113 | return cm1->addAllXmlFilesAsOptional(cm2, e); |
113 | } | 114 | } |
115 | std::set<std::string> checkUnusedHals(const HalManifest& m, const CompatibilityMatrix& cm) { | ||
116 | return m.checkUnusedHals(cm); | ||
117 | } | ||
114 | 118 | ||
115 | std::map<std::string, HalInterface> testHalInterfaces() { | 119 | std::map<std::string, HalInterface> testHalInterfaces() { |
116 | HalInterface intf; | 120 | HalInterface intf("IFoo", {"default"}); |
117 | intf.name = "IFoo"; | ||
118 | intf.instances.insert("default"); | ||
119 | std::map<std::string, HalInterface> map; | 121 | std::map<std::string, HalInterface> map; |
120 | map[intf.name] = intf; | 122 | map[intf.name()] = intf; |
121 | return map; | 123 | return map; |
122 | } | 124 | } |
123 | 125 | ||
@@ -456,7 +458,7 @@ TEST_F(LibVintfTest, VersionConverter) { | |||
456 | } | 458 | } |
457 | 459 | ||
458 | static bool insert(std::map<std::string, HalInterface>* map, HalInterface&& intf) { | 460 | static bool insert(std::map<std::string, HalInterface>* map, HalInterface&& intf) { |
459 | std::string name{intf.name}; | 461 | std::string name{intf.name()}; |
460 | return map->emplace(std::move(name), std::move(intf)).second; | 462 | return map->emplace(std::move(name), std::move(intf)).second; |
461 | } | 463 | } |
462 | 464 | ||
@@ -3287,6 +3289,144 @@ TEST_F(LibVintfTest, FqNameInvalid) { | |||
3287 | EXPECT_IN("n07 4 v4l1d 1n73rf4c3", error); | 3289 | EXPECT_IN("n07 4 v4l1d 1n73rf4c3", error); |
3288 | } | 3290 | } |
3289 | 3291 | ||
3292 | TEST_F(LibVintfTest, RegexInstanceValid) { | ||
3293 | CompatibilityMatrix matrix; | ||
3294 | std::string error; | ||
3295 | |||
3296 | std::string xml = | ||
3297 | "<compatibility-matrix version=\"1.0\" type=\"framework\">\n" | ||
3298 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
3299 | " <name>android.hardware.foo</name>\n" | ||
3300 | " <version>1.0</version>\n" | ||
3301 | " <interface>\n" | ||
3302 | " <name>IFoo</name>\n" | ||
3303 | " <regex-instance>legacy/[0-9]+</regex-instance>\n" | ||
3304 | " <regex-instance>slot[0-9]+</regex-instance>\n" | ||
3305 | " <regex-instance>.*</regex-instance>\n" | ||
3306 | " </interface>\n" | ||
3307 | " </hal>\n" | ||
3308 | "</compatibility-matrix>\n"; | ||
3309 | EXPECT_TRUE(gCompatibilityMatrixConverter(&matrix, xml, &error)) << error; | ||
3310 | } | ||
3311 | |||
3312 | TEST_F(LibVintfTest, RegexInstanceInvalid) { | ||
3313 | CompatibilityMatrix matrix; | ||
3314 | std::string error; | ||
3315 | std::string xml = | ||
3316 | "<compatibility-matrix version=\"1.0\" type=\"framework\">\n" | ||
3317 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
3318 | " <name>android.hardware.foo</name>\n" | ||
3319 | " <version>1.0</version>\n" | ||
3320 | " <interface>\n" | ||
3321 | " <name>IFoo</name>\n" | ||
3322 | " <regex-instance>e{1,2,3}</regex-instance>\n" | ||
3323 | " <regex-instance>*</regex-instance>\n" | ||
3324 | " <regex-instance>+</regex-instance>\n" | ||
3325 | " <regex-instance>[0-9]+</regex-instance>\n" | ||
3326 | " <regex-instance>[0-9]+</regex-instance>\n" | ||
3327 | " </interface>\n" | ||
3328 | " </hal>\n" | ||
3329 | "</compatibility-matrix>\n"; | ||
3330 | EXPECT_FALSE(gCompatibilityMatrixConverter(&matrix, xml, &error)); | ||
3331 | EXPECT_IN("Invalid regular expression 'e{1,2,3}'", error); | ||
3332 | EXPECT_IN("Invalid regular expression '*'", error); | ||
3333 | EXPECT_IN("Invalid regular expression '+'", error); | ||
3334 | EXPECT_IN("Duplicated regex-instance '[0-9]+'", error); | ||
3335 | } | ||
3336 | |||
3337 | TEST_F(LibVintfTest, RegexInstanceCompat) { | ||
3338 | CompatibilityMatrix matrix; | ||
3339 | std::string error; | ||
3340 | |||
3341 | std::string xml = | ||
3342 | "<compatibility-matrix version=\"1.0\" type=\"framework\">\n" | ||
3343 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
3344 | " <name>android.hardware.foo</name>\n" | ||
3345 | " <version>1.0</version>\n" | ||
3346 | " <version>3.1-2</version>\n" | ||
3347 | " <interface>\n" | ||
3348 | " <name>IFoo</name>\n" | ||
3349 | " <instance>default</instance>\n" | ||
3350 | " <regex-instance>legacy/[0-9]+</regex-instance>\n" | ||
3351 | " </interface>\n" | ||
3352 | " </hal>\n" | ||
3353 | " <sepolicy>\n" | ||
3354 | " <kernel-sepolicy-version>0</kernel-sepolicy-version>\n" | ||
3355 | " <sepolicy-version>0.0</sepolicy-version>\n" | ||
3356 | " </sepolicy>\n" | ||
3357 | "</compatibility-matrix>\n"; | ||
3358 | EXPECT_TRUE(gCompatibilityMatrixConverter(&matrix, xml)) | ||
3359 | << gCompatibilityMatrixConverter.lastError(); | ||
3360 | |||
3361 | { | ||
3362 | std::string xml = | ||
3363 | "<manifest version=\"1.0\" type=\"device\">\n" | ||
3364 | " <hal format=\"hidl\">\n" | ||
3365 | " <name>android.hardware.foo</name>\n" | ||
3366 | " <transport>hwbinder</transport>\n" | ||
3367 | " <version>1.0</version>\n" | ||
3368 | " <interface>\n" | ||
3369 | " <name>IFoo</name>\n" | ||
3370 | " <instance>default</instance>\n" | ||
3371 | " <instance>legacy/0</instance>\n" | ||
3372 | " <instance>legacy/1</instance>\n" | ||
3373 | " </interface>\n" | ||
3374 | " </hal>\n" | ||
3375 | "</manifest>\n"; | ||
3376 | |||
3377 | HalManifest manifest; | ||
3378 | EXPECT_TRUE(gHalManifestConverter(&manifest, xml)); | ||
3379 | EXPECT_TRUE(manifest.checkCompatibility(matrix, &error)) << error; | ||
3380 | |||
3381 | auto unused = checkUnusedHals(manifest, matrix); | ||
3382 | EXPECT_TRUE(unused.empty()) | ||
3383 | << "Contains unused HALs: " << android::base::Join(unused, "\n"); | ||
3384 | } | ||
3385 | |||
3386 | { | ||
3387 | std::string xml = | ||
3388 | "<manifest version=\"1.0\" type=\"device\">\n" | ||
3389 | " <hal format=\"hidl\">\n" | ||
3390 | " <name>android.hardware.foo</name>\n" | ||
3391 | " <transport>hwbinder</transport>\n" | ||
3392 | " <version>1.0</version>\n" | ||
3393 | " <interface>\n" | ||
3394 | " <name>IFoo</name>\n" | ||
3395 | " <instance>default</instance>\n" | ||
3396 | " <instance>legacy0</instance>\n" | ||
3397 | " <instance>nonmatch/legacy/0</instance>\n" | ||
3398 | " <instance>legacy/0/nonmatch</instance>\n" | ||
3399 | " </interface>\n" | ||
3400 | " </hal>\n" | ||
3401 | "</manifest>\n"; | ||
3402 | |||
3403 | HalManifest manifest; | ||
3404 | EXPECT_TRUE(gHalManifestConverter(&manifest, xml)); | ||
3405 | EXPECT_FALSE(manifest.checkCompatibility(matrix, &error)) | ||
3406 | << "Should not be compatible because no legacy/[0-9]+ is provided."; | ||
3407 | |||
3408 | auto unused = checkUnusedHals(manifest, matrix); | ||
3409 | EXPECT_EQ((std::set<std::string>{"android.hardware.foo@1.0::IFoo/nonmatch/legacy/0", | ||
3410 | "android.hardware.foo@1.0::IFoo/legacy/0/nonmatch", | ||
3411 | "android.hardware.foo@1.0::IFoo/legacy0"}), | ||
3412 | unused); | ||
3413 | } | ||
3414 | } | ||
3415 | |||
3416 | TEST_F(LibVintfTest, Regex) { | ||
3417 | details::Regex regex; | ||
3418 | |||
3419 | EXPECT_FALSE(regex.compile("+")); | ||
3420 | EXPECT_FALSE(regex.compile("*")); | ||
3421 | |||
3422 | ASSERT_TRUE(regex.compile("legacy/[0-9]+")); | ||
3423 | EXPECT_TRUE(regex.matches("legacy/0")); | ||
3424 | EXPECT_TRUE(regex.matches("legacy/000")); | ||
3425 | EXPECT_FALSE(regex.matches("legacy/")); | ||
3426 | EXPECT_FALSE(regex.matches("ssslegacy/0")); | ||
3427 | EXPECT_FALSE(regex.matches("legacy/0sss")); | ||
3428 | } | ||
3429 | |||
3290 | } // namespace vintf | 3430 | } // namespace vintf |
3291 | } // namespace android | 3431 | } // namespace android |
3292 | 3432 | ||
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp index d2f62d1..48623b8 100644 --- a/test/vintf_object_tests.cpp +++ b/test/vintf_object_tests.cpp | |||
@@ -32,7 +32,7 @@ using namespace ::testing; | |||
32 | using namespace ::android::vintf; | 32 | using namespace ::android::vintf; |
33 | using namespace ::android::vintf::details; | 33 | using namespace ::android::vintf::details; |
34 | 34 | ||
35 | using android::FQName; | 35 | using android::FqInstance; |
36 | 36 | ||
37 | static bool In(const std::string& sub, const std::string& str) { | 37 | static bool In(const std::string& sub, const std::string& str) { |
38 | return str.find(sub) != std::string::npos; | 38 | return str.find(sub) != std::string::npos; |
@@ -227,6 +227,54 @@ const std::string systemMatrixLevel2 = | |||
227 | " </hal>\n" | 227 | " </hal>\n" |
228 | "</compatibility-matrix>\n"; | 228 | "</compatibility-matrix>\n"; |
229 | 229 | ||
230 | // | ||
231 | // Set of framework matrices of different FCM version with regex. | ||
232 | // | ||
233 | |||
234 | const static std::vector<std::string> systemMatrixRegexXmls = { | ||
235 | // 1.xml | ||
236 | "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n" | ||
237 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
238 | " <name>android.hardware.regex</name>\n" | ||
239 | " <version>1.0-1</version>\n" | ||
240 | " <interface>\n" | ||
241 | " <name>IRegex</name>\n" | ||
242 | " <instance>default</instance>\n" | ||
243 | " <instance>special/1.0</instance>\n" | ||
244 | " <regex-instance>regex/1.0/[0-9]+</regex-instance>\n" | ||
245 | " <regex-instance>regex_common/[0-9]+</regex-instance>\n" | ||
246 | " </interface>\n" | ||
247 | " </hal>\n" | ||
248 | "</compatibility-matrix>\n", | ||
249 | // 2.xml | ||
250 | "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n" | ||
251 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
252 | " <name>android.hardware.regex</name>\n" | ||
253 | " <version>1.1-2</version>\n" | ||
254 | " <interface>\n" | ||
255 | " <name>IRegex</name>\n" | ||
256 | " <instance>default</instance>\n" | ||
257 | " <instance>special/1.1</instance>\n" | ||
258 | " <regex-instance>regex/1.1/[0-9]+</regex-instance>\n" | ||
259 | " <regex-instance>[a-z]+_[a-z]+/[0-9]+</regex-instance>\n" | ||
260 | " </interface>\n" | ||
261 | " </hal>\n" | ||
262 | "</compatibility-matrix>\n", | ||
263 | // 3.xml | ||
264 | "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"3\">\n" | ||
265 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
266 | " <name>android.hardware.regex</name>\n" | ||
267 | " <version>2.0</version>\n" | ||
268 | " <interface>\n" | ||
269 | " <name>IRegex</name>\n" | ||
270 | " <instance>default</instance>\n" | ||
271 | " <instance>special/2.0</instance>\n" | ||
272 | " <regex-instance>regex/2.0/[0-9]+</regex-instance>\n" | ||
273 | " <regex-instance>regex_[a-z]+/[0-9]+</regex-instance>\n" | ||
274 | " </interface>\n" | ||
275 | " </hal>\n" | ||
276 | "</compatibility-matrix>\n"}; | ||
277 | |||
230 | // Setup the MockFileFetcher used by the fetchAllInformation template | 278 | // Setup the MockFileFetcher used by the fetchAllInformation template |
231 | // so it returns the given metadata info instead of fetching from device. | 279 | // so it returns the given metadata info instead of fetching from device. |
232 | void setupMockFetcher(const std::string& vendorManifestXml, const std::string& systemMatrixXml, | 280 | void setupMockFetcher(const std::string& vendorManifestXml, const std::string& systemMatrixXml, |
@@ -332,6 +380,16 @@ class VintfObjectTestBase : public testing::Test { | |||
332 | })); | 380 | })); |
333 | } | 381 | } |
334 | 382 | ||
383 | // Expect that a file exist and can be fetched 0 or more times. | ||
384 | void expectFetchRepeatedly(const std::string& path, const std::string& content) { | ||
385 | EXPECT_CALL(fetcher(), fetch(StrEq(path), _)) | ||
386 | .Times(AnyNumber()) | ||
387 | .WillRepeatedly(Invoke([content](const auto&, auto& out) { | ||
388 | out = content; | ||
389 | return ::android::OK; | ||
390 | })); | ||
391 | } | ||
392 | |||
335 | // Expect that the file should never be fetched (whether it exists or not). | 393 | // Expect that the file should never be fetched (whether it exists or not). |
336 | void expectNeverFetch(const std::string& path) { | 394 | void expectNeverFetch(const std::string& path) { |
337 | EXPECT_CALL(fetcher(), fetch(StrEq(path), _)).Times(0); | 395 | EXPECT_CALL(fetcher(), fetch(StrEq(path), _)).Times(0); |
@@ -837,24 +895,29 @@ TEST_F(OdmManifestTest, OdmLegacyManifest) { | |||
837 | EXPECT_TRUE(containsOdmManifest(p)); | 895 | EXPECT_TRUE(containsOdmManifest(p)); |
838 | } | 896 | } |
839 | 897 | ||
840 | struct FQInstance { | 898 | struct CheckedFqInstance : FqInstance { |
841 | FQName fqName; | 899 | CheckedFqInstance(const char* s) : CheckedFqInstance(std::string(s)) {} |
842 | std::string instance; | 900 | CheckedFqInstance(const std::string& s) { CHECK(setTo(s)) << s; } |
843 | |||
844 | FQInstance(const char* s) : FQInstance(std::string(s)) {} | ||
845 | FQInstance(const std::string& s) { | ||
846 | auto tokens = android::base::Split(s, "/"); | ||
847 | CHECK(2u == tokens.size()); | ||
848 | fqName = FQName(tokens[0]); | ||
849 | CHECK(fqName.isValid()); | ||
850 | instance = tokens[1]; | ||
851 | } | ||
852 | 901 | ||
853 | Version getVersion() const { | 902 | Version getVersion() const { return FqInstance::getVersion(); } |
854 | return Version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()}; | ||
855 | } | ||
856 | }; | 903 | }; |
857 | 904 | ||
905 | static VintfObject::ListInstances getInstanceListFunc( | ||
906 | const std::vector<CheckedFqInstance>& instances) { | ||
907 | return [instances](const std::string& package, Version version, const std::string& interface, | ||
908 | const auto& /* instanceHint */) { | ||
909 | std::vector<std::pair<std::string, Version>> ret; | ||
910 | for (auto&& existing : instances) { | ||
911 | if (existing.getPackage() == package && existing.getVersion().minorAtLeast(version) && | ||
912 | existing.getInterface() == interface) { | ||
913 | ret.push_back(std::make_pair(existing.getInstance(), existing.getVersion())); | ||
914 | } | ||
915 | } | ||
916 | |||
917 | return ret; | ||
918 | }; | ||
919 | } | ||
920 | |||
858 | class DeprecateTest : public VintfObjectTestBase { | 921 | class DeprecateTest : public VintfObjectTestBase { |
859 | protected: | 922 | protected: |
860 | virtual void SetUp() override { | 923 | virtual void SetUp() override { |
@@ -879,24 +942,10 @@ class DeprecateTest : public VintfObjectTestBase { | |||
879 | VintfObject::GetDeviceHalManifest(true /* skipCache */); | 942 | VintfObject::GetDeviceHalManifest(true /* skipCache */); |
880 | } | 943 | } |
881 | 944 | ||
882 | VintfObject::IsInstanceInUse getPredicate(const std::vector<FQInstance>& instances) { | ||
883 | return [instances](const std::string& package, Version version, | ||
884 | const std::string& interface, const std::string& instance) { | ||
885 | for (auto&& existing : instances) { | ||
886 | if (existing.fqName.package() == package && | ||
887 | existing.getVersion().minorAtLeast(version) && | ||
888 | existing.fqName.name() == interface && existing.instance == instance) { | ||
889 | return std::make_pair(true, existing.getVersion()); | ||
890 | } | ||
891 | } | ||
892 | |||
893 | return std::make_pair(false, Version{}); | ||
894 | }; | ||
895 | } | ||
896 | }; | 945 | }; |
897 | 946 | ||
898 | TEST_F(DeprecateTest, CheckNoDeprecate) { | 947 | TEST_F(DeprecateTest, CheckNoDeprecate) { |
899 | auto pred = getPredicate({ | 948 | auto pred = getInstanceListFunc({ |
900 | "android.hardware.minor@1.1::IMinor/default", | 949 | "android.hardware.minor@1.1::IMinor/default", |
901 | "android.hardware.major@2.0::IMajor/default", | 950 | "android.hardware.major@2.0::IMajor/default", |
902 | }); | 951 | }); |
@@ -905,7 +954,7 @@ TEST_F(DeprecateTest, CheckNoDeprecate) { | |||
905 | } | 954 | } |
906 | 955 | ||
907 | TEST_F(DeprecateTest, CheckRemoved) { | 956 | TEST_F(DeprecateTest, CheckRemoved) { |
908 | auto pred = getPredicate({ | 957 | auto pred = getInstanceListFunc({ |
909 | "android.hardware.removed@1.0::IRemoved/default", | 958 | "android.hardware.removed@1.0::IRemoved/default", |
910 | "android.hardware.minor@1.1::IMinor/default", | 959 | "android.hardware.minor@1.1::IMinor/default", |
911 | "android.hardware.major@2.0::IMajor/default", | 960 | "android.hardware.major@2.0::IMajor/default", |
@@ -916,7 +965,7 @@ TEST_F(DeprecateTest, CheckRemoved) { | |||
916 | } | 965 | } |
917 | 966 | ||
918 | TEST_F(DeprecateTest, CheckMinor) { | 967 | TEST_F(DeprecateTest, CheckMinor) { |
919 | auto pred = getPredicate({ | 968 | auto pred = getInstanceListFunc({ |
920 | "android.hardware.minor@1.0::IMinor/default", | 969 | "android.hardware.minor@1.0::IMinor/default", |
921 | "android.hardware.major@2.0::IMajor/default", | 970 | "android.hardware.major@2.0::IMajor/default", |
922 | }); | 971 | }); |
@@ -926,7 +975,7 @@ TEST_F(DeprecateTest, CheckMinor) { | |||
926 | } | 975 | } |
927 | 976 | ||
928 | TEST_F(DeprecateTest, CheckMinorDeprecatedInstance1) { | 977 | TEST_F(DeprecateTest, CheckMinorDeprecatedInstance1) { |
929 | auto pred = getPredicate({ | 978 | auto pred = getInstanceListFunc({ |
930 | "android.hardware.minor@1.0::IMinor/legacy", | 979 | "android.hardware.minor@1.0::IMinor/legacy", |
931 | "android.hardware.minor@1.1::IMinor/default", | 980 | "android.hardware.minor@1.1::IMinor/default", |
932 | "android.hardware.major@2.0::IMajor/default", | 981 | "android.hardware.major@2.0::IMajor/default", |
@@ -937,7 +986,7 @@ TEST_F(DeprecateTest, CheckMinorDeprecatedInstance1) { | |||
937 | } | 986 | } |
938 | 987 | ||
939 | TEST_F(DeprecateTest, CheckMinorDeprecatedInstance2) { | 988 | TEST_F(DeprecateTest, CheckMinorDeprecatedInstance2) { |
940 | auto pred = getPredicate({ | 989 | auto pred = getInstanceListFunc({ |
941 | "android.hardware.minor@1.1::IMinor/default", | 990 | "android.hardware.minor@1.1::IMinor/default", |
942 | "android.hardware.minor@1.1::IMinor/legacy", | 991 | "android.hardware.minor@1.1::IMinor/legacy", |
943 | "android.hardware.major@2.0::IMajor/default", | 992 | "android.hardware.major@2.0::IMajor/default", |
@@ -948,7 +997,7 @@ TEST_F(DeprecateTest, CheckMinorDeprecatedInstance2) { | |||
948 | } | 997 | } |
949 | 998 | ||
950 | TEST_F(DeprecateTest, CheckMajor1) { | 999 | TEST_F(DeprecateTest, CheckMajor1) { |
951 | auto pred = getPredicate({ | 1000 | auto pred = getInstanceListFunc({ |
952 | "android.hardware.minor@1.1::IMinor/default", | 1001 | "android.hardware.minor@1.1::IMinor/default", |
953 | "android.hardware.major@1.0::IMajor/default", | 1002 | "android.hardware.major@1.0::IMajor/default", |
954 | "android.hardware.major@2.0::IMajor/default", | 1003 | "android.hardware.major@2.0::IMajor/default", |
@@ -959,7 +1008,7 @@ TEST_F(DeprecateTest, CheckMajor1) { | |||
959 | } | 1008 | } |
960 | 1009 | ||
961 | TEST_F(DeprecateTest, CheckMajor2) { | 1010 | TEST_F(DeprecateTest, CheckMajor2) { |
962 | auto pred = getPredicate({ | 1011 | auto pred = getInstanceListFunc({ |
963 | "android.hardware.minor@1.1::IMinor/default", | 1012 | "android.hardware.minor@1.1::IMinor/default", |
964 | "android.hardware.major@1.0::IMajor/default", | 1013 | "android.hardware.major@1.0::IMajor/default", |
965 | }); | 1014 | }); |
@@ -968,6 +1017,201 @@ TEST_F(DeprecateTest, CheckMajor2) { | |||
968 | << "major@1.0 should be deprecated. " << error; | 1017 | << "major@1.0 should be deprecated. " << error; |
969 | } | 1018 | } |
970 | 1019 | ||
1020 | class RegexTest : public VintfObjectTestBase { | ||
1021 | protected: | ||
1022 | static std::string getFileName(size_t i) { | ||
1023 | return "compatibility_matrix." + std::to_string(static_cast<Level>(i)) + ".xml"; | ||
1024 | } | ||
1025 | virtual void SetUp() override { | ||
1026 | EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _)) | ||
1027 | .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { | ||
1028 | size_t i = 1; | ||
1029 | for (const auto& content : systemMatrixRegexXmls) { | ||
1030 | (void)content; | ||
1031 | out->push_back(getFileName(i)); | ||
1032 | ++i; | ||
1033 | } | ||
1034 | return ::android::OK; | ||
1035 | })); | ||
1036 | size_t i = 1; | ||
1037 | for (const auto& content : systemMatrixRegexXmls) { | ||
1038 | expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content); | ||
1039 | ++i; | ||
1040 | } | ||
1041 | expectSystemMatrix(0); | ||
1042 | expectFileNotExist(StartsWith("/odm/")); | ||
1043 | } | ||
1044 | void expectTargetFcmVersion(size_t level) { | ||
1045 | expectFetch(kVendorManifest, "<manifest version=\"1.0\" type=\"device\" target-level=\"" + | ||
1046 | to_string(static_cast<Level>(level)) + "\"/>"); | ||
1047 | VintfObject::GetDeviceHalManifest(true /* skipCache */); | ||
1048 | } | ||
1049 | }; | ||
1050 | |||
1051 | TEST_F(RegexTest, CombineLevel1) { | ||
1052 | expectTargetFcmVersion(1); | ||
1053 | auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */); | ||
1054 | ASSERT_NE(nullptr, matrix); | ||
1055 | std::string xml = gCompatibilityMatrixConverter(*matrix); | ||
1056 | |||
1057 | EXPECT_IN( | ||
1058 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
1059 | " <name>android.hardware.regex</name>\n" | ||
1060 | " <version>1.0-2</version>\n" | ||
1061 | " <version>2.0</version>\n" | ||
1062 | " <interface>\n" | ||
1063 | " <name>IRegex</name>\n" | ||
1064 | " <instance>default</instance>\n" | ||
1065 | " </interface>\n" | ||
1066 | " </hal>\n", | ||
1067 | xml); | ||
1068 | EXPECT_IN( | ||
1069 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
1070 | " <name>android.hardware.regex</name>\n" | ||
1071 | " <version>1.0-1</version>\n" | ||
1072 | " <interface>\n" | ||
1073 | " <name>IRegex</name>\n" | ||
1074 | " <instance>special/1.0</instance>\n" | ||
1075 | " <regex-instance>regex/1.0/[0-9]+</regex-instance>\n" | ||
1076 | " <regex-instance>regex_common/[0-9]+</regex-instance>\n" | ||
1077 | " </interface>\n" | ||
1078 | " </hal>\n", | ||
1079 | xml); | ||
1080 | EXPECT_IN( | ||
1081 | " <hal format=\"hidl\" optional=\"true\">\n" | ||
1082 | " <name>android.hardware.regex</name>\n" | ||
1083 | " <version>1.1-2</version>\n" | ||
1084 | " <interface>\n" | ||
1085 | " <name>IRegex</name>\n" | ||
1086 | " <instance>special/1.1</instance>\n" | ||
1087 | " <regex-instance>[a-z]+_[a-z]+/[0-9]+</regex-instance>\n" | ||
1088 | " <regex-instance>regex/1.1/[0-9]+</regex-instance>\n" | ||
1089 | " </interface>\n" | ||
1090 | " </hal>\n", | ||
1091 | xml); | ||
1092 | EXPECT_IN( | ||
1093 | " <hal format=\"hidl\" optional=\"true\">\n" | ||
1094 | " <name>android.hardware.regex</name>\n" | ||
1095 | " <version>2.0</version>\n" | ||
1096 | " <interface>\n" | ||
1097 | " <name>IRegex</name>\n" | ||
1098 | " <instance>special/2.0</instance>\n" | ||
1099 | " <regex-instance>regex/2.0/[0-9]+</regex-instance>\n" | ||
1100 | " <regex-instance>regex_[a-z]+/[0-9]+</regex-instance>\n" | ||
1101 | " </interface>\n" | ||
1102 | " </hal>\n", | ||
1103 | xml); | ||
1104 | } | ||
1105 | |||
1106 | TEST_F(RegexTest, CombineLevel2) { | ||
1107 | expectTargetFcmVersion(2); | ||
1108 | auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */); | ||
1109 | ASSERT_NE(nullptr, matrix); | ||
1110 | std::string xml = gCompatibilityMatrixConverter(*matrix); | ||
1111 | |||
1112 | EXPECT_IN( | ||
1113 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
1114 | " <name>android.hardware.regex</name>\n" | ||
1115 | " <version>1.1-2</version>\n" | ||
1116 | " <version>2.0</version>\n" | ||
1117 | " <interface>\n" | ||
1118 | " <name>IRegex</name>\n" | ||
1119 | " <instance>default</instance>\n" | ||
1120 | " </interface>\n" | ||
1121 | " </hal>\n", | ||
1122 | xml); | ||
1123 | EXPECT_IN( | ||
1124 | " <hal format=\"hidl\" optional=\"false\">\n" | ||
1125 | " <name>android.hardware.regex</name>\n" | ||
1126 | " <version>1.1-2</version>\n" | ||
1127 | " <interface>\n" | ||
1128 | " <name>IRegex</name>\n" | ||
1129 | " <instance>special/1.1</instance>\n" | ||
1130 | " <regex-instance>[a-z]+_[a-z]+/[0-9]+</regex-instance>\n" | ||
1131 | " <regex-instance>regex/1.1/[0-9]+</regex-instance>\n" | ||
1132 | " </interface>\n" | ||
1133 | " </hal>\n", | ||
1134 | xml); | ||
1135 | EXPECT_IN( | ||
1136 | " <hal format=\"hidl\" optional=\"true\">\n" | ||
1137 | " <name>android.hardware.regex</name>\n" | ||
1138 | " <version>2.0</version>\n" | ||
1139 | " <interface>\n" | ||
1140 | " <name>IRegex</name>\n" | ||
1141 | " <instance>special/2.0</instance>\n" | ||
1142 | " <regex-instance>regex/2.0/[0-9]+</regex-instance>\n" | ||
1143 | " <regex-instance>regex_[a-z]+/[0-9]+</regex-instance>\n" | ||
1144 | " </interface>\n" | ||
1145 | " </hal>\n", | ||
1146 | xml); | ||
1147 | } | ||
1148 | |||
1149 | TEST_F(RegexTest, DeprecateLevel2) { | ||
1150 | std::string error; | ||
1151 | expectTargetFcmVersion(2); | ||
1152 | |||
1153 | auto pred = getInstanceListFunc({ | ||
1154 | "android.hardware.regex@1.1::IRegex/default", | ||
1155 | "android.hardware.regex@1.1::IRegex/special/1.1", | ||
1156 | "android.hardware.regex@1.1::IRegex/regex/1.1/1", | ||
1157 | "android.hardware.regex@1.1::IRegex/regex_common/0", | ||
1158 | "android.hardware.regex@2.0::IRegex/default", | ||
1159 | }); | ||
1160 | EXPECT_EQ(NO_DEPRECATED_HALS, VintfObject::CheckDeprecation(pred, &error)) << error; | ||
1161 | |||
1162 | for (const auto& deprecated : { | ||
1163 | "android.hardware.regex@1.0::IRegex/default", | ||
1164 | "android.hardware.regex@1.0::IRegex/special/1.0", | ||
1165 | "android.hardware.regex@1.0::IRegex/regex/1.0/1", | ||
1166 | "android.hardware.regex@1.0::IRegex/regex_common/0", | ||
1167 | "android.hardware.regex@1.1::IRegex/special/1.0", | ||
1168 | "android.hardware.regex@1.1::IRegex/regex/1.0/1", | ||
1169 | }) { | ||
1170 | // 2.0/default ensures compatibility. | ||
1171 | pred = getInstanceListFunc({ | ||
1172 | deprecated, | ||
1173 | "android.hardware.regex@2.0::IRegex/default", | ||
1174 | }); | ||
1175 | error.clear(); | ||
1176 | EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error)) | ||
1177 | << deprecated << " should be deprecated. " << error; | ||
1178 | } | ||
1179 | } | ||
1180 | |||
1181 | TEST_F(RegexTest, DeprecateLevel3) { | ||
1182 | std::string error; | ||
1183 | expectTargetFcmVersion(3); | ||
1184 | |||
1185 | auto pred = getInstanceListFunc({ | ||
1186 | "android.hardware.regex@2.0::IRegex/special/2.0", | ||
1187 | "android.hardware.regex@2.0::IRegex/regex/2.0/1", | ||
1188 | "android.hardware.regex@2.0::IRegex/default", | ||
1189 | }); | ||
1190 | EXPECT_EQ(NO_DEPRECATED_HALS, VintfObject::CheckDeprecation(pred, &error)) << error; | ||
1191 | |||
1192 | for (const auto& deprecated : { | ||
1193 | "android.hardware.regex@1.0::IRegex/default", | ||
1194 | "android.hardware.regex@1.0::IRegex/special/1.0", | ||
1195 | "android.hardware.regex@1.0::IRegex/regex/1.0/1", | ||
1196 | "android.hardware.regex@1.0::IRegex/regex_common/0", | ||
1197 | "android.hardware.regex@1.1::IRegex/special/1.0", | ||
1198 | "android.hardware.regex@1.1::IRegex/regex/1.0/1", | ||
1199 | "android.hardware.regex@1.1::IRegex/special/1.1", | ||
1200 | "android.hardware.regex@1.1::IRegex/regex/1.1/1", | ||
1201 | "android.hardware.regex@1.1::IRegex/regex_common/0", | ||
1202 | }) { | ||
1203 | // 2.0/default ensures compatibility. | ||
1204 | pred = getInstanceListFunc({ | ||
1205 | deprecated, | ||
1206 | "android.hardware.regex@2.0::IRegex/default", | ||
1207 | }); | ||
1208 | |||
1209 | error.clear(); | ||
1210 | EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error)) | ||
1211 | << deprecated << " should be deprecated."; | ||
1212 | } | ||
1213 | } | ||
1214 | |||
971 | int main(int argc, char** argv) { | 1215 | int main(int argc, char** argv) { |
972 | ::testing::InitGoogleMock(&argc, argv); | 1216 | ::testing::InitGoogleMock(&argc, argv); |
973 | 1217 | ||