assemble_vintf: accept --kernel for manifests.
Add KernelInfo to HalManifest object.
The final verified_assembled_vendor_manifest.xml will contain
<kernel> information for compatibility check during OTA.
Bug: 111125947
Test: build verified_assembled_vendor_manifest.xml
Change-Id: If5a3124b6cbed4da9b2038c30274c223ee52b259
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..f7bac29 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -413,7 +413,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 +471,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
index b9dfd9c..1a37bdf 100644
--- a/KernelInfo.cpp
+++ b/KernelInfo.cpp
@@ -102,5 +102,9 @@
return true;
}
+bool KernelInfo::operator==(const KernelInfo& other) const {
+ return mVersion == other.mVersion && mConfigs == other.mConfigs;
+}
+
} // namespace vintf
} // namespace android
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/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
index 620883f..16bb2c3 100644
--- a/include/vintf/KernelInfo.h
+++ b/include/vintf/KernelInfo.h
@@ -48,7 +48,10 @@
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;
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 6498012..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());
@@ -928,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
@@ -973,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"