summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandroid-build-team Robot2018-03-25 02:24:57 -0500
committerandroid-build-team Robot2018-03-25 02:24:57 -0500
commit804cfa5802b89600b204ff194d879ec03ce2a26f (patch)
treeff549f243107bf2a6b6c0c5246131d763b153a91
parent106ff9b2fb1fdc39190c995312f9341efd5f0cb9 (diff)
parentbb86f253002a9c3d3ff3bd55f1c219c0f7a53738 (diff)
downloadplatform-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.bp1
-rw-r--r--CompatibilityMatrix.cpp61
-rw-r--r--HalInterface.cpp47
-rw-r--r--HalManifest.cpp27
-rw-r--r--ManifestHal.cpp16
-rw-r--r--MatrixHal.cpp93
-rw-r--r--MatrixInstance.cpp45
-rw-r--r--Regex.cpp51
-rw-r--r--VintfObject.cpp111
-rw-r--r--include/vintf/CompatibilityMatrix.h7
-rw-r--r--include/vintf/HalGroup.h23
-rw-r--r--include/vintf/HalInterface.h33
-rw-r--r--include/vintf/HalManifest.h8
-rw-r--r--include/vintf/ManifestHal.h2
-rw-r--r--include/vintf/MatrixHal.h19
-rw-r--r--include/vintf/MatrixInstance.h22
-rw-r--r--include/vintf/Regex.h57
-rw-r--r--include/vintf/VintfObject.h29
-rw-r--r--main.cpp4
-rw-r--r--parse_string.cpp23
-rw-r--r--parse_xml.cpp44
-rw-r--r--test/LibVintfTest.cpp150
-rw-r--r--test/vintf_object_tests.cpp318
23 files changed, 935 insertions, 256 deletions
diff --git a/Android.bp b/Android.bp
index 03267a5..83a3586 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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.
84MatrixHal* CompatibilityMatrix::splitInstance(MatrixHal* existingHal, const std::string& interface, 84MatrixHal* 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
362bool 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 {
23namespace vintf { 23namespace vintf {
24 24
25bool operator==(const HalInterface& lft, const HalInterface& rgt) { 25bool 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
31bool 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
46bool 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
55bool 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
63bool 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.
427std::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(...).
438bool 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 {
51bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const { 51bool 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
143void 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
46std::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
55bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const { 46bool 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&)>
64bool MatrixHal::forEachInstance(const VersionRange& vr, 55bool 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
80bool MatrixHal::forEachInstance( 77bool 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
148void MatrixHal::insertInstance(const std::string& interface, const std::string& instance) { 147void 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
155bool 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
164bool MatrixHal::hasInstance(const std::string& interface, const std::string& instance) const { 155size_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
173bool MatrixHal::hasOnlyInstance(const std::string& interface, const std::string& instance) const { 164bool 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
190bool 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
198void MatrixHal::clearInstances() { 173void 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
21namespace android { 23namespace android {
22namespace vintf { 24namespace vintf {
23 25
@@ -31,12 +33,16 @@ MatrixInstance& MatrixInstance::operator=(const MatrixInstance&) = default;
31 33
32MatrixInstance& MatrixInstance::operator=(MatrixInstance&&) = default; 34MatrixInstance& MatrixInstance::operator=(MatrixInstance&&) = default;
33 35
34MatrixInstance::MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional) 36MatrixInstance::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
37MatrixInstance::MatrixInstance(const FqInstance fqInstance, const VersionRange& range, 43MatrixInstance::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
41const std::string& MatrixInstance::package() const { 47const 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
53const std::string& MatrixInstance::instance() const {
54 return mFqInstance.getInstance();
55}
56
57bool MatrixInstance::optional() const { 59bool MatrixInstance::optional() const {
58 return mOptional; 60 return mOptional;
59} 61}
@@ -61,7 +63,32 @@ bool MatrixInstance::optional() const {
61bool MatrixInstance::isSatisfiedBy(const FqInstance& provided) const { 63bool 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
69bool 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
80const std::string& MatrixInstance::regexPattern() const {
81 static const std::string kEmptyString;
82 return isRegex() ? mFqInstance.getInstance() : kEmptyString;
83}
84
85const std::string& MatrixInstance::exactInstance() const {
86 static const std::string kEmptyString;
87 return isRegex() ? kEmptyString : mFqInstance.getInstance();
88}
89
90bool 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
19namespace android {
20namespace vintf {
21namespace details {
22
23Regex::~Regex() {
24 clear();
25}
26
27void Regex::clear() {
28 if (mImpl != nullptr) {
29 regfree(mImpl.get());
30 mImpl = nullptr;
31 }
32}
33
34bool 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
41bool 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
578bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal, 578bool 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
598bool 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)
597bool 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
645int32_t VintfObject::CheckDeprecation(const IsInstanceInUse& isInstanceInUse, 661int32_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,
690int32_t VintfObject::CheckDeprecation(std::string* error) { 705int32_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
23namespace android { 26namespace android {
24namespace vintf { 27namespace vintf {
25 28
26// manifest.hal.interface element / compatibility-matrix.hal.interface element 29// manifest.hal.interface element / compatibility-matrix.hal.interface element
27struct HalInterface { 30struct 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
32bool 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
23namespace android {
24namespace vintf {
25namespace 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.
30class 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
163enum : int32_t { 172enum : int32_t {
diff --git a/main.cpp b/main.cpp
index 1c3dfef..c501bf7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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
398static std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) { 398std::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
417std::vector<std::string> expandInstances(const MatrixHal& req) { 418std::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{};
473struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { 474struct 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", &regexes, 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
32namespace android { 33namespace 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
458static bool insert(std::map<std::string, HalInterface>* map, HalInterface&& intf) { 460static 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
3292TEST_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
3312TEST_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
3337TEST_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
3416TEST_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;
32using namespace ::android::vintf; 32using namespace ::android::vintf;
33using namespace ::android::vintf::details; 33using namespace ::android::vintf::details;
34 34
35using android::FQName; 35using android::FqInstance;
36 36
37static bool In(const std::string& sub, const std::string& str) { 37static 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
234const 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.
232void setupMockFetcher(const std::string& vendorManifestXml, const std::string& systemMatrixXml, 280void 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
840struct FQInstance { 898struct 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
905static 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
858class DeprecateTest : public VintfObjectTestBase { 921class 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
898TEST_F(DeprecateTest, CheckNoDeprecate) { 947TEST_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
907TEST_F(DeprecateTest, CheckRemoved) { 956TEST_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
918TEST_F(DeprecateTest, CheckMinor) { 967TEST_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
928TEST_F(DeprecateTest, CheckMinorDeprecatedInstance1) { 977TEST_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
939TEST_F(DeprecateTest, CheckMinorDeprecatedInstance2) { 988TEST_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
950TEST_F(DeprecateTest, CheckMajor1) { 999TEST_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
961TEST_F(DeprecateTest, CheckMajor2) { 1010TEST_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
1020class 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
1051TEST_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
1106TEST_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
1149TEST_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
1181TEST_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
971int main(int argc, char** argv) { 1215int main(int argc, char** argv) {
972 ::testing::InitGoogleMock(&argc, argv); 1216 ::testing::InitGoogleMock(&argc, argv);
973 1217