xref: /aosp_15_r20/system/libvintf/MatrixHal.cpp (revision 70a7ec852fcefd15a4fb57f8f183a8b1c3aacb08)
1*70a7ec85SAndroid Build Coastguard Worker /*
2*70a7ec85SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*70a7ec85SAndroid Build Coastguard Worker  *
4*70a7ec85SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*70a7ec85SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*70a7ec85SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*70a7ec85SAndroid Build Coastguard Worker  *
8*70a7ec85SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*70a7ec85SAndroid Build Coastguard Worker  *
10*70a7ec85SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*70a7ec85SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*70a7ec85SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*70a7ec85SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*70a7ec85SAndroid Build Coastguard Worker  * limitations under the License.
15*70a7ec85SAndroid Build Coastguard Worker  */
16*70a7ec85SAndroid Build Coastguard Worker 
17*70a7ec85SAndroid Build Coastguard Worker #include "MatrixHal.h"
18*70a7ec85SAndroid Build Coastguard Worker 
19*70a7ec85SAndroid Build Coastguard Worker #include <algorithm>
20*70a7ec85SAndroid Build Coastguard Worker 
21*70a7ec85SAndroid Build Coastguard Worker #include "MapValueIterator.h"
22*70a7ec85SAndroid Build Coastguard Worker #include "constants-private.h"
23*70a7ec85SAndroid Build Coastguard Worker #include "utils.h"
24*70a7ec85SAndroid Build Coastguard Worker 
25*70a7ec85SAndroid Build Coastguard Worker namespace android {
26*70a7ec85SAndroid Build Coastguard Worker namespace vintf {
27*70a7ec85SAndroid Build Coastguard Worker 
28*70a7ec85SAndroid Build Coastguard Worker using details::convertLegacyInstanceIntoFqInstance;
29*70a7ec85SAndroid Build Coastguard Worker 
isValid(std::string * error) const30*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::isValid(std::string* error) const {
31*70a7ec85SAndroid Build Coastguard Worker     bool success = true;
32*70a7ec85SAndroid Build Coastguard Worker 
33*70a7ec85SAndroid Build Coastguard Worker     // Check legacy instances (i.e. <version> + <interface> + <instance>) can be
34*70a7ec85SAndroid Build Coastguard Worker     // converted into FqInstance because forEachInstance relies on FqInstance.
35*70a7ec85SAndroid Build Coastguard Worker     // Because <version> is a range, check both ends of the range.
36*70a7ec85SAndroid Build Coastguard Worker     for (const auto& vr : versionRanges) {
37*70a7ec85SAndroid Build Coastguard Worker         for (const auto& v : {vr.minVer(), vr.maxVer()}) {
38*70a7ec85SAndroid Build Coastguard Worker             for (const auto& intf : iterateValues(interfaces)) {
39*70a7ec85SAndroid Build Coastguard Worker                 intf.forEachInstance(
40*70a7ec85SAndroid Build Coastguard Worker                     [&](const auto& interface, const auto& instance, bool /*isRegex*/) {
41*70a7ec85SAndroid Build Coastguard Worker                         if (!convertLegacyInstanceIntoFqInstance(getName(), v, interface, instance,
42*70a7ec85SAndroid Build Coastguard Worker                                                                  format, error)
43*70a7ec85SAndroid Build Coastguard Worker                                  .has_value()) {
44*70a7ec85SAndroid Build Coastguard Worker                             success = false;
45*70a7ec85SAndroid Build Coastguard Worker                         }
46*70a7ec85SAndroid Build Coastguard Worker                         return true;  // continue
47*70a7ec85SAndroid Build Coastguard Worker                     });
48*70a7ec85SAndroid Build Coastguard Worker             }
49*70a7ec85SAndroid Build Coastguard Worker         }
50*70a7ec85SAndroid Build Coastguard Worker     }
51*70a7ec85SAndroid Build Coastguard Worker 
52*70a7ec85SAndroid Build Coastguard Worker     return success;
53*70a7ec85SAndroid Build Coastguard Worker }
54*70a7ec85SAndroid Build Coastguard Worker 
operator ==(const MatrixHal & other) const55*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::operator==(const MatrixHal &other) const {
56*70a7ec85SAndroid Build Coastguard Worker     if (format != other.format)
57*70a7ec85SAndroid Build Coastguard Worker         return false;
58*70a7ec85SAndroid Build Coastguard Worker     if (name != other.name)
59*70a7ec85SAndroid Build Coastguard Worker         return false;
60*70a7ec85SAndroid Build Coastguard Worker     if (versionRanges != other.versionRanges)
61*70a7ec85SAndroid Build Coastguard Worker         return false;
62*70a7ec85SAndroid Build Coastguard Worker     if (interfaces != other.interfaces)
63*70a7ec85SAndroid Build Coastguard Worker         return false;
64*70a7ec85SAndroid Build Coastguard Worker     // do not compare optional
65*70a7ec85SAndroid Build Coastguard Worker     return true;
66*70a7ec85SAndroid Build Coastguard Worker }
67*70a7ec85SAndroid Build Coastguard Worker 
containsVersion(const Version & version) const68*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::containsVersion(const Version& version) const {
69*70a7ec85SAndroid Build Coastguard Worker     for (VersionRange vRange : versionRanges) {
70*70a7ec85SAndroid Build Coastguard Worker         if (vRange.contains(version)) return true;
71*70a7ec85SAndroid Build Coastguard Worker     }
72*70a7ec85SAndroid Build Coastguard Worker     return false;
73*70a7ec85SAndroid Build Coastguard Worker }
74*70a7ec85SAndroid Build Coastguard Worker 
forEachInstance(const std::function<bool (const MatrixInstance &)> & func) const75*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const {
76*70a7ec85SAndroid Build Coastguard Worker     for (const auto& vr : versionRanges) {
77*70a7ec85SAndroid Build Coastguard Worker         if (!forEachInstance(vr, func)) {
78*70a7ec85SAndroid Build Coastguard Worker             return false;
79*70a7ec85SAndroid Build Coastguard Worker         }
80*70a7ec85SAndroid Build Coastguard Worker     }
81*70a7ec85SAndroid Build Coastguard Worker     return true;
82*70a7ec85SAndroid Build Coastguard Worker }
83*70a7ec85SAndroid Build Coastguard Worker 
forEachInstance(const VersionRange & vr,const std::function<bool (const MatrixInstance &)> & func) const84*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::forEachInstance(const VersionRange& vr,
85*70a7ec85SAndroid Build Coastguard Worker                                 const std::function<bool(const MatrixInstance&)>& func) const {
86*70a7ec85SAndroid Build Coastguard Worker     for (const auto& intf : iterateValues(interfaces)) {
87*70a7ec85SAndroid Build Coastguard Worker         bool cont =
88*70a7ec85SAndroid Build Coastguard Worker             intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) {
89*70a7ec85SAndroid Build Coastguard Worker                 // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps
90*70a7ec85SAndroid Build Coastguard Worker                 FqInstance fqInstance;
91*70a7ec85SAndroid Build Coastguard Worker                 if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, interface, instance)) {
92*70a7ec85SAndroid Build Coastguard Worker                     if (!func(MatrixInstance(format, exclusiveTo, std::move(fqInstance),
93*70a7ec85SAndroid Build Coastguard Worker                                              VersionRange(vr), optional, isRegex))) {
94*70a7ec85SAndroid Build Coastguard Worker                         return false;
95*70a7ec85SAndroid Build Coastguard Worker                     }
96*70a7ec85SAndroid Build Coastguard Worker                 }
97*70a7ec85SAndroid Build Coastguard Worker                 return true;
98*70a7ec85SAndroid Build Coastguard Worker             });
99*70a7ec85SAndroid Build Coastguard Worker         if (!cont) {
100*70a7ec85SAndroid Build Coastguard Worker             return false;
101*70a7ec85SAndroid Build Coastguard Worker         }
102*70a7ec85SAndroid Build Coastguard Worker     }
103*70a7ec85SAndroid Build Coastguard Worker     return true;
104*70a7ec85SAndroid Build Coastguard Worker }
105*70a7ec85SAndroid Build Coastguard Worker 
forEachInstance(const std::function<bool (const std::vector<VersionRange> &,const std::string &,const std::string &,bool isRegex)> & func) const106*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::forEachInstance(
107*70a7ec85SAndroid Build Coastguard Worker     const std::function<bool(const std::vector<VersionRange>&, const std::string&,
108*70a7ec85SAndroid Build Coastguard Worker                              const std::string&, bool isRegex)>& func) const {
109*70a7ec85SAndroid Build Coastguard Worker     for (const auto& intf : iterateValues(interfaces)) {
110*70a7ec85SAndroid Build Coastguard Worker         bool cont =
111*70a7ec85SAndroid Build Coastguard Worker             intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) {
112*70a7ec85SAndroid Build Coastguard Worker                 return func(this->versionRanges, interface, instance, isRegex);
113*70a7ec85SAndroid Build Coastguard Worker             });
114*70a7ec85SAndroid Build Coastguard Worker         if (!cont) {
115*70a7ec85SAndroid Build Coastguard Worker             return false;
116*70a7ec85SAndroid Build Coastguard Worker         }
117*70a7ec85SAndroid Build Coastguard Worker     }
118*70a7ec85SAndroid Build Coastguard Worker     return true;
119*70a7ec85SAndroid Build Coastguard Worker }
120*70a7ec85SAndroid Build Coastguard Worker 
isCompatible(const std::set<FqInstance> & providedInstances,const std::set<Version> & providedVersions) const121*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::isCompatible(const std::set<FqInstance>& providedInstances,
122*70a7ec85SAndroid Build Coastguard Worker                              const std::set<Version>& providedVersions) const {
123*70a7ec85SAndroid Build Coastguard Worker     // <version>'s are related by OR.
124*70a7ec85SAndroid Build Coastguard Worker     return std::any_of(versionRanges.begin(), versionRanges.end(), [&](const VersionRange& vr) {
125*70a7ec85SAndroid Build Coastguard Worker         return isCompatible(vr, providedInstances, providedVersions);
126*70a7ec85SAndroid Build Coastguard Worker     });
127*70a7ec85SAndroid Build Coastguard Worker }
128*70a7ec85SAndroid Build Coastguard Worker 
isCompatible(const VersionRange & vr,const std::set<FqInstance> & providedInstances,const std::set<Version> & providedVersions) const129*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::isCompatible(const VersionRange& vr, const std::set<FqInstance>& providedInstances,
130*70a7ec85SAndroid Build Coastguard Worker                              const std::set<Version>& providedVersions) const {
131*70a7ec85SAndroid Build Coastguard Worker     bool hasAnyInstance = false;
132*70a7ec85SAndroid Build Coastguard Worker     bool versionUnsatisfied = false;
133*70a7ec85SAndroid Build Coastguard Worker 
134*70a7ec85SAndroid Build Coastguard Worker     // Look at each interface/instance, and ensure that they are in providedInstances.
135*70a7ec85SAndroid Build Coastguard Worker     forEachInstance(vr, [&](const MatrixInstance& matrixInstance) {
136*70a7ec85SAndroid Build Coastguard Worker         hasAnyInstance = true;
137*70a7ec85SAndroid Build Coastguard Worker 
138*70a7ec85SAndroid Build Coastguard Worker         versionUnsatisfied |=
139*70a7ec85SAndroid Build Coastguard Worker             !std::any_of(providedInstances.begin(), providedInstances.end(),
140*70a7ec85SAndroid Build Coastguard Worker                          [&](const FqInstance& providedInstance) {
141*70a7ec85SAndroid Build Coastguard Worker                              return matrixInstance.isSatisfiedBy(providedInstance);
142*70a7ec85SAndroid Build Coastguard Worker                          });
143*70a7ec85SAndroid Build Coastguard Worker 
144*70a7ec85SAndroid Build Coastguard Worker         return !versionUnsatisfied;  // if any interface/instance is unsatisfied, break
145*70a7ec85SAndroid Build Coastguard Worker     });
146*70a7ec85SAndroid Build Coastguard Worker 
147*70a7ec85SAndroid Build Coastguard Worker     if (hasAnyInstance) {
148*70a7ec85SAndroid Build Coastguard Worker         return !versionUnsatisfied;
149*70a7ec85SAndroid Build Coastguard Worker     }
150*70a7ec85SAndroid Build Coastguard Worker 
151*70a7ec85SAndroid Build Coastguard Worker     // In some cases (e.g. tests and native HALs), compatibility matrix doesn't specify
152*70a7ec85SAndroid Build Coastguard Worker     // any instances. Check versions only.
153*70a7ec85SAndroid Build Coastguard Worker     return std::any_of(
154*70a7ec85SAndroid Build Coastguard Worker         providedVersions.begin(), providedVersions.end(),
155*70a7ec85SAndroid Build Coastguard Worker         [&](const auto& providedVersion) { return vr.supportedBy(providedVersion); });
156*70a7ec85SAndroid Build Coastguard Worker }
157*70a7ec85SAndroid Build Coastguard Worker 
setOptional(bool o)158*70a7ec85SAndroid Build Coastguard Worker void MatrixHal::setOptional(bool o) {
159*70a7ec85SAndroid Build Coastguard Worker     this->optional = o;
160*70a7ec85SAndroid Build Coastguard Worker }
161*70a7ec85SAndroid Build Coastguard Worker 
insertVersionRanges(const std::vector<VersionRange> & other)162*70a7ec85SAndroid Build Coastguard Worker void MatrixHal::insertVersionRanges(const std::vector<VersionRange>& other) {
163*70a7ec85SAndroid Build Coastguard Worker     for (const VersionRange& otherVr : other) {
164*70a7ec85SAndroid Build Coastguard Worker         auto existingVr = std::find_if(this->versionRanges.begin(), this->versionRanges.end(),
165*70a7ec85SAndroid Build Coastguard Worker                                        [&](const auto& e) { return e.overlaps(otherVr); });
166*70a7ec85SAndroid Build Coastguard Worker 
167*70a7ec85SAndroid Build Coastguard Worker         if (existingVr == this->versionRanges.end()) {
168*70a7ec85SAndroid Build Coastguard Worker             this->versionRanges.push_back(otherVr);
169*70a7ec85SAndroid Build Coastguard Worker         } else {
170*70a7ec85SAndroid Build Coastguard Worker             existingVr->minMinor = std::min(existingVr->minMinor, otherVr.minMinor);
171*70a7ec85SAndroid Build Coastguard Worker             existingVr->maxMinor = std::max(existingVr->maxMinor, otherVr.maxMinor);
172*70a7ec85SAndroid Build Coastguard Worker         }
173*70a7ec85SAndroid Build Coastguard Worker     }
174*70a7ec85SAndroid Build Coastguard Worker }
175*70a7ec85SAndroid Build Coastguard Worker 
insertInstance(const std::string & interface,const std::string & instance,bool isRegex)176*70a7ec85SAndroid Build Coastguard Worker void MatrixHal::insertInstance(const std::string& interface, const std::string& instance,
177*70a7ec85SAndroid Build Coastguard Worker                                bool isRegex) {
178*70a7ec85SAndroid Build Coastguard Worker     auto it = interfaces.find(interface);
179*70a7ec85SAndroid Build Coastguard Worker     if (it == interfaces.end())
180*70a7ec85SAndroid Build Coastguard Worker         it = interfaces.emplace(interface, HalInterface{interface, {}}).first;
181*70a7ec85SAndroid Build Coastguard Worker     it->second.insertInstance(instance, isRegex);
182*70a7ec85SAndroid Build Coastguard Worker }
183*70a7ec85SAndroid Build Coastguard Worker 
instancesCount() const184*70a7ec85SAndroid Build Coastguard Worker size_t MatrixHal::instancesCount() const {
185*70a7ec85SAndroid Build Coastguard Worker     size_t count = 0;
186*70a7ec85SAndroid Build Coastguard Worker     forEachInstance([&](const MatrixInstance&) {
187*70a7ec85SAndroid Build Coastguard Worker         ++count;
188*70a7ec85SAndroid Build Coastguard Worker         return true;  // continue;
189*70a7ec85SAndroid Build Coastguard Worker     });
190*70a7ec85SAndroid Build Coastguard Worker     return count;
191*70a7ec85SAndroid Build Coastguard Worker }
192*70a7ec85SAndroid Build Coastguard Worker 
removeInstance(const std::string & interface,const std::string & instance,bool isRegex)193*70a7ec85SAndroid Build Coastguard Worker bool MatrixHal::removeInstance(const std::string& interface, const std::string& instance,
194*70a7ec85SAndroid Build Coastguard Worker                                bool isRegex) {
195*70a7ec85SAndroid Build Coastguard Worker     auto it = interfaces.find(interface);
196*70a7ec85SAndroid Build Coastguard Worker     if (it == interfaces.end()) return false;
197*70a7ec85SAndroid Build Coastguard Worker     bool removed = it->second.removeInstance(instance, isRegex);
198*70a7ec85SAndroid Build Coastguard Worker     if (!it->second.hasAnyInstance()) interfaces.erase(it);
199*70a7ec85SAndroid Build Coastguard Worker     return removed;
200*70a7ec85SAndroid Build Coastguard Worker }
201*70a7ec85SAndroid Build Coastguard Worker 
clearInstances()202*70a7ec85SAndroid Build Coastguard Worker void MatrixHal::clearInstances() {
203*70a7ec85SAndroid Build Coastguard Worker     this->interfaces.clear();
204*70a7ec85SAndroid Build Coastguard Worker }
205*70a7ec85SAndroid Build Coastguard Worker 
206*70a7ec85SAndroid Build Coastguard Worker } // namespace vintf
207*70a7ec85SAndroid Build Coastguard Worker } // namespace android
208