Home | History | Annotate | Download | only in libvintf
      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