Reland^2: Create an abstraction for dexopt tasks
Cause of the revert / broken test:
buildbot-build.sh does not build libbinder_ndk.so. Add the missing
dependency to copy to the chroot.
Original message:
Instead of letting odrefresh building dex2oat cmdline arguments, hide
the specifics of cmdline flags behind an API abstraction. The API
defines the only necessary parameters for the actual dexopt task (e.g.
compiling BCP extension, system server) to proceed. The introduced API
is private within ART.
libdexopt.so is created to contain the API and implementation. It is put
under art/artd/ in the sense that the future ART services can reuse and
evolve the code.
This change should not have any effective change to the compilation
results. Given the large size of the change, the dex2oat cmdline is
purposely ordered in the same way as before. The compiled artifacts
should not change at all.
Also, art_odrefresh_test is no longer built for the "second" ABI. This
is to make it consistent to odrefresh, so that we won't need to test
unused variation and build "second" for the dependencies.
Bug: 193668901
Test: 1. Revert this change, run `odrefresh --force-compile`, capture
the checksum of all output files.
2. Apply this change, repeat the same step.
3. Saw all the file hashes remain the same (except for
cache-info.xml where the timestamp changed).
Test: atest ComposHostTestCases
Test: atest odsign_e2e_tests
Test: atest art_standalone_odrefresh_tests
Test: art/build/apex/runtests.sh
Test: lunch full-eng; m; art/build/apex/runtests.sh
Test: with master-art, art/tools/run-gtests.sh \
/apex/com.android.art/bin/art/arm64/art_odrefresh_tests
Test: TH
Change-Id: I3bf805fba925c197ec10508a67f0a16e74d64c62
diff --git a/artd/libdexopt_test.cc b/artd/libdexopt_test.cc
new file mode 100644
index 0000000..7536dcd
--- /dev/null
+++ b/artd/libdexopt_test.cc
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2021 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 "libdexopt.h"
+
+#include <string>
+#include <vector>
+
+#include "android-base/result.h"
+#include "android-base/strings.h"
+#include "base/common_art_test.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "aidl/com/android/art/CompilerFilter.h"
+#include "aidl/com/android/art/DexoptBcpExtArgs.h"
+#include "aidl/com/android/art/DexoptSystemServerArgs.h"
+#include "aidl/com/android/art/Isa.h"
+
+namespace art {
+
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::HasSubstr;
+using ::testing::Not;
+using aidl::com::android::art::CompilerFilter;
+using aidl::com::android::art::DexoptBcpExtArgs;
+using aidl::com::android::art::DexoptSystemServerArgs;
+using aidl::com::android::art::Isa;
+using android::base::Result;
+
+std::string GetEnvironmentVariableOrDie(const char* name) {
+ const char* value = getenv(name);
+ EXPECT_NE(value, nullptr);
+ return value;
+}
+
+// See art_artd_tests.xml for *CLASSPATH setup.
+class LibDexoptTest : public CommonArtTest {
+ protected:
+ void SetUp() override {
+ CommonArtTest::SetUp();
+
+ default_bcp_ext_args_.dexFds = {10, 11};
+ default_bcp_ext_args_.bootClasspaths = android::base::Split(
+ GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH"), ":"); // from art_artd_tests.xml
+ default_bcp_ext_args_.bootClasspathFds = {21, 22};
+ default_bcp_ext_args_.profileFd = 30;
+ default_bcp_ext_args_.dirtyImageObjectsFd = 31;
+ default_bcp_ext_args_.imageFd = 90;
+ default_bcp_ext_args_.vdexFd = 91;
+ default_bcp_ext_args_.oatFd = 92;
+ default_bcp_ext_args_.dexPaths = {"/path/to/foo.jar", "/path/to/bar.jar"};
+ default_bcp_ext_args_.oatLocation = "/oat/location/bar.odex";
+ default_bcp_ext_args_.isa = Isa::X86_64;
+ default_bcp_ext_args_.cpuSet = {0, 1};
+ default_bcp_ext_args_.threads = 42;
+ ASSERT_EQ(default_bcp_ext_args_.bootClasspaths.size(),
+ default_bcp_ext_args_.bootClasspathFds.size());
+
+ default_system_server_args_.dexFd = 10;
+ default_system_server_args_.profileFd = 11;
+ default_system_server_args_.bootClasspaths = android::base::Split(
+ GetEnvironmentVariableOrDie("BOOTCLASSPATH"), ":"); // from art_artd_tests.xml
+ default_system_server_args_.bootClasspathFds = {21, 22, 23};
+ default_system_server_args_.bootClasspathImageFds = {-1, 31, -1};
+ default_system_server_args_.bootClasspathVdexFds = {-1, 32, -1};
+ default_system_server_args_.bootClasspathOatFds = {-1, 33, -1};
+ default_system_server_args_.classloaderFds = {40, 41};
+ default_system_server_args_.classloaderContext = {"/cl/abc.jar", "/cl/def.jar"};
+ default_system_server_args_.imageFd = 90;
+ default_system_server_args_.vdexFd = 91;
+ default_system_server_args_.oatFd = 92;
+ default_system_server_args_.dexPath = "/path/to/foo.jar";
+ default_system_server_args_.oatLocation = "/oat/location/bar.odex";
+ default_system_server_args_.isa = Isa::X86_64;
+ default_system_server_args_.compilerFilter = CompilerFilter::SPEED_PROFILE;
+ default_system_server_args_.cpuSet = {0, 1};
+ default_system_server_args_.threads = 42;
+ default_system_server_args_.isBootImageOnSystem = true;
+ ASSERT_EQ(default_system_server_args_.bootClasspaths.size(),
+ default_system_server_args_.bootClasspathFds.size());
+ }
+
+ void TearDown() override {
+ CommonArtTest::TearDown();
+ }
+
+ std::vector<std::string> Dex2oatArgsFromBcpExtensionArgs(const DexoptBcpExtArgs& args) {
+ std::vector<std::string> cmdline;
+ Result<void> result = AddDex2oatArgsFromBcpExtensionArgs(args, cmdline);
+ EXPECT_TRUE(result.ok()) << "Failed expectation: " << result.error().message();
+ return cmdline;
+ }
+
+ std::vector<std::string> Dex2oatArgsFromSystemServerArgs(const DexoptSystemServerArgs& args) {
+ std::vector<std::string> cmdline;
+ Result<void> result = AddDex2oatArgsFromSystemServerArgs(args, cmdline);
+ EXPECT_TRUE(result.ok()) << "Failed expectation: " << result.error().message();
+ return cmdline;
+ }
+
+ bool DexoptBcpExtArgsIsInvalid(const DexoptBcpExtArgs& args) {
+ std::vector<std::string> cmdline;
+ Result<void> result = AddDex2oatArgsFromBcpExtensionArgs(args, cmdline);
+ return result.ok();
+ }
+
+ bool DexoptSystemServerArgsIsInvalid(const DexoptSystemServerArgs& args) {
+ std::vector<std::string> cmdline;
+ Result<void> result = AddDex2oatArgsFromSystemServerArgs(args, cmdline);
+ return result.ok();
+ }
+
+ DexoptBcpExtArgs default_bcp_ext_args_;
+ DexoptSystemServerArgs default_system_server_args_;
+};
+
+TEST_F(LibDexoptTest, AddDex2oatArgsFromBcpExtensionArgs) {
+ // Test basics with default args
+ {
+ std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(default_bcp_ext_args_);
+
+ EXPECT_THAT(cmdline, AllOf(
+ Contains("--dex-fd=10"),
+ Contains("--dex-fd=11"),
+ Contains("--dex-file=/path/to/foo.jar"),
+ Contains("--dex-file=/path/to/bar.jar"),
+ Contains(HasSubstr("-Xbootclasspath:")),
+ Contains("-Xbootclasspathfds:21:22"),
+
+ Contains("--profile-file-fd=30"),
+ Contains("--compiler-filter=speed-profile"),
+
+ Contains("--image-fd=90"),
+ Contains("--output-vdex-fd=91"),
+ Contains("--oat-fd=92"),
+ Contains("--oat-location=/oat/location/bar.odex"),
+
+ Contains("--dirty-image-objects-fd=31"),
+ Contains("--instruction-set=x86_64"),
+ Contains("--cpu-set=0,1"),
+ Contains("-j42")));
+ }
+
+ // No profile
+ {
+ auto args = default_bcp_ext_args_;
+ args.profileFd = -1;
+ std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(args);
+
+ EXPECT_THAT(cmdline, AllOf(
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=speed")));
+ }
+
+ // No dirty image objects fd
+ {
+ auto args = default_bcp_ext_args_;
+ args.dirtyImageObjectsFd = -1;
+ std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(args);
+
+ EXPECT_THAT(cmdline, Not(Contains(HasSubstr("--dirty-image-objects-fd"))));
+ }
+}
+
+TEST_F(LibDexoptTest, AddDex2oatArgsFromBcpExtensionArgs_InvalidArguments) {
+ // Mismatched dex number
+ {
+ auto args = default_bcp_ext_args_;
+ args.dexPaths = {"/path/to/foo.jar", "/path/to/bar.jar"};
+ args.dexFds = {100, 101, 102};
+
+ EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
+ }
+
+ // Mismatched classpath arguments
+ {
+ auto args = default_bcp_ext_args_;
+ args.bootClasspathFds.emplace_back(200);
+
+ EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
+ }
+
+ // Mismatched classpath arguments
+ {
+ auto args = default_bcp_ext_args_;
+ args.bootClasspaths.emplace_back("/unrecognized/jar");
+
+ EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
+ }
+
+ // Missing output fds
+ {
+ auto args = default_bcp_ext_args_;
+ args.imageFd = -1;
+ EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
+
+ args = default_bcp_ext_args_;
+ args.vdexFd = -1;
+ EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
+
+ args = default_bcp_ext_args_;
+ args.oatFd = -1;
+ EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
+ }
+}
+
+TEST_F(LibDexoptTest, AddDex2oatArgsFromSystemServerArgs) {
+ // Test basics with default args
+ {
+ std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(default_system_server_args_);
+
+ EXPECT_THAT(cmdline, AllOf(
+ Contains("--dex-fd=10"),
+ Contains("--dex-file=/path/to/foo.jar"),
+ Contains(HasSubstr("-Xbootclasspath:")),
+ Contains("-Xbootclasspathfds:21:22:23"),
+ Contains("-Xbootclasspathimagefds:-1:31:-1"),
+ Contains("-Xbootclasspathvdexfds:-1:32:-1"),
+ Contains("-Xbootclasspathoatfds:-1:33:-1"),
+
+ Contains("--profile-file-fd=11"),
+ Contains("--compiler-filter=speed-profile"),
+
+ Contains("--app-image-fd=90"),
+ Contains("--output-vdex-fd=91"),
+ Contains("--oat-fd=92"),
+ Contains("--oat-location=/oat/location/bar.odex"),
+
+ Contains("--class-loader-context-fds=40:41"),
+ Contains("--class-loader-context=PCL[/cl/abc.jar:/cl/def.jar]"),
+
+ Contains("--instruction-set=x86_64"),
+ Contains("--cpu-set=0,1"),
+ Contains("-j42")));
+ }
+
+ // Test different compiler filters
+ {
+ // speed
+ auto args = default_system_server_args_;
+ args.compilerFilter = CompilerFilter::SPEED;
+ std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(args);
+
+ EXPECT_THAT(cmdline, AllOf(
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=speed")));
+
+ // verify
+ args = default_system_server_args_;
+ args.compilerFilter = CompilerFilter::VERIFY;
+ cmdline = Dex2oatArgsFromSystemServerArgs(args);
+
+ EXPECT_THAT(cmdline, AllOf(
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=verify")));
+ }
+
+ // Test classloader context
+ {
+ auto args = default_system_server_args_;
+ args.classloaderFds = {};
+ args.classloaderContext = {};
+ std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(args);
+
+ EXPECT_THAT(cmdline, AllOf(
+ Not(Contains(HasSubstr("--class-loader-context-fds"))),
+ Contains("--class-loader-context=PCL[]")));
+ }
+}
+
+TEST_F(LibDexoptTest, AddDex2oatArgsFromSystemServerArgs_InvalidArguments) {
+ // Mismatched classpath arguments
+ {
+ auto args = default_system_server_args_;
+ args.bootClasspathFds.emplace_back(200);
+
+ EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
+ }
+
+ // Unrecognized jar path
+ {
+ auto args = default_system_server_args_;
+ args.bootClasspaths.emplace_back("/unrecognized/jar");
+
+ EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
+ }
+
+ // speed-profile without profile fd
+ {
+ auto args = default_system_server_args_;
+ args.compilerFilter = CompilerFilter::SPEED_PROFILE;
+ args.profileFd = -1;
+ EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
+ }
+
+ // Missing output fds
+ {
+ auto args = default_system_server_args_;
+ args.imageFd = -1;
+ EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
+
+ args = default_system_server_args_;
+ args.vdexFd = -1;
+ EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
+
+ args = default_system_server_args_;
+ args.oatFd = -1;
+ EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
+ }
+}
+
+} // namespace art