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