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