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 "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