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