Home | History | Annotate | Download | only in vintf
      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 <hidl-util/FqInstance.h>
     20 #include <hidl/HidlTransportUtils.h>
     21 #include <vintf/parse_string.h>
     22 
     23 #include "utils.h"
     24 
     25 namespace android {
     26 namespace vintf {
     27 namespace testing {
     28 
     29 using android::FqInstance;
     30 using android::vintf::toFQNameString;
     31 
     32 // For devices that launched <= Android O-MR1, systems/hals/implementations
     33 // were delivered to companies which either don't start up on device boot.
     34 bool LegacyAndExempt(const FQName &fq_name) {
     35   return GetShippingApiLevel() <= 27 && !IsGoogleDefinedIface(fq_name);
     36 }
     37 
     38 void FailureHalMissing(const FQName &fq_name) {
     39   if (LegacyAndExempt(fq_name)) {
     40     cout << "[  WARNING ] " << fq_name.string()
     41          << " not available but is exempted because it is legacy. It is still "
     42             "recommended to fix this."
     43          << endl;
     44   } else {
     45     ADD_FAILURE() << fq_name.string() << " not available.";
     46   }
     47 }
     48 
     49 void FailureHashMissing(const FQName &fq_name) {
     50   if (LegacyAndExempt(fq_name)) {
     51     cout << "[  WARNING ] " << fq_name.string()
     52          << " has an empty hash but is exempted because it is legacy. It is "
     53             "still recommended to fix this. This is because it was compiled "
     54             "without being frozen in a corresponding current.txt file."
     55          << endl;
     56   } else {
     57     ADD_FAILURE()
     58         << fq_name.string()
     59         << " has an empty hash. This is because it was compiled "
     60            "without being frozen in a corresponding current.txt file.";
     61   }
     62 }
     63 
     64 // Tests that no HAL outside of the allowed set is specified as passthrough in
     65 // VINTF.
     66 TEST_P(SingleManifestTest, HalsAreBinderized) {
     67   // Verifies that HAL is binderized unless it's allowed to be passthrough.
     68   HalVerifyFn is_binderized = [](const FQName &fq_name,
     69                                  const string & /* instance_name */,
     70                                  Transport transport) {
     71     cout << "Verifying transport method of: " << fq_name.string() << endl;
     72     string hal_name = fq_name.package();
     73     Version version{fq_name.getPackageMajorVersion(),
     74                     fq_name.getPackageMinorVersion()};
     75     string iface_name = fq_name.name();
     76 
     77     EXPECT_NE(transport, Transport::EMPTY)
     78         << hal_name << " has no transport specified in VINTF.";
     79 
     80     if (transport == Transport::PASSTHROUGH) {
     81       EXPECT_NE(kPassthroughHals.find(hal_name), kPassthroughHals.end())
     82           << hal_name << " can't be passthrough under Treble rules.";
     83     }
     84   };
     85 
     86   ForEachHalInstance(GetParam(), is_binderized);
     87 }
     88 
     89 // Tests that all HALs specified in the VINTF are available through service
     90 // manager.
     91 // This tests (HAL in manifest) => (HAL is served)
     92 TEST_P(SingleManifestTest, HalsAreServed) {
     93   // Returns a function that verifies that HAL is available through service
     94   // manager and is served from a specific set of partitions.
     95   auto is_available_from = [this](Partition expected_partition) -> HalVerifyFn {
     96     return [this, expected_partition](const FQName &fq_name,
     97                                       const string &instance_name,
     98                                       Transport transport) {
     99       sp<IBase> hal_service;
    100 
    101       if (transport == Transport::PASSTHROUGH) {
    102         using android::hardware::details::canCastInterface;
    103 
    104         // Passthrough services all start with minor version 0.
    105         // there are only three of them listed above. They are looked
    106         // up based on their binary location. For instance,
    107         // V1_0::IFoo::getService() might correspond to looking up
    108         // android.hardware.foo (at) 1.0-impl for the symbol
    109         // HIDL_FETCH_IFoo. For @1.1::IFoo to continue to work with
    110         // 1.0 clients, it must also be present in a library that is
    111         // called the 1.0 name. Clients can say:
    112         //     mFoo1_0 = V1_0::IFoo::getService();
    113         //     mFoo1_1 = V1_1::IFoo::castFrom(mFoo1_0);
    114         // This is the standard pattern for making a service work
    115         // for both versions (mFoo1_1 != nullptr => you have 1.1)
    116         // and a 1.0 client still works with the 1.1 interface.
    117 
    118         if (!IsGoogleDefinedIface(fq_name)) {
    119           // This isn't the case for extensions of core Google interfaces.
    120           return;
    121         }
    122 
    123         const FQName lowest_name =
    124             fq_name.withVersion(fq_name.getPackageMajorVersion(), 0);
    125         hal_service = GetHalService(lowest_name, instance_name, transport);
    126         EXPECT_TRUE(
    127             canCastInterface(hal_service.get(), fq_name.string().c_str()))
    128             << fq_name.string() << " is not on the device.";
    129       } else {
    130         hal_service = GetHalService(fq_name, instance_name, transport);
    131       }
    132 
    133       if (hal_service == nullptr) {
    134         FailureHalMissing(fq_name);
    135         return;
    136       }
    137 
    138       EXPECT_EQ(transport == Transport::HWBINDER, hal_service->isRemote())
    139           << "transport is " << transport << "but HAL service is "
    140           << (hal_service->isRemote() ? "" : "not") << " remote.";
    141       EXPECT_EQ(transport == Transport::PASSTHROUGH, !hal_service->isRemote())
    142           << "transport is " << transport << "but HAL service is "
    143           << (hal_service->isRemote() ? "" : "not") << " remote.";
    144 
    145       if (!hal_service->isRemote()) return;
    146 
    147       Partition partition = GetPartition(hal_service);
    148       if (partition == Partition::UNKNOWN) return;
    149       EXPECT_EQ(expected_partition, partition)
    150           << fq_name.string() << " is in partition " << partition
    151           << " but is expected to be in " << expected_partition;
    152     };
    153   };
    154 
    155   auto manifest = GetParam();
    156   ForEachHalInstance(manifest,
    157                      is_available_from(PartitionOfType(manifest->type())));
    158 }
    159 
    160 // Tests that all HALs which are served are specified in the VINTF
    161 // This tests (HAL is served) => (HAL in manifest)
    162 TEST_P(SingleManifestTest, ServedHwbinderHalsAreInManifest) {
    163   auto manifest = GetParam();
    164   auto expected_partition = PartitionOfType(manifest->type());
    165   std::set<std::string> manifest_hwbinder_hals_ = GetHwbinderHals(manifest);
    166 
    167   Return<void> ret = default_manager_->list([&](const auto &list) {
    168     for (const auto &name : list) {
    169       if (std::string(name).find(IBase::descriptor) == 0) continue;
    170 
    171       FqInstance fqInstanceName;
    172       EXPECT_TRUE(fqInstanceName.setTo(name));
    173 
    174       auto service =
    175           GetHalService(toFQNameString(fqInstanceName.getPackage(),
    176                                        fqInstanceName.getVersion(),
    177                                        fqInstanceName.getInterface()),
    178                         fqInstanceName.getInstance(), Transport::HWBINDER);
    179       ASSERT_NE(service, nullptr);
    180 
    181       Partition partition = GetPartition(service);
    182       if (partition == Partition::UNKNOWN) {
    183         // Caught by SystemVendorTest.ServedHwbinderHalsAreInManifest
    184         // if that test is run.
    185         return;
    186       }
    187       if (partition == expected_partition) {
    188         EXPECT_NE(manifest_hwbinder_hals_.find(name),
    189                   manifest_hwbinder_hals_.end())
    190             << name << " is being served, but it is not in a manifest.";
    191       }
    192     }
    193   });
    194   EXPECT_TRUE(ret.isOk());
    195 }
    196 
    197 TEST_P(SingleManifestTest, ServedPassthroughHalsAreInManifest) {
    198   auto manifest = GetParam();
    199   std::set<std::string> manifest_passthrough_hals_ =
    200       GetPassthroughHals(manifest);
    201 
    202   auto passthrough_interfaces_declared = [&manifest_passthrough_hals_](
    203                                              const FQName &fq_name,
    204                                              const string &instance_name,
    205                                              Transport transport) {
    206     if (transport != Transport::PASSTHROUGH) return;
    207 
    208     // See HalsAreServed. These are always retrieved through the base interface
    209     // and if it is not a google defined interface, it must be an extension of
    210     // one.
    211     if (!IsGoogleDefinedIface(fq_name)) return;
    212 
    213     const FQName lowest_name =
    214         fq_name.withVersion(fq_name.getPackageMajorVersion(), 0);
    215     sp<IBase> hal_service =
    216         GetHalService(lowest_name, instance_name, transport);
    217     if (hal_service == nullptr) {
    218       ADD_FAILURE() << "Could not get service " << fq_name.string() << "/"
    219                     << instance_name;
    220       return;
    221     }
    222 
    223     Return<void> ret = hal_service->interfaceChain(
    224         [&manifest_passthrough_hals_, &instance_name](const auto &interfaces) {
    225           for (const auto &interface : interfaces) {
    226             if (std::string(interface) == IBase::descriptor) continue;
    227 
    228             const std::string instance =
    229                 std::string(interface) + "/" + instance_name;
    230             EXPECT_NE(manifest_passthrough_hals_.find(instance),
    231                       manifest_passthrough_hals_.end())
    232                 << "Instance missing from manifest: " << instance;
    233           }
    234         });
    235     EXPECT_TRUE(ret.isOk());
    236   };
    237   ForEachHalInstance(manifest, passthrough_interfaces_declared);
    238 }
    239 
    240 // Tests that HAL interfaces are officially released.
    241 TEST_P(SingleManifestTest, InterfacesAreReleased) {
    242   // Verifies that HAL are released by fetching the hash of the interface and
    243   // comparing it to the set of known hashes of released interfaces.
    244   HalVerifyFn is_released = [](const FQName &fq_name,
    245                                const string &instance_name,
    246                                Transport transport) {
    247     // See HalsAreServed. These are always retrieved through the base interface
    248     // and if it is not a google defined interface, it must be an extension of
    249     // one.
    250     if (transport == Transport::PASSTHROUGH &&
    251         (!IsGoogleDefinedIface(fq_name) ||
    252          fq_name.getPackageMinorVersion() != 0)) {
    253       return;
    254     }
    255 
    256     sp<IBase> hal_service = GetHalService(fq_name, instance_name, transport);
    257 
    258     if (hal_service == nullptr) {
    259       FailureHalMissing(fq_name);
    260       return;
    261     }
    262 
    263     vector<string> iface_chain = GetInterfaceChain(hal_service);
    264 
    265     vector<string> hash_chain{};
    266     hal_service->getHashChain(
    267         [&hash_chain](const hidl_vec<HashCharArray> &chain) {
    268           for (const HashCharArray &hash_array : chain) {
    269             vector<uint8_t> hash{hash_array.data(),
    270                                  hash_array.data() + hash_array.size()};
    271             hash_chain.push_back(Hash::hexString(hash));
    272           }
    273         });
    274 
    275     ASSERT_EQ(iface_chain.size(), hash_chain.size());
    276     for (size_t i = 0; i < iface_chain.size(); ++i) {
    277       FQName fq_iface_name;
    278       if (!FQName::parse(iface_chain[i], &fq_iface_name)) {
    279         ADD_FAILURE() << "Could not parse iface name " << iface_chain[i]
    280                       << " from interface chain of " << fq_name.string();
    281         return;
    282       }
    283       string hash = hash_chain[i];
    284 
    285       if (hash == Hash::hexString(Hash::kEmptyHash)) {
    286         FailureHashMissing(fq_iface_name);
    287       }
    288 
    289       if (IsGoogleDefinedIface(fq_iface_name)) {
    290         set<string> released_hashes = ReleasedHashes(fq_iface_name);
    291         EXPECT_NE(released_hashes.find(hash), released_hashes.end())
    292             << "Hash not found. This interface was not released." << endl
    293             << "Interface name: " << fq_iface_name.string() << endl
    294             << "Hash: " << hash << endl;
    295       }
    296     }
    297   };
    298 
    299   ForEachHalInstance(GetParam(), is_released);
    300 }
    301 
    302 }  // namespace testing
    303 }  // namespace vintf
    304 }  // namespace android
    305