1 /*
2 * Copyright (C) 2017 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 #define LOG_TAG "VtsTestabilityChecker"
17
18 #include "VtsTestabilityChecker.h"
19
20 #include <algorithm>
21 #include <iostream>
22 #include <set>
23
24 #include <android-base/strings.h>
25 #include <vintf/parse_string.h>
26
27 using android::base::Join;
28 using android::vintf::Arch;
29 using android::vintf::CompatibilityMatrix;
30 using android::vintf::gArchStrings;
31 using android::vintf::HalManifest;
32 using android::vintf::ManifestHal;
33 using android::vintf::ManifestInstance;
34 using android::vintf::MatrixHal;
35 using android::vintf::MatrixInstance;
36 using android::vintf::toFQNameString;
37 using android::vintf::Transport;
38 using android::vintf::Version;
39 using android::vintf::operator<<;
40 using std::set;
41 using std::string;
42 using std::vector;
43
44 namespace android {
45 namespace vts {
46
CheckHalForComplianceTest(const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,const Arch & arch,set<string> * instances)47 bool VtsTestabilityChecker::CheckHalForComplianceTest(
48 const string& hal_package_name, const Version& hal_version,
49 const string& hal_interface_name, const Arch& arch,
50 set<string>* instances) {
51 CHECK(instances) << "instances set should not be NULL.";
52 set<string> famework_hal_instances;
53 set<string> vendor_hal_instances;
54 bool check_framework_hal = CheckFrameworkManifestHal(
55 hal_package_name, hal_version, hal_interface_name, arch,
56 &famework_hal_instances);
57 bool check_vendor_hal =
58 CheckVendorManifestHal(hal_package_name, hal_version, hal_interface_name,
59 arch, &vendor_hal_instances);
60 set_union(famework_hal_instances.begin(), famework_hal_instances.end(),
61 vendor_hal_instances.begin(), vendor_hal_instances.end(),
62 std::inserter(*instances, instances->begin()));
63 return check_framework_hal || check_vendor_hal;
64 }
65
CheckHalForNonComplianceTest(const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,const Arch & arch,set<string> * instances)66 bool VtsTestabilityChecker::CheckHalForNonComplianceTest(
67 const string& hal_package_name, const Version& hal_version,
68 const string& hal_interface_name, const Arch& arch,
69 set<string>* instances) {
70 CHECK(instances) << "instances set should not be NULL.";
71 set<string> vendor_hal_instances;
72 set<string> test_hal_instances;
73 bool check_vendor_hal =
74 CheckVendorManifestHal(hal_package_name, hal_version, hal_interface_name,
75 arch, &vendor_hal_instances);
76
77 bool check_test_hal = CheckTestHalWithHwManager(
78 hal_package_name, hal_version, hal_interface_name, &test_hal_instances);
79
80 set_union(vendor_hal_instances.begin(), vendor_hal_instances.end(),
81 test_hal_instances.begin(), test_hal_instances.end(),
82 std::inserter(*instances, instances->begin()));
83 return check_vendor_hal || check_test_hal;
84 }
85
FindInstance(const vector<ManifestInstance> & manifest_instances,const MatrixInstance & matrix_instance)86 vector<const ManifestInstance*> VtsTestabilityChecker::FindInstance(
87 const vector<ManifestInstance>& manifest_instances,
88 const MatrixInstance& matrix_instance) {
89 vector<const ManifestInstance*> ret;
90 for (const auto& e : manifest_instances) {
91 if (matrix_instance.matchInstance(e.instance())) {
92 ret.push_back(&e);
93 }
94 }
95 return ret;
96 }
97
FindInterface(const vector<ManifestInstance> & manifest_instances,const MatrixInstance & matrix_instance)98 vector<const ManifestInstance*> VtsTestabilityChecker::FindInterface(
99 const vector<ManifestInstance>& manifest_instances,
100 const MatrixInstance& matrix_instance) {
101 vector<const ManifestInstance*> ret;
102 for (const auto& e : manifest_instances) {
103 if (e.interface() == matrix_instance.interface()) {
104 ret.push_back(&e);
105 }
106 }
107 return ret;
108 }
109
CheckFrameworkCompatibleHal(const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,const Arch & arch,set<string> * instances)110 bool VtsTestabilityChecker::CheckFrameworkCompatibleHal(
111 const string& hal_package_name, const Version& hal_version,
112 const string& hal_interface_name, const Arch& arch,
113 set<string>* instances) {
114 CHECK(instances) << "instances set should not be NULL.";
115
116 auto matrix_instances = framework_comp_matrix_->getFqInstances(
117 hal_package_name, hal_version, hal_interface_name);
118 auto manifest_instances = device_hal_manifest_->getFqInstances(
119 hal_package_name, hal_version, hal_interface_name);
120
121 bool testable = false;
122
123 for (const auto& matrix_instance : matrix_instances) {
124 const auto& matched_instances =
125 FindInstance(manifest_instances, matrix_instance);
126 if (!matrix_instance.optional() && matched_instances.empty()) {
127 // In matrix but not in manifest.
128 // The test should still run, but expect the test
129 // to fail (due to incompatible vendor and framework HAL).
130 LOG(ERROR) << "Compatibility error. Hal " << hal_package_name
131 << " is required by framework but not supported by vendor";
132 if (!hal_interface_name.empty()) {
133 if (!matrix_instance.isRegex()) {
134 instances->insert(matrix_instance.exactInstance());
135 } else {
136 LOG(ERROR) << "Ignore regex-instance '"
137 << matrix_instance.regexPattern();
138 }
139 }
140 testable |= true;
141 continue;
142 }
143
144 if (hal_interface_name.empty()) {
145 testable |= !matched_instances.empty();
146 continue;
147 }
148
149 auto get_testable_instances =
150 [&](const vector<const vintf::ManifestInstance*>& manifest_instances) {
151 vector<string> ret;
152 for (const auto& manifest_instance : manifest_instances) {
153 if ((manifest_instance->transport() == Transport::PASSTHROUGH &&
154 CheckPassthroughManifestArch(manifest_instance->arch(),
155 arch)) ||
156 manifest_instance->transport() == Transport::HWBINDER) {
157 ret.push_back(manifest_instance->instance());
158 }
159 }
160 return ret;
161 };
162
163 auto testable_instances = get_testable_instances(matched_instances);
164 if (!testable_instances.empty()) {
165 instances->insert(testable_instances.begin(), testable_instances.end());
166 testable |= true;
167 continue;
168 }
169
170 // Special case: if a.h.foo@1.0::IFoo/default is in matrix but /custom
171 // is in manifest, the interface is still testable, but /default should
172 // not be added to instances.
173 const auto& matched_interface_instances =
174 FindInterface(manifest_instances, matrix_instance);
175 auto testable_interfaces =
176 get_testable_instances(matched_interface_instances);
177 if (!testable_interfaces.empty()) {
178 testable |= true;
179 continue;
180 }
181 }
182 if (instances->empty()) {
183 LOG(ERROR) << "Hal "
184 << toFQNameString(hal_package_name, hal_version,
185 hal_interface_name)
186 << " has no testable instance";
187 }
188 return testable;
189 }
190
CheckPassthroughManifestArch(const Arch & manifest_arch,const Arch & arch)191 bool VtsTestabilityChecker::CheckPassthroughManifestArch(
192 const Arch& manifest_arch, const Arch& arch) {
193 switch (arch) {
194 case Arch::ARCH_32: {
195 if (android::vintf::has32(manifest_arch)) {
196 return true;
197 }
198 break;
199 }
200 case Arch::ARCH_64: {
201 if (android::vintf::has64(manifest_arch)) {
202 return true;
203 }
204 break;
205 }
206 default: {
207 LOG(ERROR) << "Unexpected arch to check: " << arch;
208 break;
209 }
210 }
211 return false;
212 }
213
CheckFrameworkManifestHal(const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,const Arch & arch,set<string> * instances)214 bool VtsTestabilityChecker::CheckFrameworkManifestHal(
215 const string& hal_package_name, const Version& hal_version,
216 const string& hal_interface_name, const Arch& arch,
217 set<string>* instances) {
218 return CheckManifestHal(framework_hal_manifest_, hal_package_name,
219 hal_version, hal_interface_name, arch, instances);
220 }
221
CheckVendorManifestHal(const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,const Arch & arch,set<string> * instances)222 bool VtsTestabilityChecker::CheckVendorManifestHal(
223 const string& hal_package_name, const Version& hal_version,
224 const string& hal_interface_name, const Arch& arch,
225 set<string>* instances) {
226 return CheckManifestHal(device_hal_manifest_, hal_package_name, hal_version,
227 hal_interface_name, arch, instances);
228 }
229
CheckManifestHal(const HalManifest * hal_manifest,const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,const Arch & arch,set<string> * instances)230 bool VtsTestabilityChecker::CheckManifestHal(const HalManifest* hal_manifest,
231 const string& hal_package_name,
232 const Version& hal_version,
233 const string& hal_interface_name,
234 const Arch& arch,
235 set<string>* instances) {
236 CHECK(instances) << "instances set should not be NULL.";
237
238 const auto& manifest_instances = hal_manifest->getFqInstances(
239 hal_package_name, hal_version, hal_interface_name);
240
241 const auto& fq_instance_name =
242 toFQNameString(hal_package_name, hal_version, hal_interface_name);
243
244 if (manifest_instances.empty()) {
245 LOG(DEBUG) << "Does not find instances for " << fq_instance_name
246 << " in manifest file";
247 return false;
248 }
249
250 bool testable = false;
251 for (const auto& manifest_instance : manifest_instances) {
252 if (manifest_instance.transport() == Transport::PASSTHROUGH &&
253 !CheckPassthroughManifestArch(manifest_instance.arch(), arch)) {
254 LOG(DEBUG) << "Manifest HAL " << fq_instance_name
255 << " is passthrough and does not support arch " << arch;
256 continue; // skip this instance
257 }
258 if (!hal_interface_name.empty()) {
259 instances->insert(manifest_instance.instance());
260 }
261 testable = true;
262 }
263 return testable;
264 }
265
CheckTestHalWithHwManager(const string & hal_package_name,const Version & hal_version,const string & hal_interface_name,set<string> * instances)266 bool VtsTestabilityChecker::CheckTestHalWithHwManager(
267 const string& hal_package_name, const Version& hal_version,
268 const string& hal_interface_name, set<string>* instances) {
269 CHECK(instances) << "instances set should not be NULL.";
270
271 string fqName =
272 toFQNameString(hal_package_name, hal_version, hal_interface_name);
273 bool registered = false;
274 hardware::Return<void> res;
275 if (!hal_interface_name.empty()) {
276 res = sm_->listByInterface(fqName, [&](const auto& registered_instances) {
277 for (const string& instance : registered_instances) {
278 registered = true;
279 instances->insert(instance);
280 }
281 });
282 } else { // handle legacy data without interface info.
283 res = sm_->list([&](const auto& services) {
284 for (const string& service : services) {
285 if (service.find(fqName) == 0) {
286 registered = true;
287 break;
288 }
289 }
290 });
291 }
292 if (!res.isOk()) {
293 LOG(ERROR) << "failed to check services: " << res.description();
294 return false;
295 }
296 return registered;
297 }
298
299 } // namespace vts
300 } // namespace android
301