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 "parse_string.h" 28 #include "parse_xml.h" 29 #include "utils.h" 30 #include "CompatibilityMatrix.h" 31 32 namespace android { 33 namespace vintf { 34 35 constexpr Version HalManifest::kVersion; 36 37 // Check <version> tag for all <hal> with the same name. 38 bool HalManifest::shouldAdd(const ManifestHal& hal) const { 39 if (!hal.isValid()) { 40 return false; 41 } 42 auto existingHals = mHals.equal_range(hal.name); 43 std::set<size_t> existingMajorVersions; 44 for (auto it = existingHals.first; it != existingHals.second; ++it) { 45 for (const auto& v : it->second.versions) { 46 // Assume integrity on existingHals, so no check on emplace().second 47 existingMajorVersions.insert(v.majorVer); 48 } 49 } 50 for (const auto& v : hal.versions) { 51 if (!existingMajorVersions.emplace(v.majorVer).second /* no insertion */) { 52 return false; 53 } 54 } 55 return true; 56 } 57 58 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const { 59 auto existingXmlFiles = getXmlFiles(xmlFile.name()); 60 for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) { 61 if (xmlFile.version() == it->second.version()) { 62 return false; 63 } 64 } 65 return true; 66 } 67 68 std::set<std::string> HalManifest::getHalNames() const { 69 std::set<std::string> names{}; 70 for (const auto &hal : mHals) { 71 names.insert(hal.first); 72 } 73 return names; 74 } 75 76 std::set<std::string> HalManifest::getHalNamesAndVersions() const { 77 std::set<std::string> names{}; 78 for (const auto &hal : getHals()) { 79 for (const auto &version : hal.versions) { 80 names.insert(hal.name + "@" + to_string(version)); 81 } 82 } 83 return names; 84 } 85 86 std::set<std::string> HalManifest::getInterfaceNames(const std::string &name) const { 87 std::set<std::string> interfaceNames{}; 88 for (const ManifestHal *hal : getHals(name)) { 89 for (const auto &iface : hal->interfaces) { 90 interfaceNames.insert(iface.first); 91 } 92 } 93 return interfaceNames; 94 } 95 96 std::vector<const ManifestHal *> HalManifest::getHals(const std::string &name) const { 97 std::vector<const ManifestHal *> ret; 98 auto range = mHals.equal_range(name); 99 for (auto it = range.first; it != range.second; ++it) { 100 ret.push_back(&it->second); 101 } 102 return ret; 103 } 104 std::vector<ManifestHal *> HalManifest::getHals(const std::string &name) { 105 std::vector<ManifestHal *> ret; 106 auto range = mHals.equal_range(name); 107 for (auto it = range.first; it != range.second; ++it) { 108 ret.push_back(&it->second); 109 } 110 return ret; 111 } 112 113 Transport HalManifest::getTransport(const std::string &package, const Version &v, 114 const std::string &interfaceName, const std::string &instanceName) const { 115 116 for (const ManifestHal *hal : getHals(package)) { 117 bool found = false; 118 for (auto& ver : hal->versions) { 119 if (ver.majorVer == v.majorVer && ver.minorVer >= v.minorVer) { 120 found = true; 121 break; 122 } 123 } 124 if (!found) { 125 LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find " 126 << to_string(v) << " in supported versions of " << package; 127 continue; 128 } 129 auto it = hal->interfaces.find(interfaceName); 130 if (it == hal->interfaces.end()) { 131 LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find interface '" 132 << interfaceName << "' in " << package << "@" << to_string(v); 133 continue; 134 } 135 const auto &instances = it->second.instances; 136 if (instances.find(instanceName) == instances.end()) { 137 LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find instance '" 138 << instanceName << "' in " 139 << package << "@" << to_string(v) << "::" << interfaceName; 140 continue; 141 } 142 return hal->transportArch.transport; 143 } 144 LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot get transport for " 145 << package << "@" << v << "::" << interfaceName << "/" << instanceName; 146 return Transport::EMPTY; 147 148 } 149 150 ConstMultiMapValueIterable<std::string, ManifestHal> HalManifest::getHals() const { 151 return HalGroup<ManifestHal>::getHals(); 152 } 153 154 std::set<Version> HalManifest::getSupportedVersions(const std::string &name) const { 155 std::set<Version> ret; 156 for (const ManifestHal *hal : getHals(name)) { 157 ret.insert(hal->versions.begin(), hal->versions.end()); 158 } 159 return ret; 160 } 161 162 163 std::set<std::string> HalManifest::getInstances( 164 const std::string &halName, const std::string &interfaceName) const { 165 std::set<std::string> ret; 166 for (const ManifestHal *hal : getHals(halName)) { 167 auto it = hal->interfaces.find(interfaceName); 168 if (it != hal->interfaces.end()) { 169 ret.insert(it->second.instances.begin(), it->second.instances.end()); 170 } 171 } 172 return ret; 173 } 174 175 bool HalManifest::hasInstance(const std::string &halName, 176 const std::string &interfaceName, const std::string &instanceName) const { 177 const auto &instances = getInstances(halName, interfaceName); 178 return instances.find(instanceName) != instances.end(); 179 } 180 181 using InstancesOfVersion = std::map<std::string /* interface */, 182 std::set<std::string /* instance */>>; 183 using Instances = std::map<Version, InstancesOfVersion>; 184 185 static bool satisfyVersion(const MatrixHal& matrixHal, const Version& manifestHalVersion) { 186 for (const VersionRange &matrixVersionRange : matrixHal.versionRanges) { 187 // If Compatibility Matrix says 2.5-2.7, the "2.7" is purely informational; 188 // the framework can work with all 2.5-2.infinity. 189 if (matrixVersionRange.supportedBy(manifestHalVersion)) { 190 return true; 191 } 192 } 193 return false; 194 } 195 196 // Check if matrixHal.interfaces is a subset of instancesOfVersion 197 static bool satisfyAllInstances(const MatrixHal& matrixHal, 198 const InstancesOfVersion &instancesOfVersion) { 199 for (const auto& matrixHalInterfacePair : matrixHal.interfaces) { 200 const std::string& interface = matrixHalInterfacePair.first; 201 auto it = instancesOfVersion.find(interface); 202 if (it == instancesOfVersion.end()) { 203 return false; 204 } 205 const std::set<std::string>& manifestInterfaceInstances = it->second; 206 const std::set<std::string>& matrixInterfaceInstances = 207 matrixHalInterfacePair.second.instances; 208 if (!std::includes(manifestInterfaceInstances.begin(), manifestInterfaceInstances.end(), 209 matrixInterfaceInstances.begin(), matrixInterfaceInstances.end())) { 210 return false; 211 } 212 } 213 return true; 214 } 215 216 bool HalManifest::isCompatible(const MatrixHal& matrixHal) const { 217 Instances instances; 218 // Do the cross product version x interface x instance and sort them, 219 // because interfaces / instances can span in multiple HALs. 220 // This is efficient for small <hal> entries. 221 for (const ManifestHal* manifestHal : getHals(matrixHal.name)) { 222 for (const Version& manifestHalVersion : manifestHal->versions) { 223 instances[manifestHalVersion] = {}; 224 for (const auto& halInterfacePair : manifestHal->interfaces) { 225 const std::string& interface = halInterfacePair.first; 226 const auto& toAdd = halInterfacePair.second.instances; 227 instances[manifestHalVersion][interface].insert(toAdd.begin(), toAdd.end()); 228 } 229 } 230 } 231 for (const auto& instanceMapPair : instances) { 232 const Version& manifestHalVersion = instanceMapPair.first; 233 const InstancesOfVersion& instancesOfVersion = instanceMapPair.second; 234 if (!satisfyVersion(matrixHal, manifestHalVersion)) { 235 continue; 236 } 237 if (!satisfyAllInstances(matrixHal, instancesOfVersion)) { 238 continue; 239 } 240 return true; // match! 241 } 242 return false; 243 } 244 245 // For each hal in mat, there must be a hal in manifest that supports this. 246 std::vector<std::string> HalManifest::checkIncompatibility(const CompatibilityMatrix &mat, 247 bool includeOptional) const { 248 std::vector<std::string> incompatible; 249 for (const MatrixHal &matrixHal : mat.getHals()) { 250 if (!includeOptional && matrixHal.optional) { 251 continue; 252 } 253 // don't check optional; put it in the incompatibility list as well. 254 if (!isCompatible(matrixHal)) { 255 incompatible.push_back(matrixHal.name); 256 } 257 } 258 return incompatible; 259 } 260 261 bool HalManifest::checkCompatibility(const CompatibilityMatrix &mat, std::string *error) const { 262 if (mType == mat.mType) { 263 if (error != nullptr) { 264 *error = "Wrong type; checking " + to_string(mType) + " manifest against " 265 + to_string(mat.mType) + " compatibility matrix"; 266 } 267 return false; 268 } 269 std::vector<std::string> incompatibleHals = 270 checkIncompatibility(mat, false /* includeOptional */); 271 if (!incompatibleHals.empty()) { 272 if (error != nullptr) { 273 *error = "HALs incompatible."; 274 for (const auto &name : incompatibleHals) { 275 *error += " " + name; 276 } 277 } 278 return false; 279 } 280 if (mType == SchemaType::FRAMEWORK) { 281 // TODO(b/36400653) enable this. It is disabled since vndk is not yet defined. 282 #ifdef VINTF_CHECK_VNDK 283 bool match = false; 284 const auto &matVndk = mat.device.mVndk; 285 for (const auto &vndk : framework.mVndks) { 286 if (!vndk.mVersionRange.in(matVndk.mVersionRange)) { 287 continue; 288 } 289 // version matches, check libaries 290 std::vector<std::string> diff; 291 std::set_difference(matVndk.mLibraries.begin(), matVndk.mLibraries.end(), 292 vndk.mLibraries.begin(), vndk.mLibraries.end(), 293 std::inserter(diff, diff.begin())) 294 if (!diff.empty()) { 295 if (error != nullptr) { 296 *error = "Vndk libs incompatible."; 297 for (const auto &name : diff) { 298 *error += " " + name; 299 } 300 } 301 return false; 302 } 303 match = true; 304 break; 305 } 306 if (!match) { 307 if (error != nullptr) { 308 *error = "Vndk version " + to_string(matVndk.mVersionRange) + " is not supported."; 309 } 310 } 311 #endif 312 } else if (mType == SchemaType::DEVICE) { 313 bool match = false; 314 for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) { 315 if (range.supportedBy(device.mSepolicyVersion)) { 316 match = true; 317 break; 318 } 319 } 320 if (!match) { 321 if (error != nullptr) { 322 *error = "Sepolicy version " + to_string(device.mSepolicyVersion) 323 + " doesn't satisify the requirements."; 324 } 325 return false; 326 } 327 } 328 329 return true; 330 } 331 332 CompatibilityMatrix HalManifest::generateCompatibleMatrix() const { 333 CompatibilityMatrix matrix; 334 335 for (const ManifestHal &manifestHal : getHals()) { 336 MatrixHal matrixHal{ 337 .format = manifestHal.format, 338 .name = manifestHal.name, 339 .optional = true, 340 .interfaces = manifestHal.interfaces 341 }; 342 for (const Version &manifestVersion : manifestHal.versions) { 343 matrixHal.versionRanges.push_back({manifestVersion.majorVer, manifestVersion.minorVer}); 344 } 345 matrix.add(std::move(matrixHal)); 346 } 347 if (mType == SchemaType::FRAMEWORK) { 348 matrix.mType = SchemaType::DEVICE; 349 // VNDK does not need to be added for compatibility 350 } else if (mType == SchemaType::DEVICE) { 351 matrix.mType = SchemaType::FRAMEWORK; 352 matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */, 353 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}}); 354 } 355 356 return matrix; 357 } 358 359 status_t HalManifest::fetchAllInformation(const std::string &path) { 360 return details::fetchAllInformation(path, gHalManifestConverter, this); 361 } 362 363 SchemaType HalManifest::type() const { 364 return mType; 365 } 366 367 const Version &HalManifest::sepolicyVersion() const { 368 CHECK(mType == SchemaType::DEVICE); 369 return device.mSepolicyVersion; 370 } 371 372 const std::vector<Vndk> &HalManifest::vndks() const { 373 CHECK(mType == SchemaType::FRAMEWORK); 374 return framework.mVndks; 375 } 376 377 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName, 378 const Version& version) const { 379 using std::literals::string_literals::operator""s; 380 auto range = getXmlFiles(xmlFileName); 381 for (auto it = range.first; it != range.second; ++it) { 382 const ManifestXmlFile& manifestXmlFile = it->second; 383 if (manifestXmlFile.version() == version) { 384 if (!manifestXmlFile.overriddenPath().empty()) { 385 return manifestXmlFile.overriddenPath(); 386 } 387 return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" + 388 xmlFileName + "_V" + std::to_string(version.majorVer) + "_" + 389 std::to_string(version.minorVer) + ".xml"; 390 } 391 } 392 return ""; 393 } 394 395 bool operator==(const HalManifest &lft, const HalManifest &rgt) { 396 return lft.mType == rgt.mType && lft.mHals == rgt.mHals && lft.mXmlFiles == rgt.mXmlFiles && 397 (lft.mType != SchemaType::DEVICE || 398 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) && 399 (lft.mType != SchemaType::FRAMEWORK || (lft.framework.mVndks == rgt.framework.mVndks)); 400 } 401 402 } // namespace vintf 403 } // namespace android 404