1 /*
2 * Copyright (C) 2011 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 #include "image_test.h"
18
19 namespace art {
20 namespace linker {
21
22 class ImageWriteReadTest : public ImageTest {
23 protected:
24 void TestWriteRead(ImageHeader::StorageMode storage_mode, uint32_t max_image_block_size);
25 };
26
TestWriteRead(ImageHeader::StorageMode storage_mode,uint32_t max_image_block_size)27 void ImageWriteReadTest::TestWriteRead(ImageHeader::StorageMode storage_mode,
28 uint32_t max_image_block_size) {
29 CompilationHelper helper;
30 Compile(storage_mode, max_image_block_size, /*out*/ helper);
31 std::vector<uint64_t> image_file_sizes;
32 for (ScratchFile& image_file : helper.image_files) {
33 std::unique_ptr<File> file(OS::OpenFileForReading(image_file.GetFilename().c_str()));
34 ASSERT_TRUE(file.get() != nullptr);
35 ImageHeader image_header;
36 ASSERT_EQ(file->ReadFully(&image_header, sizeof(image_header)), true);
37 ASSERT_TRUE(image_header.IsValid());
38 const auto& bitmap_section = image_header.GetImageBitmapSection();
39 ASSERT_GE(bitmap_section.Offset(), sizeof(image_header));
40 ASSERT_NE(0U, bitmap_section.Size());
41
42 gc::Heap* heap = Runtime::Current()->GetHeap();
43 ASSERT_TRUE(heap->HaveContinuousSpaces());
44 gc::space::ContinuousSpace* space = heap->GetNonMovingSpace();
45 ASSERT_FALSE(space->IsImageSpace());
46 ASSERT_TRUE(space != nullptr);
47 ASSERT_TRUE(space->IsMallocSpace());
48 image_file_sizes.push_back(file->GetLength());
49 }
50
51 // Need to delete the compiler since it has worker threads which are attached to runtime.
52 compiler_driver_.reset();
53
54 // Tear down old runtime before making a new one, clearing out misc state.
55
56 // Remove the reservation of the memory for use to load the image.
57 // Need to do this before we reset the runtime.
58 UnreserveImageSpace();
59
60 helper.extra_dex_files.clear();
61 runtime_.reset();
62 java_lang_dex_file_ = nullptr;
63
64 MemMap::Init();
65
66 RuntimeOptions options;
67 options.emplace_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()), nullptr);
68 options.emplace_back(
69 GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()), nullptr);
70 std::string image("-Ximage:");
71 image.append(helper.image_locations[0].GetFilename());
72 options.push_back(std::make_pair(image.c_str(), static_cast<void*>(nullptr)));
73 // By default the compiler this creates will not include patch information.
74 options.push_back(std::make_pair("-Xnorelocate", nullptr));
75
76 if (!Runtime::Create(options, false)) {
77 LOG(FATAL) << "Failed to create runtime";
78 return;
79 }
80 runtime_.reset(Runtime::Current());
81 // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
82 // give it away now and then switch to a more managable ScopedObjectAccess.
83 Thread::Current()->TransitionFromRunnableToSuspended(kNative);
84 ScopedObjectAccess soa(Thread::Current());
85 ASSERT_TRUE(runtime_.get() != nullptr);
86 class_linker_ = runtime_->GetClassLinker();
87
88 gc::Heap* heap = Runtime::Current()->GetHeap();
89 ASSERT_TRUE(heap->HasBootImageSpace());
90 ASSERT_TRUE(heap->GetNonMovingSpace()->IsMallocSpace());
91
92 // We loaded the runtime with an explicit image, so it must exist.
93 ASSERT_EQ(heap->GetBootImageSpaces().size(), image_file_sizes.size());
94 const HashSet<std::string>& image_classes = compiler_options_->GetImageClasses();
95 for (size_t i = 0; i < helper.dex_file_locations.size(); ++i) {
96 std::unique_ptr<const DexFile> dex(
97 LoadExpectSingleDexFile(helper.dex_file_locations[i].c_str()));
98 ASSERT_TRUE(dex != nullptr);
99 uint64_t image_file_size = image_file_sizes[i];
100 gc::space::ImageSpace* image_space = heap->GetBootImageSpaces()[i];
101 ASSERT_TRUE(image_space != nullptr);
102 if (storage_mode == ImageHeader::kStorageModeUncompressed) {
103 // Uncompressed, image should be smaller than file.
104 ASSERT_LE(image_space->GetImageHeader().GetImageSize(), image_file_size);
105 } else if (image_file_size > 16 * KB) {
106 // Compressed, file should be smaller than image. Not really valid for small images.
107 ASSERT_LE(image_file_size, image_space->GetImageHeader().GetImageSize());
108 // TODO: Actually validate the blocks, this is hard since the blocks are not copied over for
109 // compressed images. Add kPageSize since image_size is rounded up to this.
110 ASSERT_GT(image_space->GetImageHeader().GetBlockCount() * max_image_block_size,
111 image_space->GetImageHeader().GetImageSize() - kPageSize);
112 }
113
114 image_space->VerifyImageAllocations();
115 uint8_t* image_begin = image_space->Begin();
116 uint8_t* image_end = image_space->End();
117 if (i == 0) {
118 // This check is only valid for image 0.
119 CHECK_EQ(kRequestedImageBase, reinterpret_cast<uintptr_t>(image_begin));
120 }
121 for (size_t j = 0; j < dex->NumClassDefs(); ++j) {
122 const dex::ClassDef& class_def = dex->GetClassDef(j);
123 const char* descriptor = dex->GetClassDescriptor(class_def);
124 ObjPtr<mirror::Class> klass = class_linker_->FindSystemClass(soa.Self(), descriptor);
125 EXPECT_TRUE(klass != nullptr) << descriptor;
126 uint8_t* raw_klass = reinterpret_cast<uint8_t*>(klass.Ptr());
127 if (image_classes.find(std::string_view(descriptor)) == image_classes.end()) {
128 EXPECT_TRUE(raw_klass >= image_end || raw_klass < image_begin) << descriptor;
129 } else {
130 // Image classes should be located inside the image.
131 EXPECT_LT(image_begin, raw_klass) << descriptor;
132 EXPECT_LT(raw_klass, image_end) << descriptor;
133 }
134 EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord(false)));
135 }
136 }
137 }
138
TEST_F(ImageWriteReadTest,WriteReadUncompressed)139 TEST_F(ImageWriteReadTest, WriteReadUncompressed) {
140 TestWriteRead(ImageHeader::kStorageModeUncompressed,
141 /*max_image_block_size=*/std::numeric_limits<uint32_t>::max());
142 }
143
TEST_F(ImageWriteReadTest,WriteReadLZ4)144 TEST_F(ImageWriteReadTest, WriteReadLZ4) {
145 TestWriteRead(ImageHeader::kStorageModeLZ4,
146 /*max_image_block_size=*/std::numeric_limits<uint32_t>::max());
147 }
148
TEST_F(ImageWriteReadTest,WriteReadLZ4HC)149 TEST_F(ImageWriteReadTest, WriteReadLZ4HC) {
150 TestWriteRead(ImageHeader::kStorageModeLZ4HC,
151 /*max_image_block_size=*/std::numeric_limits<uint32_t>::max());
152 }
153
154
TEST_F(ImageWriteReadTest,WriteReadLZ4HCKBBlock)155 TEST_F(ImageWriteReadTest, WriteReadLZ4HCKBBlock) {
156 TestWriteRead(ImageHeader::kStorageModeLZ4HC, /*max_image_block_size=*/KB);
157 }
158
159 } // namespace linker
160 } // namespace art
161