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 
operator ==(const MatrixHal & other) const26 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 
containsVersion(const Version & version) const39 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 
forEachInstance(const std::function<bool (const MatrixInstance &)> & func) const46 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 
forEachInstance(const VersionRange & vr,const std::function<bool (const MatrixInstance &)> & func) const55 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 
forEachInstance(const std::function<bool (const std::vector<VersionRange> &,const std::string &,const std::string &,bool isRegex)> & func) const77 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 
isCompatible(const std::set<FqInstance> & providedInstances,const std::set<Version> & providedVersions) const92 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 
isCompatible(const VersionRange & vr,const std::set<FqInstance> & providedInstances,const std::set<Version> & providedVersions) const100 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 
setOptional(bool o)129 void MatrixHal::setOptional(bool o) {
130     this->optional = o;
131 }
132 
insertVersionRanges(const std::vector<VersionRange> & other)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 
insertInstance(const std::string & interface,const std::string & instance,bool isRegex)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 
instancesCount() const155 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 
removeInstance(const std::string & interface,const std::string & instance,bool isRegex)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 
clearInstances()173 void MatrixHal::clearInstances() {
174     this->interfaces.clear();
175 }
176 
177 } // namespace vintf
178 } // namespace android
179