1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // A test to verify that the compilation artifacts built in the system image for all system server
18 // jars are used. It will fail if odrefresh has run (in which case, artifacts in /data will be used
19 // instead) or the artifacts in the system image are rejected by the runtime. This test should only
20 // run on a clean system without any APEX (including com.android.art.testing) installed on data,
21 // which otherwise will trigger odrefresh.
22
23 #include <stdlib.h>
24 #include <sys/mman.h>
25 #include <sys/types.h>
26
27 #include <algorithm>
28 #include <iterator>
29 #include <string>
30 #include <unordered_set>
31 #include <utility>
32 #include <vector>
33
34 #include "android-base/properties.h"
35 #include "android-base/result.h"
36 #include "android-base/stringprintf.h"
37 #include "android-base/strings.h"
38 #include "arch/instruction_set.h"
39 #include "base/common_art_test.h"
40 #include "base/file_utils.h"
41 #include "base/os.h"
42 #include "gmock/gmock.h"
43 #include "gtest/gtest.h"
44 #include "oat/oat_file_assistant.h"
45 #include "procinfo/process_map.h"
46
47 namespace art {
48
49 using ::android::base::Error;
50 using ::testing::IsSupersetOf;
51
52 constexpr const char* kZygote32 = "zygote";
53 constexpr const char* kZygote64 = "zygote64";
54
GetListFromEnv(const std::string & name)55 std::vector<std::string> GetListFromEnv(const std::string& name) {
56 const char* env_value = getenv(name.c_str());
57 if (env_value == nullptr || strlen(env_value) == 0) {
58 return {};
59 }
60 return android::base::Split(env_value, ":");
61 }
62
GetZygoteNamesAndIsas()63 android::base::Result<std::vector<std::pair<std::string, InstructionSet>>> GetZygoteNamesAndIsas() {
64 std::vector<std::pair<std::string, InstructionSet>> names_and_isas;
65
66 // Possible values are: "zygote32", "zygote64", "zygote32_64", "zygote64_32".
67 std::string zygote_kinds = android::base::GetProperty("ro.zygote", {});
68 if (zygote_kinds.empty()) {
69 return Errorf("Unable to get Zygote kinds");
70 }
71
72 switch (kRuntimeISA) {
73 case InstructionSet::kArm:
74 case InstructionSet::kArm64:
75 if (zygote_kinds.find("32") != std::string::npos) {
76 names_and_isas.push_back(std::make_pair(kZygote32, InstructionSet::kArm));
77 }
78 if (zygote_kinds.find("64") != std::string::npos) {
79 names_and_isas.push_back(std::make_pair(kZygote64, InstructionSet::kArm64));
80 }
81 break;
82 case InstructionSet::kX86:
83 case InstructionSet::kX86_64:
84 if (zygote_kinds.find("32") != std::string::npos) {
85 names_and_isas.push_back(std::make_pair(kZygote32, InstructionSet::kX86));
86 }
87 if (zygote_kinds.find("64") != std::string::npos) {
88 names_and_isas.push_back(std::make_pair(kZygote64, InstructionSet::kX86_64));
89 }
90 break;
91 default:
92 return Errorf("Unknown runtime ISA: {}", GetInstructionSetString(kRuntimeISA));
93 }
94
95 return names_and_isas;
96 }
97
GetZygoteExpectedArtifacts(InstructionSet isa)98 android::base::Result<std::vector<std::string>> GetZygoteExpectedArtifacts(InstructionSet isa) {
99 std::vector<std::string> jars = GetListFromEnv("DEX2OATBOOTCLASSPATH");
100 if (jars.empty()) {
101 return Errorf("Environment variable `DEX2OATBOOTCLASSPATH` is not defined or empty");
102 }
103 std::string error_msg;
104 std::string first_mainline_jar = GetFirstMainlineFrameworkLibraryFilename(&error_msg);
105 if (first_mainline_jar.empty()) {
106 return Error() << error_msg;
107 }
108 jars.push_back(std::move(first_mainline_jar));
109 std::string art_root = GetArtRoot();
110 std::string android_root = GetAndroidRoot();
111 std::vector<std::string> artifacts;
112 for (size_t i = 0; i < jars.size(); i++) {
113 const std::string& jar = jars[i];
114 std::string basename =
115 i == 0 ? "boot.oat" : "boot-" + ReplaceFileExtension(android::base::Basename(jar), "oat");
116 std::string dir = jar.starts_with(art_root) ? GetPrebuiltPrimaryBootImageDir()
117 : android_root + "/framework";
118 std::string oat_file = android::base::StringPrintf(
119 "%s/%s/%s", dir.c_str(), GetInstructionSetString(isa), basename.c_str());
120
121 if (!OS::FileExists(oat_file.c_str())) {
122 if (errno == EACCES) {
123 return ErrnoErrorf("Failed to stat() {}", oat_file);
124 }
125 // Dexpreopting is probably disabled. No need to report missing artifacts here because
126 // artifact generation is already checked at build time.
127 continue;
128 }
129
130 artifacts.push_back(oat_file);
131 }
132 return artifacts;
133 }
134
GetSystemServerExpectedArtifacts()135 android::base::Result<std::vector<std::string>> GetSystemServerExpectedArtifacts() {
136 std::vector<std::string> jars = GetListFromEnv("SYSTEMSERVERCLASSPATH");
137 if (jars.empty()) {
138 return Errorf("Environment variable `SYSTEMSERVERCLASSPATH` is not defined or empty");
139 }
140 std::vector<std::string> standalone_jars = GetListFromEnv("STANDALONE_SYSTEMSERVER_JARS");
141 std::move(standalone_jars.begin(), standalone_jars.end(), std::back_inserter(jars));
142 if (kRuntimeISA == InstructionSet::kNone) {
143 return Errorf("Unable to get system server ISA");
144 }
145 std::vector<std::string> artifacts;
146 for (const std::string& jar : jars) {
147 std::string error_msg;
148 std::string odex_file;
149
150 if (!OatFileAssistant::DexLocationToOdexFilename(jar, kRuntimeISA, &odex_file, &error_msg)) {
151 return Errorf("Failed to get odex filename: {}", error_msg);
152 }
153
154 if (!OS::FileExists(odex_file.c_str())) {
155 if (errno == EACCES) {
156 return ErrnoErrorf("Failed to stat() {}", odex_file);
157 }
158 // Dexpreopting is probably disabled. No need to report missing artifacts here because
159 // artifact generation is already checked at build time.
160 continue;
161 }
162
163 artifacts.push_back(odex_file);
164 }
165 return artifacts;
166 }
167
GetMappedFiles(pid_t pid,const std::string & extension,uint16_t flags)168 android::base::Result<std::vector<std::string>> GetMappedFiles(pid_t pid,
169 const std::string& extension,
170 uint16_t flags) {
171 std::vector<android::procinfo::MapInfo> maps;
172 if (!android::procinfo::ReadProcessMaps(pid, &maps)) {
173 return ErrnoErrorf("Failed to get mapped memory regions of pid {}", pid);
174 }
175 std::vector<std::string> files;
176 for (const android::procinfo::MapInfo& map : maps) {
177 if ((map.flags & flags) && map.name.ends_with(extension)) {
178 files.push_back(map.name);
179 }
180 }
181 return files;
182 }
183
GetZygoteMappedOatFiles(const std::string & zygote_name)184 android::base::Result<std::vector<std::string>> GetZygoteMappedOatFiles(
185 const std::string& zygote_name) {
186 std::vector<pid_t> pids = art::GetPidByName(zygote_name);
187 if (pids.empty()) {
188 return Errorf("Unable to find Zygote process: {}", zygote_name);
189 }
190 // OAT files in boot images may not be mmaped with PROT_EXEC if they don't contain executable
191 // code. Checking PROT_READ is sufficient because an OAT file will be unmapped if the runtime
192 // rejects it.
193 return GetMappedFiles(pids[0], ".oat", PROT_READ);
194 }
195
GetSystemServerArtifactsMappedOdexes()196 android::base::Result<std::vector<std::string>> GetSystemServerArtifactsMappedOdexes() {
197 std::vector<pid_t> pids = art::GetPidByName("system_server");
198 if (pids.size() != 1) {
199 return Errorf("There should be exactly one `system_server` process, found {}", pids.size());
200 }
201 return GetMappedFiles(pids[0], ".odex", PROT_READ);
202 }
203
TEST(DexpreoptTest,ForZygote)204 TEST(DexpreoptTest, ForZygote) {
205 android::base::Result<std::vector<std::pair<std::string, InstructionSet>>> zygote_names_and_isas =
206 GetZygoteNamesAndIsas();
207 ASSERT_RESULT_OK(zygote_names_and_isas);
208
209 for (const auto& [zygote_name, isa] : *zygote_names_and_isas) {
210 android::base::Result<std::vector<std::string>> expected_artifacts =
211 GetZygoteExpectedArtifacts(isa);
212 ASSERT_RESULT_OK(expected_artifacts);
213
214 if (expected_artifacts->empty()) {
215 // Skip the test if dexpreopting is disabled.
216 return;
217 }
218
219 android::base::Result<std::vector<std::string>> mapped_oat_files =
220 GetZygoteMappedOatFiles(zygote_name);
221 ASSERT_RESULT_OK(mapped_oat_files);
222
223 EXPECT_THAT(mapped_oat_files.value(), IsSupersetOf(expected_artifacts.value()));
224 }
225 }
226
TEST(DexpreoptTest,ForSystemServer)227 TEST(DexpreoptTest, ForSystemServer) {
228 android::base::Result<std::vector<std::string>> expected_artifacts =
229 GetSystemServerExpectedArtifacts();
230 ASSERT_RESULT_OK(expected_artifacts);
231
232 if (expected_artifacts->empty()) {
233 // Skip the test if dexpreopting is disabled.
234 return;
235 }
236
237 android::base::Result<std::vector<std::string>> mapped_odexes =
238 GetSystemServerArtifactsMappedOdexes();
239 ASSERT_RESULT_OK(mapped_odexes);
240
241 EXPECT_THAT(mapped_odexes.value(), IsSupersetOf(expected_artifacts.value()));
242 }
243
244 } // namespace art
245