1 /* 2 * Copyright (C) 2017 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 #define LOG_TAG "libvintf" 18 #include <android-base/logging.h> 19 20 #include "HalManifest.h" 21 22 #include <dirent.h> 23 24 #include <mutex> 25 #include <set> 26 27 #include <android-base/strings.h> 28 29 #include "parse_string.h" 30 #include "parse_xml.h" 31 #include "utils.h" 32 #include "CompatibilityMatrix.h" 33 34 namespace android { 35 namespace vintf { 36 37 using details::Instances; 38 using details::InstancesOfVersion; 39 40 // Check <version> tag for all <hal> with the same name. 41 bool HalManifest::shouldAdd(const ManifestHal& hal) const { 42 if (!hal.isValid()) { 43 return false; 44 } 45 if (hal.isOverride()) { 46 return true; 47 } 48 auto existingHals = mHals.equal_range(hal.name); 49 std::set<size_t> existingMajorVersions; 50 for (auto it = existingHals.first; it != existingHals.second; ++it) { 51 for (const auto& v : it->second.versions) { 52 // Assume integrity on existingHals, so no check on emplace().second 53 existingMajorVersions.insert(v.majorVer); 54 } 55 } 56 for (const auto& v : hal.versions) { 57 if (!existingMajorVersions.emplace(v.majorVer).second /* no insertion */) { 58 return false; 59 } 60 } 61 return true; 62 } 63 64 // Remove elements from "list" if p(element) returns true. 65 template <typename List, typename Predicate> 66 static void removeIf(List& list, Predicate predicate) { 67 for (auto it = list.begin(); it != list.end();) { 68 if (predicate(*it)) { 69 it = list.erase(it); 70 } else { 71 ++it; 72 } 73 } 74 } 75 76 void HalManifest::removeHals(const std::string& name, size_t majorVer) { 77 removeIf(mHals, [&name, majorVer](auto& existingHalPair) { 78 auto& existingHal = existingHalPair.second; 79 if (existingHal.name != name) { 80 return false; 81 } 82 auto& existingVersions = existingHal.versions; 83 removeIf(existingVersions, [majorVer](const auto& existingVersion) { 84 return existingVersion.majorVer == majorVer; 85 }); 86 return existingVersions.empty(); 87 }); 88 } 89 90 bool HalManifest::add(ManifestHal&& halToAdd) { 91 if (halToAdd.isOverride()) { 92 if (halToAdd.isDisabledHal()) { 93 // Special syntax when there are no instances at all. Remove all existing HALs 94 // with the given name. 95 mHals.erase(halToAdd.name); 96 } 97 // If there are <version> tags, remove all existing major versions that causes a conflict. 98 for (const Version& versionToAdd : halToAdd.versions) { 99 removeHals(halToAdd.name, versionToAdd.majorVer); 100 } 101 } 102 103 return HalGroup::add(std::move(halToAdd)); 104 } 105 106 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const { 107 auto existingXmlFiles = getXmlFiles(xmlFile.name()); 108 for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) { 109 if (xmlFile.version() == it->second.version()) { 110 return false; 111 } 112 } 113 return true; 114 } 115 116 std::set<std::string> HalManifest::getHalNames() const { 117 std::set<std::string> names{}; 118 for (const auto &hal : mHals) { 119 names.insert(hal.first); 120 } 121 return names; 122 } 123 124 std::set<std::string> HalManifest::getHalNamesAndVersions() const { 125 std::set<std::string> names{}; 126 forEachInstance([&names](const ManifestInstance& e) { 127 names.insert(toFQNameString(e.interface(), e.version())); 128 return true; 129 }); 130 return names; 131 } 132 133 Transport HalManifest::getTransport(const std::string &package, const Version &v, 134 const std::string &interfaceName, const std::string &instanceName) const { 135 Transport transport{Transport::EMPTY}; 136 forEachInstanceOfInterface(package, v, interfaceName, [&](const auto& e) { 137 if (e.instance() == instanceName) { 138 transport = e.transport(); 139 } 140 return transport == Transport::EMPTY; // if not found, continue 141 }); 142 if (transport == Transport::EMPTY) { 143 LOG(DEBUG) << "HalManifest::getTransport(" << mType << "): Cannot find " 144 << toFQNameString(package, v, interfaceName, instanceName); 145 } 146 return transport; 147 } 148 149 bool HalManifest::forEachInstanceOfVersion( 150 const std::string& package, const Version& expectVersion, 151 const std::function<bool(const ManifestInstance&)>& func) const { 152 for (const ManifestHal* hal : getHals(package)) { 153 bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) { 154 if (manifestInstance.version().minorAtLeast(expectVersion)) { 155 return func(manifestInstance); 156 } 157 return true; 158 }); 159 if (!cont) return false; 160 } 161 return true; 162 } 163 164 // indent = 2, {"foo"} => "foo" 165 // indent = 2, {"foo", "bar"} => "\n foo\n bar"; 166 template <typename Container> 167 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) { 168 if (lines.size() == 1) { 169 os << *lines.begin(); 170 return; 171 } 172 for (const auto& line : lines) { 173 os << "\n"; 174 for (size_t i = 0; i < indent; ++i) os << " "; 175 os << line; 176 } 177 } 178 179 // For each hal in mat, there must be a hal in manifest that supports this. 180 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const { 181 std::vector<std::string> ret; 182 for (const MatrixHal &matrixHal : mat.getHals()) { 183 if (matrixHal.optional) { 184 continue; 185 } 186 187 std::set<FqInstance> manifestInstances; 188 std::set<FqInstance> manifestInstancesNoPackage; 189 std::set<Version> versions; 190 for (const ManifestHal* manifestHal : getHals(matrixHal.name)) { 191 manifestHal->forEachInstance([&](const auto& manifestInstance) { 192 manifestInstances.insert(manifestInstance.getFqInstance()); 193 manifestInstancesNoPackage.insert(manifestInstance.getFqInstanceNoPackage()); 194 return true; 195 }); 196 manifestHal->appendAllVersions(&versions); 197 } 198 199 if (!matrixHal.isCompatible(manifestInstances, versions)) { 200 std::ostringstream oss; 201 oss << matrixHal.name << ":\n required: "; 202 multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal)); 203 oss << "\n provided: "; 204 if (manifestInstances.empty()) { 205 multilineIndent(oss, 8, versions); 206 } else { 207 multilineIndent(oss, 8, manifestInstancesNoPackage); 208 } 209 210 ret.insert(ret.end(), oss.str()); 211 } 212 } 213 return ret; 214 } 215 216 std::set<std::string> HalManifest::checkUnusedHals(const CompatibilityMatrix& mat) const { 217 std::set<std::string> ret; 218 219 forEachInstance([&ret, &mat](const auto& manifestInstance) { 220 const auto& fqInstance = manifestInstance.getFqInstance(); 221 if (!mat.matchInstance(fqInstance.getPackage(), fqInstance.getVersion(), 222 fqInstance.getInterface(), fqInstance.getInstance())) { 223 ret.insert(fqInstance.string()); 224 } 225 return true; 226 }); 227 228 return ret; 229 } 230 231 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk, 232 const std::vector<VendorNdk>& manifestVendorNdk, 233 std::string* error) { 234 // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk> 235 // tag. Ignore the check for these devices. 236 if (matVendorNdk.version().empty()) { 237 return true; 238 } 239 for (const auto& vndk : manifestVendorNdk) { 240 if (vndk.version() != matVendorNdk.version()) { 241 continue; 242 } 243 // version matches, check libraries 244 std::vector<std::string> diff; 245 std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(), 246 vndk.libraries().begin(), vndk.libraries().end(), 247 std::inserter(diff, diff.begin())); 248 if (!diff.empty()) { 249 if (error != nullptr) { 250 *error = "Vndk libs incompatible for version " + matVendorNdk.version() + 251 ". These libs are not in framework manifest:"; 252 for (const auto& name : diff) { 253 *error += " " + name; 254 } 255 } 256 return false; 257 } 258 return true; 259 } 260 261 // no match is found. 262 if (error != nullptr) { 263 *error = "Vndk version " + matVendorNdk.version() + " is not supported. " + 264 "Supported versions in framework manifest are:"; 265 for (const auto& vndk : manifestVendorNdk) { 266 *error += " " + vndk.version(); 267 } 268 } 269 return false; 270 } 271 272 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk, 273 const SystemSdk& manifestSystemSdk, std::string* error) { 274 SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk); 275 if (!notSupported.empty()) { 276 if (error) { 277 *error = 278 "The following System SDK versions are required by device " 279 "compatibility matrix but not supported by the framework manifest: [" + 280 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" + 281 base::Join(manifestSystemSdk.versions(), ", ") + "]."; 282 } 283 return false; 284 } 285 return true; 286 } 287 288 bool HalManifest::checkCompatibility(const CompatibilityMatrix &mat, std::string *error) const { 289 if (mType == mat.mType) { 290 if (error != nullptr) { 291 *error = "Wrong type; checking " + to_string(mType) + " manifest against " 292 + to_string(mat.mType) + " compatibility matrix"; 293 } 294 return false; 295 } 296 auto incompatibleHals = checkIncompatibleHals(mat); 297 if (!incompatibleHals.empty()) { 298 if (error != nullptr) { 299 *error = "HALs incompatible."; 300 if (mat.level() != Level::UNSPECIFIED) 301 *error += " Matrix level = " + to_string(mat.level()) + "."; 302 if (level() != Level::UNSPECIFIED) 303 *error += " Manifest level = " + to_string(level()) + "."; 304 *error += " The following requirements are not met:\n"; 305 for (const auto& e : incompatibleHals) { 306 *error += e + "\n"; 307 } 308 } 309 return false; 310 } 311 if (mType == SchemaType::FRAMEWORK) { 312 if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) { 313 return false; 314 } 315 316 if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) { 317 return false; 318 } 319 } else if (mType == SchemaType::DEVICE) { 320 bool match = false; 321 for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) { 322 if (range.supportedBy(device.mSepolicyVersion)) { 323 match = true; 324 break; 325 } 326 } 327 if (!match) { 328 if (error != nullptr) { 329 *error = "Sepolicy version " + to_string(device.mSepolicyVersion) 330 + " doesn't satisify the requirements."; 331 } 332 return false; 333 } 334 } 335 336 return true; 337 } 338 339 CompatibilityMatrix HalManifest::generateCompatibleMatrix() const { 340 CompatibilityMatrix matrix; 341 342 forEachInstance([&matrix](const ManifestInstance& e) { 343 matrix.add(MatrixHal{ 344 .format = e.format(), 345 .name = e.package(), 346 .optional = true, 347 .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}}, 348 .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}}); 349 return true; 350 }); 351 if (mType == SchemaType::FRAMEWORK) { 352 matrix.mType = SchemaType::DEVICE; 353 // VNDK does not need to be added for compatibility 354 } else if (mType == SchemaType::DEVICE) { 355 matrix.mType = SchemaType::FRAMEWORK; 356 matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */, 357 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}}); 358 } 359 360 return matrix; 361 } 362 363 status_t HalManifest::fetchAllInformation(const std::string& path, std::string* error) { 364 return details::fetchAllInformation(path, gHalManifestConverter, this, error); 365 } 366 367 SchemaType HalManifest::type() const { 368 return mType; 369 } 370 371 void HalManifest::setType(SchemaType type) { 372 mType = type; 373 } 374 375 Level HalManifest::level() const { 376 return mLevel; 377 } 378 379 Version HalManifest::getMetaVersion() const { 380 return mMetaVersion; 381 } 382 383 const Version &HalManifest::sepolicyVersion() const { 384 CHECK(mType == SchemaType::DEVICE); 385 return device.mSepolicyVersion; 386 } 387 388 const std::vector<VendorNdk>& HalManifest::vendorNdks() const { 389 CHECK(mType == SchemaType::FRAMEWORK); 390 return framework.mVendorNdks; 391 } 392 393 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName, 394 const Version& version) const { 395 using std::literals::string_literals::operator""s; 396 auto range = getXmlFiles(xmlFileName); 397 for (auto it = range.first; it != range.second; ++it) { 398 const ManifestXmlFile& manifestXmlFile = it->second; 399 if (manifestXmlFile.version() == version) { 400 if (!manifestXmlFile.overriddenPath().empty()) { 401 return manifestXmlFile.overriddenPath(); 402 } 403 return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" + 404 xmlFileName + "_V" + std::to_string(version.majorVer) + "_" + 405 std::to_string(version.minorVer) + ".xml"; 406 } 407 } 408 return ""; 409 } 410 411 bool operator==(const HalManifest &lft, const HalManifest &rgt) { 412 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals && 413 lft.mXmlFiles == rgt.mXmlFiles && 414 (lft.mType != SchemaType::DEVICE || 415 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) && 416 (lft.mType != SchemaType::FRAMEWORK || 417 ( 418 #pragma clang diagnostic push 419 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 420 lft.framework.mVndks == rgt.framework.mVndks && 421 #pragma clang diagnostic pop 422 lft.framework.mVendorNdks == rgt.framework.mVendorNdks && 423 lft.framework.mSystemSdk == rgt.framework.mSystemSdk)); 424 } 425 426 // Alternative to forEachInstance if you just need a set of instance names instead. 427 std::set<std::string> HalManifest::getInstances(const std::string& halName, const Version& version, 428 const std::string& interfaceName) const { 429 std::set<std::string> ret; 430 (void)forEachInstanceOfInterface(halName, version, interfaceName, [&ret](const auto& e) { 431 ret.insert(e.instance()); 432 return true; 433 }); 434 return ret; 435 } 436 437 // Return whether instance is in getInstances(...). 438 bool HalManifest::hasInstance(const std::string& halName, const Version& version, 439 const std::string& interfaceName, const std::string& instance) const { 440 bool found = false; 441 (void)forEachInstanceOfInterface(halName, version, interfaceName, 442 [&found, &instance](const auto& e) { 443 found |= (instance == e.instance()); 444 return !found; // if not found, continue 445 }); 446 return found; 447 } 448 449 } // namespace vintf 450 } // namespace android 451