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