blob: d3c4ebf36a6ab8d34b413c2a783179823f051195 [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 Hongfeb454e2018-01-09 16:16:40 -0800165 (lft.mType != SchemaType::DEVICE ||
166 (
Yifan Hong0f529fa2018-01-10 14:51:59 -0800167#pragma clang diagnostic push
168#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Yifan Hongfeb454e2018-01-09 16:16:40 -0800169 lft.device.mVndk == rgt.device.mVndk &&
Yifan Hong0f529fa2018-01-10 14:51:59 -0800170#pragma clang diagnostic pop
Yifan Honga28729e2018-01-17 13:40:35 -0800171 lft.device.mVendorNdk == rgt.device.mVendorNdk &&
172 lft.device.mSystemSdk == rgt.device.mSystemSdk)) &&
Yifan Hongd4857902017-06-13 14:13:56 -0700173 (lft.mType != SchemaType::FRAMEWORK ||
174 (lft.framework.mKernels == rgt.framework.mKernels &&
175 lft.framework.mSepolicy == rgt.framework.mSepolicy &&
176 lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
Yifan Hongfb7469c2017-04-05 19:15:21 -0700177}
178
Yifan Hongddae77e2017-12-18 16:57:07 -0800179// Find compatibility_matrix.empty.xml (which has unspecified level) and use it
180// as a base matrix.
181CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
Yifan Hongffcaf992018-01-09 17:08:51 -0800182 std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800183 bool multipleFound = false;
184 CompatibilityMatrix* matrix = nullptr;
185 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800186 if (e.object.level() == Level::UNSPECIFIED) {
187 if (!e.object.mHals.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800188 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800189 *error = "Error: File \"" + e.name + "\" should not contain " + "HAL elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800190 }
191 return nullptr;
192 }
193
Yifan Hongffcaf992018-01-09 17:08:51 -0800194 if (!e.object.mXmlFiles.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800195 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800196 *error =
197 "Error: File \"" + e.name + "\" should not contain " + "XML File elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800198 }
199 return nullptr;
200 }
201
202 if (matrix != nullptr) {
203 multipleFound = true;
204 }
205
Yifan Hongffcaf992018-01-09 17:08:51 -0800206 matrix = &e.object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800207 // continue to detect multiple files with "unspecified" levels
208 }
209 }
210
211 if (multipleFound) {
212 if (error) {
213 *error =
214 "Error: multiple framework compatibility matrix files have "
215 "unspecified level; there should only be one such file.\n";
216 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800217 if (e.object.level() == Level::UNSPECIFIED) {
218 *error += " " + e.name + "\n";
Yifan Hongddae77e2017-12-18 16:57:07 -0800219 }
220 }
221 }
222 return nullptr;
223 }
224
225 if (matrix == nullptr) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800226 matrix = &matrices->emplace(matrices->end())->object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800227 matrix->mType = SchemaType::FRAMEWORK;
228 matrix->mLevel = Level::UNSPECIFIED;
229 }
230
231 return matrix;
232}
233
Yifan Hongffcaf992018-01-09 17:08:51 -0800234CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
235 std::vector<Named<CompatibilityMatrix>>* matrices,
236 std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800237 if (deviceLevel == Level::UNSPECIFIED) {
238 if (error) {
239 *error = "Error: device level is unspecified.";
240 }
241 return nullptr;
242 }
243
244 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
245 if (matrix == nullptr) {
246 return nullptr;
247 }
248
249 matrix->mLevel = deviceLevel;
250
251 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800252 if (&e.object != matrix && e.object.level() == deviceLevel) {
253 if (!matrix->addAllHals(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800254 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800255 *error = "File \"" + e.name + "\" cannot be added: HAL " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800256 " has a conflict.";
257 }
258 return nullptr;
259 }
260
Yifan Hongffcaf992018-01-09 17:08:51 -0800261 if (!matrix->addAllXmlFiles(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800262 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800263 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800264 " has a conflict.";
265 }
266 return nullptr;
267 }
268 }
269 }
270
271 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800272 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
273 e.object.level() > deviceLevel) {
274 if (!matrix->addAllHalsAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800275 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800276 *error = "File \"" + e.name + "\" cannot be added: " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800277 ". See <hal> with the same name " +
278 "in previously parsed files or previously declared in this file.";
279 }
280 return nullptr;
281 }
282
Yifan Hongffcaf992018-01-09 17:08:51 -0800283 if (!matrix->addAllXmlFilesAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800284 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800285 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800286 " has a conflict.";
287 }
288 return nullptr;
289 }
290 }
291 }
292
293 return matrix;
294}
295
Yifan Hong676447a2016-11-15 12:57:23 -0800296} // namespace vintf
297} // namespace android