blob: a2c594f7c25a2ac96b0e10488d21b6fb7d984914 [file] [log] [blame]
Yifan Hong90ed9972018-12-03 15:08:34 -08001/*
2 * Copyright (C) 2019 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#include "KernelInfo.h"
17
18#include "parse_string.h"
Yifan Hongf66094f2019-12-11 14:23:08 -080019#include "utils.h"
Yifan Hong90ed9972018-12-03 15:08:34 -080020
21namespace android {
22namespace vintf {
23
Yifan Hongf66094f2019-12-11 14:23:08 -080024using details::mergeField;
25
Yifan Hong90ed9972018-12-03 15:08:34 -080026const KernelVersion& KernelInfo::version() const {
27 return mVersion;
28}
29
30const std::map<std::string, std::string>& KernelInfo::configs() const {
31 return mConfigs;
32}
33
Yifan Honge6248442019-12-11 13:33:00 -080034Level KernelInfo::level() const {
35 return mLevel;
36}
37
Yifan Hong90ed9972018-12-03 15:08:34 -080038bool KernelInfo::matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
39 std::string* error) const {
40 for (const KernelConfig& matrixConfig : matrixConfigs) {
41 const std::string& key = matrixConfig.first;
42 auto it = this->mConfigs.find(key);
43 if (it == this->mConfigs.end()) {
44 // special case: <value type="tristate">n</value> matches if the config doesn't exist.
45 if (matrixConfig.second == KernelConfigTypedValue::gMissingConfig) {
46 continue;
47 }
48 if (error != nullptr) {
49 *error = "Missing config " + key;
50 }
51 return false;
52 }
53 const std::string& kernelValue = it->second;
54 if (!matrixConfig.second.matchValue(kernelValue)) {
55 if (error != nullptr) {
56 *error = "For config " + key + ", value = " + kernelValue + " but required " +
57 to_string(matrixConfig.second);
58 }
59 return false;
60 }
61 }
62 return true;
63}
64
65bool KernelInfo::matchKernelVersion(const KernelVersion& minLts) const {
66 return minLts.version == mVersion.version && minLts.majorRev == mVersion.majorRev &&
67 minLts.minorRev <= mVersion.minorRev;
68}
69
Yifan Hong1e8febd2019-08-07 16:17:19 -070070std::vector<const MatrixKernel*> KernelInfo::getMatchedKernelRequirements(
71 const std::vector<MatrixKernel>& kernels, std::string* error) const {
72 std::vector<const MatrixKernel*> result;
Yifan Hong90ed9972018-12-03 15:08:34 -080073 bool foundMatchedKernelVersion = false;
Yifan Hong90ed9972018-12-03 15:08:34 -080074 for (const MatrixKernel& matrixKernel : kernels) {
75 if (!matchKernelVersion(matrixKernel.minLts())) {
76 continue;
77 }
78 foundMatchedKernelVersion = true;
79 // ignore this fragment if not all conditions are met.
80 if (!matchKernelConfigs(matrixKernel.conditions(), error)) {
81 continue;
82 }
Yifan Hong90ed9972018-12-03 15:08:34 -080083 if (!matchKernelConfigs(matrixKernel.configs(), error)) {
Yifan Hong1e8febd2019-08-07 16:17:19 -070084 return {};
Yifan Hong90ed9972018-12-03 15:08:34 -080085 }
Yifan Hong1e8febd2019-08-07 16:17:19 -070086 result.push_back(&matrixKernel);
Yifan Hong90ed9972018-12-03 15:08:34 -080087 }
88 if (!foundMatchedKernelVersion) {
89 if (error != nullptr) {
90 std::stringstream ss;
91 ss << "Framework is incompatible with kernel version " << version()
92 << ", compatible kernel versions are";
93 for (const MatrixKernel& matrixKernel : kernels) ss << " " << matrixKernel.minLts();
94 *error = ss.str();
95 }
Yifan Hong1e8febd2019-08-07 16:17:19 -070096 return {};
Yifan Hong90ed9972018-12-03 15:08:34 -080097 }
Yifan Hong1e8febd2019-08-07 16:17:19 -070098 if (result.empty()) {
99 // This means matchKernelVersion passes but matchKernelConfigs(conditions) fails.
Yifan Hong90ed9972018-12-03 15:08:34 -0800100 // This should not happen because first <conditions> for each <kernel> must be
101 // empty. Reject here for inconsistency.
102 if (error != nullptr) {
103 error->insert(0, "Framework match kernel version with unmet conditions:");
104 }
Yifan Hong1e8febd2019-08-07 16:17:19 -0700105 return {};
Yifan Hong90ed9972018-12-03 15:08:34 -0800106 }
107 if (error != nullptr) {
108 error->clear();
109 }
Yifan Hong1e8febd2019-08-07 16:17:19 -0700110 return result;
Yifan Hong90ed9972018-12-03 15:08:34 -0800111}
112
Yifan Honga45f77d2018-12-03 16:42:52 -0800113bool KernelInfo::operator==(const KernelInfo& other) const {
114 return mVersion == other.mVersion && mConfigs == other.mConfigs;
115}
116
Yifan Hongf66094f2019-12-11 14:23:08 -0800117bool KernelInfo::merge(KernelInfo* other, std::string* error) {
118 if (!mergeField(&mVersion, &other->mVersion)) {
119 if (error) {
120 *error = "Conflicting kernel version: " + to_string(version()) + " vs. " +
121 to_string(other->version());
122 }
123 return false;
124 }
125
126 // Do not allow merging configs. One of them must be empty.
127 if (!mergeField(&mConfigs, &other->mConfigs)) {
128 if (error) {
129 *error = "Found <kernel><config> items in two manifests.";
130 }
131 return false;
132 }
133
134 if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
135 if (error) {
136 *error = "Conflicting kernel level: " + to_string(level()) + " vs. " +
137 to_string(other->level());
138 }
139 return false;
140 }
141 return true;
142}
143
Yifan Hong90ed9972018-12-03 15:08:34 -0800144} // namespace vintf
145} // namespace android