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