Merge "Add android::fs_mgr namespace for new Fstab code"
diff --git a/Android.bp b/Android.bp
index 4689832..1ff4812 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,6 +45,7 @@
"HalInterface.cpp",
"KernelConfigTypedValue.cpp",
"KernelConfigParser.cpp",
+ "KernelInfo.cpp",
"RuntimeInfo.cpp",
"ManifestHal.cpp",
"ManifestInstance.cpp",
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index 2353216..bcefc73 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -206,13 +206,7 @@
static bool parseFileForKernelConfigs(std::basic_istream<char>& stream,
std::vector<KernelConfig>* out) {
KernelConfigParser parser(true /* processComments */, true /* relaxedFormat */);
- std::string content = read(stream);
- status_t err = parser.process(content.c_str(), content.size());
- if (err != OK) {
- std::cerr << parser.error();
- return false;
- }
- err = parser.finish();
+ status_t err = parser.processAndFinish(read(stream));
if (err != OK) {
std::cerr << parser.error();
return false;
@@ -314,6 +308,36 @@
out() << "-->" << std::endl;
}
+ // Parse --kernel arguments and write to output manifest.
+ bool setDeviceManifestKernel(HalManifest* manifest) {
+ if (mKernels.empty()) {
+ return true;
+ }
+ if (mKernels.size() > 1) {
+ std::cerr << "Warning: multiple --kernel is specified when building device manifest. "
+ << "Only the first one will be used." << std::endl;
+ }
+ auto& kernelArg = *mKernels.begin();
+ const auto& kernelVer = kernelArg.first;
+ auto& kernelConfigFiles = kernelArg.second;
+ // addKernel() guarantees that !kernelConfigFiles.empty().
+ if (kernelConfigFiles.size() > 1) {
+ std::cerr << "Warning: multiple config files are specified in --kernel when building "
+ << "device manfiest. Only the first one will be used." << std::endl;
+ }
+
+ KernelConfigParser parser(true /* processComments */, false /* relaxedFormat */);
+ status_t err = parser.processAndFinish(read(kernelConfigFiles[0].stream()));
+ if (err != OK) {
+ std::cerr << parser.error();
+ return false;
+ }
+ manifest->device.mKernel = std::make_optional<KernelInfo>();
+ manifest->device.mKernel->mVersion = kernelVer;
+ manifest->device.mKernel->mConfigs = parser.configs();
+ return true;
+ }
+
bool assembleHalManifest(HalManifests* halManifests) {
std::string error;
HalManifest* halManifest = &halManifests->front().object;
@@ -364,6 +388,10 @@
if (!setDeviceFcmVersion(halManifest)) {
return false;
}
+
+ if (!setDeviceManifestKernel(halManifest)) {
+ return false;
+ }
}
if (halManifest->mType == SchemaType::FRAMEWORK) {
diff --git a/HalManifest.cpp b/HalManifest.cpp
index b795136..d844c4c 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -317,20 +317,24 @@
return false;
}
} else if (mType == SchemaType::DEVICE) {
- bool match = false;
+ bool sepolicyMatch = false;
for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
if (range.supportedBy(device.mSepolicyVersion)) {
- match = true;
+ sepolicyMatch = true;
break;
}
}
- if (!match) {
+ if (!sepolicyMatch) {
if (error != nullptr) {
*error = "Sepolicy version " + to_string(device.mSepolicyVersion)
+ " doesn't satisify the requirements.";
}
return false;
}
+
+ if (!!kernel() && !kernel()->matchKernelRequirements(mat.framework.mKernels, error)) {
+ return false;
+ }
}
return true;
@@ -413,7 +417,8 @@
return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
lft.mXmlFiles == rgt.mXmlFiles &&
(lft.mType != SchemaType::DEVICE ||
- (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) &&
+ (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
+ lft.device.mKernel == rgt.device.mKernel)) &&
(lft.mType != SchemaType::FRAMEWORK ||
(
#pragma clang diagnostic push
@@ -470,5 +475,9 @@
return (*this) == emptyManifest;
}
+const std::optional<KernelInfo>& HalManifest::kernel() const {
+ return device.mKernel;
+}
+
} // namespace vintf
} // namespace android
diff --git a/KernelConfigParser.cpp b/KernelConfigParser.cpp
index a0955e2..5713f22 100644
--- a/KernelConfigParser.cpp
+++ b/KernelConfigParser.cpp
@@ -133,5 +133,17 @@
return err;
}
+status_t KernelConfigParser::processAndFinish(const char* buf, size_t len) {
+ status_t err = process(buf, len);
+ if (err != OK) {
+ return err;
+ }
+ return finish();
+}
+
+status_t KernelConfigParser::processAndFinish(const std::string& content) {
+ return processAndFinish(content.c_str(), content.size());
+}
+
} // namespace vintf
} // namespace android
diff --git a/KernelInfo.cpp b/KernelInfo.cpp
new file mode 100644
index 0000000..1a37bdf
--- /dev/null
+++ b/KernelInfo.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "KernelInfo.h"
+
+#include "parse_string.h"
+
+namespace android {
+namespace vintf {
+
+const KernelVersion& KernelInfo::version() const {
+ return mVersion;
+}
+
+const std::map<std::string, std::string>& KernelInfo::configs() const {
+ return mConfigs;
+}
+
+bool KernelInfo::matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
+ std::string* error) const {
+ for (const KernelConfig& matrixConfig : matrixConfigs) {
+ const std::string& key = matrixConfig.first;
+ auto it = this->mConfigs.find(key);
+ if (it == this->mConfigs.end()) {
+ // special case: <value type="tristate">n</value> matches if the config doesn't exist.
+ if (matrixConfig.second == KernelConfigTypedValue::gMissingConfig) {
+ continue;
+ }
+ if (error != nullptr) {
+ *error = "Missing config " + key;
+ }
+ return false;
+ }
+ const std::string& kernelValue = it->second;
+ if (!matrixConfig.second.matchValue(kernelValue)) {
+ if (error != nullptr) {
+ *error = "For config " + key + ", value = " + kernelValue + " but required " +
+ to_string(matrixConfig.second);
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+bool KernelInfo::matchKernelVersion(const KernelVersion& minLts) const {
+ return minLts.version == mVersion.version && minLts.majorRev == mVersion.majorRev &&
+ minLts.minorRev <= mVersion.minorRev;
+}
+
+bool KernelInfo::matchKernelRequirements(const std::vector<MatrixKernel>& kernels,
+ std::string* error) const {
+ bool foundMatchedKernelVersion = false;
+ bool foundMatchedConditions = false;
+ for (const MatrixKernel& matrixKernel : kernels) {
+ if (!matchKernelVersion(matrixKernel.minLts())) {
+ continue;
+ }
+ foundMatchedKernelVersion = true;
+ // ignore this fragment if not all conditions are met.
+ if (!matchKernelConfigs(matrixKernel.conditions(), error)) {
+ continue;
+ }
+ foundMatchedConditions = true;
+ if (!matchKernelConfigs(matrixKernel.configs(), error)) {
+ return false;
+ }
+ }
+ if (!foundMatchedKernelVersion) {
+ if (error != nullptr) {
+ std::stringstream ss;
+ ss << "Framework is incompatible with kernel version " << version()
+ << ", compatible kernel versions are";
+ for (const MatrixKernel& matrixKernel : kernels) ss << " " << matrixKernel.minLts();
+ *error = ss.str();
+ }
+ return false;
+ }
+ if (!foundMatchedConditions) {
+ // This should not happen because first <conditions> for each <kernel> must be
+ // empty. Reject here for inconsistency.
+ if (error != nullptr) {
+ error->insert(0, "Framework match kernel version with unmet conditions:");
+ }
+ return false;
+ }
+ if (error != nullptr) {
+ error->clear();
+ }
+ return true;
+}
+
+bool KernelInfo::operator==(const KernelInfo& other) const {
+ return mVersion == other.mVersion && mConfigs == other.mConfigs;
+}
+
+} // namespace vintf
+} // namespace android
diff --git a/RuntimeInfo-target.cpp b/RuntimeInfo-target.cpp
index 6f2e9e8..d221897 100644
--- a/RuntimeInfo-target.cpp
+++ b/RuntimeInfo-target.cpp
@@ -80,7 +80,7 @@
}
mConfigParser.finish();
gzclose(f);
- mRuntimeInfo->mKernelConfigs = std::move(mConfigParser.configs());
+ mRuntimeInfo->mKernel.mConfigs = std::move(mConfigParser.configs());
return err;
}
@@ -141,7 +141,7 @@
}
pos = mRuntimeInfo->mOsRelease.find_first_not_of("0123456789", pos + 1);
// no need to check pos == std::string::npos, because substr will handle this
- if (!parse(mRuntimeInfo->mOsRelease.substr(0, pos), &mRuntimeInfo->mKernelVersion)) {
+ if (!parse(mRuntimeInfo->mOsRelease.substr(0, pos), &mRuntimeInfo->mKernel.mVersion)) {
return UNKNOWN_ERROR;
}
return OK;
diff --git a/RuntimeInfo.cpp b/RuntimeInfo.cpp
index 2338cd2..86f021c 100644
--- a/RuntimeInfo.cpp
+++ b/RuntimeInfo.cpp
@@ -46,11 +46,11 @@
}
const KernelVersion &RuntimeInfo::kernelVersion() const {
- return mKernelVersion;
+ return mKernel.version();
}
const std::map<std::string, std::string> &RuntimeInfo::kernelConfigs() const {
- return mKernelConfigs;
+ return mKernel.configs();
}
size_t RuntimeInfo::kernelSepolicyVersion() const {
@@ -69,38 +69,6 @@
return mBootAvbVersion;
}
-bool RuntimeInfo::matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
- std::string* error) const {
- for (const KernelConfig& matrixConfig : matrixConfigs) {
- const std::string& key = matrixConfig.first;
- auto it = this->mKernelConfigs.find(key);
- if (it == this->mKernelConfigs.end()) {
- // special case: <value type="tristate">n</value> matches if the config doesn't exist.
- if (matrixConfig.second == KernelConfigTypedValue::gMissingConfig) {
- continue;
- }
- if (error != nullptr) {
- *error = "Missing config " + key;
- }
- return false;
- }
- const std::string& kernelValue = it->second;
- if (!matrixConfig.second.matchValue(kernelValue)) {
- if (error != nullptr) {
- *error = "For config " + key + ", value = " + kernelValue + " but required " +
- to_string(matrixConfig.second);
- }
- return false;
- }
- }
- return true;
-}
-
-bool RuntimeInfo::matchKernelVersion(const KernelVersion& minLts) const {
- return minLts.version == mKernelVersion.version && minLts.majorRev == mKernelVersion.majorRev &&
- minLts.minorRev <= mKernelVersion.minorRev;
-}
-
bool RuntimeInfo::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
CheckFlags::Type flags) const {
if (mat.mType != SchemaType::FRAMEWORK) {
@@ -123,44 +91,9 @@
// HalManifest.device.mSepolicyVersion in HalManifest::checkCompatibility.
if (flags.isKernelEnabled()) {
- bool foundMatchedKernelVersion = false;
- bool foundMatchedConditions = false;
- for (const MatrixKernel& matrixKernel : mat.framework.mKernels) {
- if (!matchKernelVersion(matrixKernel.minLts())) {
- continue;
- }
- foundMatchedKernelVersion = true;
- // ignore this fragment if not all conditions are met.
- if (!matchKernelConfigs(matrixKernel.conditions(), error)) {
- continue;
- }
- foundMatchedConditions = true;
- if (!matchKernelConfigs(matrixKernel.configs(), error)) {
- return false;
- }
- }
- if (!foundMatchedKernelVersion) {
- if (error != nullptr) {
- std::stringstream ss;
- ss << "Framework is incompatible with kernel version " << mKernelVersion
- << ", compatible kernel versions are";
- for (const MatrixKernel& matrixKernel : mat.framework.mKernels)
- ss << " " << matrixKernel.minLts();
- *error = ss.str();
- }
+ if (!mKernel.matchKernelRequirements(mat.framework.mKernels, error)) {
return false;
}
- if (!foundMatchedConditions) {
- // This should not happen because first <conditions> for each <kernel> must be
- // empty. Reject here for inconsistency.
- if (error != nullptr) {
- error->insert(0, "Framework match kernel version with unmet conditions:");
- }
- return false;
- }
- if (error != nullptr) {
- error->clear();
- }
}
if (flags.isAvbEnabled()) {
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 1100977..fbe4045 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -548,9 +548,15 @@
return INCOMPATIBLE;
}
+ CheckFlags::Type runtimeInfoCheckFlags = flags;
+ if (!!getDeviceHalManifest()->kernel()) {
+ // Use kernel from incoming OTA package, but not on the device.
+ runtimeInfoCheckFlags = runtimeInfoCheckFlags.disableKernel();
+ }
+
if (flags.isRuntimeInfoEnabled()) {
if (!getRuntimeInfo()->checkCompatibility(*getFrameworkCompatibilityMatrix(), error,
- flags)) {
+ runtimeInfoCheckFlags)) {
if (error) {
error->insert(0,
"Runtime info and framework compatibility matrix are incompatible: ");
diff --git a/assemble_vintf_main.cpp b/assemble_vintf_main.cpp
index 2733261..b25a477 100644
--- a/assemble_vintf_main.cpp
+++ b/assemble_vintf_main.cpp
@@ -53,8 +53,11 @@
" If any check fails, an error message is written to stderr.\n"
" Return 1.\n"
" --kernel=<version>:<android-base.config>[:<android-base-arch.config>[...]]\n"
- " Add a kernel entry to framework compatibility matrix.\n"
- " Ignored for other input format.\n"
+ " Add a kernel entry to framework compatibility matrix or device\n"
+ " manifest. Ignored for other input format.\n"
+ " There can be any number of --kernel for framework compatibility\n"
+ " matrix, but at most one --kernel and at most one config file for\n"
+ " device manifest.\n"
" <version> has format: 3.18.0\n"
" <android-base.config> is the location of android-base.config\n"
" <android-base-arch.config> is the location of an optional\n"
diff --git a/include/vintf/CheckFlags.h b/include/vintf/CheckFlags.h
index 2da807c..52d35a7 100644
--- a/include/vintf/CheckFlags.h
+++ b/include/vintf/CheckFlags.h
@@ -25,9 +25,9 @@
// Flags for *::checkCompatibility functions.
class Type {
public:
-#define VINTF_CHECK_FLAGS_FIELD(name, bit) \
- constexpr Type enable##name() const { return Type(mValue | (1 << bit)); } \
- constexpr Type disable##name() const { return Type(mValue & ~(1 << bit)); } \
+#define VINTF_CHECK_FLAGS_FIELD(name, bit) \
+ [[nodiscard]] constexpr Type enable##name() const { return Type(mValue | (1 << bit)); } \
+ [[nodiscard]] constexpr Type disable##name() const { return Type(mValue & ~(1 << bit)); } \
constexpr bool is##name##Enabled() const { return mValue & (1 << bit); }
VINTF_CHECK_FLAGS_FIELD(Avb, 0)
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index 9b88c6a..1c90d17 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -20,11 +20,13 @@
#include <utils/Errors.h>
#include <map>
+#include <optional>
#include <string>
#include <vector>
#include "FileSystem.h"
#include "HalGroup.h"
+#include "KernelInfo.h"
#include "Level.h"
#include "ManifestHal.h"
#include "ManifestInstance.h"
@@ -126,6 +128,9 @@
bool insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch, HalFormat fmt,
std::string* error = nullptr);
+ // Get the <kernel> tag. Assumes type() == DEVICE.
+ const std::optional<KernelInfo>& kernel() const;
+
protected:
// Check before add()
bool shouldAdd(const ManifestHal& toAdd) const override;
@@ -172,6 +177,7 @@
// entries for device hal manifest only
struct {
Version mSepolicyVersion;
+ std::optional<KernelInfo> mKernel;
} device;
// entries for framework hal manifest only
diff --git a/include/vintf/KernelConfigParser.h b/include/vintf/KernelConfigParser.h
index 06a034d..9d5a8fe 100644
--- a/include/vintf/KernelConfigParser.h
+++ b/include/vintf/KernelConfigParser.h
@@ -33,6 +33,8 @@
status_t process(const char* buf, size_t len);
status_t finish();
+ status_t processAndFinish(const char* buf, size_t len);
+ status_t processAndFinish(const std::string& content);
std::stringbuf* error() const;
std::map<std::string, std::string>& configs();
const std::map<std::string, std::string>& configs() const;
diff --git a/include/vintf/KernelInfo.h b/include/vintf/KernelInfo.h
new file mode 100644
index 0000000..16bb2c3
--- /dev/null
+++ b/include/vintf/KernelInfo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "MatrixKernel.h"
+#include "Version.h"
+
+namespace android {
+namespace vintf {
+
+namespace details {
+class MockRuntimeInfo;
+} // namespace details
+
+// KernelInfo includes kernel-specific information on a device.
+class KernelInfo {
+ public:
+ KernelInfo() = default;
+
+ const KernelVersion& version() const;
+ const std::map<std::string, std::string>& configs() const;
+
+ // mVersion = x'.y'.z', minLts = x.y.z,
+ // match if x == x' , y == y' , and z <= z'.
+ bool matchKernelVersion(const KernelVersion& minLts) const;
+ // return true if all kernel configs in matrixConfigs matches.
+ bool matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
+ std::string* error = nullptr) const;
+ // return true if this matches kernel requirement specified.
+ bool matchKernelRequirements(const std::vector<MatrixKernel>& kernels,
+ std::string* error = nullptr) const;
+
+ bool operator==(const KernelInfo& other) const;
+
+ private:
+ friend class AssembleVintfImpl;
+ friend class details::MockRuntimeInfo;
+ friend struct KernelInfoConverter;
+ friend struct LibVintfTest;
+ friend struct RuntimeInfoFetcher;
+ // x.y.z
+ KernelVersion mVersion;
+ // /proc/config.gz
+ // Key: CONFIG_xxx; Value: the value after = sign.
+ std::map<std::string, std::string> mConfigs;
+};
+
+} // namespace vintf
+} // namespace android
diff --git a/include/vintf/RuntimeInfo.h b/include/vintf/RuntimeInfo.h
index 2e04279..61a9b23 100644
--- a/include/vintf/RuntimeInfo.h
+++ b/include/vintf/RuntimeInfo.h
@@ -26,6 +26,7 @@
#include <utils/Errors.h>
#include "CheckFlags.h"
+#include "KernelInfo.h"
#include "MatrixKernel.h"
#include "Version.h"
@@ -96,22 +97,14 @@
friend struct LibVintfTest;
friend std::string dump(const RuntimeInfo& ki, bool);
- // mKernelVersion = x'.y'.z', minLts = x.y.z,
- // match if x == x' , y == y' , and z <= z'.
- bool matchKernelVersion(const KernelVersion& minLts) const;
- // return true if all kernel configs in matrixConfigs matches.
- bool matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
- std::string* error = nullptr) const;
-
// /proc/config.gz
// Key: CONFIG_xxx; Value: the value after = sign.
- std::map<std::string, std::string> mKernelConfigs;
+ KernelInfo mKernel;
std::string mOsName;
std::string mNodeName;
std::string mOsRelease;
std::string mOsVersion;
std::string mHardwareId;
- KernelVersion mKernelVersion;
std::vector<std::string> mSepolicyFilePaths;
std::string mCpuInfo;
diff --git a/parse_string.cpp b/parse_string.cpp
index e3310f3..1c6f3b8 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -469,10 +469,10 @@
oss << "\n\ncpu info:\n" << ki.cpuInfo();
}
- oss << "\n#CONFIG's loaded = " << ki.mKernelConfigs.size() << ";\n";
+ oss << "\n#CONFIG's loaded = " << ki.kernelConfigs().size() << ";\n";
if (verbose) {
- for (const auto& pair : ki.mKernelConfigs) {
+ for (const auto& pair : ki.kernelConfigs()) {
oss << pair.first << "=" << pair.second << "\n";
}
}
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 0cc514d..fee7ba6 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -331,6 +331,18 @@
}
template <typename T>
+ inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
+ std::optional<T>* t, std::string* error) const {
+ NodeType* child = getChild(root, conv.elementName());
+ if (child == nullptr) {
+ *t = std::nullopt;
+ return true;
+ }
+ *t = std::make_optional<T>();
+ return conv.deserialize(&**t, child, error);
+ }
+
+ template <typename T>
inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v,
std::string* error) const {
auto nodes = getChildren(root, conv.elementName());
@@ -345,8 +357,9 @@
return true;
}
- template <typename T>
- inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::set<T>* s,
+ template <typename Container, typename T = typename Container::value_type,
+ typename = typename Container::key_compare>
+ inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, Container* s,
std::string* error) const {
std::vector<T> vec;
if (!parseChildren(root, conv, &vec, error)) {
@@ -363,6 +376,12 @@
return true;
}
+ template <typename K, typename V>
+ inline bool parseChildren(NodeType* root, const XmlNodeConverter<std::pair<K, V>>& conv,
+ std::map<K, V>* s, std::string* error) const {
+ return parseChildren<std::map<K, V>, std::pair<K, V>>(root, conv, s, error);
+ }
+
inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const {
*s = getText(node);
return true;
@@ -399,14 +418,38 @@
std::string mElementName;
};
+template <typename Pair>
+struct XmlPairConverter : public XmlNodeConverter<Pair> {
+ XmlPairConverter(
+ const std::string& elementName,
+ std::unique_ptr<XmlNodeConverter<typename Pair::first_type>>&& firstConverter,
+ std::unique_ptr<XmlNodeConverter<typename Pair::second_type>>&& secondConverter)
+ : mElementName(elementName),
+ mFirstConverter(std::move(firstConverter)),
+ mSecondConverter(std::move(secondConverter)) {}
+
+ virtual void mutateNode(const Pair& pair, NodeType* root, DocType* d) const override {
+ appendChild(root, mFirstConverter->serialize(pair.first, d));
+ appendChild(root, mSecondConverter->serialize(pair.second, d));
+ }
+ virtual bool buildObject(Pair* pair, NodeType* root, std::string* error) const override {
+ return this->parseChild(root, *mFirstConverter, &pair->first, error) &&
+ this->parseChild(root, *mSecondConverter, &pair->second, error);
+ }
+ virtual std::string elementName() const { return mElementName; }
+
+ private:
+ std::string mElementName;
+ std::unique_ptr<XmlNodeConverter<typename Pair::first_type>> mFirstConverter;
+ std::unique_ptr<XmlNodeConverter<typename Pair::second_type>> mSecondConverter;
+};
+
// ---------------------- XmlNodeConverter definitions end
XmlTextConverter<Version> versionConverter{"version"};
XmlTextConverter<VersionRange> versionRangeConverter{"version"};
-XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
-
struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
std::string elementName() const override { return "transport"; }
void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override {
@@ -455,22 +498,9 @@
KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
-struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
- std::string elementName() const override { return "config"; }
- void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override {
- appendChild(root, kernelConfigKeyConverter(object.first, d));
- appendChild(root, kernelConfigTypedValueConverter(object.second, d));
- }
- bool buildObject(KernelConfig* object, NodeType* root, std::string* error) const override {
- if (!parseChild(root, kernelConfigKeyConverter, &object->first, error) ||
- !parseChild(root, kernelConfigTypedValueConverter, &object->second, error)) {
- return false;
- }
- return true;
- }
-};
-
-KernelConfigConverter kernelConfigConverter{};
+XmlPairConverter<KernelConfig> matrixKernelConfigConverter{
+ "config", std::make_unique<XmlTextConverter<KernelConfigKey>>("key"),
+ std::make_unique<KernelConfigTypedValueConverter>(kernelConfigTypedValueConverter)};
struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
std::string elementName() const override { return "interface"; }
@@ -589,11 +619,11 @@
std::string elementName() const override { return "conditions"; }
void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root,
DocType* d) const override {
- appendChildren(root, kernelConfigConverter, conds, d);
+ appendChildren(root, matrixKernelConfigConverter, conds, d);
}
bool buildObject(std::vector<KernelConfig>* object, NodeType* root,
std::string* error) const override {
- return parseChildren(root, kernelConfigConverter, object, error);
+ return parseChildren(root, matrixKernelConfigConverter, object, error);
}
};
@@ -616,14 +646,14 @@
appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d));
}
if (flags.isKernelConfigsEnabled()) {
- appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
+ appendChildren(root, matrixKernelConfigConverter, kernel.mConfigs, d);
}
}
bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
if (!parseAttr(root, "version", &object->mMinLts, error) ||
!parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions,
error) ||
- !parseChildren(root, kernelConfigConverter, &object->mConfigs, error)) {
+ !parseChildren(root, matrixKernelConfigConverter, &object->mConfigs, error)) {
return false;
}
return true;
@@ -858,6 +888,32 @@
};
ManifestXmlFileConverter manifestXmlFileConverter{};
+XmlPairConverter<std::pair<std::string, std::string>> kernelConfigConverter{
+ "config", std::make_unique<XmlTextConverter<std::string>>("key"),
+ std::make_unique<XmlTextConverter<std::string>>("value")};
+
+struct KernelInfoConverter : public XmlNodeConverter<KernelInfo> {
+ std::string elementName() const override { return "kernel"; }
+ void mutateNode(const KernelInfo& o, NodeType* root, DocType* d) const override {
+ mutateNode(o, root, d, SerializeFlags::EVERYTHING);
+ }
+ void mutateNode(const KernelInfo& o, NodeType* root, DocType* d,
+ SerializeFlags::Type flags) const override {
+ if (o.version() != KernelVersion{}) {
+ appendAttr(root, "version", o.version());
+ }
+ if (flags.isKernelConfigsEnabled()) {
+ appendChildren(root, kernelConfigConverter, o.configs(), d);
+ }
+ }
+ bool buildObject(KernelInfo* o, NodeType* root, std::string* error) const override {
+ return parseOptionalAttr(root, "version", {}, &o->mVersion, error) &&
+ parseChildren(root, kernelConfigConverter, &o->mConfigs, error);
+ }
+};
+
+KernelInfoConverter kernelInfoConverter{};
+
struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
std::string elementName() const override { return "manifest"; }
void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
@@ -884,6 +940,12 @@
if (m.mLevel != Level::UNSPECIFIED) {
this->appendAttr(root, "target-level", m.mLevel);
}
+
+ if (flags.isKernelEnabled()) {
+ if (!!m.kernel()) {
+ appendChild(root, kernelInfoConverter.serialize(*m.kernel(), d, flags));
+ }
+ }
} else if (m.mType == SchemaType::FRAMEWORK) {
if (flags.isVndkEnabled()) {
#pragma clang diagnostic push
@@ -929,6 +991,10 @@
error)) {
return false;
}
+
+ if (!parseOptionalChild(root, kernelInfoConverter, &object->device.mKernel, error)) {
+ return false;
+ }
} else if (object->mType == SchemaType::FRAMEWORK) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -1189,6 +1255,7 @@
kernelConfigTypedValueConverter;
XmlConverter<MatrixHal>& gMatrixHalConverter = matrixHalConverter;
XmlConverter<ManifestHal>& gManifestHalConverter = manifestHalConverter;
+XmlConverter<KernelInfo>& gKernelInfoConverter = kernelInfoConverter;
} // namespace vintf
} // namespace android
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index 49a3a84..f5690aa 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -37,6 +37,7 @@
extern XmlConverter<ManifestHal>& gManifestHalConverter;
extern XmlConverter<MatrixHal>& gMatrixHalConverter;
extern XmlConverter<KernelConfigTypedValue>& gKernelConfigTypedValueConverter;
+extern XmlConverter<KernelInfo>& gKernelInfoConverter;
extern XmlConverter<HalManifest>& gHalManifestConverter;
extern XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter;
@@ -183,20 +184,23 @@
info.mOsName = "Linux";
info.mNodeName = "localhost";
info.mOsRelease = "3.18.31-g936f9a479d0f";
- info.mKernelVersion = {3, 18, 31};
info.mOsVersion = "#4 SMP PREEMPT Wed Feb 1 18:10:52 PST 2017";
info.mHardwareId = "aarch64";
info.mKernelSepolicyVersion = 30;
- info.mKernelConfigs = {
- {"CONFIG_64BIT", "y"},
- {"CONFIG_ANDROID_BINDER_DEVICES", "\"binder,hwbinder\""},
- {"CONFIG_ARCH_MMAP_RND_BITS", "24"},
- {"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", "\"\""},
- {"CONFIG_ILLEGAL_POINTER_VALUE", "0xdead000000000000"}
- };
+ info.mKernel = testKernelInfo();
setAvb(info, {2, 1}, {2, 1});
return info;
}
+ KernelInfo testKernelInfo() {
+ KernelInfo info;
+ info.mVersion = {3, 18, 31};
+ info.mConfigs = {{"CONFIG_64BIT", "y"},
+ {"CONFIG_ANDROID_BINDER_DEVICES", "\"binder,hwbinder\""},
+ {"CONFIG_ARCH_MMAP_RND_BITS", "24"},
+ {"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", "\"\""},
+ {"CONFIG_ILLEGAL_POINTER_VALUE", "0xdead000000000000"}};
+ return info;
+ }
};
TEST_F(LibVintfTest, ArchOperatorOr) {
@@ -3442,6 +3446,35 @@
std::set<std::string>({"android.hardware.camera@2.0", "android.hardware.nfc@1.0"}));
}
+TEST_F(LibVintfTest, KernelInfo) {
+ KernelInfo ki = testKernelInfo();
+
+ EXPECT_EQ(
+ "<kernel version=\"3.18.31\">\n"
+ " <config>\n"
+ " <key>CONFIG_64BIT</key>\n"
+ " <value>y</value>\n"
+ " </config>\n"
+ " <config>\n"
+ " <key>CONFIG_ANDROID_BINDER_DEVICES</key>\n"
+ " <value>\"binder,hwbinder\"</value>\n"
+ " </config>\n"
+ " <config>\n"
+ " <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+ " <value>24</value>\n"
+ " </config>\n"
+ " <config>\n"
+ " <key>CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES</key>\n"
+ " <value>\"\"</value>\n"
+ " </config>\n"
+ " <config>\n"
+ " <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+ " <value>0xdead000000000000</value>\n"
+ " </config>\n"
+ "</kernel>\n",
+ gKernelInfoConverter(ki, SerializeFlags::NO_TAGS.enableKernelConfigs()));
+}
+
} // namespace vintf
} // namespace android
diff --git a/test/RuntimeInfo-fake.cpp b/test/RuntimeInfo-fake.cpp
index 0efcae7..8ee8305 100644
--- a/test/RuntimeInfo-fake.cpp
+++ b/test/RuntimeInfo-fake.cpp
@@ -27,15 +27,15 @@
mOsName = "Linux";
mNodeName = "localhost";
mOsRelease = "3.18.31-g936f9a479d0f";
- mKernelVersion = {3, 18, 31};
mOsVersion = "#4 SMP PREEMPT Wed Feb 1 18:10:52 PST 2017";
mHardwareId = "aarch64";
mKernelSepolicyVersion = 30;
- mKernelConfigs = {{"CONFIG_64BIT", "y"},
- {"CONFIG_ANDROID_BINDER_DEVICES", "\"binder,hwbinder\""},
- {"CONFIG_ARCH_MMAP_RND_BITS", "24"},
- {"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", "\"\""},
- {"CONFIG_ILLEGAL_POINTER_VALUE", "0xdead000000000000"}};
+ mKernel.mVersion = {3, 18, 31};
+ mKernel.mConfigs = {{"CONFIG_64BIT", "y"},
+ {"CONFIG_ANDROID_BINDER_DEVICES", "\"binder,hwbinder\""},
+ {"CONFIG_ARCH_MMAP_RND_BITS", "24"},
+ {"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", "\"\""},
+ {"CONFIG_ILLEGAL_POINTER_VALUE", "0xdead000000000000"}};
return OK;
}
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 92e2ce9..f97d81f 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -327,6 +327,27 @@
" </hal>\n"
"</manifest>\n";
+//
+// Set of metadata for kernel requirements
+//
+
+const std::string vendorManifestKernel318 =
+ "<manifest version=\"1.0\" type=\"device\">\n"
+ " <kernel version=\"3.18.999\" />\n"
+ " <sepolicy>\n"
+ " <version>25.5</version>\n"
+ " </sepolicy>\n"
+ "</manifest>\n";
+
+const std::string systemMatrixKernel318 =
+ "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+ " <kernel version=\"3.18.999\"></kernel>\n"
+ " <sepolicy>\n"
+ " <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+ " <sepolicy-version>25.5</sepolicy-version>\n"
+ " </sepolicy>\n"
+ "</compatibility-matrix>\n";
+
class VintfObjectTestBase : public ::testing::Test {
protected:
MockFileSystem& fetcher() {
@@ -585,6 +606,28 @@
ASSERT_STREQ(error.c_str(), "");
}
+// Test that framework-only OTA fails when kernel is not compatible with incoming system.
+TEST_F(VintfObjectCompatibleTest, KernelInfoIncompatible) {
+ std::string error;
+ std::vector<std::string> packageInfo = {systemMatrixKernel318};
+
+ int result = checkCompatibility(packageInfo, &error);
+
+ ASSERT_EQ(result, INCOMPATIBLE) << "Should have failed.";
+ EXPECT_IN("Framework is incompatible with kernel version 3.18.31", error);
+}
+
+// Test that full OTA is successful when the OTA package provides a compatible kernel.
+TEST_F(VintfObjectCompatibleTest, UpdateKernel) {
+ std::string error;
+ std::vector<std::string> packageInfo = {vendorManifestKernel318, systemMatrixKernel318};
+
+ int result = checkCompatibility(packageInfo, &error);
+
+ ASSERT_EQ(result, COMPATIBLE) << "Fail message:" << error;
+ ASSERT_STREQ(error.c_str(), "");
+}
+
// Test fixture that provides incompatible metadata from the mock device.
class VintfObjectIncompatibleTest : public VintfObjectTestBase {
protected:
diff --git a/xsd/compatibilityMatrix/api/current.txt b/xsd/compatibilityMatrix/api/current.txt
index 3db4d27..a504dbb 100644
--- a/xsd/compatibilityMatrix/api/current.txt
+++ b/xsd/compatibilityMatrix/api/current.txt
@@ -41,7 +41,9 @@
public static class Config.Value {
ctor public Config.Value();
method public String getType();
+ method public String getValue();
method public void setType(String);
+ method public void setValue(String);
}
public class Hal {
diff --git a/xsd/compatibilityMatrix/compatibility_matrix.xsd b/xsd/compatibilityMatrix/compatibility_matrix.xsd
index 7c2c8a0..b8c9fa5 100644
--- a/xsd/compatibilityMatrix/compatibility_matrix.xsd
+++ b/xsd/compatibilityMatrix/compatibility_matrix.xsd
@@ -21,14 +21,14 @@
<xs:element name="compatibility-matrix">
<xs:complexType>
<xs:sequence>
- <xs:element name="hal" type="hal" maxOccurs="unbounded"/>
- <xs:element name="kernel" type="kernel" maxOccurs="unbounded"/>
- <xs:element name="sepolicy" type="sepolicy"/>
- <xs:element name="avb" type="avb"/>
- <xs:element name="vndk" type="vndk"/>
- <xs:element name="vendor-ndk" type="vendor-ndk"/>
- <xs:element name="system-sdk" type="system-sdk"/>
- <xs:element name="xmlfile" type="xmlfile" maxOccurs="unbounded"/>
+ <xs:element name="hal" type="hal" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="kernel" type="kernel" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="sepolicy" type="sepolicy" minOccurs="0"/>
+ <xs:element name="avb" type="avb" minOccurs="0"/>
+ <xs:element name="vndk" type="vndk" minOccurs="0"/>
+ <xs:element name="vendor-ndk" type="vendor-ndk" minOccurs="0"/>
+ <xs:element name="system-sdk" type="system-sdk" minOccurs="0"/>
+ <xs:element name="xmlfile" type="xmlfile" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="version" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="required"/>
@@ -38,9 +38,9 @@
<xs:complexType name="hal">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
- <xs:element name="version" type="xs:string" maxOccurs="unbounded"/>
- <xs:element name="interface" type="interface" maxOccurs="unbounded"/>
- <xs:element name="fqname" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="version" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="interface" type="interface" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="fqname" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="format" type="xs:string"/>
<xs:attribute name="optional" type="xs:string"/>
@@ -48,20 +48,20 @@
<xs:complexType name="interface">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
- <xs:element name="instance" type="xs:string" maxOccurs="unbounded"/>
- <xs:element name="regex-instance" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="instance" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="regex-instance" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="kernel">
<xs:sequence>
- <xs:element name="conditions">
+ <xs:element name="conditions" minOccurs="0">
<xs:complexType>
<xs:sequence>
- <xs:element name="config" type="config" maxOccurs="unbounded"/>
+ <xs:element name="config" type="config" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
- <xs:element name="config" type="config" maxOccurs="unbounded"/>
+ <xs:element name="config" type="config" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="version" type="xs:string"/>
</xs:complexType>
@@ -70,7 +70,11 @@
<xs:element name="key" type="xs:string"/>
<xs:element name="value">
<xs:complexType>
- <xs:attribute name="type" type="xs:string"/>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="type" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
@@ -78,7 +82,7 @@
<xs:complexType name="sepolicy">
<xs:sequence>
<xs:element name="kernel-sepolicy-version" type="xs:string"/>
- <xs:element name="sepolicy-version" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="sepolicy-version" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="avb">
@@ -89,18 +93,18 @@
<xs:complexType name="vndk">
<xs:sequence>
<xs:element name="version" type="xs:string"/>
- <xs:element name="library" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="library" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="vendor-ndk">
<xs:sequence>
<xs:element name="version" type="xs:string"/>
- <xs:element name="library" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="library" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="system-sdk">
<xs:sequence>
- <xs:element name="version" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="version" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="xmlfile">
diff --git a/xsd/halManifest/api/current.txt b/xsd/halManifest/api/current.txt
index 938324c..13acf6b 100644
--- a/xsd/halManifest/api/current.txt
+++ b/xsd/halManifest/api/current.txt
@@ -7,24 +7,49 @@
method public java.util.List<java.lang.String> getFqname();
method public String getName();
method public String getOptional();
+ method public hal.manifest.Hal.Transport getTransport();
method public java.util.List<java.lang.String> getVersion();
method public java.util.List<hal.manifest.Interface> get_interface();
method public void setFormat(String);
method public void setName(String);
method public void setOptional(String);
+ method public void setTransport(hal.manifest.Hal.Transport);
+ }
+
+ public static class Hal.Transport {
+ ctor public Hal.Transport();
+ method public String getArch();
+ method public String getValue();
+ method public void setArch(String);
+ method public void setValue(String);
}
public class Interface {
ctor public Interface();
method public java.util.List<java.lang.String> getInstance();
method public String getName();
- method public java.util.List<java.lang.String> getRegexinstance();
method public void setName(String);
}
+ public class Kernel {
+ ctor public Kernel();
+ method public java.util.List<hal.manifest.Kernel.Config> getConfig();
+ method public String getVersion();
+ method public void setVersion(String);
+ }
+
+ public static class Kernel.Config {
+ ctor public Kernel.Config();
+ method public String getKey();
+ method public String getValue();
+ method public void setKey(String);
+ method public void setValue(String);
+ }
+
public class Manifest {
ctor public Manifest();
method public java.util.List<hal.manifest.Hal> getHal();
+ method public hal.manifest.Kernel getKernel();
method public hal.manifest.Sepolicy getSepolicy();
method public hal.manifest.Systemsdk getSystemsdk();
method public String getTargetlevel();
@@ -32,6 +57,7 @@
method public java.util.List<hal.manifest.Vendorndk> getVendorndk();
method public String getVersion();
method public java.util.List<hal.manifest.Vndk> getVndk();
+ method public void setKernel(hal.manifest.Kernel);
method public void setSepolicy(hal.manifest.Sepolicy);
method public void setSystemsdk(hal.manifest.Systemsdk);
method public void setTargetlevel(String);
@@ -41,9 +67,8 @@
public class Sepolicy {
ctor public Sepolicy();
- method public String getKernelsepolicyversion();
- method public java.util.List<java.lang.String> getSepolicyversion();
- method public void setKernelsepolicyversion(String);
+ method public String getVersion();
+ method public void setVersion(String);
}
public class Systemsdk {
diff --git a/xsd/halManifest/hal_manifest.xsd b/xsd/halManifest/hal_manifest.xsd
index 635d2c2..688abeb 100644
--- a/xsd/halManifest/hal_manifest.xsd
+++ b/xsd/halManifest/hal_manifest.xsd
@@ -21,23 +21,33 @@
<xs:element name="manifest">
<xs:complexType>
<xs:sequence>
- <xs:element name="hal" type="hal" maxOccurs="unbounded"/>
- <xs:element name="sepolicy" type="sepolicy"/>
- <xs:element name="vndk" type="vndk" maxOccurs="unbounded"/>
- <xs:element name="vendor-ndk" type="vendor-ndk" maxOccurs="unbounded"/>
- <xs:element name="system-sdk" type="system-sdk"/>
+ <xs:element name="hal" type="hal" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="sepolicy" type="sepolicy" minOccurs="0"/>
+ <xs:element name="kernel" type="kernel" minOccurs="0"/>
+ <xs:element name="vndk" type="vndk" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="vendor-ndk" type="vendor-ndk" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="system-sdk" type="system-sdk" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="version" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="required"/>
- <xs:attribute name="target-level" type="xs:string" use="required"/>
+ <xs:attribute name="target-level" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:complexType name="hal">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
- <xs:element name="version" type="xs:string" maxOccurs="unbounded"/>
- <xs:element name="interface" type="interface" maxOccurs="unbounded"/>
- <xs:element name="fqname" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="transport">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="arch" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="version" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="interface" type="interface" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="fqname" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="format" type="xs:string"/>
<xs:attribute name="optional" type="xs:string"/>
@@ -45,31 +55,42 @@
<xs:complexType name="interface">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
- <xs:element name="instance" type="xs:string" maxOccurs="unbounded"/>
- <xs:element name="regex-instance" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="instance" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="sepolicy">
<xs:sequence>
- <xs:element name="kernel-sepolicy-version" type="xs:string"/>
- <xs:element name="sepolicy-version" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="version" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="vndk">
<xs:sequence>
<xs:element name="version" type="xs:string"/>
- <xs:element name="library" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="library" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="vendor-ndk">
<xs:sequence>
<xs:element name="version" type="xs:string"/>
- <xs:element name="library" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="library" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="system-sdk">
<xs:sequence>
- <xs:element name="version" type="xs:string" maxOccurs="unbounded"/>
+ <xs:element name="version" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="kernel">
+ <xs:sequence>
+ <xs:element name="config" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="key" type="xs:string"/>
+ <xs:element name="value" type="xs:string"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="version" type="xs:string"/>
+ </xs:complexType>
</xs:schema>