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