Packaging support for deploy JAR embedded JDK files (hermetic Java).
This is the initial implementation that supports packaging runtime needed JDK files into deploy JAR, which is part of the phase III development for hermetic Java support (b/212719968).
- The runtime needed JDK files specified via --resources flag are packaged as regular JAR entries in deploy JAR. Any JDK file that needs to be packaged at page aligned offset should not be included in --resource input list.
- JDK 'lib/modules' file has page alignment requirement (runtime mmap the modules image). A new singlejar flag is introduced for specifying the lib/modules file:
* --jdk_lib_modules <jdk_lib_modules_path>
Following manifest attribute is written in the JAR META-INF/MANIFEST.MF, if lib/modules is specified via the new flag:
* JDK-Lib-Modules-Offset: <offset>
The lib/modules offset information will be used at runtime in JDK when mapping the file.
Please see more details on design requirements/considerations and decisions in[]
The support for launcher part is handled by unknown commit.
RELNOTES: Packaging support for deploy JAR embedded JDK files (hermetic Java).
PiperOrigin-RevId: 437310998
diff --git a/src/tools/singlejar/options.cc b/src/tools/singlejar/options.cc
index 633fd97..692e306 100644
--- a/src/tools/singlejar/options.cc
+++ b/src/tools/singlejar/options.cc
@@ -37,6 +37,7 @@
tokens->MatchAndSet("--main_class", &main_class) ||
tokens->MatchAndSet("--java_launcher", &java_launcher) ||
tokens->MatchAndSet("--cds_archive", &cds_archive) ||
+ tokens->MatchAndSet("--jdk_lib_modules", &jdk_lib_modules) ||
tokens->MatchAndSet("--deploy_manifest_lines", &manifest_lines) ||
tokens->MatchAndSet("--sources", &input_jars) ||
tokens->MatchAndSet("--resources", &resources) ||
diff --git a/src/tools/singlejar/options.h b/src/tools/singlejar/options.h
index 977e5de..23b96c9 100644
--- a/src/tools/singlejar/options.h
+++ b/src/tools/singlejar/options.h
@@ -45,6 +45,7 @@
std::string main_class;
std::string java_launcher;
std::string cds_archive;
+ std::string jdk_lib_modules;
std::vector<std::string> manifest_lines;
std::vector<std::pair<std::string, std::string> > input_jars;
std::vector<std::string> resources;
diff --git a/src/tools/singlejar/options_test.cc b/src/tools/singlejar/options_test.cc
index 9da883d..2d2b831 100644
--- a/src/tools/singlejar/options_test.cc
+++ b/src/tools/singlejar/options_test.cc
@@ -70,7 +70,8 @@
"--extra_build_info", "extra_build_line1",
"--build_info_file", "build_file2",
"--extra_build_info", "extra_build_line2",
- "--cds_archive", "classes.jsa"};
+ "--cds_archive", "classes.jsa",
+ "--jdk_lib_modules", "modules"};
Options options;
options.ParseCommandLine(arraysize(args), args);
@@ -84,6 +85,7 @@
EXPECT_EQ("extra_build_line1", options.build_info_lines[0]);
EXPECT_EQ("extra_build_line2", options.build_info_lines[1]);
EXPECT_EQ("classes.jsa", options.cds_archive);
+ EXPECT_EQ("modules", options.jdk_lib_modules);
}
TEST(OptionsTest, MultiOptargs) {
diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc
index d6b2081..f47e8bd 100644
--- a/src/tools/singlejar/output_jar.cc
+++ b/src/tools/singlejar/output_jar.cc
@@ -129,9 +129,17 @@
manifest_.AppendLine("Main-Class: " + options_->main_class);
}
- // Copy CDS archive file (.jsa) if it is set.
+ // Copy CDS archive file (.jsa) if it is set. Page aligned start offset
+ // is required.
if (!options_->cds_archive.empty()) {
- AppendCDSArchive(options->cds_archive);
+ AppendPageAlignedFile(options->cds_archive, "Jsa-Offset", "cds.archive");
+ }
+
+ // Copy JDK lib/modules if set. Page aligned start offset is required for
+ // the file.
+ if (!options_->jdk_lib_modules.empty()) {
+ AppendPageAlignedFile(options_->jdk_lib_modules,
+ "JDK-Lib-Modules-Offset", std::string());
}
if (options_->multi_release) {
@@ -1041,22 +1049,25 @@
return aligned_offset;
}
-void OutputJar::AppendCDSArchive(const std::string &cds_archive) {
+void OutputJar::AppendPageAlignedFile(const std::string &file,
+ const std::string &manifest_attr_name,
+ const std::string &property_name) {
// Align the shared archive start offset at page alignment, which is
// required by mmap.
- off64_t aligned_offset = OutputJar::PageAlignedAppendFile(cds_archive);
+ off64_t aligned_offset = OutputJar::PageAlignedAppendFile(file);
- // Write the file offset of the shared archive section as a manifest
- // attribute.
- char cds_manifest_attr[50];
- snprintf( cds_manifest_attr, sizeof(cds_manifest_attr),
- "Jsa-Offset: %ld", (long)aligned_offset); // NOLINT(runtime/int,
- // google-runtime-int)
- manifest_.AppendLine(cds_manifest_attr);
+ // Write the start offset of the copied content as a manifest attribute.
+ char manifest_attr[50];
+ snprintf(manifest_attr, sizeof(manifest_attr),
+ "%s: %ld", manifest_attr_name.c_str(),
+ (long)aligned_offset); // NOLINT(runtime/int,
+ // google-runtime-int)
+ manifest_.AppendLine(manifest_attr);
- // Add to build_properties
- build_properties_.AddProperty("cds.archive",
- cds_archive.c_str());
+ if (!property_name.empty()) {
+ // Add to build_properties.
+ build_properties_.AddProperty(property_name.c_str(), file.c_str());
+ }
}
void OutputJar::ExtraCombiner(const std::string &entry_name,
diff --git a/src/tools/singlejar/output_jar.h b/src/tools/singlejar/output_jar.h
index 21a93fa..d867488 100644
--- a/src/tools/singlejar/output_jar.h
+++ b/src/tools/singlejar/output_jar.h
@@ -96,10 +96,11 @@
// Set classpath resource with given resource name and path.
void ClasspathResource(const std::string& resource_name,
const std::string& resource_path);
- // Append CDS archive file.
- void AppendCDSArchive(const std::string &cds_archive);
// Append file starting at page boundary.
off64_t PageAlignedAppendFile(const std::string &file_path);
+ void AppendPageAlignedFile(const std::string &file,
+ const std::string &manifest_attr_name,
+ const std::string &property_name);
// Append data from the file specified by file_path.
void AppendFile(Options *options, const char *const file_path);
// Copy 'count' bytes starting at 'offset' from the given file.
diff --git a/src/tools/singlejar/output_jar_simple_test.cc b/src/tools/singlejar/output_jar_simple_test.cc
index d1a6645..ee9d11b 100644
--- a/src/tools/singlejar/output_jar_simple_test.cc
+++ b/src/tools/singlejar/output_jar_simple_test.cc
@@ -307,6 +307,80 @@
EXPECT_PRED2(HasSubstr, build_properties, prop);
}
+// --jdk_lib_modules option
+TEST_F(OutputJarSimpleTest, JDKLibModules) {
+ string out_path = OutputFilePath("out.jar");
+ string launcher_path = CreateTextFile("launcher", "Dummy");
+ string jdk_lib_modules_path = CreateTextFile("modules", "Dummy");
+ CreateOutput(out_path, {"--java_launcher", launcher_path,
+ "--jdk_lib_modules", jdk_lib_modules_path});
+
+ // Test META-INF/MANIFEST.MF attribute.
+ string manifest = GetEntryContents(out_path, "META-INF/MANIFEST.MF");
+ size_t pagesize;
+#ifndef _WIN32
+ pagesize = sysconf(_SC_PAGESIZE);
+#else
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ pagesize = si.dwPageSize;
+#endif
+ char attr[128];
+ snprintf(attr, sizeof(attr), "JDK-Lib-Modules-Offset: %ld", pagesize);
+ EXPECT_PRED2(HasSubstr, manifest, attr);
+}
+
+// --cds_archive & --jdk_lib_modules options
+TEST_F(OutputJarSimpleTest, CDSAndJDKLibModules) {
+ string cds_data = "cafebabe";
+ string modules_data = "deadbeef";
+ string out_path = OutputFilePath("out.jar");
+ string launcher_path = CreateTextFile("launcher", "Dummy");
+ string cds_archive_path = CreateTextFile("classes.jsa", cds_data.c_str());
+ string jdk_lib_modules_path = CreateTextFile("modules", modules_data.c_str());
+ CreateOutput(out_path, {"--java_launcher", launcher_path,
+ "--cds_archive", cds_archive_path,
+ "--jdk_lib_modules", jdk_lib_modules_path});
+
+ FILE *fp = fopen(out_path.c_str(), "r");
+ ASSERT_NE(nullptr, fp);
+
+ // Test META-INF/MANIFEST.MF attributes.
+ string manifest = GetEntryContents(out_path, "META-INF/MANIFEST.MF");
+ size_t pagesize;
+#ifndef _WIN32
+ pagesize = sysconf(_SC_PAGESIZE);
+#else
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ pagesize = si.dwPageSize;
+#endif
+ size_t page_aligned_cds_offset = pagesize;
+ char buf[8];
+ size_t buf_len = sizeof(buf);
+
+ char cds_attr[128];
+ snprintf(cds_attr, sizeof(cds_attr), "Jsa-Offset: %ld",
+ page_aligned_cds_offset);
+ EXPECT_PRED2(HasSubstr, manifest, cds_attr);
+
+ fseek(fp, page_aligned_cds_offset, 0);
+ fread(buf, 1, buf_len, fp);
+ ASSERT_EQ(cds_data, string(buf, buf_len));
+
+ size_t page_aligned_modules_offset = pagesize * 2;
+ char modules_attr[128];
+ snprintf(modules_attr, sizeof(modules_attr), "JDK-Lib-Modules-Offset: %ld",
+ page_aligned_modules_offset);
+ EXPECT_PRED2(HasSubstr, manifest, modules_attr);
+
+ fseek(fp, page_aligned_modules_offset, 0);
+ fread(buf, 1, buf_len, fp);
+ ASSERT_EQ(modules_data, string(buf, buf_len));
+
+ fclose(fp);
+}
+
// --main_class option.
TEST_F(OutputJarSimpleTest, MainClass) {
string out_path = OutputFilePath("out.jar");