blob: f3398e94a6942feb01493b3c4c2ea60576df0d49 [file] [log] [blame]
Richard Uhler84f50ae2017-02-06 15:12:45 +00001/*
2 * Copyright (C) 2017 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 <gtest/gtest.h>
18
Andreas Gampe178c8802017-11-07 12:23:07 -080019#include "android-base/stringprintf.h"
Vladimir Markod8302632019-11-14 13:16:16 +000020#include "android-base/strings.h"
Andreas Gampe178c8802017-11-07 12:23:07 -080021
Vladimir Marko3f795d22019-05-14 13:49:35 +010022#include "base/stl_util.h"
Vladimir Markod8302632019-11-14 13:16:16 +000023#include "class_linker.h"
Richard Uhler84f50ae2017-02-06 15:12:45 +000024#include "dexopt_test.h"
Andreas Gampe178c8802017-11-07 12:23:07 -080025#include "noop_compiler_callbacks.h"
Richard Uhler84f50ae2017-02-06 15:12:45 +000026
27namespace art {
28namespace gc {
29namespace space {
30
31TEST_F(DexoptTest, ValidateOatFile) {
32 std::string dex1 = GetScratchDir() + "/Dex1.jar";
33 std::string multidex1 = GetScratchDir() + "/MultiDex1.jar";
34 std::string dex2 = GetScratchDir() + "/Dex2.jar";
35 std::string oat_location = GetScratchDir() + "/Oat.oat";
36
37 Copy(GetDexSrc1(), dex1);
38 Copy(GetMultiDexSrc1(), multidex1);
39 Copy(GetDexSrc2(), dex2);
40
41 std::string error_msg;
42 std::vector<std::string> args;
43 args.push_back("--dex-file=" + dex1);
44 args.push_back("--dex-file=" + multidex1);
45 args.push_back("--dex-file=" + dex2);
46 args.push_back("--oat-file=" + oat_location);
Nicolas Geoffray3d8a78a2018-08-29 21:10:16 +000047 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
Richard Uhler84f50ae2017-02-06 15:12:45 +000048
Vladimir Markof4efa9e2018-10-17 14:12:45 +010049 std::unique_ptr<OatFile> oat(OatFile::Open(/*zip_fd=*/ -1,
Nicolas Geoffray30025092018-04-19 14:43:29 +010050 oat_location.c_str(),
Richard Uhler84f50ae2017-02-06 15:12:45 +000051 oat_location.c_str(),
Vladimir Markof4efa9e2018-10-17 14:12:45 +010052 /*executable=*/ false,
53 /*low_4gb=*/ false,
54 /*abs_dex_location=*/ nullptr,
55 /*reservation=*/ nullptr,
Richard Uhler84f50ae2017-02-06 15:12:45 +000056 &error_msg));
57 ASSERT_TRUE(oat != nullptr) << error_msg;
58
59 // Originally all the dex checksums should be up to date.
60 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
61
62 // Invalidate the dex1 checksum.
63 Copy(GetDexSrc2(), dex1);
64 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
65
66 // Restore the dex1 checksum.
67 Copy(GetDexSrc1(), dex1);
68 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
69
70 // Invalidate the non-main multidex checksum.
71 Copy(GetMultiDexSrc2(), multidex1);
72 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
73
74 // Restore the multidex checksum.
75 Copy(GetMultiDexSrc1(), multidex1);
76 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
77
78 // Invalidate the dex2 checksum.
79 Copy(GetDexSrc1(), dex2);
80 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
81
82 // restore the dex2 checksum.
83 Copy(GetDexSrc2(), dex2);
84 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
85
86 // Replace the multidex file with a non-multidex file.
87 Copy(GetDexSrc1(), multidex1);
88 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
89
90 // Restore the multidex file
91 Copy(GetMultiDexSrc1(), multidex1);
92 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
93
94 // Replace dex1 with a multidex file.
95 Copy(GetMultiDexSrc1(), dex1);
96 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
97
98 // Restore the dex1 file.
99 Copy(GetDexSrc1(), dex1);
100 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
101
102 // Remove the dex2 file.
103 EXPECT_EQ(0, unlink(dex2.c_str()));
104 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
105
106 // Restore the dex2 file.
107 Copy(GetDexSrc2(), dex2);
108 EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
109
110 // Remove the multidex file.
111 EXPECT_EQ(0, unlink(multidex1.c_str()));
112 EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
113}
114
Vladimir Markod8302632019-11-14 13:16:16 +0000115TEST_F(DexoptTest, Checksums) {
116 Runtime* runtime = Runtime::Current();
117 ASSERT_TRUE(runtime != nullptr);
118 ASSERT_FALSE(runtime->GetHeap()->GetBootImageSpaces().empty());
119
120 std::vector<std::string> bcp = runtime->GetBootClassPath();
121 std::vector<std::string> bcp_locations = runtime->GetBootClassPathLocations();
122 std::vector<const DexFile*> dex_files = runtime->GetClassLinker()->GetBootClassPath();
123
124 std::string error_msg;
125 auto create_and_verify = [&]() {
126 std::string checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
127 ArrayRef<gc::space::ImageSpace* const>(runtime->GetHeap()->GetBootImageSpaces()),
128 ArrayRef<const DexFile* const>(dex_files));
129 return gc::space::ImageSpace::VerifyBootClassPathChecksums(
130 checksums,
131 android::base::Join(bcp_locations, ':'),
132 runtime->GetImageLocation(),
133 ArrayRef<const std::string>(bcp_locations),
134 ArrayRef<const std::string>(bcp),
135 kRuntimeISA,
136 gc::space::ImageSpaceLoadingOrder::kSystemFirst,
137 &error_msg);
138 };
139
140 ASSERT_TRUE(create_and_verify()) << error_msg;
141
142 std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
143 for (const std::string& src : { GetDexSrc1(), GetDexSrc2() }) {
144 std::vector<std::unique_ptr<const DexFile>> new_dex_files;
145 const ArtDexFileLoader dex_file_loader;
146 ASSERT_TRUE(dex_file_loader.Open(src.c_str(),
147 src,
148 /*verify=*/ true,
149 /*verify_checksum=*/ false,
150 &error_msg,
151 &new_dex_files))
152 << error_msg;
153
154 bcp.push_back(src);
155 bcp_locations.push_back(src);
156 for (std::unique_ptr<const DexFile>& df : new_dex_files) {
157 dex_files.push_back(df.get());
158 opened_dex_files.push_back(std::move(df));
159 }
160
161 ASSERT_TRUE(create_and_verify()) << error_msg;
162 }
163}
164
Vladimir Marko4df2d802018-09-27 16:42:44 +0000165template <bool kImage, bool kRelocate, bool kImageDex2oat>
Andreas Gampe178c8802017-11-07 12:23:07 -0800166class ImageSpaceLoadingTest : public CommonRuntimeTest {
167 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100168 void SetUpRuntimeOptions(RuntimeOptions* options) override {
Andreas Gampe178c8802017-11-07 12:23:07 -0800169 if (kImage) {
170 options->emplace_back(android::base::StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str()),
171 nullptr);
172 }
173 options->emplace_back(kRelocate ? "-Xrelocate" : "-Xnorelocate", nullptr);
Andreas Gampe178c8802017-11-07 12:23:07 -0800174 options->emplace_back(kImageDex2oat ? "-Ximage-dex2oat" : "-Xnoimage-dex2oat", nullptr);
175
176 // We want to test the relocation behavior of ImageSpace. As such, don't pretend we're a
177 // compiler.
178 callbacks_.reset();
Vladimir Marko3f795d22019-05-14 13:49:35 +0100179
180 // Clear DEX2OATBOOTCLASSPATH environment variable used for boot image compilation.
181 // We don't want that environment variable to affect the behavior of this test.
182 CHECK(old_dex2oat_bcp_ == nullptr);
183 const char* old_dex2oat_bcp = getenv("DEX2OATBOOTCLASSPATH");
184 if (old_dex2oat_bcp != nullptr) {
185 old_dex2oat_bcp_.reset(strdup(old_dex2oat_bcp));
186 CHECK(old_dex2oat_bcp_ != nullptr);
187 unsetenv("DEX2OATBOOTCLASSPATH");
188 }
Andreas Gampe178c8802017-11-07 12:23:07 -0800189 }
Vladimir Marko3f795d22019-05-14 13:49:35 +0100190
191 void TearDown() override {
192 if (old_dex2oat_bcp_ != nullptr) {
193 int result = setenv("DEX2OATBOOTCLASSPATH", old_dex2oat_bcp_.get(), /* replace */ 0);
194 CHECK_EQ(result, 0);
195 old_dex2oat_bcp_.reset();
196 }
197 }
198
199 private:
200 UniqueCPtr<const char[]> old_dex2oat_bcp_;
Andreas Gampe178c8802017-11-07 12:23:07 -0800201};
202
Vladimir Marko4df2d802018-09-27 16:42:44 +0000203using ImageSpaceDex2oatTest = ImageSpaceLoadingTest<false, true, true>;
Andreas Gampe178c8802017-11-07 12:23:07 -0800204TEST_F(ImageSpaceDex2oatTest, Test) {
205 EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
206}
207
Vladimir Marko4df2d802018-09-27 16:42:44 +0000208using ImageSpaceNoDex2oatTest = ImageSpaceLoadingTest<true, true, false>;
209TEST_F(ImageSpaceNoDex2oatTest, Test) {
Andreas Gampe178c8802017-11-07 12:23:07 -0800210 EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
211}
212
Vladimir Marko4df2d802018-09-27 16:42:44 +0000213using ImageSpaceNoRelocateNoDex2oatTest = ImageSpaceLoadingTest<true, false, false>;
214TEST_F(ImageSpaceNoRelocateNoDex2oatTest, Test) {
215 EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
216}
217
218class NoAccessAndroidDataTest : public ImageSpaceLoadingTest<false, true, true> {
Vladimir Markoe3070022018-08-22 09:36:19 +0000219 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100220 void SetUpRuntimeOptions(RuntimeOptions* options) override {
Vladimir Markoe3070022018-08-22 09:36:19 +0000221 const char* android_data = getenv("ANDROID_DATA");
222 CHECK(android_data != nullptr);
223 old_android_data_ = android_data;
224 bad_android_data_ = old_android_data_ + "/no-android-data";
225 int result = setenv("ANDROID_DATA", bad_android_data_.c_str(), /* replace */ 1);
226 CHECK_EQ(result, 0) << strerror(errno);
227 result = mkdir(bad_android_data_.c_str(), /* mode */ 0700);
228 CHECK_EQ(result, 0) << strerror(errno);
229 // Create a regular file "dalvik_cache". GetDalvikCache() shall get EEXIST
230 // when trying to create a directory with the same name and creating a
231 // subdirectory for a particular architecture shall fail.
232 bad_dalvik_cache_ = bad_android_data_ + "/dalvik-cache";
233 int fd = creat(bad_dalvik_cache_.c_str(), /* mode */ 0);
234 CHECK_NE(fd, -1) << strerror(errno);
235 result = close(fd);
236 CHECK_EQ(result, 0) << strerror(errno);
Vladimir Marko4df2d802018-09-27 16:42:44 +0000237 ImageSpaceLoadingTest<false, true, true>::SetUpRuntimeOptions(options);
Vladimir Markoe3070022018-08-22 09:36:19 +0000238 }
239
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100240 void TearDown() override {
Vladimir Markoe3070022018-08-22 09:36:19 +0000241 int result = unlink(bad_dalvik_cache_.c_str());
242 CHECK_EQ(result, 0) << strerror(errno);
243 result = rmdir(bad_android_data_.c_str());
244 CHECK_EQ(result, 0) << strerror(errno);
245 result = setenv("ANDROID_DATA", old_android_data_.c_str(), /* replace */ 1);
246 CHECK_EQ(result, 0) << strerror(errno);
Vladimir Marko4df2d802018-09-27 16:42:44 +0000247 ImageSpaceLoadingTest<false, true, true>::TearDown();
Vladimir Markoe3070022018-08-22 09:36:19 +0000248 }
249
250 private:
251 std::string old_android_data_;
252 std::string bad_android_data_;
253 std::string bad_dalvik_cache_;
254};
255
256TEST_F(NoAccessAndroidDataTest, Test) {
257 EXPECT_TRUE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
258}
259
Richard Uhler84f50ae2017-02-06 15:12:45 +0000260} // namespace space
261} // namespace gc
262} // namespace art