blob: 076055ca11f5565e963fe0f4ae4ffa1377c460b1 [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 Hongd4857902017-06-13 14:13:56 -0700165 (lft.mType != SchemaType::DEVICE || (lft.device.mVndk == rgt.device.mVndk)) &&
166 (lft.mType != SchemaType::FRAMEWORK ||
167 (lft.framework.mKernels == rgt.framework.mKernels &&
168 lft.framework.mSepolicy == rgt.framework.mSepolicy &&
169 lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
Yifan Hongfb7469c2017-04-05 19:15:21 -0700170}
171
Yifan Hongddae77e2017-12-18 16:57:07 -0800172// Find compatibility_matrix.empty.xml (which has unspecified level) and use it
173// as a base matrix.
174CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
Yifan Hongffcaf992018-01-09 17:08:51 -0800175 std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800176 bool multipleFound = false;
177 CompatibilityMatrix* matrix = nullptr;
178 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800179 if (e.object.level() == Level::UNSPECIFIED) {
180 if (!e.object.mHals.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800181 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800182 *error = "Error: File \"" + e.name + "\" should not contain " + "HAL elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800183 }
184 return nullptr;
185 }
186
Yifan Hongffcaf992018-01-09 17:08:51 -0800187 if (!e.object.mXmlFiles.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800188 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800189 *error =
190 "Error: File \"" + e.name + "\" should not contain " + "XML File elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800191 }
192 return nullptr;
193 }
194
195 if (matrix != nullptr) {
196 multipleFound = true;
197 }
198
Yifan Hongffcaf992018-01-09 17:08:51 -0800199 matrix = &e.object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800200 // continue to detect multiple files with "unspecified" levels
201 }
202 }
203
204 if (multipleFound) {
205 if (error) {
206 *error =
207 "Error: multiple framework compatibility matrix files have "
208 "unspecified level; there should only be one such file.\n";
209 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800210 if (e.object.level() == Level::UNSPECIFIED) {
211 *error += " " + e.name + "\n";
Yifan Hongddae77e2017-12-18 16:57:07 -0800212 }
213 }
214 }
215 return nullptr;
216 }
217
218 if (matrix == nullptr) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800219 matrix = &matrices->emplace(matrices->end())->object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800220 matrix->mType = SchemaType::FRAMEWORK;
221 matrix->mLevel = Level::UNSPECIFIED;
222 }
223
224 return matrix;
225}
226
Yifan Hongffcaf992018-01-09 17:08:51 -0800227CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
228 std::vector<Named<CompatibilityMatrix>>* matrices,
229 std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800230 if (deviceLevel == Level::UNSPECIFIED) {
231 if (error) {
232 *error = "Error: device level is unspecified.";
233 }
234 return nullptr;
235 }
236
237 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
238 if (matrix == nullptr) {
239 return nullptr;
240 }
241
242 matrix->mLevel = deviceLevel;
243
244 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800245 if (&e.object != matrix && e.object.level() == deviceLevel) {
246 if (!matrix->addAllHals(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800247 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800248 *error = "File \"" + e.name + "\" cannot be added: HAL " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800249 " has a conflict.";
250 }
251 return nullptr;
252 }
253
Yifan Hongffcaf992018-01-09 17:08:51 -0800254 if (!matrix->addAllXmlFiles(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800255 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800256 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800257 " has a conflict.";
258 }
259 return nullptr;
260 }
261 }
262 }
263
264 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800265 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
266 e.object.level() > deviceLevel) {
267 if (!matrix->addAllHalsAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800268 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800269 *error = "File \"" + e.name + "\" cannot be added: " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800270 ". See <hal> with the same name " +
271 "in previously parsed files or previously declared in this file.";
272 }
273 return nullptr;
274 }
275
Yifan Hongffcaf992018-01-09 17:08:51 -0800276 if (!matrix->addAllXmlFilesAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800277 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800278 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800279 " has a conflict.";
280 }
281 return nullptr;
282 }
283 }
284 }
285
286 return matrix;
287}
288
Yifan Hong676447a2016-11-15 12:57:23 -0800289} // namespace vintf
290} // namespace android