summaryrefslogblamecommitdiffstats
blob: 45816f635c73403f878ab0bfcb69e61e63da6173 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                           
                          
                                 
 
                        
 
                   
 
                
              
 
                         
                      
                  
                                



                   

                                                           


                         















                                                                                   









                                                                                 







                                                        









                                                                   

                                                                                      

                                                     







                                                                           
                                                                                               




                                                                                 
                                                                                                          




                                                                                    
                                                                                                         




                                                                                 
     
                                                                                                    


                                                                                        

 



                                                                                    
     
               

 



                                                                                 


                                                           










                                                                                           
     


































                                                                                                


             










                                                                              


                 
                                                                           

                                                                                          

                                                      


                                                     
                                                                            

                                                   


                        

 








































                                                                                             



















                                                                                                

                                                                                                
         



















                                                                                 







                                                                   
                                                

















                                                                                                    

                                                                                        

 



                                      



                                  



                                             




                                                     
                                                               
                                          
                                 

 

















                                                                                          
                                                                 

                                                                                          

                                                                            

                                                 

                                                            
                                                               
                            
                                                                         
 
 

                      
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "libvintf"
#include <android-base/logging.h>

#include "HalManifest.h"

#include <dirent.h>

#include <mutex>
#include <set>

#include "parse_string.h"
#include "parse_xml.h"
#include "utils.h"
#include "CompatibilityMatrix.h"

namespace android {
namespace vintf {

// Check <version> tag for all <hal> with the same name.
bool HalManifest::shouldAdd(const ManifestHal& hal) const {
    if (!hal.isValid()) {
        return false;
    }
    auto existingHals = mHals.equal_range(hal.name);
    std::set<size_t> existingMajorVersions;
    for (auto it = existingHals.first; it != existingHals.second; ++it) {
        for (const auto& v : it->second.versions) {
            // Assume integrity on existingHals, so no check on emplace().second
            existingMajorVersions.insert(v.majorVer);
        }
    }
    for (const auto& v : hal.versions) {
        if (!existingMajorVersions.emplace(v.majorVer).second /* no insertion */) {
            return false;
        }
    }
    return true;
}

bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
    auto existingXmlFiles = getXmlFiles(xmlFile.name());
    for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
        if (xmlFile.version() == it->second.version()) {
            return false;
        }
    }
    return true;
}

std::set<std::string> HalManifest::getHalNames() const {
    std::set<std::string> names{};
    for (const auto &hal : mHals) {
        names.insert(hal.first);
    }
    return names;
}

std::set<std::string> HalManifest::getHalNamesAndVersions() const {
    std::set<std::string> names{};
    for (const auto &hal : getHals()) {
        for (const auto &version : hal.versions) {
            names.insert(hal.name + "@" + to_string(version));
        }
    }
    return names;
}

Transport HalManifest::getTransport(const std::string &package, const Version &v,
            const std::string &interfaceName, const std::string &instanceName) const {

    for (const ManifestHal *hal : getHals(package)) {
        bool found = false;
        for (auto& ver : hal->versions) {
            if (ver.majorVer == v.majorVer && ver.minorVer >= v.minorVer) {
                found = true;
                break;
            }
        }
        if (!found) {
            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find "
                      << to_string(v) << " in supported versions of " << package;
            continue;
        }
        auto it = hal->interfaces.find(interfaceName);
        if (it == hal->interfaces.end()) {
            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find interface '"
                      << interfaceName << "' in " << package << "@" << to_string(v);
            continue;
        }
        const auto &instances = it->second.instances;
        if (instances.find(instanceName) == instances.end()) {
            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find instance '"
                      << instanceName << "' in "
                      << package << "@" << to_string(v) << "::" << interfaceName;
            continue;
        }
        return hal->transportArch.transport;
    }
    LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot get transport for "
                 << package << "@" << v << "::" << interfaceName << "/" << instanceName;
    return Transport::EMPTY;

}

std::set<Version> HalManifest::getSupportedVersions(const std::string &name) const {
    std::set<Version> ret;
    for (const ManifestHal *hal : getHals(name)) {
        ret.insert(hal->versions.begin(), hal->versions.end());
    }
    return ret;
}

bool HalManifest::hasInstance(const std::string& halName, const Version& version,
                              const std::string& interfaceName,
                              const std::string& instanceName) const {
    const auto& instances = getInstances(halName, version, interfaceName);
    return instances.find(instanceName) != instances.end();
}

using InstancesOfVersion = std::map<std::string /* interface */,
                                    std::set<std::string /* instance */>>;
using Instances = std::map<Version, InstancesOfVersion>;

static bool satisfyVersion(const MatrixHal& matrixHal, const Version& manifestHalVersion) {
    for (const VersionRange &matrixVersionRange : matrixHal.versionRanges) {
        // If Compatibility Matrix says 2.5-2.7, the "2.7" is purely informational;
        // the framework can work with all 2.5-2.infinity.
        if (matrixVersionRange.supportedBy(manifestHalVersion)) {
            return true;
        }
    }
    return false;
}

// Check if matrixHal.interfaces is a subset of instancesOfVersion
static bool satisfyAllInstances(const MatrixHal& matrixHal,
        const InstancesOfVersion &instancesOfVersion) {
    for (const auto& matrixHalInterfacePair : matrixHal.interfaces) {
        const std::string& interface = matrixHalInterfacePair.first;
        auto it = instancesOfVersion.find(interface);
        if (it == instancesOfVersion.end()) {
            return false;
        }
        const std::set<std::string>& manifestInterfaceInstances = it->second;
        const std::set<std::string>& matrixInterfaceInstances =
                matrixHalInterfacePair.second.instances;
        if (!std::includes(manifestInterfaceInstances.begin(), manifestInterfaceInstances.end(),
                           matrixInterfaceInstances.begin(), matrixInterfaceInstances.end())) {
            return false;
        }
    }
    return true;
}

bool HalManifest::isCompatible(const MatrixHal& matrixHal) const {
    Instances instances;
    // Do the cross product version x interface x instance and sort them,
    // because interfaces / instances can span in multiple HALs.
    // This is efficient for small <hal> entries.
    for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
        for (const Version& manifestHalVersion : manifestHal->versions) {
            instances[manifestHalVersion] = {};
            for (const auto& halInterfacePair : manifestHal->interfaces) {
                const std::string& interface = halInterfacePair.first;
                const auto& toAdd = halInterfacePair.second.instances;
                instances[manifestHalVersion][interface].insert(toAdd.begin(), toAdd.end());
            }
        }
    }
    for (const auto& instanceMapPair : instances) {
        const Version& manifestHalVersion = instanceMapPair.first;
        const InstancesOfVersion& instancesOfVersion = instanceMapPair.second;
        if (!satisfyVersion(matrixHal, manifestHalVersion)) {
            continue;
        }
        if (!satisfyAllInstances(matrixHal, instancesOfVersion)) {
            continue;
        }
        return true; // match!
    }
    return false;
}

// For each hal in mat, there must be a hal in manifest that supports this.
std::vector<std::string> HalManifest::checkIncompatibility(const CompatibilityMatrix &mat,
        bool includeOptional) const {
    std::vector<std::string> incompatible;
    for (const MatrixHal &matrixHal : mat.getHals()) {
        if (!includeOptional && matrixHal.optional) {
            continue;
        }
        // don't check optional; put it in the incompatibility list as well.
        if (!isCompatible(matrixHal)) {
            incompatible.push_back(matrixHal.name);
        }
    }
    return incompatible;
}

static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
                                        const std::vector<VendorNdk>& manifestVendorNdk,
                                        std::string* error) {
    // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
    // tag. Ignore the check for these devices.
    if (matVendorNdk.version().empty()) {
        return true;
    }
    for (const auto& vndk : manifestVendorNdk) {
        if (vndk.version() != matVendorNdk.version()) {
            continue;
        }
        // version matches, check libraries
        std::vector<std::string> diff;
        std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
                            vndk.libraries().begin(), vndk.libraries().end(),
                            std::inserter(diff, diff.begin()));
        if (!diff.empty()) {
            if (error != nullptr) {
                *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
                         ". These libs are not in framework manifest:";
                for (const auto& name : diff) {
                    *error += " " + name;
                }
            }
            return false;
        }
        return true;
    }

    // no match is found.
    if (error != nullptr) {
        *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
                 "Supported versions in framework manifest are:";
        for (const auto& vndk : manifestVendorNdk) {
            *error += " " + vndk.version();
        }
    }
    return false;
}

bool HalManifest::checkCompatibility(const CompatibilityMatrix &mat, std::string *error) const {
    if (mType == mat.mType) {
        if (error != nullptr) {
            *error = "Wrong type; checking " + to_string(mType) + " manifest against "
                    + to_string(mat.mType) + " compatibility matrix";
        }
        return false;
    }
    std::vector<std::string> incompatibleHals =
            checkIncompatibility(mat, false /* includeOptional */);
    if (!incompatibleHals.empty()) {
        if (error != nullptr) {
            *error = "HALs incompatible.";
            for (const auto &name : incompatibleHals) {
                *error += " " + name;
            }
        }
        return false;
    }
    if (mType == SchemaType::FRAMEWORK) {
        if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
            return false;
        }
    } else if (mType == SchemaType::DEVICE) {
        bool match = false;
        for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
            if (range.supportedBy(device.mSepolicyVersion)) {
                match = true;
                break;
            }
        }
        if (!match) {
            if (error != nullptr) {
                *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
                        + " doesn't satisify the requirements.";
            }
            return false;
        }
    }

    return true;
}

CompatibilityMatrix HalManifest::generateCompatibleMatrix() const {
    CompatibilityMatrix matrix;

    for (const ManifestHal &manifestHal : getHals()) {
        MatrixHal matrixHal{
            .format = manifestHal.format,
            .name = manifestHal.name,
            .optional = true,
            .interfaces = manifestHal.interfaces
        };
        for (const Version &manifestVersion : manifestHal.versions) {
            matrixHal.versionRanges.push_back({manifestVersion.majorVer, manifestVersion.minorVer});
        }
        matrix.add(std::move(matrixHal));
    }
    if (mType == SchemaType::FRAMEWORK) {
        matrix.mType = SchemaType::DEVICE;
        // VNDK does not need to be added for compatibility
    } else if (mType == SchemaType::DEVICE) {
        matrix.mType = SchemaType::FRAMEWORK;
        matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
                {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
    }

    return matrix;
}

status_t HalManifest::fetchAllInformation(const std::string& path, std::string* error) {
    return details::fetchAllInformation(path, gHalManifestConverter, this, error);
}

SchemaType HalManifest::type() const {
    return mType;
}

Level HalManifest::level() const {
    return mLevel;
}

Version HalManifest::getMetaVersion() const {
    return mMetaVersion;
}

const Version &HalManifest::sepolicyVersion() const {
    CHECK(mType == SchemaType::DEVICE);
    return device.mSepolicyVersion;
}

const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
    CHECK(mType == SchemaType::FRAMEWORK);
    return framework.mVendorNdks;
}

std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
                                        const Version& version) const {
    using std::literals::string_literals::operator""s;
    auto range = getXmlFiles(xmlFileName);
    for (auto it = range.first; it != range.second; ++it) {
        const ManifestXmlFile& manifestXmlFile = it->second;
        if (manifestXmlFile.version() == version) {
            if (!manifestXmlFile.overriddenPath().empty()) {
                return manifestXmlFile.overriddenPath();
            }
            return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
                   xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
                   std::to_string(version.minorVer) + ".xml";
        }
    }
    return "";
}

bool operator==(const HalManifest &lft, const HalManifest &rgt) {
    return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
           lft.mXmlFiles == rgt.mXmlFiles &&
           (lft.mType != SchemaType::DEVICE ||
            (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) &&
           (lft.mType != SchemaType::FRAMEWORK ||
            (
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                lft.framework.mVndks == rgt.framework.mVndks &&
#pragma clang diagnostic pop
                lft.framework.mVendorNdks == rgt.framework.mVendorNdks));
}

} // namespace vintf
} // namespace android