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 "SingleManifestTest.h"
18
19 #include <android-base/strings.h>
20 #include <gmock/gmock.h>
21 #include <hidl-util/FqInstance.h>
22 #include <hidl/HidlTransportUtils.h>
23 #include <vintf/parse_string.h>
24
25 #include <algorithm>
26
27 #include "utils.h"
28
29 using ::testing::AnyOf;
30
31 namespace android {
32 namespace vintf {
33 namespace testing {
34
35 using android::FqInstance;
36 using android::vintf::toFQNameString;
37
38 // For devices that launched <= Android O-MR1, systems/hals/implementations
39 // were delivered to companies which either don't start up on device boot.
LegacyAndExempt(const FQName & fq_name)40 bool LegacyAndExempt(const FQName &fq_name) {
41 return GetShippingApiLevel() <= 27 && !IsAndroidPlatformInterface(fq_name);
42 }
43
FailureHalMissing(const FQName & fq_name)44 void FailureHalMissing(const FQName &fq_name) {
45 if (LegacyAndExempt(fq_name)) {
46 cout << "[ WARNING ] " << fq_name.string()
47 << " not available but is exempted because it is legacy. It is still "
48 "recommended to fix this."
49 << endl;
50 } else {
51 ADD_FAILURE() << fq_name.string() << " not available.";
52 }
53 }
54
FailureHashMissing(const FQName & fq_name)55 void FailureHashMissing(const FQName &fq_name) {
56 if (LegacyAndExempt(fq_name)) {
57 cout << "[ WARNING ] " << fq_name.string()
58 << " has an empty hash but is exempted because it is legacy. It is "
59 "still recommended to fix this. This is because it was compiled "
60 "without being frozen in a corresponding current.txt file."
61 << endl;
62 } else {
63 ADD_FAILURE()
64 << fq_name.string()
65 << " has an empty hash. This is because it was compiled "
66 "without being frozen in a corresponding current.txt file.";
67 }
68 }
69
70 template <typename It>
RangeInstancesToString(const std::pair<It,It> & range)71 static string RangeInstancesToString(const std::pair<It, It> &range) {
72 std::stringstream ss;
73 for (auto it = range.first; it != range.second; ++it) {
74 if (it != range.first) ss << ", ";
75 ss << it->second.string();
76 }
77 return ss.str();
78 }
79
80 template <typename Container>
InstancesToString(const Container & container)81 static string InstancesToString(const Container &container) {
82 std::stringstream ss;
83 for (auto it = container.begin(); it != container.end(); ++it) {
84 if (it != container.begin()) ss << ", ";
85 ss << *it;
86 }
87 return ss.str();
88 }
89
ToFqInstance(const string & interface,const string & instance)90 static FqInstance ToFqInstance(const string &interface,
91 const string &instance) {
92 FqInstance fq_interface;
93 FqInstance ret;
94
95 if (!fq_interface.setTo(interface)) {
96 ADD_FAILURE() << interface << " is not a valid FQName";
97 return ret;
98 }
99 if (!ret.setTo(fq_interface.getPackage(), fq_interface.getMajorVersion(),
100 fq_interface.getMinorVersion(), fq_interface.getInterface(),
101 instance)) {
102 ADD_FAILURE() << "Cannot convert to FqInstance: " << interface << "/"
103 << instance;
104 }
105 return ret;
106 }
107
108 // Given android.foo.bar@x.y::IFoo/default, attempt to get
109 // android.foo.bar@x.y::IFoo/default, android.foo.bar@x.(y-1)::IFoo/default,
110 // ... android.foo.bar@x.0::IFoo/default until the passthrough HAL is retrieved.
GetPassthroughService(const FqInstance & fq_instance)111 static sp<IBase> GetPassthroughService(const FqInstance &fq_instance) {
112 for (size_t minor_version = fq_instance.getMinorVersion();; --minor_version) {
113 // String out instance name from fq_instance.
114 FqInstance interface;
115 if (!interface.setTo(fq_instance.getPackage(),
116 fq_instance.getMajorVersion(), minor_version,
117 fq_instance.getInterface())) {
118 ADD_FAILURE() << fq_instance.string()
119 << " doesn't contain a valid FQName";
120 return nullptr;
121 }
122
123 auto hal_service = VtsTrebleVintfTestBase::GetHalService(
124 interface.string(), fq_instance.getInstance(), Transport::PASSTHROUGH);
125
126 if (hal_service != nullptr) {
127 bool interface_chain_valid = false;
128 hal_service->interfaceChain([&](const auto &chain) {
129 for (const auto &intf : chain) {
130 if (intf == interface.string()) {
131 interface_chain_valid = true;
132 return;
133 }
134 }
135 });
136 if (!interface_chain_valid) {
137 ADD_FAILURE() << "Retrieved " << interface.string() << "/"
138 << fq_instance.getInstance() << " as "
139 << fq_instance.string()
140 << " but interfaceChain() doesn't contain "
141 << fq_instance.string();
142 return nullptr;
143 }
144 cout << "Retrieved " << interface.string() << "/"
145 << fq_instance.getInstance() << " as " << fq_instance.string()
146 << endl;
147 return hal_service;
148 }
149
150 if (minor_version == 0) {
151 return nullptr;
152 }
153 }
154 ADD_FAILURE() << "Should not reach here";
155 return nullptr;
156 }
157
158 // Tests that no HAL outside of the allowed set is specified as passthrough in
159 // VINTF.
TEST_P(SingleManifestTest,HalsAreBinderized)160 TEST_P(SingleManifestTest, HalsAreBinderized) {
161 multimap<Transport, FqInstance> instances;
162 ForEachHalInstance(GetParam(), [&instances](const FQName &fq_name,
163 const string &instance_name,
164 Transport transport) {
165 FqInstance fqInstance;
166 ASSERT_TRUE(fqInstance.setTo(
167 fq_name.package(), fq_name.getPackageMajorVersion(),
168 fq_name.getPackageMinorVersion(), fq_name.name(), instance_name));
169 instances.emplace(transport, std::move(fqInstance));
170 });
171
172 for (auto it = instances.begin(); it != instances.end();
173 it = instances.upper_bound(it->first)) {
174 EXPECT_THAT(it->first, AnyOf(Transport::HWBINDER, Transport::PASSTHROUGH))
175 << "The following HALs has unknown transport specified in VINTF ("
176 << it->first << ", ordinal "
177 << static_cast<std::underlying_type_t<Transport>>(it->first) << ")"
178 << RangeInstancesToString(instances.equal_range(it->first));
179 }
180
181 auto passthrough_declared_range =
182 instances.equal_range(Transport::PASSTHROUGH);
183 set<FqInstance> passthrough_declared;
184 std::transform(
185 passthrough_declared_range.first, passthrough_declared_range.second,
186 std::inserter(passthrough_declared, passthrough_declared.begin()),
187 [](const auto &pair) { return pair.second; });
188
189 set<FqInstance> passthrough_allowed;
190 for (const auto &declared_instance : passthrough_declared) {
191 auto hal_service = GetPassthroughService(declared_instance);
192
193 // For vendor extensions, hal_service may be null because we don't know
194 // its interfaceChain()[1] to call getService(). However, the base interface
195 // should be declared in the manifest, so other iterations of this for-loop
196 // verify that vendor extension.
197 if (hal_service == nullptr) {
198 cout << "Skip calling interfaceChain on " << declared_instance.string()
199 << " because it can't be retrieved directly." << endl;
200 continue;
201 }
202
203 // For example, given the following interfaceChain when
204 // hal_service is "android.hardware.mapper@2.0::IMapper/default":
205 // ["vendor.foo.mapper@1.0::IMapper",
206 // "android.hardware.mapper@2.1::IMapper",
207 // "android.hardware.mapper@2.0::IMapper",
208 // "android.hidl.base@1.0::IBase"],
209 // Allow the following:
210 // ["vendor.foo.mapper@1.0::IMapper/default",
211 // "android.hardware.mapper@2.1::IMapper/default",
212 // "android.hardware.mapper@2.0::IMapper/default"]
213 hal_service->interfaceChain([&](const auto &chain) {
214 vector<FqInstance> fq_instances;
215 std::transform(
216 chain.begin(), chain.end(), std::back_inserter(fq_instances),
217 [&](const auto &interface) {
218 return ToFqInstance(interface, declared_instance.getInstance());
219 });
220
221 bool allowing = false;
222 for (auto it = fq_instances.rbegin(); it != fq_instances.rend(); ++it) {
223 if (kPassthroughHals.find(it->getPackage()) != kPassthroughHals.end()) {
224 allowing = true;
225 }
226 if (allowing) {
227 cout << it->string() << " is allowed to be passthrough" << endl;
228 passthrough_allowed.insert(*it);
229 }
230 }
231 });
232 }
233
234 set<FqInstance> passthrough_not_allowed;
235 std::set_difference(
236 passthrough_declared.begin(), passthrough_declared.end(),
237 passthrough_allowed.begin(), passthrough_allowed.end(),
238 std::inserter(passthrough_not_allowed, passthrough_not_allowed.begin()));
239
240 EXPECT_TRUE(passthrough_not_allowed.empty())
241 << "The following HALs can't be passthrough under Treble rules: ["
242 << InstancesToString(passthrough_not_allowed) << "].";
243 }
244
245 // Tests that all HALs specified in the VINTF are available through service
246 // manager.
247 // This tests (HAL in manifest) => (HAL is served)
TEST_P(SingleManifestTest,HalsAreServed)248 TEST_P(SingleManifestTest, HalsAreServed) {
249 // Returns a function that verifies that HAL is available through service
250 // manager and is served from a specific set of partitions.
251 auto is_available_from = [this](Partition expected_partition) -> HalVerifyFn {
252 return [this, expected_partition](const FQName &fq_name,
253 const string &instance_name,
254 Transport transport) {
255 sp<IBase> hal_service;
256
257 if (transport == Transport::PASSTHROUGH) {
258 using android::hardware::details::canCastInterface;
259
260 // Passthrough services all start with minor version 0.
261 // there are only three of them listed above. They are looked
262 // up based on their binary location. For instance,
263 // V1_0::IFoo::getService() might correspond to looking up
264 // android.hardware.foo@1.0-impl for the symbol
265 // HIDL_FETCH_IFoo. For @1.1::IFoo to continue to work with
266 // 1.0 clients, it must also be present in a library that is
267 // called the 1.0 name. Clients can say:
268 // mFoo1_0 = V1_0::IFoo::getService();
269 // mFoo1_1 = V1_1::IFoo::castFrom(mFoo1_0);
270 // This is the standard pattern for making a service work
271 // for both versions (mFoo1_1 != nullptr => you have 1.1)
272 // and a 1.0 client still works with the 1.1 interface.
273
274 if (!IsAndroidPlatformInterface(fq_name)) {
275 // This isn't the case for extensions of core Google interfaces.
276 return;
277 }
278
279 const FQName lowest_name =
280 fq_name.withVersion(fq_name.getPackageMajorVersion(), 0);
281 hal_service = GetHalService(lowest_name, instance_name, transport);
282 EXPECT_TRUE(
283 canCastInterface(hal_service.get(), fq_name.string().c_str()))
284 << fq_name.string() << " is not on the device.";
285 } else {
286 hal_service = GetHalService(fq_name, instance_name, transport);
287 }
288
289 if (hal_service == nullptr) {
290 FailureHalMissing(fq_name);
291 return;
292 }
293
294 EXPECT_EQ(transport == Transport::HWBINDER, hal_service->isRemote())
295 << "transport is " << transport << "but HAL service is "
296 << (hal_service->isRemote() ? "" : "not") << " remote.";
297 EXPECT_EQ(transport == Transport::PASSTHROUGH, !hal_service->isRemote())
298 << "transport is " << transport << "but HAL service is "
299 << (hal_service->isRemote() ? "" : "not") << " remote.";
300
301 if (!hal_service->isRemote()) return;
302
303 Partition partition = GetPartition(hal_service);
304 if (partition == Partition::UNKNOWN) return;
305 EXPECT_EQ(expected_partition, partition)
306 << fq_name.string() << "/" << instance_name << " is in partition "
307 << partition << " but is expected to be in " << expected_partition;
308 };
309 };
310
311 auto manifest = GetParam();
312 ForEachHalInstance(manifest,
313 is_available_from(PartitionOfType(manifest->type())));
314 }
315
316 // Tests that all HALs which are served are specified in the VINTF
317 // This tests (HAL is served) => (HAL in manifest)
TEST_P(SingleManifestTest,ServedHwbinderHalsAreInManifest)318 TEST_P(SingleManifestTest, ServedHwbinderHalsAreInManifest) {
319 auto manifest = GetParam();
320 auto expected_partition = PartitionOfType(manifest->type());
321 std::set<std::string> manifest_hwbinder_hals_ = GetHwbinderHals(manifest);
322
323 Return<void> ret = default_manager_->list([&](const auto &list) {
324 for (const auto &name : list) {
325 if (std::string(name).find(IBase::descriptor) == 0) continue;
326
327 FqInstance fqInstanceName;
328 EXPECT_TRUE(fqInstanceName.setTo(name));
329
330 auto service =
331 GetHalService(toFQNameString(fqInstanceName.getPackage(),
332 fqInstanceName.getVersion(),
333 fqInstanceName.getInterface()),
334 fqInstanceName.getInstance(), Transport::HWBINDER);
335 ASSERT_NE(service, nullptr);
336
337 Partition partition = GetPartition(service);
338 if (partition == Partition::UNKNOWN) {
339 // Caught by SystemVendorTest.ServedHwbinderHalsAreInManifest
340 // if that test is run.
341 return;
342 }
343 if (partition == expected_partition) {
344 EXPECT_NE(manifest_hwbinder_hals_.find(name),
345 manifest_hwbinder_hals_.end())
346 << name << " is being served, but it is not in a manifest.";
347 }
348 }
349 });
350 EXPECT_TRUE(ret.isOk());
351 }
352
TEST_P(SingleManifestTest,ServedPassthroughHalsAreInManifest)353 TEST_P(SingleManifestTest, ServedPassthroughHalsAreInManifest) {
354 auto manifest = GetParam();
355 std::set<std::string> manifest_passthrough_hals_ =
356 GetPassthroughHals(manifest);
357
358 auto passthrough_interfaces_declared = [&manifest_passthrough_hals_](
359 const FQName &fq_name,
360 const string &instance_name,
361 Transport transport) {
362 if (transport != Transport::PASSTHROUGH) return;
363
364 // See HalsAreServed. These are always retrieved through the base interface
365 // and if it is not a google defined interface, it must be an extension of
366 // one.
367 if (!IsAndroidPlatformInterface(fq_name)) return;
368
369 const FQName lowest_name =
370 fq_name.withVersion(fq_name.getPackageMajorVersion(), 0);
371 sp<IBase> hal_service =
372 GetHalService(lowest_name, instance_name, transport);
373 if (hal_service == nullptr) {
374 ADD_FAILURE() << "Could not get service " << fq_name.string() << "/"
375 << instance_name;
376 return;
377 }
378
379 Return<void> ret = hal_service->interfaceChain(
380 [&manifest_passthrough_hals_, &instance_name](const auto &interfaces) {
381 for (const auto &interface : interfaces) {
382 if (std::string(interface) == IBase::descriptor) continue;
383
384 const std::string instance =
385 std::string(interface) + "/" + instance_name;
386 EXPECT_NE(manifest_passthrough_hals_.find(instance),
387 manifest_passthrough_hals_.end())
388 << "Instance missing from manifest: " << instance;
389 }
390 });
391 EXPECT_TRUE(ret.isOk());
392 };
393 ForEachHalInstance(manifest, passthrough_interfaces_declared);
394 }
395
396 // Tests that HAL interfaces are officially released.
TEST_P(SingleManifestTest,InterfacesAreReleased)397 TEST_P(SingleManifestTest, InterfacesAreReleased) {
398 // Verifies that HAL are released by fetching the hash of the interface and
399 // comparing it to the set of known hashes of released interfaces.
400 HalVerifyFn is_released = [](const FQName &fq_name,
401 const string &instance_name,
402 Transport transport) {
403 // See HalsAreServed. These are always retrieved through the base interface
404 // and if it is not a google defined interface, it must be an extension of
405 // one.
406 if (transport == Transport::PASSTHROUGH &&
407 (!IsAndroidPlatformInterface(fq_name) ||
408 fq_name.getPackageMinorVersion() != 0)) {
409 return;
410 }
411
412 sp<IBase> hal_service = GetHalService(fq_name, instance_name, transport);
413
414 if (hal_service == nullptr) {
415 FailureHalMissing(fq_name);
416 return;
417 }
418
419 vector<string> iface_chain = GetInterfaceChain(hal_service);
420
421 vector<string> hash_chain{};
422 hal_service->getHashChain(
423 [&hash_chain](const hidl_vec<HashCharArray> &chain) {
424 for (const HashCharArray &hash_array : chain) {
425 vector<uint8_t> hash{hash_array.data(),
426 hash_array.data() + hash_array.size()};
427 hash_chain.push_back(Hash::hexString(hash));
428 }
429 });
430
431 ASSERT_EQ(iface_chain.size(), hash_chain.size());
432 for (size_t i = 0; i < iface_chain.size(); ++i) {
433 FQName fq_iface_name;
434 if (!FQName::parse(iface_chain[i], &fq_iface_name)) {
435 ADD_FAILURE() << "Could not parse iface name " << iface_chain[i]
436 << " from interface chain of " << fq_name.string();
437 return;
438 }
439 string hash = hash_chain[i];
440
441 if (hash == Hash::hexString(Hash::kEmptyHash)) {
442 FailureHashMissing(fq_iface_name);
443 }
444
445 if (IsAndroidPlatformInterface(fq_iface_name)) {
446 set<string> released_hashes = ReleasedHashes(fq_iface_name);
447 EXPECT_NE(released_hashes.find(hash), released_hashes.end())
448 << "Hash not found. This interface was not released." << endl
449 << "Interface name: " << fq_iface_name.string() << endl
450 << "Hash: " << hash << endl;
451 }
452 }
453 };
454
455 ForEachHalInstance(GetParam(), is_released);
456 }
457
458 } // namespace testing
459 } // namespace vintf
460 } // namespace android
461