/* * 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. */ #include "MatrixHal.h" #include #include "MapValueIterator.h" #include "constants-private.h" #include "utils.h" namespace android { namespace vintf { using details::canConvertToFqInstance; bool MatrixHal::isValid(std::string* error) const { bool success = true; // Check legacy instances (i.e. + + ) can be // converted into FqInstance because forEachInstance relies on FqInstance. // Because is a range, check both ends of the range. for (const auto& vr : versionRanges) { for (const auto& v : {vr.minVer(), vr.maxVer()}) { for (const auto& intf : iterateValues(interfaces)) { intf.forEachInstance([&](const auto& interface, const auto& instance, bool /*isRegex*/) { if (!canConvertToFqInstance(getName(), v, interface, instance, format, error)) { success = false; } return true; // continue }); } } } return success; } bool MatrixHal::operator==(const MatrixHal &other) const { if (format != other.format) return false; if (name != other.name) return false; if (versionRanges != other.versionRanges) return false; if (interfaces != other.interfaces) return false; // do not compare optional return true; } bool MatrixHal::containsVersion(const Version& version) const { for (VersionRange vRange : versionRanges) { if (vRange.contains(version)) return true; } return false; } bool MatrixHal::forEachInstance(const std::function& func) const { for (const auto& vr : versionRanges) { if (!forEachInstance(vr, func)) { return false; } } return true; } bool MatrixHal::forEachInstance(const VersionRange& vr, const std::function& func) const { for (const auto& intf : iterateValues(interfaces)) { bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) { // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps FqInstance fqInstance; if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, interface, instance)) { if (!func(MatrixInstance(format, std::move(fqInstance), VersionRange(vr), optional, isRegex))) { return false; } } return true; }); if (!cont) { return false; } } return true; } bool MatrixHal::forEachInstance( const std::function&, const std::string&, const std::string&, bool isRegex)>& func) const { for (const auto& intf : iterateValues(interfaces)) { bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) { return func(this->versionRanges, interface, instance, isRegex); }); if (!cont) { return false; } } return true; } bool MatrixHal::isCompatible(const std::set& providedInstances, const std::set& providedVersions) const { // 's are related by OR. return std::any_of(versionRanges.begin(), versionRanges.end(), [&](const VersionRange& vr) { return isCompatible(vr, providedInstances, providedVersions); }); } bool MatrixHal::isCompatible(const VersionRange& vr, const std::set& providedInstances, const std::set& providedVersions) const { bool hasAnyInstance = false; bool versionUnsatisfied = false; // Look at each interface/instance, and ensure that they are in providedInstances. forEachInstance(vr, [&](const MatrixInstance& matrixInstance) { hasAnyInstance = true; versionUnsatisfied |= !std::any_of(providedInstances.begin(), providedInstances.end(), [&](const FqInstance& providedInstance) { return matrixInstance.isSatisfiedBy(providedInstance); }); return !versionUnsatisfied; // if any interface/instance is unsatisfied, break }); if (hasAnyInstance) { return !versionUnsatisfied; } // In some cases (e.g. tests and native HALs), compatibility matrix doesn't specify // any instances. Check versions only. return std::any_of( providedVersions.begin(), providedVersions.end(), [&](const auto& providedVersion) { return vr.supportedBy(providedVersion); }); } void MatrixHal::setOptional(bool o) { this->optional = o; } void MatrixHal::insertVersionRanges(const std::vector& other) { for (const VersionRange& otherVr : other) { auto existingVr = std::find_if(this->versionRanges.begin(), this->versionRanges.end(), [&](const auto& e) { return e.overlaps(otherVr); }); if (existingVr == this->versionRanges.end()) { this->versionRanges.push_back(otherVr); } else { existingVr->minMinor = std::min(existingVr->minMinor, otherVr.minMinor); existingVr->maxMinor = std::max(existingVr->maxMinor, otherVr.maxMinor); } } } void MatrixHal::insertInstance(const std::string& interface, const std::string& instance, bool isRegex) { auto it = interfaces.find(interface); if (it == interfaces.end()) it = interfaces.emplace(interface, HalInterface{interface, {}}).first; it->second.insertInstance(instance, isRegex); } size_t MatrixHal::instancesCount() const { size_t count = 0; forEachInstance([&](const MatrixInstance&) { ++count; return true; // continue; }); return count; } bool MatrixHal::removeInstance(const std::string& interface, const std::string& instance, bool isRegex) { auto it = interfaces.find(interface); if (it == interfaces.end()) return false; bool removed = it->second.removeInstance(instance, isRegex); if (!it->second.hasAnyInstance()) interfaces.erase(it); return removed; } void MatrixHal::clearInstances() { this->interfaces.clear(); } } // namespace vintf } // namespace android