Add dexpreopt_test.
This is a test to verify that the compilation artifacts built in the
system image for all system server jars are used. If will fail if the
artifacts are rejected by the runtime or odrefresh has run.
Bug: 201491591
Test: atest art_standalone_dexpreopt_tests
Change-Id: Id0f943cf822b55580eb121ee25375386397ae515
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 8bd3bd1..fcd2564 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -234,10 +234,16 @@
"libnativehelper_header_only",
],
static: {
- whole_static_libs: ["libc++fs"],
+ whole_static_libs: [
+ "libc++fs",
+ "libprocinfo",
+ ],
},
shared: {
- static_libs: ["libc++fs"],
+ static_libs: [
+ "libc++fs",
+ "libprocinfo",
+ ],
},
}
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 843f286..20bc87c 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -16,23 +16,23 @@
#include "common_art_test.h"
-#include <cstdio>
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
-#include <filesystem>
#include <ftw.h>
#include <libgen.h>
#include <stdlib.h>
#include <unistd.h>
+
+#include <cstdio>
+#include <filesystem>
+
#include "android-base/file.h"
#include "android-base/logging.h"
-#include "nativehelper/scoped_local_ref.h"
-
+#include "android-base/process.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
#include "android-base/unique_fd.h"
-
#include "art_field-inl.h"
#include "base/file_utils.h"
#include "base/logging.h"
@@ -49,6 +49,8 @@
#include "dex/dex_file_loader.h"
#include "dex/primitive.h"
#include "gtest/gtest.h"
+#include "nativehelper/scoped_local_ref.h"
+#include "procinfo/process.h"
namespace art {
@@ -675,4 +677,19 @@
return ForkAndExec(argv, post_fork, string_collect_fn);
}
+std::vector<pid_t> GetPidByName(const std::string& process_name) {
+ std::vector<pid_t> results;
+ for (pid_t pid : android::base::AllPids{}) {
+ android::procinfo::ProcessInfo process_info;
+ std::string error;
+ if (!android::procinfo::GetProcessInfo(pid, &process_info, &error)) {
+ continue;
+ }
+ if (process_info.name == process_name) {
+ results.push_back(pid);
+ }
+ }
+ return results;
+}
+
} // namespace art
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index 8dd1f88..268877a 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -17,15 +17,14 @@
#ifndef ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_
#define ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_
-#include <gtest/gtest.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <functional>
#include <string>
+#include <vector>
-#include <sys/wait.h>
-
-#include <android-base/logging.h>
-
+#include "android-base/logging.h"
#include "base/file_utils.h"
#include "base/globals.h"
#include "base/memory_tool.h"
@@ -33,8 +32,9 @@
#include "base/os.h"
#include "base/unix_file/fd_file.h"
#include "dex/art_dex_file_loader.h"
-#include "dex/compact_dex_level.h"
#include "dex/compact_dex_file.h"
+#include "dex/compact_dex_level.h"
+#include "gtest/gtest.h"
namespace art {
@@ -287,6 +287,10 @@
template <typename Param>
using CommonArtTestWithParam = CommonArtTestBase<testing::TestWithParam<Param>>;
+// Returns a list of PIDs of the processes whose process name (the name of the binary without path)
+// fully matches the given name.
+std::vector<pid_t> GetPidByName(const std::string& process_name);
+
#define TEST_DISABLED_FOR_TARGET() \
if (kIsTargetBuild) { \
printf("WARNING: TEST DISABLED FOR TARGET\n"); \
diff --git a/odrefresh/Android.bp b/odrefresh/Android.bp
index a8ec76c..8d5e443 100644
--- a/odrefresh/Android.bp
+++ b/odrefresh/Android.bp
@@ -200,7 +200,7 @@
"libdexfiled",
"libdexoptd",
],
- test_config_template: "art_odrefresh_tests.xml",
+ test_config_template: "//art/test:art-gtests-target-standalone-root-template",
}
// Standalone version of ART gtest `art_odrefresh_tests`, not bundled with the ART APEX on target.
@@ -214,7 +214,7 @@
"libdexfile",
"libdexopt",
],
- test_config_template: "art_odrefresh_tests.xml",
+ test_config_template: "//art/test:art-gtests-target-standalone-root-template",
}
genrule {
diff --git a/test/Android.bp b/test/Android.bp
index d618477..3a1bf85 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -126,6 +126,15 @@
],
}
+// Test configuration template for standalone ART gtests run as root on target (not bundled with
+// the ART APEX).
+filegroup {
+ name: "art-gtests-target-standalone-root-template",
+ srcs: [
+ "art-gtests-target-standalone-root-template.xml",
+ ],
+}
+
art_cc_defaults {
name: "art_standalone_test_defaults",
defaults: [
diff --git a/odrefresh/art_odrefresh_tests.xml b/test/art-gtests-target-standalone-root-template.xml
similarity index 96%
rename from odrefresh/art_odrefresh_tests.xml
rename to test/art-gtests-target-standalone-root-template.xml
index 29fa631..a8ed9dc 100644
--- a/odrefresh/art_odrefresh_tests.xml
+++ b/test/art-gtests-target-standalone-root-template.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<!-- Note: This test config file for {MODULE} is generated from a template. -->
-<configuration description="Runs {MODULE}.">
+<configuration description="Runs {MODULE} as root.">
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
diff --git a/test/dexpreopt/Android.bp b/test/dexpreopt/Android.bp
new file mode 100644
index 0000000..b39565b
--- /dev/null
+++ b/test/dexpreopt/Android.bp
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+art_cc_test {
+ name: "art_standalone_dexpreopt_tests",
+ defaults: [
+ "art_standalone_gtest_defaults",
+ ],
+ host_supported: false,
+ srcs: [
+ "dexpreopt_test.cc",
+ ],
+ static_libs: [
+ "libgmock",
+ "libprocinfo",
+ ],
+ test_config_template: "//art/test:art-gtests-target-standalone-root-template",
+}
diff --git a/test/dexpreopt/TEST_MAPPING b/test/dexpreopt/TEST_MAPPING
new file mode 100644
index 0000000..3075987
--- /dev/null
+++ b/test/dexpreopt/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "art_standalone_dexpreopt_tests"
+ }
+ ]
+}
diff --git a/test/dexpreopt/dexpreopt_test.cc b/test/dexpreopt/dexpreopt_test.cc
new file mode 100644
index 0000000..aaa6501
--- /dev/null
+++ b/test/dexpreopt/dexpreopt_test.cc
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+// A test to verify that the compilation artifacts built in the system image for all system server
+// jars are used. It will fail if odrefresh has run (in which case, artifacts in /data will be used
+// instead) or the artifacts in the system image are rejected by the runtime. This test should only
+// run on a clean system without any APEX (including com.android.art.testing) installed on data,
+// which otherwise will trigger odrefresh.
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "android-base/result.h"
+#include "android-base/strings.h"
+#include "arch/instruction_set.h"
+#include "base/common_art_test.h"
+#include "base/os.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "oat_file_assistant.h"
+#include "procinfo/process_map.h"
+
+namespace art {
+
+using ::testing::IsSubsetOf;
+
+android::base::Result<std::vector<std::string>> GetSystemServerArtifacts() {
+ const char* env_value = getenv("SYSTEMSERVERCLASSPATH");
+ if (env_value == nullptr) {
+ return Errorf("Environment variable `SYSTEMSERVERCLASSPATH` is not defined");
+ }
+ if (kRuntimeISA == InstructionSet::kNone) {
+ return Errorf("Unable to get system server ISA");
+ }
+ std::vector<std::string> artifacts;
+ for (const std::string& jar : android::base::Split(env_value, ":")) {
+ std::string error_msg;
+ std::string odex_file;
+
+ if (!OatFileAssistant::DexLocationToOdexFilename(jar, kRuntimeISA, &odex_file, &error_msg)) {
+ return Errorf("Failed to get odex filename: {}", error_msg);
+ }
+
+ if (!OS::FileExists(odex_file.c_str())) {
+ if (errno == EACCES) {
+ return ErrnoErrorf("Failed to stat() {}", odex_file);
+ }
+ // Dexpreopting is probably disabled. No need to report missing artifacts here because
+ // artifact generation is already checked at build time.
+ continue;
+ }
+
+ artifacts.push_back(odex_file);
+ }
+ return artifacts;
+}
+
+android::base::Result<std::vector<std::string>> GetSystemServerArtifactsMappedOdexes() {
+ std::vector<pid_t> pids = art::GetPidByName("system_server");
+ if (pids.size() != 1) {
+ return Errorf("There should be exactly one `system_server` process, found {}", pids.size());
+ }
+ pid_t pid = pids[0];
+ std::vector<android::procinfo::MapInfo> maps;
+ if (!android::procinfo::ReadProcessMaps(pid, &maps)) {
+ return ErrnoErrorf("Failed to get mapped memory regions of `system_server`");
+ }
+ std::vector<std::string> odexes;
+ for (const android::procinfo::MapInfo& map : maps) {
+ if ((map.flags & PROT_EXEC) && android::base::EndsWith(map.name, ".odex")) {
+ odexes.push_back(map.name);
+ }
+ }
+ return odexes;
+}
+
+TEST(DexpreoptTest, ForSystemServer) {
+ android::base::Result<std::vector<std::string>> system_server_artifacts =
+ GetSystemServerArtifacts();
+ ASSERT_RESULT_OK(system_server_artifacts);
+
+ if (system_server_artifacts->empty()) {
+ // Skip the test if dexpreopting is disabled.
+ return;
+ }
+
+ android::base::Result<std::vector<std::string>> mapped_odexes =
+ GetSystemServerArtifactsMappedOdexes();
+ ASSERT_RESULT_OK(mapped_odexes);
+
+ EXPECT_THAT(system_server_artifacts.value(), IsSubsetOf(mapped_odexes.value()));
+}
+
+} // namespace art