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 #include "MatrixHal.h" 18 19 #include <algorithm> 20 21 #include "MapValueIterator.h" 22 23 namespace android { 24 namespace vintf { 25 26 bool MatrixHal::operator==(const MatrixHal &other) const { 27 if (format != other.format) 28 return false; 29 if (name != other.name) 30 return false; 31 if (versionRanges != other.versionRanges) 32 return false; 33 if (interfaces != other.interfaces) 34 return false; 35 // do not compare optional 36 return true; 37 } 38 39 bool MatrixHal::containsVersion(const Version& version) const { 40 for (VersionRange vRange : versionRanges) { 41 if (vRange.contains(version)) return true; 42 } 43 return false; 44 } 45 46 bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const { 47 for (const auto& vr : versionRanges) { 48 if (!forEachInstance(vr, func)) { 49 return false; 50 } 51 } 52 return true; 53 } 54 55 bool MatrixHal::forEachInstance(const VersionRange& vr, 56 const std::function<bool(const MatrixInstance&)>& func) const { 57 for (const auto& intf : iterateValues(interfaces)) { 58 bool cont = 59 intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) { 60 // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps 61 FqInstance fqInstance; 62 if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, interface, instance)) { 63 if (!func(MatrixInstance(format, std::move(fqInstance), VersionRange(vr), 64 optional, isRegex))) { 65 return false; 66 } 67 } 68 return true; 69 }); 70 if (!cont) { 71 return false; 72 } 73 } 74 return true; 75 } 76 77 bool MatrixHal::forEachInstance( 78 const std::function<bool(const std::vector<VersionRange>&, const std::string&, 79 const std::string&, bool isRegex)>& func) const { 80 for (const auto& intf : iterateValues(interfaces)) { 81 bool cont = 82 intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) { 83 return func(this->versionRanges, interface, instance, isRegex); 84 }); 85 if (!cont) { 86 return false; 87 } 88 } 89 return true; 90 } 91 92 bool MatrixHal::isCompatible(const std::set<FqInstance>& providedInstances, 93 const std::set<Version>& providedVersions) const { 94 // <version>'s are related by OR. 95 return std::any_of(versionRanges.begin(), versionRanges.end(), [&](const VersionRange& vr) { 96 return isCompatible(vr, providedInstances, providedVersions); 97 }); 98 } 99 100 bool MatrixHal::isCompatible(const VersionRange& vr, const std::set<FqInstance>& providedInstances, 101 const std::set<Version>& providedVersions) const { 102 bool hasAnyInstance = false; 103 bool versionUnsatisfied = false; 104 105 // Look at each interface/instance, and ensure that they are in providedInstances. 106 forEachInstance(vr, [&](const MatrixInstance& matrixInstance) { 107 hasAnyInstance = true; 108 109 versionUnsatisfied |= 110 !std::any_of(providedInstances.begin(), providedInstances.end(), 111 [&](const FqInstance& providedInstance) { 112 return matrixInstance.isSatisfiedBy(providedInstance); 113 }); 114 115 return !versionUnsatisfied; // if any interface/instance is unsatisfied, break 116 }); 117 118 if (hasAnyInstance) { 119 return !versionUnsatisfied; 120 } 121 122 // In some cases (e.g. tests and native HALs), compatibility matrix doesn't specify 123 // any instances. Check versions only. 124 return std::any_of( 125 providedVersions.begin(), providedVersions.end(), 126 [&](const auto& providedVersion) { return vr.supportedBy(providedVersion); }); 127 } 128 129 void MatrixHal::setOptional(bool o) { 130 this->optional = o; 131 } 132 133 void MatrixHal::insertVersionRanges(const std::vector<VersionRange>& other) { 134 for (const VersionRange& otherVr : other) { 135 auto existingVr = std::find_if(this->versionRanges.begin(), this->versionRanges.end(), 136 [&](const auto& e) { return e.overlaps(otherVr); }); 137 138 if (existingVr == this->versionRanges.end()) { 139 this->versionRanges.push_back(otherVr); 140 } else { 141 existingVr->minMinor = std::min(existingVr->minMinor, otherVr.minMinor); 142 existingVr->maxMinor = std::max(existingVr->maxMinor, otherVr.maxMinor); 143 } 144 } 145 } 146 147 void MatrixHal::insertInstance(const std::string& interface, const std::string& instance, 148 bool isRegex) { 149 auto it = interfaces.find(interface); 150 if (it == interfaces.end()) 151 it = interfaces.emplace(interface, HalInterface{interface, {}}).first; 152 it->second.insertInstance(instance, isRegex); 153 } 154 155 size_t MatrixHal::instancesCount() const { 156 size_t count = 0; 157 forEachInstance([&](const MatrixInstance&) { 158 ++count; 159 return true; // continue; 160 }); 161 return count; 162 } 163 164 bool MatrixHal::removeInstance(const std::string& interface, const std::string& instance, 165 bool isRegex) { 166 auto it = interfaces.find(interface); 167 if (it == interfaces.end()) return false; 168 bool removed = it->second.removeInstance(instance, isRegex); 169 if (!it->second.hasAnyInstance()) interfaces.erase(it); 170 return removed; 171 } 172 173 void MatrixHal::clearInstances() { 174 this->interfaces.clear(); 175 } 176 177 } // namespace vintf 178 } // namespace android 179