xref: /aosp_15_r20/art/runtime/gc/space/image_space_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
20*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
21*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
24*795d594fSAndroid Build Coastguard Worker #include "class_linker.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/utf.h"
26*795d594fSAndroid Build Coastguard Worker #include "dexopt_test.h"
27*795d594fSAndroid Build Coastguard Worker #include "intern_table-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "noop_compiler_callbacks.h"
29*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file.h"
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
32*795d594fSAndroid Build Coastguard Worker namespace gc {
33*795d594fSAndroid Build Coastguard Worker namespace space {
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker class ImageSpaceTest : public CommonRuntimeTest {
36*795d594fSAndroid Build Coastguard Worker  protected:
SetUpRuntimeOptions(RuntimeOptions * options)37*795d594fSAndroid Build Coastguard Worker   void SetUpRuntimeOptions(RuntimeOptions* options) override {
38*795d594fSAndroid Build Coastguard Worker     // Disable relocation.
39*795d594fSAndroid Build Coastguard Worker     options->emplace_back("-Xnorelocate", nullptr);
40*795d594fSAndroid Build Coastguard Worker   }
41*795d594fSAndroid Build Coastguard Worker 
GetFilenameBase(const std::string & full_path)42*795d594fSAndroid Build Coastguard Worker   std::string GetFilenameBase(const std::string& full_path) {
43*795d594fSAndroid Build Coastguard Worker     size_t slash_pos = full_path.rfind('/');
44*795d594fSAndroid Build Coastguard Worker     CHECK_NE(std::string::npos, slash_pos);
45*795d594fSAndroid Build Coastguard Worker     size_t dot_pos = full_path.rfind('.');
46*795d594fSAndroid Build Coastguard Worker     CHECK_NE(std::string::npos, dot_pos);
47*795d594fSAndroid Build Coastguard Worker     CHECK_GT(dot_pos, slash_pos + 1u);
48*795d594fSAndroid Build Coastguard Worker     return full_path.substr(slash_pos + 1u, dot_pos - (slash_pos + 1u));
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker };
51*795d594fSAndroid Build Coastguard Worker 
TEST_F(ImageSpaceTest,StringDeduplication)52*795d594fSAndroid Build Coastguard Worker TEST_F(ImageSpaceTest, StringDeduplication) {
53*795d594fSAndroid Build Coastguard Worker   const char* const kBaseNames[] = {"Extension1", "Extension2"};
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker   ScratchDir scratch;
56*795d594fSAndroid Build Coastguard Worker   const std::string& scratch_dir = scratch.GetPath();
57*795d594fSAndroid Build Coastguard Worker   std::string image_dir = scratch_dir + GetInstructionSetString(kRuntimeISA);
58*795d594fSAndroid Build Coastguard Worker   int mkdir_result = mkdir(image_dir.c_str(), 0700);
59*795d594fSAndroid Build Coastguard Worker   ASSERT_EQ(0, mkdir_result);
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker   // Prepare boot class path variables.
62*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> bcp = GetLibCoreDexFileNames();
63*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> bcp_locations = GetLibCoreDexLocations();
64*795d594fSAndroid Build Coastguard Worker   CHECK_EQ(bcp.size(), bcp_locations.size());
65*795d594fSAndroid Build Coastguard Worker   std::string base_bcp_string = android::base::Join(bcp, ':');
66*795d594fSAndroid Build Coastguard Worker   std::string base_bcp_locations_string = android::base::Join(bcp_locations, ':');
67*795d594fSAndroid Build Coastguard Worker   std::string base_image_location = GetImageLocation();
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker   // Compile the two extensions independently.
70*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> extension_image_locations;
71*795d594fSAndroid Build Coastguard Worker   for (const char* base_name : kBaseNames) {
72*795d594fSAndroid Build Coastguard Worker     std::string jar_name = GetTestDexFileName(base_name);
73*795d594fSAndroid Build Coastguard Worker     ArrayRef<const std::string> dex_files(&jar_name, /*size=*/1u);
74*795d594fSAndroid Build Coastguard Worker     ScratchFile profile_file;
75*795d594fSAndroid Build Coastguard Worker     GenerateBootProfile(dex_files, profile_file.GetFile());
76*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> extra_args = {
77*795d594fSAndroid Build Coastguard Worker         "--profile-file=" + profile_file.GetFilename(),
78*795d594fSAndroid Build Coastguard Worker         "--runtime-arg",
79*795d594fSAndroid Build Coastguard Worker         ART_FORMAT("-Xbootclasspath:{}:{}", base_bcp_string, jar_name),
80*795d594fSAndroid Build Coastguard Worker         "--runtime-arg",
81*795d594fSAndroid Build Coastguard Worker         ART_FORMAT("-Xbootclasspath-locations:{}:{}", base_bcp_locations_string, jar_name),
82*795d594fSAndroid Build Coastguard Worker         "--boot-image=" + base_image_location,
83*795d594fSAndroid Build Coastguard Worker     };
84*795d594fSAndroid Build Coastguard Worker     std::string prefix = GetFilenameBase(base_image_location);
85*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
86*795d594fSAndroid Build Coastguard Worker     bool success =
87*795d594fSAndroid Build Coastguard Worker         CompileBootImage(extra_args, ART_FORMAT("{}/{}", image_dir, prefix), dex_files, &error_msg);
88*795d594fSAndroid Build Coastguard Worker     ASSERT_TRUE(success) << error_msg;
89*795d594fSAndroid Build Coastguard Worker     bcp.push_back(jar_name);
90*795d594fSAndroid Build Coastguard Worker     bcp_locations.push_back(jar_name);
91*795d594fSAndroid Build Coastguard Worker     extension_image_locations.push_back(scratch_dir + prefix + '-' + GetFilenameBase(jar_name) +
92*795d594fSAndroid Build Coastguard Worker                                         ".art");
93*795d594fSAndroid Build Coastguard Worker   }
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker   // Also compile the second extension as an app with app image.
96*795d594fSAndroid Build Coastguard Worker   const char* app_base_name = kBaseNames[std::size(kBaseNames) - 1u];
97*795d594fSAndroid Build Coastguard Worker   std::string app_jar_name = GetTestDexFileName(app_base_name);
98*795d594fSAndroid Build Coastguard Worker   std::string app_odex_name = scratch_dir + app_base_name + ".odex";
99*795d594fSAndroid Build Coastguard Worker   std::string app_image_name = scratch_dir + app_base_name + ".art";
100*795d594fSAndroid Build Coastguard Worker   {
101*795d594fSAndroid Build Coastguard Worker     ArrayRef<const std::string> dex_files(&app_jar_name, /*size=*/1u);
102*795d594fSAndroid Build Coastguard Worker     ScratchFile profile_file;
103*795d594fSAndroid Build Coastguard Worker     GenerateProfile(dex_files, profile_file.GetFile());
104*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> argv;
105*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
106*795d594fSAndroid Build Coastguard Worker     bool success = StartDex2OatCommandLine(&argv, &error_msg, /*use_runtime_bcp_and_image=*/false);
107*795d594fSAndroid Build Coastguard Worker     ASSERT_TRUE(success) << error_msg;
108*795d594fSAndroid Build Coastguard Worker     argv.insert(argv.end(),
109*795d594fSAndroid Build Coastguard Worker                 {
110*795d594fSAndroid Build Coastguard Worker                     "--profile-file=" + profile_file.GetFilename(),
111*795d594fSAndroid Build Coastguard Worker                     "--runtime-arg",
112*795d594fSAndroid Build Coastguard Worker                     "-Xbootclasspath:" + base_bcp_string,
113*795d594fSAndroid Build Coastguard Worker                     "--runtime-arg",
114*795d594fSAndroid Build Coastguard Worker                     "-Xbootclasspath-locations:" + base_bcp_locations_string,
115*795d594fSAndroid Build Coastguard Worker                     "--boot-image=" + base_image_location,
116*795d594fSAndroid Build Coastguard Worker                     "--dex-file=" + app_jar_name,
117*795d594fSAndroid Build Coastguard Worker                     "--dex-location=" + app_jar_name,
118*795d594fSAndroid Build Coastguard Worker                     "--oat-file=" + app_odex_name,
119*795d594fSAndroid Build Coastguard Worker                     "--app-image-file=" + app_image_name,
120*795d594fSAndroid Build Coastguard Worker                     "--initialize-app-image-classes=true",
121*795d594fSAndroid Build Coastguard Worker                 });
122*795d594fSAndroid Build Coastguard Worker     success = RunDex2Oat(argv, &error_msg);
123*795d594fSAndroid Build Coastguard Worker     ASSERT_TRUE(success) << error_msg;
124*795d594fSAndroid Build Coastguard Worker   }
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> full_image_locations;
127*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<gc::space::ImageSpace>> boot_image_spaces;
128*795d594fSAndroid Build Coastguard Worker   MemMap extra_reservation;
129*795d594fSAndroid Build Coastguard Worker   auto load_boot_image = [&]() REQUIRES_SHARED(Locks::mutator_lock_) {
130*795d594fSAndroid Build Coastguard Worker     boot_image_spaces.clear();
131*795d594fSAndroid Build Coastguard Worker     extra_reservation = MemMap::Invalid();
132*795d594fSAndroid Build Coastguard Worker     return ImageSpace::LoadBootImage(
133*795d594fSAndroid Build Coastguard Worker         bcp,
134*795d594fSAndroid Build Coastguard Worker         bcp_locations,
135*795d594fSAndroid Build Coastguard Worker         /*boot_class_path_files=*/{},
136*795d594fSAndroid Build Coastguard Worker         /*boot_class_path_image_files=*/{},
137*795d594fSAndroid Build Coastguard Worker         /*boot_class_path_vdex_files=*/{},
138*795d594fSAndroid Build Coastguard Worker         /*boot_class_path_oat_files=*/{},
139*795d594fSAndroid Build Coastguard Worker         full_image_locations,
140*795d594fSAndroid Build Coastguard Worker         kRuntimeISA,
141*795d594fSAndroid Build Coastguard Worker         /*relocate=*/false,
142*795d594fSAndroid Build Coastguard Worker         /*executable=*/true,
143*795d594fSAndroid Build Coastguard Worker         /*extra_reservation_size=*/0u,
144*795d594fSAndroid Build Coastguard Worker         /*allow_in_memory_compilation=*/false,
145*795d594fSAndroid Build Coastguard Worker         Runtime::GetApexVersions(ArrayRef<const std::string>(bcp_locations)),
146*795d594fSAndroid Build Coastguard Worker         &boot_image_spaces,
147*795d594fSAndroid Build Coastguard Worker         &extra_reservation);
148*795d594fSAndroid Build Coastguard Worker   };
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker   const char test_string[] = "SharedBootImageExtensionTestString";
151*795d594fSAndroid Build Coastguard Worker   size_t test_string_length = std::size(test_string) - 1u;  // Equals UTF-16 length.
152*795d594fSAndroid Build Coastguard Worker   uint32_t hash = InternTable::Utf8String::Hash(test_string_length, test_string);
153*795d594fSAndroid Build Coastguard Worker   InternTable::Utf8String utf8_test_string(test_string_length, test_string);
154*795d594fSAndroid Build Coastguard Worker   auto contains_test_string = [utf8_test_string,
155*795d594fSAndroid Build Coastguard Worker                                hash](ImageSpace* space) REQUIRES_SHARED(Locks::mutator_lock_) {
156*795d594fSAndroid Build Coastguard Worker     const ImageHeader& image_header = space->GetImageHeader();
157*795d594fSAndroid Build Coastguard Worker     if (image_header.GetInternedStringsSection().Size() != 0u) {
158*795d594fSAndroid Build Coastguard Worker       const uint8_t* data = space->Begin() + image_header.GetInternedStringsSection().Offset();
159*795d594fSAndroid Build Coastguard Worker       size_t read_count;
160*795d594fSAndroid Build Coastguard Worker       InternTable::UnorderedSet temp_set(data, /*make_copy_of_data=*/false, &read_count);
161*795d594fSAndroid Build Coastguard Worker       return temp_set.FindWithHash(utf8_test_string, hash) != temp_set.end();
162*795d594fSAndroid Build Coastguard Worker     } else {
163*795d594fSAndroid Build Coastguard Worker       return false;
164*795d594fSAndroid Build Coastguard Worker     }
165*795d594fSAndroid Build Coastguard Worker   };
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker   // Load extensions and test for the presence of the test string.
168*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(Thread::Current());
169*795d594fSAndroid Build Coastguard Worker   ASSERT_EQ(2u, extension_image_locations.size());
170*795d594fSAndroid Build Coastguard Worker   full_image_locations = {
171*795d594fSAndroid Build Coastguard Worker       base_image_location, extension_image_locations[0], extension_image_locations[1]};
172*795d594fSAndroid Build Coastguard Worker   bool success = load_boot_image();
173*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(success);
174*795d594fSAndroid Build Coastguard Worker   ASSERT_EQ(bcp.size(), boot_image_spaces.size());
175*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(contains_test_string(boot_image_spaces[boot_image_spaces.size() - 2u].get()));
176*795d594fSAndroid Build Coastguard Worker   // The string in the second extension should be replaced and removed from interned string section.
177*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(contains_test_string(boot_image_spaces[boot_image_spaces.size() - 1u].get()));
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker   // Reload extensions in reverse order and test for the presence of the test string.
180*795d594fSAndroid Build Coastguard Worker   std::swap(bcp[bcp.size() - 2u], bcp[bcp.size() - 1u]);
181*795d594fSAndroid Build Coastguard Worker   std::swap(bcp_locations[bcp_locations.size() - 2u], bcp_locations[bcp_locations.size() - 1u]);
182*795d594fSAndroid Build Coastguard Worker   full_image_locations = {
183*795d594fSAndroid Build Coastguard Worker       base_image_location, extension_image_locations[1], extension_image_locations[0]};
184*795d594fSAndroid Build Coastguard Worker   success = load_boot_image();
185*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(success);
186*795d594fSAndroid Build Coastguard Worker   ASSERT_EQ(bcp.size(), boot_image_spaces.size());
187*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(contains_test_string(boot_image_spaces[boot_image_spaces.size() - 2u].get()));
188*795d594fSAndroid Build Coastguard Worker   // The string in the second extension should be replaced and removed from interned string section.
189*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(contains_test_string(boot_image_spaces[boot_image_spaces.size() - 1u].get()));
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker   // Reload the image without the second extension.
192*795d594fSAndroid Build Coastguard Worker   bcp.erase(bcp.end() - 2u);
193*795d594fSAndroid Build Coastguard Worker   bcp_locations.erase(bcp_locations.end() - 2u);
194*795d594fSAndroid Build Coastguard Worker   full_image_locations = {base_image_location, extension_image_locations[0]};
195*795d594fSAndroid Build Coastguard Worker   success = load_boot_image();
196*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(success);
197*795d594fSAndroid Build Coastguard Worker   ASSERT_EQ(bcp.size(), boot_image_spaces.size());
198*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(contains_test_string(boot_image_spaces[boot_image_spaces.size() - 1u].get()));
199*795d594fSAndroid Build Coastguard Worker 
200*795d594fSAndroid Build Coastguard Worker   // Load the app odex file and app image.
201*795d594fSAndroid Build Coastguard Worker   std::string error_msg;
202*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
203*795d594fSAndroid Build Coastguard Worker                                                    app_odex_name,
204*795d594fSAndroid Build Coastguard Worker                                                    app_odex_name,
205*795d594fSAndroid Build Coastguard Worker                                                    /*executable=*/false,
206*795d594fSAndroid Build Coastguard Worker                                                    /*low_4gb=*/false,
207*795d594fSAndroid Build Coastguard Worker                                                    app_jar_name,
208*795d594fSAndroid Build Coastguard Worker                                                    &error_msg));
209*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(odex_file != nullptr) << error_msg;
210*795d594fSAndroid Build Coastguard Worker   std::vector<ImageSpace*> non_owning_boot_image_spaces =
211*795d594fSAndroid Build Coastguard Worker       MakeNonOwningPointerVector(boot_image_spaces);
212*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ImageSpace> app_image_space;
213*795d594fSAndroid Build Coastguard Worker   {
214*795d594fSAndroid Build Coastguard Worker     ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
215*795d594fSAndroid Build Coastguard Worker     app_image_space = ImageSpace::CreateFromAppImage(
216*795d594fSAndroid Build Coastguard Worker         app_image_name.c_str(),
217*795d594fSAndroid Build Coastguard Worker         odex_file.get(),
218*795d594fSAndroid Build Coastguard Worker         ArrayRef<ImageSpace* const>(non_owning_boot_image_spaces),
219*795d594fSAndroid Build Coastguard Worker         &error_msg);
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(app_image_space != nullptr) << error_msg;
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   // The string in the app image should be replaced and removed from interned string section.
224*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(contains_test_string(app_image_space.get()));
225*795d594fSAndroid Build Coastguard Worker }
226*795d594fSAndroid Build Coastguard Worker 
TEST_F(DexoptTest,ValidateOatFile)227*795d594fSAndroid Build Coastguard Worker TEST_F(DexoptTest, ValidateOatFile) {
228*795d594fSAndroid Build Coastguard Worker   std::string dex1 = GetScratchDir() + "/Dex1.jar";
229*795d594fSAndroid Build Coastguard Worker   std::string multidex1 = GetScratchDir() + "/MultiDex1.jar";
230*795d594fSAndroid Build Coastguard Worker   std::string dex2 = GetScratchDir() + "/Dex2.jar";
231*795d594fSAndroid Build Coastguard Worker   std::string oat_location = GetScratchDir() + "/Oat.oat";
232*795d594fSAndroid Build Coastguard Worker 
233*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc1(), dex1);
234*795d594fSAndroid Build Coastguard Worker   Copy(GetMultiDexSrc1(), multidex1);
235*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc2(), dex2);
236*795d594fSAndroid Build Coastguard Worker 
237*795d594fSAndroid Build Coastguard Worker   std::string error_msg;
238*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> args;
239*795d594fSAndroid Build Coastguard Worker   args.push_back("--dex-file=" + dex1);
240*795d594fSAndroid Build Coastguard Worker   args.push_back("--dex-file=" + multidex1);
241*795d594fSAndroid Build Coastguard Worker   args.push_back("--dex-file=" + dex2);
242*795d594fSAndroid Build Coastguard Worker   args.push_back("--oat-file=" + oat_location);
243*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
244*795d594fSAndroid Build Coastguard Worker 
245*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<OatFile> oat(OatFile::Open(/*zip_fd=*/-1,
246*795d594fSAndroid Build Coastguard Worker                                              oat_location,
247*795d594fSAndroid Build Coastguard Worker                                              oat_location,
248*795d594fSAndroid Build Coastguard Worker                                              /*executable=*/false,
249*795d594fSAndroid Build Coastguard Worker                                              /*low_4gb=*/false,
250*795d594fSAndroid Build Coastguard Worker                                              &error_msg));
251*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(oat != nullptr) << error_msg;
252*795d594fSAndroid Build Coastguard Worker 
253*795d594fSAndroid Build Coastguard Worker   {
254*795d594fSAndroid Build Coastguard Worker     // Test opening the oat file also with explicit dex filenames.
255*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> dex_filenames{dex1, multidex1, dex2};
256*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<OatFile> oat2(OatFile::Open(/*zip_fd=*/-1,
257*795d594fSAndroid Build Coastguard Worker                                                 oat_location,
258*795d594fSAndroid Build Coastguard Worker                                                 oat_location,
259*795d594fSAndroid Build Coastguard Worker                                                 /*executable=*/false,
260*795d594fSAndroid Build Coastguard Worker                                                 /*low_4gb=*/false,
261*795d594fSAndroid Build Coastguard Worker                                                 ArrayRef<const std::string>(dex_filenames),
262*795d594fSAndroid Build Coastguard Worker                                                 /*dex_files=*/{},
263*795d594fSAndroid Build Coastguard Worker                                                 /*reservation=*/nullptr,
264*795d594fSAndroid Build Coastguard Worker                                                 &error_msg));
265*795d594fSAndroid Build Coastguard Worker     ASSERT_TRUE(oat2 != nullptr) << error_msg;
266*795d594fSAndroid Build Coastguard Worker   }
267*795d594fSAndroid Build Coastguard Worker 
268*795d594fSAndroid Build Coastguard Worker   // Originally all the dex checksums should be up to date.
269*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
270*795d594fSAndroid Build Coastguard Worker 
271*795d594fSAndroid Build Coastguard Worker   // Invalidate the dex1 checksum.
272*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc2(), dex1);
273*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
274*795d594fSAndroid Build Coastguard Worker 
275*795d594fSAndroid Build Coastguard Worker   // Restore the dex1 checksum.
276*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc1(), dex1);
277*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker   // Invalidate the non-main multidex checksum.
280*795d594fSAndroid Build Coastguard Worker   Copy(GetMultiDexSrc2(), multidex1);
281*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
282*795d594fSAndroid Build Coastguard Worker 
283*795d594fSAndroid Build Coastguard Worker   // Restore the multidex checksum.
284*795d594fSAndroid Build Coastguard Worker   Copy(GetMultiDexSrc1(), multidex1);
285*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker   // Invalidate the dex2 checksum.
288*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc1(), dex2);
289*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
290*795d594fSAndroid Build Coastguard Worker 
291*795d594fSAndroid Build Coastguard Worker   // restore the dex2 checksum.
292*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc2(), dex2);
293*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
294*795d594fSAndroid Build Coastguard Worker 
295*795d594fSAndroid Build Coastguard Worker   // Replace the multidex file with a non-multidex file.
296*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc1(), multidex1);
297*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
298*795d594fSAndroid Build Coastguard Worker 
299*795d594fSAndroid Build Coastguard Worker   // Restore the multidex file
300*795d594fSAndroid Build Coastguard Worker   Copy(GetMultiDexSrc1(), multidex1);
301*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
302*795d594fSAndroid Build Coastguard Worker 
303*795d594fSAndroid Build Coastguard Worker   // Replace dex1 with a multidex file.
304*795d594fSAndroid Build Coastguard Worker   Copy(GetMultiDexSrc1(), dex1);
305*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker   // Restore the dex1 file.
308*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc1(), dex1);
309*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
310*795d594fSAndroid Build Coastguard Worker 
311*795d594fSAndroid Build Coastguard Worker   // Remove the dex2 file.
312*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(0, unlink(dex2.c_str()));
313*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker   // Restore the dex2 file.
316*795d594fSAndroid Build Coastguard Worker   Copy(GetDexSrc2(), dex2);
317*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
318*795d594fSAndroid Build Coastguard Worker 
319*795d594fSAndroid Build Coastguard Worker   // Remove the multidex file.
320*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(0, unlink(multidex1.c_str()));
321*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
322*795d594fSAndroid Build Coastguard Worker }
323*795d594fSAndroid Build Coastguard Worker 
324*795d594fSAndroid Build Coastguard Worker template <bool kImage, bool kRelocate>
325*795d594fSAndroid Build Coastguard Worker class ImageSpaceLoadingTest : public CommonRuntimeTest {
326*795d594fSAndroid Build Coastguard Worker  protected:
SetUpRuntimeOptions(RuntimeOptions * options)327*795d594fSAndroid Build Coastguard Worker   void SetUpRuntimeOptions(RuntimeOptions* options) override {
328*795d594fSAndroid Build Coastguard Worker     missing_image_base_ = std::make_unique<ScratchFile>();
329*795d594fSAndroid Build Coastguard Worker     std::string image_location = PrepareImageLocation();
330*795d594fSAndroid Build Coastguard Worker     options->emplace_back(android::base::StringPrintf("-Ximage:%s", image_location.c_str()),
331*795d594fSAndroid Build Coastguard Worker                           nullptr);
332*795d594fSAndroid Build Coastguard Worker     options->emplace_back(kRelocate ? "-Xrelocate" : "-Xnorelocate", nullptr);
333*795d594fSAndroid Build Coastguard Worker     options->emplace_back("-Xallowinmemorycompilation", nullptr);
334*795d594fSAndroid Build Coastguard Worker 
335*795d594fSAndroid Build Coastguard Worker     // We want to test the relocation behavior of ImageSpace. As such, don't pretend we're a
336*795d594fSAndroid Build Coastguard Worker     // compiler.
337*795d594fSAndroid Build Coastguard Worker     callbacks_.reset();
338*795d594fSAndroid Build Coastguard Worker 
339*795d594fSAndroid Build Coastguard Worker     // Clear DEX2OATBOOTCLASSPATH environment variable used for boot image compilation.
340*795d594fSAndroid Build Coastguard Worker     // We don't want that environment variable to affect the behavior of this test.
341*795d594fSAndroid Build Coastguard Worker     CHECK(old_dex2oat_bcp_ == nullptr);
342*795d594fSAndroid Build Coastguard Worker     const char* old_dex2oat_bcp = getenv("DEX2OATBOOTCLASSPATH");
343*795d594fSAndroid Build Coastguard Worker     if (old_dex2oat_bcp != nullptr) {
344*795d594fSAndroid Build Coastguard Worker       old_dex2oat_bcp_.reset(strdup(old_dex2oat_bcp));
345*795d594fSAndroid Build Coastguard Worker       CHECK(old_dex2oat_bcp_ != nullptr);
346*795d594fSAndroid Build Coastguard Worker       unsetenv("DEX2OATBOOTCLASSPATH");
347*795d594fSAndroid Build Coastguard Worker     }
348*795d594fSAndroid Build Coastguard Worker   }
349*795d594fSAndroid Build Coastguard Worker 
TearDown()350*795d594fSAndroid Build Coastguard Worker   void TearDown() override {
351*795d594fSAndroid Build Coastguard Worker     if (old_dex2oat_bcp_ != nullptr) {
352*795d594fSAndroid Build Coastguard Worker       int result = setenv("DEX2OATBOOTCLASSPATH", old_dex2oat_bcp_.get(), /* replace */ 0);
353*795d594fSAndroid Build Coastguard Worker       CHECK_EQ(result, 0);
354*795d594fSAndroid Build Coastguard Worker       old_dex2oat_bcp_.reset();
355*795d594fSAndroid Build Coastguard Worker     }
356*795d594fSAndroid Build Coastguard Worker     missing_image_base_.reset();
357*795d594fSAndroid Build Coastguard Worker   }
358*795d594fSAndroid Build Coastguard Worker 
PrepareImageLocation()359*795d594fSAndroid Build Coastguard Worker   virtual std::string PrepareImageLocation() {
360*795d594fSAndroid Build Coastguard Worker     std::string image_location = GetCoreArtLocation();
361*795d594fSAndroid Build Coastguard Worker     if (!kImage) {
362*795d594fSAndroid Build Coastguard Worker       image_location = missing_image_base_->GetFilename() + ".art";
363*795d594fSAndroid Build Coastguard Worker     }
364*795d594fSAndroid Build Coastguard Worker     return image_location;
365*795d594fSAndroid Build Coastguard Worker   }
366*795d594fSAndroid Build Coastguard Worker 
CheckImageSpaceAndOatFile(size_t space_count)367*795d594fSAndroid Build Coastguard Worker   void CheckImageSpaceAndOatFile(size_t space_count) {
368*795d594fSAndroid Build Coastguard Worker     const std::vector<ImageSpace*>& image_spaces =
369*795d594fSAndroid Build Coastguard Worker         Runtime::Current()->GetHeap()->GetBootImageSpaces();
370*795d594fSAndroid Build Coastguard Worker     ASSERT_EQ(image_spaces.size(), space_count);
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < space_count; i++) {
373*795d594fSAndroid Build Coastguard Worker       // This test does not support multi-image compilation.
374*795d594fSAndroid Build Coastguard Worker       ASSERT_NE(image_spaces[i]->GetImageHeader().GetImageReservationSize(), 0u);
375*795d594fSAndroid Build Coastguard Worker 
376*795d594fSAndroid Build Coastguard Worker       const OatFile* oat_file = image_spaces[i]->GetOatFile();
377*795d594fSAndroid Build Coastguard Worker       ASSERT_TRUE(oat_file != nullptr);
378*795d594fSAndroid Build Coastguard Worker 
379*795d594fSAndroid Build Coastguard Worker       // Compiled by JIT Zygote.
380*795d594fSAndroid Build Coastguard Worker       EXPECT_EQ(oat_file->GetCompilerFilter(), CompilerFilter::Filter::kVerify);
381*795d594fSAndroid Build Coastguard Worker     }
382*795d594fSAndroid Build Coastguard Worker   }
383*795d594fSAndroid Build Coastguard Worker 
384*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ScratchFile> missing_image_base_;
385*795d594fSAndroid Build Coastguard Worker 
386*795d594fSAndroid Build Coastguard Worker  private:
387*795d594fSAndroid Build Coastguard Worker   UniqueCPtr<const char[]> old_dex2oat_bcp_;
388*795d594fSAndroid Build Coastguard Worker };
389*795d594fSAndroid Build Coastguard Worker 
390*795d594fSAndroid Build Coastguard Worker using ImageSpaceNoDex2oatTest = ImageSpaceLoadingTest</*kImage=*/true, /*kRelocate=*/true>;
TEST_F(ImageSpaceNoDex2oatTest,Test)391*795d594fSAndroid Build Coastguard Worker TEST_F(ImageSpaceNoDex2oatTest, Test) {
392*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
393*795d594fSAndroid Build Coastguard Worker }
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker using ImageSpaceNoRelocateNoDex2oatTest =
396*795d594fSAndroid Build Coastguard Worker     ImageSpaceLoadingTest</*kImage=*/true, /*kRelocate=*/false>;
TEST_F(ImageSpaceNoRelocateNoDex2oatTest,Test)397*795d594fSAndroid Build Coastguard Worker TEST_F(ImageSpaceNoRelocateNoDex2oatTest, Test) {
398*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
399*795d594fSAndroid Build Coastguard Worker }
400*795d594fSAndroid Build Coastguard Worker 
401*795d594fSAndroid Build Coastguard Worker using ImageSpaceNoImageNoProfileTest = ImageSpaceLoadingTest</*kImage=*/false, /*kRelocate=*/true>;
TEST_F(ImageSpaceNoImageNoProfileTest,Test)402*795d594fSAndroid Build Coastguard Worker TEST_F(ImageSpaceNoImageNoProfileTest, Test) {
403*795d594fSAndroid Build Coastguard Worker   // Imageless mode.
404*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
405*795d594fSAndroid Build Coastguard Worker }
406*795d594fSAndroid Build Coastguard Worker 
407*795d594fSAndroid Build Coastguard Worker class ImageSpaceLoadingSingleComponentWithProfilesTest
408*795d594fSAndroid Build Coastguard Worker     : public ImageSpaceLoadingTest</*kImage=*/false, /*kRelocate=*/true> {
409*795d594fSAndroid Build Coastguard Worker  protected:
PrepareImageLocation()410*795d594fSAndroid Build Coastguard Worker   std::string PrepareImageLocation() override {
411*795d594fSAndroid Build Coastguard Worker     std::string image_location = missing_image_base_->GetFilename() + ".art";
412*795d594fSAndroid Build Coastguard Worker     // Compiling the primary boot image into a single image is not allowed on host.
413*795d594fSAndroid Build Coastguard Worker     if (kIsTargetBuild) {
414*795d594fSAndroid Build Coastguard Worker       std::vector<std::string> dex_files(GetLibCoreDexFileNames());
415*795d594fSAndroid Build Coastguard Worker       profile1_ = std::make_unique<ScratchFile>();
416*795d594fSAndroid Build Coastguard Worker       GenerateBootProfile(ArrayRef<const std::string>(dex_files),
417*795d594fSAndroid Build Coastguard Worker                           profile1_->GetFile(),
418*795d594fSAndroid Build Coastguard Worker                           /*method_frequency=*/6,
419*795d594fSAndroid Build Coastguard Worker                           /*type_frequency=*/6);
420*795d594fSAndroid Build Coastguard Worker       profile2_ = std::make_unique<ScratchFile>();
421*795d594fSAndroid Build Coastguard Worker       GenerateBootProfile(ArrayRef<const std::string>(dex_files),
422*795d594fSAndroid Build Coastguard Worker                           profile2_->GetFile(),
423*795d594fSAndroid Build Coastguard Worker                           /*method_frequency=*/8,
424*795d594fSAndroid Build Coastguard Worker                           /*type_frequency=*/8);
425*795d594fSAndroid Build Coastguard Worker       image_location += "!" + profile1_->GetFilename() + "!" + profile2_->GetFilename();
426*795d594fSAndroid Build Coastguard Worker     }
427*795d594fSAndroid Build Coastguard Worker     // "/path/to/image.art!/path/to/profile1!/path/to/profile2"
428*795d594fSAndroid Build Coastguard Worker     return image_location;
429*795d594fSAndroid Build Coastguard Worker   }
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker  private:
432*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ScratchFile> profile1_;
433*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ScratchFile> profile2_;
434*795d594fSAndroid Build Coastguard Worker };
435*795d594fSAndroid Build Coastguard Worker 
TEST_F(ImageSpaceLoadingSingleComponentWithProfilesTest,Test)436*795d594fSAndroid Build Coastguard Worker TEST_F(ImageSpaceLoadingSingleComponentWithProfilesTest, Test) {
437*795d594fSAndroid Build Coastguard Worker   // Compiling the primary boot image into a single image is not allowed on host.
438*795d594fSAndroid Build Coastguard Worker   TEST_DISABLED_FOR_HOST();
439*795d594fSAndroid Build Coastguard Worker 
440*795d594fSAndroid Build Coastguard Worker   CheckImageSpaceAndOatFile(/*space_count=*/1);
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker 
443*795d594fSAndroid Build Coastguard Worker class ImageSpaceLoadingMultipleComponentsWithProfilesTest
444*795d594fSAndroid Build Coastguard Worker     : public ImageSpaceLoadingTest</*kImage=*/false, /*kRelocate=*/true> {
445*795d594fSAndroid Build Coastguard Worker  protected:
PrepareImageLocation()446*795d594fSAndroid Build Coastguard Worker   std::string PrepareImageLocation() override {
447*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> dex_files(GetLibCoreDexFileNames());
448*795d594fSAndroid Build Coastguard Worker     CHECK_GE(dex_files.size(), 2);
449*795d594fSAndroid Build Coastguard Worker     std::string image_location_1 = missing_image_base_->GetFilename() + ".art";
450*795d594fSAndroid Build Coastguard Worker     std::string image_location_2 =
451*795d594fSAndroid Build Coastguard Worker         missing_image_base_->GetFilename() + "-" + Stem(dex_files[dex_files.size() - 1]) + ".art";
452*795d594fSAndroid Build Coastguard Worker     // Compiling the primary boot image into a single image is not allowed on host.
453*795d594fSAndroid Build Coastguard Worker     if (kIsTargetBuild) {
454*795d594fSAndroid Build Coastguard Worker       profile1_ = std::make_unique<ScratchFile>();
455*795d594fSAndroid Build Coastguard Worker       GenerateBootProfile(ArrayRef<const std::string>(dex_files).SubArray(
456*795d594fSAndroid Build Coastguard Worker                               /*pos=*/0, /*length=*/dex_files.size() - 1),
457*795d594fSAndroid Build Coastguard Worker                           profile1_->GetFile(),
458*795d594fSAndroid Build Coastguard Worker                           /*method_frequency=*/6,
459*795d594fSAndroid Build Coastguard Worker                           /*type_frequency=*/6);
460*795d594fSAndroid Build Coastguard Worker       image_location_1 += "!" + profile1_->GetFilename();
461*795d594fSAndroid Build Coastguard Worker       profile2_ = std::make_unique<ScratchFile>();
462*795d594fSAndroid Build Coastguard Worker       GenerateBootProfile(ArrayRef<const std::string>(dex_files).SubArray(
463*795d594fSAndroid Build Coastguard Worker                               /*pos=*/dex_files.size() - 1, /*length=*/1),
464*795d594fSAndroid Build Coastguard Worker                           profile2_->GetFile(),
465*795d594fSAndroid Build Coastguard Worker                           /*method_frequency=*/8,
466*795d594fSAndroid Build Coastguard Worker                           /*type_frequency=*/8);
467*795d594fSAndroid Build Coastguard Worker       image_location_2 += "!" + profile2_->GetFilename();
468*795d594fSAndroid Build Coastguard Worker     }
469*795d594fSAndroid Build Coastguard Worker     // "/path/to/image.art!/path/to/profile1:/path/to/image-lastdex.art!/path/to/profile2"
470*795d594fSAndroid Build Coastguard Worker     return image_location_1 + ":" + image_location_2;
471*795d594fSAndroid Build Coastguard Worker   }
472*795d594fSAndroid Build Coastguard Worker 
Stem(std::string filename)473*795d594fSAndroid Build Coastguard Worker   std::string Stem(std::string filename) {
474*795d594fSAndroid Build Coastguard Worker     size_t last_slash = filename.rfind('/');
475*795d594fSAndroid Build Coastguard Worker     if (last_slash != std::string::npos) {
476*795d594fSAndroid Build Coastguard Worker       filename = filename.substr(last_slash + 1);
477*795d594fSAndroid Build Coastguard Worker     }
478*795d594fSAndroid Build Coastguard Worker     size_t last_dot = filename.rfind('.');
479*795d594fSAndroid Build Coastguard Worker     if (last_dot != std::string::npos) {
480*795d594fSAndroid Build Coastguard Worker       filename.resize(last_dot);
481*795d594fSAndroid Build Coastguard Worker     }
482*795d594fSAndroid Build Coastguard Worker     return filename;
483*795d594fSAndroid Build Coastguard Worker   }
484*795d594fSAndroid Build Coastguard Worker 
485*795d594fSAndroid Build Coastguard Worker  private:
486*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ScratchFile> profile1_;
487*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ScratchFile> profile2_;
488*795d594fSAndroid Build Coastguard Worker };
489*795d594fSAndroid Build Coastguard Worker 
TEST_F(ImageSpaceLoadingMultipleComponentsWithProfilesTest,Test)490*795d594fSAndroid Build Coastguard Worker TEST_F(ImageSpaceLoadingMultipleComponentsWithProfilesTest, Test) {
491*795d594fSAndroid Build Coastguard Worker   // Compiling the primary boot image into a single image is not allowed on host.
492*795d594fSAndroid Build Coastguard Worker   TEST_DISABLED_FOR_HOST();
493*795d594fSAndroid Build Coastguard Worker 
494*795d594fSAndroid Build Coastguard Worker   CheckImageSpaceAndOatFile(/*space_count=*/1);
495*795d594fSAndroid Build Coastguard Worker }
496*795d594fSAndroid Build Coastguard Worker 
497*795d594fSAndroid Build Coastguard Worker }  // namespace space
498*795d594fSAndroid Build Coastguard Worker }  // namespace gc
499*795d594fSAndroid Build Coastguard Worker }  // namespace art
500