blob: 845e4434c0fe55bb73ce02fc2b0a2e266c022cfd [file] [log] [blame]
Yifan Hong676447a2016-11-15 12:57:23 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "CompatibilityMatrix.h"
18
Yifan Hongdbe9db32017-12-11 19:06:11 -080019#include <utility>
20
Yifan Hongbbfff302017-06-06 17:10:13 -070021#include "parse_string.h"
Yifan Hong1e5a0542017-04-28 14:37:56 -070022#include "utils.h"
23
Yifan Hongddae77e2017-12-18 16:57:07 -080024#include <iostream>
25#include "parse_xml.h"
26
Yifan Hong676447a2016-11-15 12:57:23 -080027namespace android {
28namespace vintf {
29
Yifan Hong676447a2016-11-15 12:57:23 -080030bool CompatibilityMatrix::add(MatrixHal &&hal) {
Yifan Hong0fd7aef2017-05-24 14:37:19 -070031 return HalGroup<MatrixHal>::add(std::move(hal));
Yifan Hong676447a2016-11-15 12:57:23 -080032}
33
34bool CompatibilityMatrix::add(MatrixKernel &&kernel) {
Yifan Hong7c7d7062017-04-04 16:26:51 -070035 if (mType != SchemaType::FRAMEWORK) {
36 return false;
37 }
38 framework.mKernels.push_back(std::move(kernel));
Yifan Hong676447a2016-11-15 12:57:23 -080039 return true;
40}
41
Yifan Hong398f4c72017-04-13 20:18:01 -070042SchemaType CompatibilityMatrix::type() const {
43 return mType;
44}
45
Yifan Hong2027a492017-12-11 15:21:19 -080046Level CompatibilityMatrix::level() const {
47 return mLevel;
48}
49
Yifan Hongdb127cb2017-09-19 13:36:21 -070050Version CompatibilityMatrix::getMinimumMetaVersion() const {
51 // TODO(b/62801658): this needs to depend on whether there are 1.1 requirements
52 // (e.g. required <xmlfile> entry)
53 return {1, 0};
54}
Yifan Hong1e5a0542017-04-28 14:37:56 -070055
Yifan Hong60217032018-01-08 16:19:42 -080056status_t CompatibilityMatrix::fetchAllInformation(const std::string& path, std::string* error) {
57 return details::fetchAllInformation(path, gCompatibilityMatrixConverter, this, error);
Yifan Hong1e5a0542017-04-28 14:37:56 -070058}
59
Yifan Hongbbfff302017-06-06 17:10:13 -070060std::string CompatibilityMatrix::getXmlSchemaPath(const std::string& xmlFileName,
61 const Version& version) const {
62 using std::literals::string_literals::operator""s;
63 auto range = getXmlFiles(xmlFileName);
64 for (auto it = range.first; it != range.second; ++it) {
65 const MatrixXmlFile& matrixXmlFile = it->second;
66 if (matrixXmlFile.versionRange().contains(version)) {
67 if (!matrixXmlFile.overriddenPath().empty()) {
68 return matrixXmlFile.overriddenPath();
69 }
70 return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
71 xmlFileName + "_V" + std::to_string(matrixXmlFile.versionRange().majorVer) +
72 "_" + std::to_string(matrixXmlFile.versionRange().maxMinor) + "." +
73 to_string(matrixXmlFile.format());
74 }
75 }
76 return "";
77}
78
Yifan Hongdbe9db32017-12-11 19:06:11 -080079static VersionRange* findRangeWithMajorVersion(std::vector<VersionRange>& versionRanges,
80 size_t majorVer) {
81 for (VersionRange& vr : versionRanges) {
82 if (vr.majorVer == majorVer) {
83 return &vr;
84 }
85 }
86 return nullptr;
87}
88
89std::pair<MatrixHal*, VersionRange*> CompatibilityMatrix::getHalWithMajorVersion(
90 const std::string& name, size_t majorVer) {
91 for (MatrixHal* hal : getHals(name)) {
92 VersionRange* vr = findRangeWithMajorVersion(hal->versionRanges, majorVer);
93 if (vr != nullptr) {
94 return {hal, vr};
95 }
96 }
97 return {nullptr, nullptr};
98}
99
100bool CompatibilityMatrix::addAllHalsAsOptional(CompatibilityMatrix* other, std::string* error) {
101 if (other == nullptr || other->level() <= level()) {
102 return true;
103 }
104
105 for (auto& pair : other->mHals) {
106 const std::string& name = pair.first;
107 MatrixHal& halToAdd = pair.second;
108 for (const VersionRange& vr : halToAdd.versionRanges) {
109 MatrixHal* existingHal;
110 VersionRange* existingVr;
111 std::tie(existingHal, existingVr) = getHalWithMajorVersion(name, vr.majorVer);
112
113 if (existingHal == nullptr) {
Yifan Hongd8eea9e2017-12-22 15:13:42 -0800114 MatrixHal optionalHalToAdd(halToAdd);
115 optionalHalToAdd.optional = true;
116 optionalHalToAdd.versionRanges = {vr};
117 if (!add(std::move(optionalHalToAdd))) {
Yifan Hong78c911a2017-12-20 15:16:59 -0800118 if (error) {
119 *error = "Cannot add HAL " + name + " for unknown reason.";
120 }
121 return false;
122 }
Yifan Hongdbe9db32017-12-11 19:06:11 -0800123 continue;
124 }
125
126 if (!existingHal->optional && !existingHal->containsInstances(halToAdd)) {
127 if (error != nullptr) {
128 *error = "HAL " + name + "@" + to_string(vr.minVer()) + " is a required " +
129 "HAL, but fully qualified instance names don't match (at FCM "
130 "Version " +
131 std::to_string(level()) + " and " + std::to_string(other->level()) +
132 ")";
133 }
134 return false;
135 }
136
137 existingVr->maxMinor = std::max(existingVr->maxMinor, vr.maxMinor);
138 }
139 }
140 return true;
141}
142
Yifan Hongd4b92fe2017-12-20 15:29:03 -0800143bool CompatibilityMatrix::addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error) {
144 if (other == nullptr || other->level() <= level()) {
145 return true;
146 }
147 for (auto& pair : other->mXmlFiles) {
148 const std::string& name = pair.first;
149 MatrixXmlFile& xmlFileToAdd = pair.second;
150
151 xmlFileToAdd.mOptional = true;
152 if (!addXmlFile(std::move(xmlFileToAdd))) {
153 if (error) {
154 *error = "Cannot add XML File " + name + " for unknown reason.";
155 }
156 return false;
157 }
158 }
159 return true;
160}
161
Yifan Hongfb7469c2017-04-05 19:15:21 -0700162bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
Yifan Hong2027a492017-12-11 15:21:19 -0800163 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
164 lft.mXmlFiles == rgt.mXmlFiles &&
Yifan Hong0f529fa2018-01-10 14:51:59 -0800165 (lft.mType != SchemaType::DEVICE || (
166#pragma clang diagnostic push
167#pragma clang diagnostic ignored "-Wdeprecated-declarations"
168 lft.device.mVndk == rgt.device.mVndk
169#pragma clang diagnostic pop
170 )) &&
Yifan Hongd4857902017-06-13 14:13:56 -0700171 (lft.mType != SchemaType::FRAMEWORK ||
172 (lft.framework.mKernels == rgt.framework.mKernels &&
173 lft.framework.mSepolicy == rgt.framework.mSepolicy &&
174 lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
Yifan Hongfb7469c2017-04-05 19:15:21 -0700175}
176
Yifan Hongddae77e2017-12-18 16:57:07 -0800177// Find compatibility_matrix.empty.xml (which has unspecified level) and use it
178// as a base matrix.
179CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
Yifan Hongffcaf992018-01-09 17:08:51 -0800180 std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800181 bool multipleFound = false;
182 CompatibilityMatrix* matrix = nullptr;
183 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800184 if (e.object.level() == Level::UNSPECIFIED) {
185 if (!e.object.mHals.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800186 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800187 *error = "Error: File \"" + e.name + "\" should not contain " + "HAL elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800188 }
189 return nullptr;
190 }
191
Yifan Hongffcaf992018-01-09 17:08:51 -0800192 if (!e.object.mXmlFiles.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800193 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800194 *error =
195 "Error: File \"" + e.name + "\" should not contain " + "XML File elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800196 }
197 return nullptr;
198 }
199
200 if (matrix != nullptr) {
201 multipleFound = true;
202 }
203
Yifan Hongffcaf992018-01-09 17:08:51 -0800204 matrix = &e.object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800205 // continue to detect multiple files with "unspecified" levels
206 }
207 }
208
209 if (multipleFound) {
210 if (error) {
211 *error =
212 "Error: multiple framework compatibility matrix files have "
213 "unspecified level; there should only be one such file.\n";
214 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800215 if (e.object.level() == Level::UNSPECIFIED) {
216 *error += " " + e.name + "\n";
Yifan Hongddae77e2017-12-18 16:57:07 -0800217 }
218 }
219 }
220 return nullptr;
221 }
222
223 if (matrix == nullptr) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800224 matrix = &matrices->emplace(matrices->end())->object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800225 matrix->mType = SchemaType::FRAMEWORK;
226 matrix->mLevel = Level::UNSPECIFIED;
227 }
228
229 return matrix;
230}
231
Yifan Hongffcaf992018-01-09 17:08:51 -0800232CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
233 std::vector<Named<CompatibilityMatrix>>* matrices,
234 std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800235 if (deviceLevel == Level::UNSPECIFIED) {
236 if (error) {
237 *error = "Error: device level is unspecified.";
238 }
239 return nullptr;
240 }
241
242 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
243 if (matrix == nullptr) {
244 return nullptr;
245 }
246
247 matrix->mLevel = deviceLevel;
248
249 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800250 if (&e.object != matrix && e.object.level() == deviceLevel) {
251 if (!matrix->addAllHals(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800252 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800253 *error = "File \"" + e.name + "\" cannot be added: HAL " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800254 " has a conflict.";
255 }
256 return nullptr;
257 }
258
Yifan Hongffcaf992018-01-09 17:08:51 -0800259 if (!matrix->addAllXmlFiles(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800260 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800261 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800262 " has a conflict.";
263 }
264 return nullptr;
265 }
266 }
267 }
268
269 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800270 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
271 e.object.level() > deviceLevel) {
272 if (!matrix->addAllHalsAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800273 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800274 *error = "File \"" + e.name + "\" cannot be added: " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800275 ". See <hal> with the same name " +
276 "in previously parsed files or previously declared in this file.";
277 }
278 return nullptr;
279 }
280
Yifan Hongffcaf992018-01-09 17:08:51 -0800281 if (!matrix->addAllXmlFilesAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800282 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800283 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800284 " has a conflict.";
285 }
286 return nullptr;
287 }
288 }
289 }
290
291 return matrix;
292}
293
Yifan Hong676447a2016-11-15 12:57:23 -0800294} // namespace vintf
295} // namespace android