blob: 7bdc3a98f7976c51dbf991f299115e0f7f54e5f4 [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}
Yifan Hongf73ba512018-01-17 15:52:30 -080099std::pair<const MatrixHal*, const VersionRange*> CompatibilityMatrix::getHalWithMajorVersion(
100 const std::string& name, size_t majorVer) const {
101 return const_cast<CompatibilityMatrix*>(this)->getHalWithMajorVersion(name, majorVer);
102}
Yifan Hongdbe9db32017-12-11 19:06:11 -0800103
104bool CompatibilityMatrix::addAllHalsAsOptional(CompatibilityMatrix* other, std::string* error) {
105 if (other == nullptr || other->level() <= level()) {
106 return true;
107 }
108
109 for (auto& pair : other->mHals) {
110 const std::string& name = pair.first;
111 MatrixHal& halToAdd = pair.second;
112 for (const VersionRange& vr : halToAdd.versionRanges) {
113 MatrixHal* existingHal;
114 VersionRange* existingVr;
115 std::tie(existingHal, existingVr) = getHalWithMajorVersion(name, vr.majorVer);
116
117 if (existingHal == nullptr) {
Yifan Hongd8eea9e2017-12-22 15:13:42 -0800118 MatrixHal optionalHalToAdd(halToAdd);
119 optionalHalToAdd.optional = true;
120 optionalHalToAdd.versionRanges = {vr};
121 if (!add(std::move(optionalHalToAdd))) {
Yifan Hong78c911a2017-12-20 15:16:59 -0800122 if (error) {
123 *error = "Cannot add HAL " + name + " for unknown reason.";
124 }
125 return false;
126 }
Yifan Hongdbe9db32017-12-11 19:06:11 -0800127 continue;
128 }
129
130 if (!existingHal->optional && !existingHal->containsInstances(halToAdd)) {
131 if (error != nullptr) {
132 *error = "HAL " + name + "@" + to_string(vr.minVer()) + " is a required " +
133 "HAL, but fully qualified instance names don't match (at FCM "
134 "Version " +
135 std::to_string(level()) + " and " + std::to_string(other->level()) +
136 ")";
137 }
138 return false;
139 }
140
141 existingVr->maxMinor = std::max(existingVr->maxMinor, vr.maxMinor);
142 }
143 }
144 return true;
145}
146
Yifan Hongd4b92fe2017-12-20 15:29:03 -0800147bool CompatibilityMatrix::addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error) {
148 if (other == nullptr || other->level() <= level()) {
149 return true;
150 }
151 for (auto& pair : other->mXmlFiles) {
152 const std::string& name = pair.first;
153 MatrixXmlFile& xmlFileToAdd = pair.second;
154
155 xmlFileToAdd.mOptional = true;
156 if (!addXmlFile(std::move(xmlFileToAdd))) {
157 if (error) {
158 *error = "Cannot add XML File " + name + " for unknown reason.";
159 }
160 return false;
161 }
162 }
163 return true;
164}
165
Yifan Hongfb7469c2017-04-05 19:15:21 -0700166bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
Yifan Hong2027a492017-12-11 15:21:19 -0800167 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
168 lft.mXmlFiles == rgt.mXmlFiles &&
Yifan Hongfeb454e2018-01-09 16:16:40 -0800169 (lft.mType != SchemaType::DEVICE ||
170 (
Yifan Hong0f529fa2018-01-10 14:51:59 -0800171#pragma clang diagnostic push
172#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Yifan Hongfeb454e2018-01-09 16:16:40 -0800173 lft.device.mVndk == rgt.device.mVndk &&
Yifan Hong0f529fa2018-01-10 14:51:59 -0800174#pragma clang diagnostic pop
Yifan Honga28729e2018-01-17 13:40:35 -0800175 lft.device.mVendorNdk == rgt.device.mVendorNdk &&
176 lft.device.mSystemSdk == rgt.device.mSystemSdk)) &&
Yifan Hongd4857902017-06-13 14:13:56 -0700177 (lft.mType != SchemaType::FRAMEWORK ||
178 (lft.framework.mKernels == rgt.framework.mKernels &&
179 lft.framework.mSepolicy == rgt.framework.mSepolicy &&
180 lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
Yifan Hongfb7469c2017-04-05 19:15:21 -0700181}
182
Yifan Hongddae77e2017-12-18 16:57:07 -0800183// Find compatibility_matrix.empty.xml (which has unspecified level) and use it
184// as a base matrix.
185CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
Yifan Hongffcaf992018-01-09 17:08:51 -0800186 std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800187 bool multipleFound = false;
188 CompatibilityMatrix* matrix = nullptr;
189 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800190 if (e.object.level() == Level::UNSPECIFIED) {
191 if (!e.object.mHals.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800192 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800193 *error = "Error: File \"" + e.name + "\" should not contain " + "HAL elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800194 }
195 return nullptr;
196 }
197
Yifan Hongffcaf992018-01-09 17:08:51 -0800198 if (!e.object.mXmlFiles.empty()) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800199 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800200 *error =
201 "Error: File \"" + e.name + "\" should not contain " + "XML File elements.";
Yifan Hongddae77e2017-12-18 16:57:07 -0800202 }
203 return nullptr;
204 }
205
206 if (matrix != nullptr) {
207 multipleFound = true;
208 }
209
Yifan Hongffcaf992018-01-09 17:08:51 -0800210 matrix = &e.object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800211 // continue to detect multiple files with "unspecified" levels
212 }
213 }
214
215 if (multipleFound) {
216 if (error) {
217 *error =
218 "Error: multiple framework compatibility matrix files have "
219 "unspecified level; there should only be one such file.\n";
220 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800221 if (e.object.level() == Level::UNSPECIFIED) {
222 *error += " " + e.name + "\n";
Yifan Hongddae77e2017-12-18 16:57:07 -0800223 }
224 }
225 }
226 return nullptr;
227 }
228
229 if (matrix == nullptr) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800230 matrix = &matrices->emplace(matrices->end())->object;
Yifan Hongddae77e2017-12-18 16:57:07 -0800231 matrix->mType = SchemaType::FRAMEWORK;
232 matrix->mLevel = Level::UNSPECIFIED;
233 }
234
235 return matrix;
236}
237
Yifan Hongffcaf992018-01-09 17:08:51 -0800238CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
239 std::vector<Named<CompatibilityMatrix>>* matrices,
240 std::string* error) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800241 if (deviceLevel == Level::UNSPECIFIED) {
242 if (error) {
243 *error = "Error: device level is unspecified.";
244 }
245 return nullptr;
246 }
247
248 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
249 if (matrix == nullptr) {
250 return nullptr;
251 }
252
253 matrix->mLevel = deviceLevel;
254
255 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800256 if (&e.object != matrix && e.object.level() == deviceLevel) {
257 if (!matrix->addAllHals(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800258 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800259 *error = "File \"" + e.name + "\" cannot be added: HAL " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800260 " has a conflict.";
261 }
262 return nullptr;
263 }
264
Yifan Hongffcaf992018-01-09 17:08:51 -0800265 if (!matrix->addAllXmlFiles(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800266 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800267 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800268 " has a conflict.";
269 }
270 return nullptr;
271 }
272 }
273 }
274
275 for (auto& e : *matrices) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800276 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
277 e.object.level() > deviceLevel) {
278 if (!matrix->addAllHalsAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800279 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800280 *error = "File \"" + e.name + "\" cannot be added: " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800281 ". See <hal> with the same name " +
282 "in previously parsed files or previously declared in this file.";
283 }
284 return nullptr;
285 }
286
Yifan Hongffcaf992018-01-09 17:08:51 -0800287 if (!matrix->addAllXmlFilesAsOptional(&e.object, error)) {
Yifan Hongddae77e2017-12-18 16:57:07 -0800288 if (error) {
Yifan Hongffcaf992018-01-09 17:08:51 -0800289 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
Yifan Hongddae77e2017-12-18 16:57:07 -0800290 " has a conflict.";
291 }
292 return nullptr;
293 }
294 }
295 }
296
Yifan Hongf7e8b1b2018-01-23 15:30:35 -0800297 for (auto& e : *matrices) {
298 if (&e.object != matrix && e.object.level() == deviceLevel &&
299 e.object.type() == SchemaType::FRAMEWORK) {
300 for (MatrixKernel& kernel : e.object.framework.mKernels) {
301 KernelVersion ver = kernel.minLts();
302 if (!matrix->add(std::move(kernel))) {
303 if (error) {
304 *error = "Cannot add kernel version " + to_string(ver) +
305 " from FCM version " + to_string(deviceLevel);
306 }
307 return nullptr;
308 }
309 }
310 }
311 }
312
Yifan Hongddae77e2017-12-18 16:57:07 -0800313 return matrix;
314}
315
Yifan Honge3a92342018-01-25 17:00:16 -0800316void CompatibilityMatrix::forEachInstance(
317 const std::function<void(const std::string&, const VersionRange&, const std::string&,
318 const std::string&, bool, bool*)>& f) const {
319 bool stop = false;
320 for (const auto& hal : getHals()) {
321 for (const auto& v : hal.versionRanges) {
322 for (const auto& intf : iterateValues(hal.interfaces)) {
323 for (const auto& instance : intf.instances) {
324 f(hal.name, v, intf.name, instance, hal.optional, &stop);
325 if (stop) break;
326 }
327 }
328 }
329 }
330}
331
Yifan Hong676447a2016-11-15 12:57:23 -0800332} // namespace vintf
333} // namespace android