HalManifest.cpp 20 KB

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