• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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