1*70a7ec85SAndroid Build Coastguard Worker /*
2*70a7ec85SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*70a7ec85SAndroid Build Coastguard Worker *
4*70a7ec85SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*70a7ec85SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*70a7ec85SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*70a7ec85SAndroid Build Coastguard Worker *
8*70a7ec85SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*70a7ec85SAndroid Build Coastguard Worker *
10*70a7ec85SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*70a7ec85SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*70a7ec85SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*70a7ec85SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*70a7ec85SAndroid Build Coastguard Worker * limitations under the License.
15*70a7ec85SAndroid Build Coastguard Worker */
16*70a7ec85SAndroid Build Coastguard Worker #include "KernelInfo.h"
17*70a7ec85SAndroid Build Coastguard Worker
18*70a7ec85SAndroid Build Coastguard Worker #include "parse_string.h"
19*70a7ec85SAndroid Build Coastguard Worker #include "parse_xml.h"
20*70a7ec85SAndroid Build Coastguard Worker #include "parse_xml_internal.h"
21*70a7ec85SAndroid Build Coastguard Worker #include "utils.h"
22*70a7ec85SAndroid Build Coastguard Worker
23*70a7ec85SAndroid Build Coastguard Worker namespace android {
24*70a7ec85SAndroid Build Coastguard Worker namespace vintf {
25*70a7ec85SAndroid Build Coastguard Worker
26*70a7ec85SAndroid Build Coastguard Worker using details::mergeField;
27*70a7ec85SAndroid Build Coastguard Worker
version() const28*70a7ec85SAndroid Build Coastguard Worker const KernelVersion& KernelInfo::version() const {
29*70a7ec85SAndroid Build Coastguard Worker return mVersion;
30*70a7ec85SAndroid Build Coastguard Worker }
31*70a7ec85SAndroid Build Coastguard Worker
configs() const32*70a7ec85SAndroid Build Coastguard Worker const std::map<std::string, std::string>& KernelInfo::configs() const {
33*70a7ec85SAndroid Build Coastguard Worker return mConfigs;
34*70a7ec85SAndroid Build Coastguard Worker }
35*70a7ec85SAndroid Build Coastguard Worker
level() const36*70a7ec85SAndroid Build Coastguard Worker Level KernelInfo::level() const {
37*70a7ec85SAndroid Build Coastguard Worker return mLevel;
38*70a7ec85SAndroid Build Coastguard Worker }
39*70a7ec85SAndroid Build Coastguard Worker
matchKernelConfigs(const std::vector<KernelConfig> & matrixConfigs,std::string * error) const40*70a7ec85SAndroid Build Coastguard Worker bool KernelInfo::matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
41*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
42*70a7ec85SAndroid Build Coastguard Worker std::stringstream ss;
43*70a7ec85SAndroid Build Coastguard Worker ss << "Kernel config errors:";
44*70a7ec85SAndroid Build Coastguard Worker bool configMatches = true;
45*70a7ec85SAndroid Build Coastguard Worker for (const KernelConfig& matrixConfig : matrixConfigs) {
46*70a7ec85SAndroid Build Coastguard Worker const std::string& key = matrixConfig.first;
47*70a7ec85SAndroid Build Coastguard Worker auto it = this->mConfigs.find(key);
48*70a7ec85SAndroid Build Coastguard Worker if (it == this->mConfigs.end()) {
49*70a7ec85SAndroid Build Coastguard Worker // special case: <value type="tristate">n</value> matches if the config doesn't exist.
50*70a7ec85SAndroid Build Coastguard Worker if (matrixConfig.second == KernelConfigTypedValue::gMissingConfig) {
51*70a7ec85SAndroid Build Coastguard Worker continue;
52*70a7ec85SAndroid Build Coastguard Worker }
53*70a7ec85SAndroid Build Coastguard Worker ss << "\n Missing config " << key;
54*70a7ec85SAndroid Build Coastguard Worker configMatches = false;
55*70a7ec85SAndroid Build Coastguard Worker continue;
56*70a7ec85SAndroid Build Coastguard Worker }
57*70a7ec85SAndroid Build Coastguard Worker const std::string& kernelValue = it->second;
58*70a7ec85SAndroid Build Coastguard Worker if (!matrixConfig.second.matchValue(kernelValue)) {
59*70a7ec85SAndroid Build Coastguard Worker ss << "\n For config " << key << ", value = " << kernelValue << " but required "
60*70a7ec85SAndroid Build Coastguard Worker << to_string(matrixConfig.second);
61*70a7ec85SAndroid Build Coastguard Worker configMatches = false;
62*70a7ec85SAndroid Build Coastguard Worker continue;
63*70a7ec85SAndroid Build Coastguard Worker }
64*70a7ec85SAndroid Build Coastguard Worker }
65*70a7ec85SAndroid Build Coastguard Worker if (!configMatches && error != nullptr) {
66*70a7ec85SAndroid Build Coastguard Worker *error = ss.str();
67*70a7ec85SAndroid Build Coastguard Worker }
68*70a7ec85SAndroid Build Coastguard Worker return configMatches;
69*70a7ec85SAndroid Build Coastguard Worker }
70*70a7ec85SAndroid Build Coastguard Worker
matchKernelVersion(const KernelVersion & minLts) const71*70a7ec85SAndroid Build Coastguard Worker bool KernelInfo::matchKernelVersion(const KernelVersion& minLts) const {
72*70a7ec85SAndroid Build Coastguard Worker return mVersion.dropMinor() == minLts.dropMinor() && minLts.minorRev <= mVersion.minorRev;
73*70a7ec85SAndroid Build Coastguard Worker }
74*70a7ec85SAndroid Build Coastguard Worker
getMatchedKernelRequirements(const std::vector<MatrixKernel> & kernels,Level kernelLevel,std::string * error) const75*70a7ec85SAndroid Build Coastguard Worker std::vector<const MatrixKernel*> KernelInfo::getMatchedKernelRequirements(
76*70a7ec85SAndroid Build Coastguard Worker const std::vector<MatrixKernel>& kernels, Level kernelLevel, std::string* error) const {
77*70a7ec85SAndroid Build Coastguard Worker std::map<Level, std::vector<const MatrixKernel*>> kernelsForLevel;
78*70a7ec85SAndroid Build Coastguard Worker for (const MatrixKernel& matrixKernel : kernels) {
79*70a7ec85SAndroid Build Coastguard Worker const auto& minLts = matrixKernel.minLts();
80*70a7ec85SAndroid Build Coastguard Worker auto matrixKernelLevel = matrixKernel.getSourceMatrixLevel();
81*70a7ec85SAndroid Build Coastguard Worker
82*70a7ec85SAndroid Build Coastguard Worker // Filter out kernels with different x.y.
83*70a7ec85SAndroid Build Coastguard Worker if (mVersion.dropMinor() != minLts.dropMinor()) {
84*70a7ec85SAndroid Build Coastguard Worker continue;
85*70a7ec85SAndroid Build Coastguard Worker }
86*70a7ec85SAndroid Build Coastguard Worker
87*70a7ec85SAndroid Build Coastguard Worker // Check matrix kernel level
88*70a7ec85SAndroid Build Coastguard Worker
89*70a7ec85SAndroid Build Coastguard Worker // Use legacy behavior when kernel FCM version is not specified. Blindly add all of them
90*70a7ec85SAndroid Build Coastguard Worker // here. The correct one (with smallest matrixKernelLevel) will be picked later.
91*70a7ec85SAndroid Build Coastguard Worker if (kernelLevel == Level::UNSPECIFIED) {
92*70a7ec85SAndroid Build Coastguard Worker kernelsForLevel[matrixKernelLevel].push_back(&matrixKernel);
93*70a7ec85SAndroid Build Coastguard Worker continue;
94*70a7ec85SAndroid Build Coastguard Worker }
95*70a7ec85SAndroid Build Coastguard Worker
96*70a7ec85SAndroid Build Coastguard Worker if (matrixKernelLevel == Level::UNSPECIFIED) {
97*70a7ec85SAndroid Build Coastguard Worker if (error) {
98*70a7ec85SAndroid Build Coastguard Worker *error = "Seen unspecified source matrix level; this should not happen.";
99*70a7ec85SAndroid Build Coastguard Worker }
100*70a7ec85SAndroid Build Coastguard Worker return {};
101*70a7ec85SAndroid Build Coastguard Worker }
102*70a7ec85SAndroid Build Coastguard Worker
103*70a7ec85SAndroid Build Coastguard Worker if (matrixKernelLevel < kernelLevel) {
104*70a7ec85SAndroid Build Coastguard Worker continue;
105*70a7ec85SAndroid Build Coastguard Worker }
106*70a7ec85SAndroid Build Coastguard Worker
107*70a7ec85SAndroid Build Coastguard Worker // matrix level >= kernel level
108*70a7ec85SAndroid Build Coastguard Worker
109*70a7ec85SAndroid Build Coastguard Worker // for kernel level >= S, do not allow matrix level > kernel level; i.e. only check
110*70a7ec85SAndroid Build Coastguard Worker // matching KMI.
111*70a7ec85SAndroid Build Coastguard Worker if (kernelLevel >= Level::S && matrixKernelLevel > kernelLevel) {
112*70a7ec85SAndroid Build Coastguard Worker continue;
113*70a7ec85SAndroid Build Coastguard Worker }
114*70a7ec85SAndroid Build Coastguard Worker
115*70a7ec85SAndroid Build Coastguard Worker kernelsForLevel[matrixKernelLevel].push_back(&matrixKernel);
116*70a7ec85SAndroid Build Coastguard Worker }
117*70a7ec85SAndroid Build Coastguard Worker
118*70a7ec85SAndroid Build Coastguard Worker if (kernelsForLevel.empty()) {
119*70a7ec85SAndroid Build Coastguard Worker if (error) {
120*70a7ec85SAndroid Build Coastguard Worker std::stringstream ss;
121*70a7ec85SAndroid Build Coastguard Worker ss << "No kernel entry found for kernel version " << mVersion.dropMinor()
122*70a7ec85SAndroid Build Coastguard Worker << " at kernel FCM version "
123*70a7ec85SAndroid Build Coastguard Worker << (kernelLevel == Level::UNSPECIFIED ? "unspecified" : to_string(kernelLevel))
124*70a7ec85SAndroid Build Coastguard Worker << ". The following kernel requirements are checked:";
125*70a7ec85SAndroid Build Coastguard Worker for (const MatrixKernel& matrixKernel : kernels) {
126*70a7ec85SAndroid Build Coastguard Worker ss << "\n Minimum LTS: " << matrixKernel.minLts()
127*70a7ec85SAndroid Build Coastguard Worker << ", kernel FCM version: " << matrixKernel.getSourceMatrixLevel()
128*70a7ec85SAndroid Build Coastguard Worker << (matrixKernel.conditions().empty() ? "" : ", with conditionals");
129*70a7ec85SAndroid Build Coastguard Worker };
130*70a7ec85SAndroid Build Coastguard Worker *error = ss.str();
131*70a7ec85SAndroid Build Coastguard Worker }
132*70a7ec85SAndroid Build Coastguard Worker return {};
133*70a7ec85SAndroid Build Coastguard Worker }
134*70a7ec85SAndroid Build Coastguard Worker
135*70a7ec85SAndroid Build Coastguard Worker // At this point, kernelsForLevel contains kernel requirements for each level.
136*70a7ec85SAndroid Build Coastguard Worker // For example, if the running kernel version is 4.14.y then kernelsForLevel contains
137*70a7ec85SAndroid Build Coastguard Worker // 4.14-p, 4.14-q, 4.14-r.
138*70a7ec85SAndroid Build Coastguard Worker // (This excludes kernels < kernel FCM version, or device FCM version if kernel FCM version is
139*70a7ec85SAndroid Build Coastguard Worker // empty. For example, if device level = Q and kernel level is unspecified, this list only
140*70a7ec85SAndroid Build Coastguard Worker // contains 4.14-q and 4.14-r).
141*70a7ec85SAndroid Build Coastguard Worker
142*70a7ec85SAndroid Build Coastguard Worker // Use legacy behavior when kernel FCM version is not specified. e.g. target FCM version 3 (P)
143*70a7ec85SAndroid Build Coastguard Worker // matches kernel 4.4-p, 4.9-p, 4.14-p, 4.19-q, etc., but not 4.9-q or 4.14-q.
144*70a7ec85SAndroid Build Coastguard Worker // Since we already filtered |kernels| based on kernel version, we only need to check the first
145*70a7ec85SAndroid Build Coastguard Worker // item in kernelsForLevel.
146*70a7ec85SAndroid Build Coastguard Worker // Note that this excludes *-r and above kernels. Devices with target FCM version >= 5 (R) must
147*70a7ec85SAndroid Build Coastguard Worker // state kernel FCM version explicitly in the device manifest. The value is automatically
148*70a7ec85SAndroid Build Coastguard Worker // inserted for devices with target FCM version >= 5 when manifest is built with assemble_vintf.
149*70a7ec85SAndroid Build Coastguard Worker if (kernelLevel == Level::UNSPECIFIED) {
150*70a7ec85SAndroid Build Coastguard Worker auto [matrixKernelLevel, matrixKernels] = *kernelsForLevel.begin();
151*70a7ec85SAndroid Build Coastguard Worker
152*70a7ec85SAndroid Build Coastguard Worker // Do not allow *-r and above kernels.
153*70a7ec85SAndroid Build Coastguard Worker if (matrixKernelLevel != Level::UNSPECIFIED && matrixKernelLevel >= Level::R) {
154*70a7ec85SAndroid Build Coastguard Worker if (error) {
155*70a7ec85SAndroid Build Coastguard Worker KernelInfo msg;
156*70a7ec85SAndroid Build Coastguard Worker msg.mLevel = Level::R;
157*70a7ec85SAndroid Build Coastguard Worker *error = "Kernel FCM version is not specified, but kernel version " +
158*70a7ec85SAndroid Build Coastguard Worker to_string(mVersion) +
159*70a7ec85SAndroid Build Coastguard Worker " is found. Fix by specifying kernel FCM version in device manifest. "
160*70a7ec85SAndroid Build Coastguard Worker "For example, for a *-r kernel:\n" +
161*70a7ec85SAndroid Build Coastguard Worker toXml(msg);
162*70a7ec85SAndroid Build Coastguard Worker }
163*70a7ec85SAndroid Build Coastguard Worker return {};
164*70a7ec85SAndroid Build Coastguard Worker }
165*70a7ec85SAndroid Build Coastguard Worker
166*70a7ec85SAndroid Build Coastguard Worker auto matchedMatrixKernels = getMatchedKernelVersionAndConfigs(matrixKernels, error);
167*70a7ec85SAndroid Build Coastguard Worker if (matchedMatrixKernels.empty()) {
168*70a7ec85SAndroid Build Coastguard Worker return {};
169*70a7ec85SAndroid Build Coastguard Worker }
170*70a7ec85SAndroid Build Coastguard Worker return matchedMatrixKernels;
171*70a7ec85SAndroid Build Coastguard Worker }
172*70a7ec85SAndroid Build Coastguard Worker
173*70a7ec85SAndroid Build Coastguard Worker // Use new behavior when kernel FCM version is specified. e.g. kernel FCM version 3 (P)
174*70a7ec85SAndroid Build Coastguard Worker // matches kernel 4.4-p, 4.9-p, 4.14-p, 4.9-q, 4.14-q, 4.14-r etc., but not 5.4-r.
175*70a7ec85SAndroid Build Coastguard Worker // For kernel FCM version >= S, only matching KMI is accepted. e.g. kernel FCM version 6 (S)
176*70a7ec85SAndroid Build Coastguard Worker // matches 4.19-stable, 5.10-android12, 5.4-android12, not x.y-android13.
177*70a7ec85SAndroid Build Coastguard Worker // Note we already filtered |kernels| based on kernel version.
178*70a7ec85SAndroid Build Coastguard Worker auto [firstMatrixKernelLevel, firstMatrixKernels] = *kernelsForLevel.begin();
179*70a7ec85SAndroid Build Coastguard Worker if (firstMatrixKernelLevel == Level::UNSPECIFIED || firstMatrixKernelLevel > kernelLevel) {
180*70a7ec85SAndroid Build Coastguard Worker if (error) {
181*70a7ec85SAndroid Build Coastguard Worker *error = "Kernel FCM Version is " + to_string(kernelLevel) + " and kernel version is " +
182*70a7ec85SAndroid Build Coastguard Worker to_string(mVersion) +
183*70a7ec85SAndroid Build Coastguard Worker ", but the first kernel FCM version allowed for kernel version " +
184*70a7ec85SAndroid Build Coastguard Worker to_string(mVersion.dropMinor()) + ".y is " + to_string(firstMatrixKernelLevel);
185*70a7ec85SAndroid Build Coastguard Worker }
186*70a7ec85SAndroid Build Coastguard Worker return {};
187*70a7ec85SAndroid Build Coastguard Worker }
188*70a7ec85SAndroid Build Coastguard Worker for (auto [matrixKernelLevel, matrixKernels] : kernelsForLevel) {
189*70a7ec85SAndroid Build Coastguard Worker if (matrixKernelLevel == Level::UNSPECIFIED || matrixKernelLevel < kernelLevel) {
190*70a7ec85SAndroid Build Coastguard Worker continue;
191*70a7ec85SAndroid Build Coastguard Worker }
192*70a7ec85SAndroid Build Coastguard Worker std::string errorForLevel;
193*70a7ec85SAndroid Build Coastguard Worker auto matchedMatrixKernels =
194*70a7ec85SAndroid Build Coastguard Worker getMatchedKernelVersionAndConfigs(matrixKernels, &errorForLevel);
195*70a7ec85SAndroid Build Coastguard Worker if (matchedMatrixKernels.empty()) {
196*70a7ec85SAndroid Build Coastguard Worker if (error) {
197*70a7ec85SAndroid Build Coastguard Worker *error += "For kernel requirements at matrix level " +
198*70a7ec85SAndroid Build Coastguard Worker to_string(matrixKernelLevel) + ", " + errorForLevel + "\n";
199*70a7ec85SAndroid Build Coastguard Worker }
200*70a7ec85SAndroid Build Coastguard Worker continue;
201*70a7ec85SAndroid Build Coastguard Worker }
202*70a7ec85SAndroid Build Coastguard Worker return matchedMatrixKernels;
203*70a7ec85SAndroid Build Coastguard Worker }
204*70a7ec85SAndroid Build Coastguard Worker
205*70a7ec85SAndroid Build Coastguard Worker if (error) {
206*70a7ec85SAndroid Build Coastguard Worker error->insert(0, "No compatible kernel requirement found (kernel FCM version = " +
207*70a7ec85SAndroid Build Coastguard Worker to_string(kernelLevel) + ").\n");
208*70a7ec85SAndroid Build Coastguard Worker }
209*70a7ec85SAndroid Build Coastguard Worker return {};
210*70a7ec85SAndroid Build Coastguard Worker }
211*70a7ec85SAndroid Build Coastguard Worker
getMatchedKernelVersionAndConfigs(const std::vector<const MatrixKernel * > & kernels,std::string * error) const212*70a7ec85SAndroid Build Coastguard Worker std::vector<const MatrixKernel*> KernelInfo::getMatchedKernelVersionAndConfigs(
213*70a7ec85SAndroid Build Coastguard Worker const std::vector<const MatrixKernel*>& kernels, std::string* error) const {
214*70a7ec85SAndroid Build Coastguard Worker std::vector<const MatrixKernel*> result;
215*70a7ec85SAndroid Build Coastguard Worker bool foundMatchedKernelVersion = false;
216*70a7ec85SAndroid Build Coastguard Worker for (const MatrixKernel* matrixKernel : kernels) {
217*70a7ec85SAndroid Build Coastguard Worker if (!matchKernelVersion(matrixKernel->minLts())) {
218*70a7ec85SAndroid Build Coastguard Worker continue;
219*70a7ec85SAndroid Build Coastguard Worker }
220*70a7ec85SAndroid Build Coastguard Worker foundMatchedKernelVersion = true;
221*70a7ec85SAndroid Build Coastguard Worker // ignore this fragment if not all conditions are met.
222*70a7ec85SAndroid Build Coastguard Worker if (!matchKernelConfigs(matrixKernel->conditions(), nullptr)) {
223*70a7ec85SAndroid Build Coastguard Worker continue;
224*70a7ec85SAndroid Build Coastguard Worker }
225*70a7ec85SAndroid Build Coastguard Worker if (!matchKernelConfigs(matrixKernel->configs(), error)) {
226*70a7ec85SAndroid Build Coastguard Worker return {};
227*70a7ec85SAndroid Build Coastguard Worker }
228*70a7ec85SAndroid Build Coastguard Worker result.push_back(matrixKernel);
229*70a7ec85SAndroid Build Coastguard Worker }
230*70a7ec85SAndroid Build Coastguard Worker if (!foundMatchedKernelVersion) {
231*70a7ec85SAndroid Build Coastguard Worker if (error != nullptr) {
232*70a7ec85SAndroid Build Coastguard Worker std::stringstream ss;
233*70a7ec85SAndroid Build Coastguard Worker ss << "Framework is incompatible with kernel version " << version()
234*70a7ec85SAndroid Build Coastguard Worker << ", compatible kernel versions are:";
235*70a7ec85SAndroid Build Coastguard Worker for (const MatrixKernel* matrixKernel : kernels) {
236*70a7ec85SAndroid Build Coastguard Worker ss << "\n Minimum LTS: " << matrixKernel->minLts()
237*70a7ec85SAndroid Build Coastguard Worker << ", kernel FCM version: " << matrixKernel->getSourceMatrixLevel()
238*70a7ec85SAndroid Build Coastguard Worker << (matrixKernel->conditions().empty() ? "" : ", with conditionals");
239*70a7ec85SAndroid Build Coastguard Worker };
240*70a7ec85SAndroid Build Coastguard Worker *error = ss.str();
241*70a7ec85SAndroid Build Coastguard Worker }
242*70a7ec85SAndroid Build Coastguard Worker return {};
243*70a7ec85SAndroid Build Coastguard Worker }
244*70a7ec85SAndroid Build Coastguard Worker if (result.empty()) {
245*70a7ec85SAndroid Build Coastguard Worker // This means matchKernelVersion passes but all matchKernelConfigs(conditions) fails.
246*70a7ec85SAndroid Build Coastguard Worker // This should not happen because first <conditions> for each <kernel> must be
247*70a7ec85SAndroid Build Coastguard Worker // empty. Reject here for inconsistency.
248*70a7ec85SAndroid Build Coastguard Worker if (error != nullptr) {
249*70a7ec85SAndroid Build Coastguard Worker error->insert(0, "Framework matches kernel version with unmet conditions.");
250*70a7ec85SAndroid Build Coastguard Worker }
251*70a7ec85SAndroid Build Coastguard Worker return {};
252*70a7ec85SAndroid Build Coastguard Worker }
253*70a7ec85SAndroid Build Coastguard Worker if (error != nullptr) {
254*70a7ec85SAndroid Build Coastguard Worker error->clear();
255*70a7ec85SAndroid Build Coastguard Worker }
256*70a7ec85SAndroid Build Coastguard Worker return result;
257*70a7ec85SAndroid Build Coastguard Worker }
258*70a7ec85SAndroid Build Coastguard Worker
operator ==(const KernelInfo & other) const259*70a7ec85SAndroid Build Coastguard Worker bool KernelInfo::operator==(const KernelInfo& other) const {
260*70a7ec85SAndroid Build Coastguard Worker return mVersion == other.mVersion && mConfigs == other.mConfigs;
261*70a7ec85SAndroid Build Coastguard Worker }
262*70a7ec85SAndroid Build Coastguard Worker
merge(KernelInfo * other,std::string * error)263*70a7ec85SAndroid Build Coastguard Worker bool KernelInfo::merge(KernelInfo* other, std::string* error) {
264*70a7ec85SAndroid Build Coastguard Worker if (!mergeField(&mVersion, &other->mVersion)) {
265*70a7ec85SAndroid Build Coastguard Worker if (error) {
266*70a7ec85SAndroid Build Coastguard Worker *error = "Conflicting kernel version: " + to_string(version()) + " vs. " +
267*70a7ec85SAndroid Build Coastguard Worker to_string(other->version());
268*70a7ec85SAndroid Build Coastguard Worker }
269*70a7ec85SAndroid Build Coastguard Worker return false;
270*70a7ec85SAndroid Build Coastguard Worker }
271*70a7ec85SAndroid Build Coastguard Worker
272*70a7ec85SAndroid Build Coastguard Worker // Do not allow merging configs. One of them must be empty.
273*70a7ec85SAndroid Build Coastguard Worker if (!mergeField(&mConfigs, &other->mConfigs)) {
274*70a7ec85SAndroid Build Coastguard Worker if (error) {
275*70a7ec85SAndroid Build Coastguard Worker *error = "Found <kernel><config> items in two manifests.";
276*70a7ec85SAndroid Build Coastguard Worker }
277*70a7ec85SAndroid Build Coastguard Worker return false;
278*70a7ec85SAndroid Build Coastguard Worker }
279*70a7ec85SAndroid Build Coastguard Worker
280*70a7ec85SAndroid Build Coastguard Worker if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
281*70a7ec85SAndroid Build Coastguard Worker if (error) {
282*70a7ec85SAndroid Build Coastguard Worker *error = "Conflicting kernel level: " + to_string(level()) + " vs. " +
283*70a7ec85SAndroid Build Coastguard Worker to_string(other->level());
284*70a7ec85SAndroid Build Coastguard Worker }
285*70a7ec85SAndroid Build Coastguard Worker return false;
286*70a7ec85SAndroid Build Coastguard Worker }
287*70a7ec85SAndroid Build Coastguard Worker return true;
288*70a7ec85SAndroid Build Coastguard Worker }
289*70a7ec85SAndroid Build Coastguard Worker
290*70a7ec85SAndroid Build Coastguard Worker } // namespace vintf
291*70a7ec85SAndroid Build Coastguard Worker } // namespace android
292