xref: /aosp_15_r20/art/test/dexpreopt/dexpreopt_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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