xref: /aosp_15_r20/system/libvintf/CompatibilityMatrix.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 "CompatibilityMatrix.h"
18*70a7ec85SAndroid Build Coastguard Worker 
19*70a7ec85SAndroid Build Coastguard Worker #include <iostream>
20*70a7ec85SAndroid Build Coastguard Worker #include <utility>
21*70a7ec85SAndroid Build Coastguard Worker 
22*70a7ec85SAndroid Build Coastguard Worker #include <android-base/logging.h>
23*70a7ec85SAndroid Build Coastguard Worker #include <android-base/strings.h>
24*70a7ec85SAndroid Build Coastguard Worker 
25*70a7ec85SAndroid Build Coastguard Worker #include "parse_string.h"
26*70a7ec85SAndroid Build Coastguard Worker #include "parse_xml.h"
27*70a7ec85SAndroid Build Coastguard Worker #include "utils.h"
28*70a7ec85SAndroid Build Coastguard Worker 
29*70a7ec85SAndroid Build Coastguard Worker namespace android {
30*70a7ec85SAndroid Build Coastguard Worker namespace vintf {
31*70a7ec85SAndroid Build Coastguard Worker 
32*70a7ec85SAndroid Build Coastguard Worker using details::mergeField;
33*70a7ec85SAndroid Build Coastguard Worker 
add(MatrixHal && halToAdd,std::string *)34*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::add(MatrixHal&& halToAdd, std::string*) {
35*70a7ec85SAndroid Build Coastguard Worker     CHECK(addInternal(std::move(halToAdd)) != nullptr);
36*70a7ec85SAndroid Build Coastguard Worker     return true;
37*70a7ec85SAndroid Build Coastguard Worker }
38*70a7ec85SAndroid Build Coastguard Worker 
addAllHals(CompatibilityMatrix * other,std::string *)39*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAllHals(CompatibilityMatrix* other, std::string*) {
40*70a7ec85SAndroid Build Coastguard Worker     std::string internalError;
41*70a7ec85SAndroid Build Coastguard Worker     for (auto& entry : other->mHals) {
42*70a7ec85SAndroid Build Coastguard Worker         CHECK(add(std::move(entry.second), &internalError)) << internalError;
43*70a7ec85SAndroid Build Coastguard Worker     }
44*70a7ec85SAndroid Build Coastguard Worker     other->mHals.clear();
45*70a7ec85SAndroid Build Coastguard Worker     return true;
46*70a7ec85SAndroid Build Coastguard Worker }
47*70a7ec85SAndroid Build Coastguard Worker 
addKernel(MatrixKernel && kernel,std::string * error)48*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addKernel(MatrixKernel&& kernel, std::string* error) {
49*70a7ec85SAndroid Build Coastguard Worker     if (mType != SchemaType::FRAMEWORK) {
50*70a7ec85SAndroid Build Coastguard Worker         if (error) {
51*70a7ec85SAndroid Build Coastguard Worker             *error = "Cannot add <kernel> to a " + to_string(mType) + " compatibility matrix.";
52*70a7ec85SAndroid Build Coastguard Worker         }
53*70a7ec85SAndroid Build Coastguard Worker         return false;
54*70a7ec85SAndroid Build Coastguard Worker     }
55*70a7ec85SAndroid Build Coastguard Worker 
56*70a7ec85SAndroid Build Coastguard Worker     if (kernel.getSourceMatrixLevel() == Level::UNSPECIFIED) {
57*70a7ec85SAndroid Build Coastguard Worker         kernel.setSourceMatrixLevel(level());
58*70a7ec85SAndroid Build Coastguard Worker     }
59*70a7ec85SAndroid Build Coastguard Worker 
60*70a7ec85SAndroid Build Coastguard Worker     auto it = framework.mKernels.begin();
61*70a7ec85SAndroid Build Coastguard Worker     for (; it != framework.mKernels.end(); ++it) {
62*70a7ec85SAndroid Build Coastguard Worker         if (it->getSourceMatrixLevel() != kernel.getSourceMatrixLevel()) {
63*70a7ec85SAndroid Build Coastguard Worker             continue;
64*70a7ec85SAndroid Build Coastguard Worker         }
65*70a7ec85SAndroid Build Coastguard Worker         if (it->minLts() == kernel.minLts()) {
66*70a7ec85SAndroid Build Coastguard Worker             break;
67*70a7ec85SAndroid Build Coastguard Worker         }
68*70a7ec85SAndroid Build Coastguard Worker         if (it->minLts().dropMinor() == kernel.minLts().dropMinor()) {
69*70a7ec85SAndroid Build Coastguard Worker             if (error) {
70*70a7ec85SAndroid Build Coastguard Worker                 *error = "Kernel version mismatch; for level " +
71*70a7ec85SAndroid Build Coastguard Worker                          to_string(kernel.getSourceMatrixLevel()) + ", cannot add " +
72*70a7ec85SAndroid Build Coastguard Worker                          to_string(kernel.minLts()) + " because " + to_string(it->minLts()) +
73*70a7ec85SAndroid Build Coastguard Worker                          " was added.";
74*70a7ec85SAndroid Build Coastguard Worker             }
75*70a7ec85SAndroid Build Coastguard Worker             return false;
76*70a7ec85SAndroid Build Coastguard Worker         }
77*70a7ec85SAndroid Build Coastguard Worker     }
78*70a7ec85SAndroid Build Coastguard Worker 
79*70a7ec85SAndroid Build Coastguard Worker     bool seenVersion = it != framework.mKernels.end();
80*70a7ec85SAndroid Build Coastguard Worker 
81*70a7ec85SAndroid Build Coastguard Worker     if (seenVersion) {
82*70a7ec85SAndroid Build Coastguard Worker         // If no conditions, must be the first among the same minLts
83*70a7ec85SAndroid Build Coastguard Worker         // because O libvintf only checks the first <kernel> tag that version matches.
84*70a7ec85SAndroid Build Coastguard Worker         if (kernel.conditions().empty()) {
85*70a7ec85SAndroid Build Coastguard Worker             // Found first <kernel> with the same minLts.
86*70a7ec85SAndroid Build Coastguard Worker             // Append config if it does not have <condition>s, else error.
87*70a7ec85SAndroid Build Coastguard Worker             if (it->conditions().empty()) {
88*70a7ec85SAndroid Build Coastguard Worker                 const auto& configs = kernel.configs();
89*70a7ec85SAndroid Build Coastguard Worker                 it->mConfigs.insert(it->mConfigs.end(), configs.begin(), configs.end());
90*70a7ec85SAndroid Build Coastguard Worker             } else {
91*70a7ec85SAndroid Build Coastguard Worker                 if (error) {
92*70a7ec85SAndroid Build Coastguard Worker                     *error =
93*70a7ec85SAndroid Build Coastguard Worker                         "Base compatibility matrix has <condition> for the first <kernel> "
94*70a7ec85SAndroid Build Coastguard Worker                         "with minlts " +
95*70a7ec85SAndroid Build Coastguard Worker                         to_string(kernel.minLts()) + " for unknown reason.";
96*70a7ec85SAndroid Build Coastguard Worker                 }
97*70a7ec85SAndroid Build Coastguard Worker                 return false;
98*70a7ec85SAndroid Build Coastguard Worker             }
99*70a7ec85SAndroid Build Coastguard Worker             return true;
100*70a7ec85SAndroid Build Coastguard Worker         }
101*70a7ec85SAndroid Build Coastguard Worker     } else {
102*70a7ec85SAndroid Build Coastguard Worker         // First <kernel> of a minLts must not have <condition>'s for backwards compatibility
103*70a7ec85SAndroid Build Coastguard Worker         // with O libvintf.
104*70a7ec85SAndroid Build Coastguard Worker         if (!kernel.conditions().empty()) {
105*70a7ec85SAndroid Build Coastguard Worker             framework.mKernels.push_back(MatrixKernel(KernelVersion{kernel.minLts()}, {}));
106*70a7ec85SAndroid Build Coastguard Worker         }
107*70a7ec85SAndroid Build Coastguard Worker     }
108*70a7ec85SAndroid Build Coastguard Worker 
109*70a7ec85SAndroid Build Coastguard Worker     framework.mKernels.push_back(std::move(kernel));
110*70a7ec85SAndroid Build Coastguard Worker     return true;
111*70a7ec85SAndroid Build Coastguard Worker }
112*70a7ec85SAndroid Build Coastguard Worker 
type() const113*70a7ec85SAndroid Build Coastguard Worker SchemaType CompatibilityMatrix::type() const {
114*70a7ec85SAndroid Build Coastguard Worker     return mType;
115*70a7ec85SAndroid Build Coastguard Worker }
116*70a7ec85SAndroid Build Coastguard Worker 
level() const117*70a7ec85SAndroid Build Coastguard Worker Level CompatibilityMatrix::level() const {
118*70a7ec85SAndroid Build Coastguard Worker     return mLevel;
119*70a7ec85SAndroid Build Coastguard Worker }
120*70a7ec85SAndroid Build Coastguard Worker 
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)121*70a7ec85SAndroid Build Coastguard Worker status_t CompatibilityMatrix::fetchAllInformation(const FileSystem* fileSystem,
122*70a7ec85SAndroid Build Coastguard Worker                                                   const std::string& path, std::string* error) {
123*70a7ec85SAndroid Build Coastguard Worker     return details::fetchAllInformation(fileSystem, path, this, error);
124*70a7ec85SAndroid Build Coastguard Worker }
125*70a7ec85SAndroid Build Coastguard Worker 
getXmlSchemaPath(const std::string & xmlFileName,const Version & version) const126*70a7ec85SAndroid Build Coastguard Worker std::string CompatibilityMatrix::getXmlSchemaPath(const std::string& xmlFileName,
127*70a7ec85SAndroid Build Coastguard Worker                                                   const Version& version) const {
128*70a7ec85SAndroid Build Coastguard Worker     using std::literals::string_literals::operator""s;
129*70a7ec85SAndroid Build Coastguard Worker     auto range = getXmlFiles(xmlFileName);
130*70a7ec85SAndroid Build Coastguard Worker     for (auto it = range.first; it != range.second; ++it) {
131*70a7ec85SAndroid Build Coastguard Worker         const MatrixXmlFile& matrixXmlFile = it->second;
132*70a7ec85SAndroid Build Coastguard Worker         if (matrixXmlFile.versionRange().contains(version)) {
133*70a7ec85SAndroid Build Coastguard Worker             if (!matrixXmlFile.overriddenPath().empty()) {
134*70a7ec85SAndroid Build Coastguard Worker                 return matrixXmlFile.overriddenPath();
135*70a7ec85SAndroid Build Coastguard Worker             }
136*70a7ec85SAndroid Build Coastguard Worker             return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
137*70a7ec85SAndroid Build Coastguard Worker                    xmlFileName + "_V" + std::to_string(matrixXmlFile.versionRange().majorVer) +
138*70a7ec85SAndroid Build Coastguard Worker                    "_" + std::to_string(matrixXmlFile.versionRange().maxMinor) + "." +
139*70a7ec85SAndroid Build Coastguard Worker                    to_string(matrixXmlFile.format());
140*70a7ec85SAndroid Build Coastguard Worker         }
141*70a7ec85SAndroid Build Coastguard Worker     }
142*70a7ec85SAndroid Build Coastguard Worker     return "";
143*70a7ec85SAndroid Build Coastguard Worker }
144*70a7ec85SAndroid Build Coastguard Worker 
145*70a7ec85SAndroid Build Coastguard Worker // Split existingHal into a HAL that contains only interface/instance and a HAL
146*70a7ec85SAndroid Build Coastguard Worker // that does not contain it. Return the HAL that contains only interface/instance.
147*70a7ec85SAndroid Build Coastguard Worker // - Return nullptr if existingHal does not contain interface/instance
148*70a7ec85SAndroid Build Coastguard Worker // - Return existingHal if existingHal contains only interface/instance
149*70a7ec85SAndroid Build Coastguard Worker // - Remove interface/instance from existingHal, and return a new MatrixHal (that is added
150*70a7ec85SAndroid Build Coastguard Worker //   to "this") that contains only interface/instance.
splitInstance(MatrixHal * existingHal,const std::string & interface,const std::string & instanceOrPattern,bool isRegex)151*70a7ec85SAndroid Build Coastguard Worker MatrixHal* CompatibilityMatrix::splitInstance(MatrixHal* existingHal, const std::string& interface,
152*70a7ec85SAndroid Build Coastguard Worker                                               const std::string& instanceOrPattern, bool isRegex) {
153*70a7ec85SAndroid Build Coastguard Worker     bool found = false;
154*70a7ec85SAndroid Build Coastguard Worker     bool foundOthers = false;
155*70a7ec85SAndroid Build Coastguard Worker     existingHal->forEachInstance([&](const auto& matrixInstance) {
156*70a7ec85SAndroid Build Coastguard Worker         bool interfaceMatch = matrixInstance.interface() == interface;
157*70a7ec85SAndroid Build Coastguard Worker         bool instanceMatch = false;
158*70a7ec85SAndroid Build Coastguard Worker         if (matrixInstance.isRegex() && isRegex) {
159*70a7ec85SAndroid Build Coastguard Worker             instanceMatch = (matrixInstance.regexPattern() == instanceOrPattern);
160*70a7ec85SAndroid Build Coastguard Worker         } else if (!matrixInstance.isRegex() && !isRegex) {
161*70a7ec85SAndroid Build Coastguard Worker             instanceMatch = (matrixInstance.exactInstance() == instanceOrPattern);
162*70a7ec85SAndroid Build Coastguard Worker         }
163*70a7ec85SAndroid Build Coastguard Worker 
164*70a7ec85SAndroid Build Coastguard Worker         bool match = interfaceMatch && instanceMatch;
165*70a7ec85SAndroid Build Coastguard Worker 
166*70a7ec85SAndroid Build Coastguard Worker         found |= match;
167*70a7ec85SAndroid Build Coastguard Worker         foundOthers |= (!match);
168*70a7ec85SAndroid Build Coastguard Worker 
169*70a7ec85SAndroid Build Coastguard Worker         return !found || !foundOthers;
170*70a7ec85SAndroid Build Coastguard Worker     });
171*70a7ec85SAndroid Build Coastguard Worker 
172*70a7ec85SAndroid Build Coastguard Worker     if (!found) {
173*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
174*70a7ec85SAndroid Build Coastguard Worker     }
175*70a7ec85SAndroid Build Coastguard Worker 
176*70a7ec85SAndroid Build Coastguard Worker     if (!foundOthers) {
177*70a7ec85SAndroid Build Coastguard Worker         return existingHal;
178*70a7ec85SAndroid Build Coastguard Worker     }
179*70a7ec85SAndroid Build Coastguard Worker 
180*70a7ec85SAndroid Build Coastguard Worker     existingHal->removeInstance(interface, instanceOrPattern, isRegex);
181*70a7ec85SAndroid Build Coastguard Worker     MatrixHal copy = *existingHal;
182*70a7ec85SAndroid Build Coastguard Worker     copy.clearInstances();
183*70a7ec85SAndroid Build Coastguard Worker     copy.insertInstance(interface, instanceOrPattern, isRegex);
184*70a7ec85SAndroid Build Coastguard Worker 
185*70a7ec85SAndroid Build Coastguard Worker     return addInternal(std::move(copy));
186*70a7ec85SAndroid Build Coastguard Worker }
187*70a7ec85SAndroid Build Coastguard Worker 
188*70a7ec85SAndroid Build Coastguard Worker // Add all package@other_version::interface/instance as an optional instance.
189*70a7ec85SAndroid Build Coastguard Worker // If package@this_version::interface/instance is in this (that is, some instance
190*70a7ec85SAndroid Build Coastguard Worker // with the same package and interface and instance exists), then other_version is
191*70a7ec85SAndroid Build Coastguard Worker // considered a possible replacement to this_version.
192*70a7ec85SAndroid Build Coastguard Worker // See LibVintfTest.AddOptionalHal* tests for details.
addAllHalsAsOptional(CompatibilityMatrix * other,std::string * error)193*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAllHalsAsOptional(CompatibilityMatrix* other, std::string* error) {
194*70a7ec85SAndroid Build Coastguard Worker     if (other == nullptr || other->level() <= level()) {
195*70a7ec85SAndroid Build Coastguard Worker         return true;
196*70a7ec85SAndroid Build Coastguard Worker     }
197*70a7ec85SAndroid Build Coastguard Worker 
198*70a7ec85SAndroid Build Coastguard Worker     for (auto& halEntry : other->mHals) {
199*70a7ec85SAndroid Build Coastguard Worker         const std::string& name = halEntry.first;
200*70a7ec85SAndroid Build Coastguard Worker         MatrixHal& halToAdd = halEntry.second;
201*70a7ec85SAndroid Build Coastguard Worker 
202*70a7ec85SAndroid Build Coastguard Worker         std::set<std::pair<std::string, std::string>> insertedInstances;
203*70a7ec85SAndroid Build Coastguard Worker         std::set<std::pair<std::string, std::string>> insertedRegex;
204*70a7ec85SAndroid Build Coastguard Worker         auto existingHals = getHals(name);
205*70a7ec85SAndroid Build Coastguard Worker 
206*70a7ec85SAndroid Build Coastguard Worker         halToAdd.forEachInstance([&](const std::vector<VersionRange>& versionRanges,
207*70a7ec85SAndroid Build Coastguard Worker                                      const std::string& interface,
208*70a7ec85SAndroid Build Coastguard Worker                                      const std::string& instanceOrPattern, bool isRegex) {
209*70a7ec85SAndroid Build Coastguard Worker             for (auto* existingHal : existingHals) {
210*70a7ec85SAndroid Build Coastguard Worker                 // Ignore HALs with different format.
211*70a7ec85SAndroid Build Coastguard Worker                 if (halToAdd.format != existingHal->format) {
212*70a7ec85SAndroid Build Coastguard Worker                     continue;
213*70a7ec85SAndroid Build Coastguard Worker                 }
214*70a7ec85SAndroid Build Coastguard Worker 
215*70a7ec85SAndroid Build Coastguard Worker                 MatrixHal* splitInstance =
216*70a7ec85SAndroid Build Coastguard Worker                     this->splitInstance(existingHal, interface, instanceOrPattern, isRegex);
217*70a7ec85SAndroid Build Coastguard Worker                 if (splitInstance != nullptr) {
218*70a7ec85SAndroid Build Coastguard Worker                     splitInstance->updatableViaApex |= halToAdd.updatableViaApex;
219*70a7ec85SAndroid Build Coastguard Worker                     splitInstance->insertVersionRanges(versionRanges);
220*70a7ec85SAndroid Build Coastguard Worker                     if (isRegex) {
221*70a7ec85SAndroid Build Coastguard Worker                         insertedRegex.insert(std::make_pair(interface, instanceOrPattern));
222*70a7ec85SAndroid Build Coastguard Worker                     } else {
223*70a7ec85SAndroid Build Coastguard Worker                         insertedInstances.insert(std::make_pair(interface, instanceOrPattern));
224*70a7ec85SAndroid Build Coastguard Worker                     }
225*70a7ec85SAndroid Build Coastguard Worker                 }
226*70a7ec85SAndroid Build Coastguard Worker             }
227*70a7ec85SAndroid Build Coastguard Worker             return true;
228*70a7ec85SAndroid Build Coastguard Worker         });
229*70a7ec85SAndroid Build Coastguard Worker 
230*70a7ec85SAndroid Build Coastguard Worker         // Add the remaining instances.
231*70a7ec85SAndroid Build Coastguard Worker         for (const auto& entry : insertedInstances) {
232*70a7ec85SAndroid Build Coastguard Worker             halToAdd.removeInstance(entry.first, entry.second, false /* isRegex */);
233*70a7ec85SAndroid Build Coastguard Worker         }
234*70a7ec85SAndroid Build Coastguard Worker         for (const auto& entry : insertedRegex) {
235*70a7ec85SAndroid Build Coastguard Worker             halToAdd.removeInstance(entry.first, entry.second, true /* isRegex */);
236*70a7ec85SAndroid Build Coastguard Worker         }
237*70a7ec85SAndroid Build Coastguard Worker 
238*70a7ec85SAndroid Build Coastguard Worker         if (halToAdd.instancesCount() > 0) {
239*70a7ec85SAndroid Build Coastguard Worker             halToAdd.setOptional(true);
240*70a7ec85SAndroid Build Coastguard Worker             if (!add(std::move(halToAdd))) {
241*70a7ec85SAndroid Build Coastguard Worker                 if (error) {
242*70a7ec85SAndroid Build Coastguard Worker                     *error = "Cannot add HAL " + name + " for unknown reason.";
243*70a7ec85SAndroid Build Coastguard Worker                 }
244*70a7ec85SAndroid Build Coastguard Worker                 return false;
245*70a7ec85SAndroid Build Coastguard Worker             }
246*70a7ec85SAndroid Build Coastguard Worker         }
247*70a7ec85SAndroid Build Coastguard Worker     }
248*70a7ec85SAndroid Build Coastguard Worker     return true;
249*70a7ec85SAndroid Build Coastguard Worker }
250*70a7ec85SAndroid Build Coastguard Worker 
addAllXmlFilesAsOptional(CompatibilityMatrix * other,std::string * error)251*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error) {
252*70a7ec85SAndroid Build Coastguard Worker     if (other == nullptr || other->level() <= level()) {
253*70a7ec85SAndroid Build Coastguard Worker         return true;
254*70a7ec85SAndroid Build Coastguard Worker     }
255*70a7ec85SAndroid Build Coastguard Worker     for (auto& pair : other->mXmlFiles) {
256*70a7ec85SAndroid Build Coastguard Worker         const std::string& name = pair.first;
257*70a7ec85SAndroid Build Coastguard Worker         MatrixXmlFile& xmlFileToAdd = pair.second;
258*70a7ec85SAndroid Build Coastguard Worker 
259*70a7ec85SAndroid Build Coastguard Worker         xmlFileToAdd.mOptional = true;
260*70a7ec85SAndroid Build Coastguard Worker         if (!addXmlFile(std::move(xmlFileToAdd))) {
261*70a7ec85SAndroid Build Coastguard Worker             if (error) {
262*70a7ec85SAndroid Build Coastguard Worker                 *error = "Cannot add XML File " + name + " for unknown reason.";
263*70a7ec85SAndroid Build Coastguard Worker             }
264*70a7ec85SAndroid Build Coastguard Worker             return false;
265*70a7ec85SAndroid Build Coastguard Worker         }
266*70a7ec85SAndroid Build Coastguard Worker     }
267*70a7ec85SAndroid Build Coastguard Worker     return true;
268*70a7ec85SAndroid Build Coastguard Worker }
269*70a7ec85SAndroid Build Coastguard Worker 
270*70a7ec85SAndroid Build Coastguard Worker // Merge Kernel. See KernelInfo::getMatchedKernelRequirements for details on compatibility checks.
addAllKernels(CompatibilityMatrix * other,std::string * error)271*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAllKernels(CompatibilityMatrix* other, std::string* error) {
272*70a7ec85SAndroid Build Coastguard Worker     for (MatrixKernel& kernel : other->framework.mKernels) {
273*70a7ec85SAndroid Build Coastguard Worker         if (kernel.getSourceMatrixLevel() == Level::UNSPECIFIED) {
274*70a7ec85SAndroid Build Coastguard Worker             kernel.setSourceMatrixLevel(other->level());
275*70a7ec85SAndroid Build Coastguard Worker         }
276*70a7ec85SAndroid Build Coastguard Worker         KernelVersion ver = kernel.minLts();
277*70a7ec85SAndroid Build Coastguard Worker         if (!addKernel(std::move(kernel), error)) {
278*70a7ec85SAndroid Build Coastguard Worker             if (error) {
279*70a7ec85SAndroid Build Coastguard Worker                 *error = "Cannot add kernel version " + to_string(ver) + ": " + *error;
280*70a7ec85SAndroid Build Coastguard Worker             }
281*70a7ec85SAndroid Build Coastguard Worker             return false;
282*70a7ec85SAndroid Build Coastguard Worker         }
283*70a7ec85SAndroid Build Coastguard Worker     }
284*70a7ec85SAndroid Build Coastguard Worker     return true;
285*70a7ec85SAndroid Build Coastguard Worker }
286*70a7ec85SAndroid Build Coastguard Worker 
addSepolicy(CompatibilityMatrix * other,std::string * error)287*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addSepolicy(CompatibilityMatrix* other, std::string* error) {
288*70a7ec85SAndroid Build Coastguard Worker     bool success = mergeField(&this->framework.mSepolicy, &other->framework.mSepolicy);
289*70a7ec85SAndroid Build Coastguard Worker     if (!success && error) *error = "<sepolicy> is already defined";
290*70a7ec85SAndroid Build Coastguard Worker     return success;
291*70a7ec85SAndroid Build Coastguard Worker }
292*70a7ec85SAndroid Build Coastguard Worker 
addAvbMetaVersion(CompatibilityMatrix * other,std::string * error)293*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAvbMetaVersion(CompatibilityMatrix* other, std::string* error) {
294*70a7ec85SAndroid Build Coastguard Worker     bool success = mergeField(&this->framework.mAvbMetaVersion, &other->framework.mAvbMetaVersion);
295*70a7ec85SAndroid Build Coastguard Worker     if (!success && error) *error = "<avb><vbmeta-version> is already defined";
296*70a7ec85SAndroid Build Coastguard Worker     return success;
297*70a7ec85SAndroid Build Coastguard Worker }
298*70a7ec85SAndroid Build Coastguard Worker 
addVndk(CompatibilityMatrix * other,std::string * error)299*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addVndk(CompatibilityMatrix* other, std::string* error) {
300*70a7ec85SAndroid Build Coastguard Worker #pragma clang diagnostic push
301*70a7ec85SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wdeprecated-declarations"
302*70a7ec85SAndroid Build Coastguard Worker     bool success = mergeField(&this->device.mVndk, &other->device.mVndk);
303*70a7ec85SAndroid Build Coastguard Worker #pragma clang diagnostic pop
304*70a7ec85SAndroid Build Coastguard Worker     if (!success && error) *error = "<vndk> is already defined";
305*70a7ec85SAndroid Build Coastguard Worker     return success;
306*70a7ec85SAndroid Build Coastguard Worker }
307*70a7ec85SAndroid Build Coastguard Worker 
addVendorNdk(CompatibilityMatrix * other,std::string * error)308*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addVendorNdk(CompatibilityMatrix* other, std::string* error) {
309*70a7ec85SAndroid Build Coastguard Worker     bool success = mergeField(&this->device.mVendorNdk, &other->device.mVendorNdk);
310*70a7ec85SAndroid Build Coastguard Worker     if (!success && error) *error = "<vendor-ndk> is already defined";
311*70a7ec85SAndroid Build Coastguard Worker     return success;
312*70a7ec85SAndroid Build Coastguard Worker }
313*70a7ec85SAndroid Build Coastguard Worker 
addSystemSdk(CompatibilityMatrix * other,std::string *)314*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addSystemSdk(CompatibilityMatrix* other, std::string* /* error */) {
315*70a7ec85SAndroid Build Coastguard Worker     this->device.mSystemSdk.addAll(&other->device.mSystemSdk);
316*70a7ec85SAndroid Build Coastguard Worker     return true;
317*70a7ec85SAndroid Build Coastguard Worker }
318*70a7ec85SAndroid Build Coastguard Worker 
operator ==(const CompatibilityMatrix & lft,const CompatibilityMatrix & rgt)319*70a7ec85SAndroid Build Coastguard Worker bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
320*70a7ec85SAndroid Build Coastguard Worker     // ignore fileName().
321*70a7ec85SAndroid Build Coastguard Worker     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
322*70a7ec85SAndroid Build Coastguard Worker            lft.mXmlFiles == rgt.mXmlFiles &&
323*70a7ec85SAndroid Build Coastguard Worker            (lft.mType != SchemaType::DEVICE ||
324*70a7ec85SAndroid Build Coastguard Worker             (
325*70a7ec85SAndroid Build Coastguard Worker #pragma clang diagnostic push
326*70a7ec85SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wdeprecated-declarations"
327*70a7ec85SAndroid Build Coastguard Worker                 lft.device.mVndk == rgt.device.mVndk &&
328*70a7ec85SAndroid Build Coastguard Worker #pragma clang diagnostic pop
329*70a7ec85SAndroid Build Coastguard Worker                 lft.device.mVendorNdk == rgt.device.mVendorNdk &&
330*70a7ec85SAndroid Build Coastguard Worker                 lft.device.mSystemSdk == rgt.device.mSystemSdk)) &&
331*70a7ec85SAndroid Build Coastguard Worker            (lft.mType != SchemaType::FRAMEWORK ||
332*70a7ec85SAndroid Build Coastguard Worker             (lft.framework.mKernels == rgt.framework.mKernels &&
333*70a7ec85SAndroid Build Coastguard Worker              lft.framework.mSepolicy == rgt.framework.mSepolicy &&
334*70a7ec85SAndroid Build Coastguard Worker              lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
335*70a7ec85SAndroid Build Coastguard Worker }
336*70a7ec85SAndroid Build Coastguard Worker 
combine(Level deviceLevel,Level kernelLevel,std::vector<CompatibilityMatrix> * matrices,std::string * error)337*70a7ec85SAndroid Build Coastguard Worker std::unique_ptr<CompatibilityMatrix> CompatibilityMatrix::combine(
338*70a7ec85SAndroid Build Coastguard Worker     Level deviceLevel, Level kernelLevel, std::vector<CompatibilityMatrix>* matrices,
339*70a7ec85SAndroid Build Coastguard Worker     std::string* error) {
340*70a7ec85SAndroid Build Coastguard Worker     // Check type.
341*70a7ec85SAndroid Build Coastguard Worker     for (const auto& e : *matrices) {
342*70a7ec85SAndroid Build Coastguard Worker         if (e.type() != SchemaType::FRAMEWORK) {
343*70a7ec85SAndroid Build Coastguard Worker             if (error) {
344*70a7ec85SAndroid Build Coastguard Worker                 *error = "File \"" + e.fileName() + "\" is not a framework compatibility matrix.";
345*70a7ec85SAndroid Build Coastguard Worker                 return nullptr;
346*70a7ec85SAndroid Build Coastguard Worker             }
347*70a7ec85SAndroid Build Coastguard Worker         }
348*70a7ec85SAndroid Build Coastguard Worker     }
349*70a7ec85SAndroid Build Coastguard Worker 
350*70a7ec85SAndroid Build Coastguard Worker     // Matrices with unspecified (empty) level are auto-filled with deviceLevel.
351*70a7ec85SAndroid Build Coastguard Worker     for (auto& e : *matrices) {
352*70a7ec85SAndroid Build Coastguard Worker         if (e.level() == Level::UNSPECIFIED) {
353*70a7ec85SAndroid Build Coastguard Worker             e.mLevel = deviceLevel;
354*70a7ec85SAndroid Build Coastguard Worker         }
355*70a7ec85SAndroid Build Coastguard Worker     }
356*70a7ec85SAndroid Build Coastguard Worker 
357*70a7ec85SAndroid Build Coastguard Worker     // Add from low to high FCM version so that optional <kernel> requirements are added correctly.
358*70a7ec85SAndroid Build Coastguard Worker     // See comment in addAllAsOptional.
359*70a7ec85SAndroid Build Coastguard Worker     std::sort(matrices->begin(), matrices->end(),
360*70a7ec85SAndroid Build Coastguard Worker               [](const auto& x, const auto& y) { return x.level() < y.level(); });
361*70a7ec85SAndroid Build Coastguard Worker 
362*70a7ec85SAndroid Build Coastguard Worker     auto baseMatrix = std::make_unique<CompatibilityMatrix>();
363*70a7ec85SAndroid Build Coastguard Worker     baseMatrix->mLevel = deviceLevel;
364*70a7ec85SAndroid Build Coastguard Worker     baseMatrix->mType = SchemaType::FRAMEWORK;
365*70a7ec85SAndroid Build Coastguard Worker 
366*70a7ec85SAndroid Build Coastguard Worker     std::vector<std::string> parsedFiles;
367*70a7ec85SAndroid Build Coastguard Worker     for (auto& e : *matrices) {
368*70a7ec85SAndroid Build Coastguard Worker         bool success = false;
369*70a7ec85SAndroid Build Coastguard Worker         if (e.level() < deviceLevel) {
370*70a7ec85SAndroid Build Coastguard Worker             if (kernelLevel == Level::UNSPECIFIED) continue;
371*70a7ec85SAndroid Build Coastguard Worker             if (e.level() < kernelLevel) continue;
372*70a7ec85SAndroid Build Coastguard Worker             success = baseMatrix->addAllKernels(&e, error);
373*70a7ec85SAndroid Build Coastguard Worker         } else if (e.level() == deviceLevel) {
374*70a7ec85SAndroid Build Coastguard Worker             success = baseMatrix->addAll(&e, error);
375*70a7ec85SAndroid Build Coastguard Worker         } else {
376*70a7ec85SAndroid Build Coastguard Worker             success = baseMatrix->addAllAsOptional(&e, error);
377*70a7ec85SAndroid Build Coastguard Worker         }
378*70a7ec85SAndroid Build Coastguard Worker         if (!success) {
379*70a7ec85SAndroid Build Coastguard Worker             if (error) {
380*70a7ec85SAndroid Build Coastguard Worker                 *error = "Conflict when merging \"" + e.fileName() + "\": " + *error + "\n" +
381*70a7ec85SAndroid Build Coastguard Worker                          "Previous files:\n" + base::Join(parsedFiles, "\n");
382*70a7ec85SAndroid Build Coastguard Worker             }
383*70a7ec85SAndroid Build Coastguard Worker             return nullptr;
384*70a7ec85SAndroid Build Coastguard Worker         }
385*70a7ec85SAndroid Build Coastguard Worker         parsedFiles.push_back(e.fileName());
386*70a7ec85SAndroid Build Coastguard Worker     }
387*70a7ec85SAndroid Build Coastguard Worker 
388*70a7ec85SAndroid Build Coastguard Worker     return baseMatrix;
389*70a7ec85SAndroid Build Coastguard Worker }
390*70a7ec85SAndroid Build Coastguard Worker 
combineDeviceMatrices(std::vector<CompatibilityMatrix> * matrices,std::string * error)391*70a7ec85SAndroid Build Coastguard Worker std::unique_ptr<CompatibilityMatrix> CompatibilityMatrix::combineDeviceMatrices(
392*70a7ec85SAndroid Build Coastguard Worker     std::vector<CompatibilityMatrix>* matrices, std::string* error) {
393*70a7ec85SAndroid Build Coastguard Worker     auto baseMatrix = std::make_unique<CompatibilityMatrix>();
394*70a7ec85SAndroid Build Coastguard Worker     baseMatrix->mType = SchemaType::DEVICE;
395*70a7ec85SAndroid Build Coastguard Worker 
396*70a7ec85SAndroid Build Coastguard Worker     std::vector<std::string> parsedFiles;
397*70a7ec85SAndroid Build Coastguard Worker     for (auto& e : *matrices) {
398*70a7ec85SAndroid Build Coastguard Worker         bool success = baseMatrix->addAll(&e, error);
399*70a7ec85SAndroid Build Coastguard Worker         if (!success) {
400*70a7ec85SAndroid Build Coastguard Worker             if (error) {
401*70a7ec85SAndroid Build Coastguard Worker                 *error = "Conflict when merging \"" + e.fileName() + "\": " + *error + "\n" +
402*70a7ec85SAndroid Build Coastguard Worker                          "Previous files:\n" + base::Join(parsedFiles, "\n");
403*70a7ec85SAndroid Build Coastguard Worker             }
404*70a7ec85SAndroid Build Coastguard Worker             return nullptr;
405*70a7ec85SAndroid Build Coastguard Worker         }
406*70a7ec85SAndroid Build Coastguard Worker         parsedFiles.push_back(e.fileName());
407*70a7ec85SAndroid Build Coastguard Worker     }
408*70a7ec85SAndroid Build Coastguard Worker     return baseMatrix;
409*70a7ec85SAndroid Build Coastguard Worker }
410*70a7ec85SAndroid Build Coastguard Worker 
addAll(CompatibilityMatrix * inputMatrix,std::string * error)411*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAll(CompatibilityMatrix* inputMatrix, std::string* error) {
412*70a7ec85SAndroid Build Coastguard Worker     if (!addAllHals(inputMatrix, error) || !addAllXmlFiles(inputMatrix, error) ||
413*70a7ec85SAndroid Build Coastguard Worker         !addAllKernels(inputMatrix, error) || !addSepolicy(inputMatrix, error) ||
414*70a7ec85SAndroid Build Coastguard Worker         !addAvbMetaVersion(inputMatrix, error) || !addVndk(inputMatrix, error) ||
415*70a7ec85SAndroid Build Coastguard Worker         !addVendorNdk(inputMatrix, error) || !addSystemSdk(inputMatrix, error)) {
416*70a7ec85SAndroid Build Coastguard Worker         if (error) {
417*70a7ec85SAndroid Build Coastguard Worker             *error = "File \"" + inputMatrix->fileName() + "\" cannot be added: " + *error + ".";
418*70a7ec85SAndroid Build Coastguard Worker         }
419*70a7ec85SAndroid Build Coastguard Worker         return false;
420*70a7ec85SAndroid Build Coastguard Worker     }
421*70a7ec85SAndroid Build Coastguard Worker     return true;
422*70a7ec85SAndroid Build Coastguard Worker }
423*70a7ec85SAndroid Build Coastguard Worker 
addAllAsOptional(CompatibilityMatrix * inputMatrix,std::string * error)424*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::addAllAsOptional(CompatibilityMatrix* inputMatrix, std::string* error) {
425*70a7ec85SAndroid Build Coastguard Worker     if (!addAllHalsAsOptional(inputMatrix, error) ||
426*70a7ec85SAndroid Build Coastguard Worker         !addAllXmlFilesAsOptional(inputMatrix, error) || !addAllKernels(inputMatrix, error)) {
427*70a7ec85SAndroid Build Coastguard Worker         if (error) {
428*70a7ec85SAndroid Build Coastguard Worker             *error = "File \"" + inputMatrix->fileName() + "\" cannot be added: " + *error;
429*70a7ec85SAndroid Build Coastguard Worker         }
430*70a7ec85SAndroid Build Coastguard Worker         return false;
431*70a7ec85SAndroid Build Coastguard Worker     }
432*70a7ec85SAndroid Build Coastguard Worker     // ignore <sepolicy> requirement from higher level
433*70a7ec85SAndroid Build Coastguard Worker     // ignore <avb> requirement from higher level
434*70a7ec85SAndroid Build Coastguard Worker     return true;
435*70a7ec85SAndroid Build Coastguard Worker }
436*70a7ec85SAndroid Build Coastguard Worker 
forEachInstanceOfVersion(HalFormat format,ExclusiveTo exclusiveTo,const std::string & package,const Version & expectVersion,const std::function<bool (const MatrixInstance &)> & func) const437*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::forEachInstanceOfVersion(
438*70a7ec85SAndroid Build Coastguard Worker     HalFormat format, ExclusiveTo exclusiveTo, const std::string& package,
439*70a7ec85SAndroid Build Coastguard Worker     const Version& expectVersion, const std::function<bool(const MatrixInstance&)>& func) const {
440*70a7ec85SAndroid Build Coastguard Worker     for (const MatrixHal* hal : getHals(package)) {
441*70a7ec85SAndroid Build Coastguard Worker         bool cont = hal->forEachInstance([&](const MatrixInstance& matrixInstance) {
442*70a7ec85SAndroid Build Coastguard Worker             if (matrixInstance.format() == format &&
443*70a7ec85SAndroid Build Coastguard Worker                 matrixInstance.versionRange().contains(expectVersion) &&
444*70a7ec85SAndroid Build Coastguard Worker                 matrixInstance.exclusiveTo() == exclusiveTo) {
445*70a7ec85SAndroid Build Coastguard Worker                 return func(matrixInstance);
446*70a7ec85SAndroid Build Coastguard Worker             }
447*70a7ec85SAndroid Build Coastguard Worker             return true;
448*70a7ec85SAndroid Build Coastguard Worker         });
449*70a7ec85SAndroid Build Coastguard Worker         if (!cont) return false;
450*70a7ec85SAndroid Build Coastguard Worker     }
451*70a7ec85SAndroid Build Coastguard Worker     return true;
452*70a7ec85SAndroid Build Coastguard Worker }
453*70a7ec85SAndroid Build Coastguard Worker 
matchInstance(HalFormat format,ExclusiveTo exclusiveTo,const std::string & halName,const Version & version,const std::string & interfaceName,const std::string & instance) const454*70a7ec85SAndroid Build Coastguard Worker bool CompatibilityMatrix::matchInstance(HalFormat format, ExclusiveTo exclusiveTo,
455*70a7ec85SAndroid Build Coastguard Worker                                         const std::string& halName, const Version& version,
456*70a7ec85SAndroid Build Coastguard Worker                                         const std::string& interfaceName,
457*70a7ec85SAndroid Build Coastguard Worker                                         const std::string& instance) const {
458*70a7ec85SAndroid Build Coastguard Worker     bool found = false;
459*70a7ec85SAndroid Build Coastguard Worker     (void)forEachInstanceOfInterface(format, exclusiveTo, halName, version, interfaceName,
460*70a7ec85SAndroid Build Coastguard Worker                                      [&found, &instance](const auto& e) {
461*70a7ec85SAndroid Build Coastguard Worker                                          found |= (e.matchInstance(instance));
462*70a7ec85SAndroid Build Coastguard Worker                                          return !found;  // if not found, continue
463*70a7ec85SAndroid Build Coastguard Worker                                      });
464*70a7ec85SAndroid Build Coastguard Worker     return found;
465*70a7ec85SAndroid Build Coastguard Worker }
466*70a7ec85SAndroid Build Coastguard Worker 
getSepolicyVersions() const467*70a7ec85SAndroid Build Coastguard Worker std::vector<SepolicyVersionRange> CompatibilityMatrix::getSepolicyVersions() const {
468*70a7ec85SAndroid Build Coastguard Worker     if (type() == SchemaType::FRAMEWORK) return framework.mSepolicy.sepolicyVersions();
469*70a7ec85SAndroid Build Coastguard Worker     return {};
470*70a7ec85SAndroid Build Coastguard Worker }
471*70a7ec85SAndroid Build Coastguard Worker 
getVendorNdkVersion() const472*70a7ec85SAndroid Build Coastguard Worker std::string CompatibilityMatrix::getVendorNdkVersion() const {
473*70a7ec85SAndroid Build Coastguard Worker     return type() == SchemaType::DEVICE ? device.mVendorNdk.version() : "";
474*70a7ec85SAndroid Build Coastguard Worker }
475*70a7ec85SAndroid Build Coastguard Worker 
getLatestKernelMinLts() const476*70a7ec85SAndroid Build Coastguard Worker KernelVersion CompatibilityMatrix::getLatestKernelMinLts() const {
477*70a7ec85SAndroid Build Coastguard Worker     if (type() != SchemaType::FRAMEWORK) {
478*70a7ec85SAndroid Build Coastguard Worker         return {};
479*70a7ec85SAndroid Build Coastguard Worker     }
480*70a7ec85SAndroid Build Coastguard Worker     auto maxIt = std::max_element(
481*70a7ec85SAndroid Build Coastguard Worker         framework.mKernels.begin(), framework.mKernels.end(),
482*70a7ec85SAndroid Build Coastguard Worker         [](const MatrixKernel& a, const MatrixKernel& b) { return a.minLts() < b.minLts(); });
483*70a7ec85SAndroid Build Coastguard Worker     if (maxIt == framework.mKernels.end()) {
484*70a7ec85SAndroid Build Coastguard Worker         return {};
485*70a7ec85SAndroid Build Coastguard Worker     }
486*70a7ec85SAndroid Build Coastguard Worker     return maxIt->minLts();
487*70a7ec85SAndroid Build Coastguard Worker }
488*70a7ec85SAndroid Build Coastguard Worker 
489*70a7ec85SAndroid Build Coastguard Worker } // namespace vintf
490*70a7ec85SAndroid Build Coastguard Worker } // namespace android
491