blob: 41dc2d7206ddeb2f4a9650e4564e552a0f313049 [file] [log] [blame]
Richard Uhler66d874d2015-01-15 09:37:19 -08001/*
2 * Copyright (C) 2014 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 "oat_file_assistant.h"
18
19#include <algorithm>
20#include <fstream>
21#include <string>
22#include <vector>
23#include <sys/param.h>
24
25#include <backtrace/BacktraceMap.h>
26#include <gtest/gtest.h>
27
28#include "class_linker.h"
29#include "common_runtime_test.h"
30#include "mem_map.h"
31#include "os.h"
32#include "thread-inl.h"
33#include "utils.h"
34
35namespace art {
36
37class OatFileAssistantTest : public CommonRuntimeTest {
38 public:
39 virtual void SetUp() {
40 ReserveImageSpace();
41 CommonRuntimeTest::SetUp();
42
43 // Create a scratch directory to work from.
44 scratch_dir_ = android_data_ + "/OatFileAssistantTest";
45 ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
46
47 // Create a subdirectory in scratch for the current isa.
48 // This is the location that will be used for odex files in the tests.
49 isa_dir_ = scratch_dir_ + "/" + GetInstructionSetString(kRuntimeISA);
50 ASSERT_EQ(0, mkdir(isa_dir_.c_str(), 0700));
51
52 // Verify the environment is as we expect
53 uint32_t checksum;
54 std::string error_msg;
55 ASSERT_TRUE(OS::FileExists(GetImageFile().c_str()))
56 << "Expected pre-compiled boot image to be at: " << GetImageFile();
57 ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str()))
58 << "Expected dex file to be at: " << GetDexSrc1();
59 ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
60 << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
61 ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
62 << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
63 ASSERT_TRUE(OS::FileExists(GetMultiDexSrc1().c_str()))
64 << "Expected multidex file to be at: " << GetMultiDexSrc1();
65 ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
66 << "Expected dex file to be at: " << GetDexSrc2();
67 }
68
69 virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
Richard Uhler892fc962015-03-10 16:57:05 +000070 // options->push_back(std::make_pair("-verbose:oat", nullptr));
Richard Uhler66d874d2015-01-15 09:37:19 -080071
72 // Set up the image location.
73 options->push_back(std::make_pair("-Ximage:" + GetImageLocation(),
74 nullptr));
75 // Make sure compilercallbacks are not set so that relocation will be
76 // enabled.
77 for (std::pair<std::string, const void*>& pair : *options) {
78 if (pair.first == "compilercallbacks") {
79 pair.second = nullptr;
80 }
81 }
82 }
83
84 virtual void PreRuntimeCreate() {
85 UnreserveImageSpace();
86 }
87
88 virtual void PostRuntimeCreate() {
89 ReserveImageSpace();
90 }
91
92 virtual void TearDown() {
93 ClearDirectory(isa_dir_.c_str());
94 ASSERT_EQ(0, rmdir(isa_dir_.c_str()));
95
96 ClearDirectory(scratch_dir_.c_str());
97 ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
98
99 CommonRuntimeTest::TearDown();
100 }
101
102 void Copy(std::string src, std::string dst) {
103 std::ifstream src_stream(src, std::ios::binary);
104 std::ofstream dst_stream(dst, std::ios::binary);
105
106 dst_stream << src_stream.rdbuf();
107 }
108
109 // Returns the directory where the pre-compiled core.art can be found.
110 // TODO: We should factor out this into common tests somewhere rather than
111 // re-hardcoding it here (This was copied originally from the elf writer
112 // test).
113 std::string GetImageDirectory() {
114 if (IsHost()) {
115 const char* host_dir = getenv("ANDROID_HOST_OUT");
116 CHECK(host_dir != NULL);
117 return std::string(host_dir) + "/framework";
118 } else {
119 return std::string("/data/art-test");
120 }
121 }
122
123 std::string GetImageLocation() {
124 return GetImageDirectory() + "/core.art";
125 }
126
127 std::string GetImageFile() {
128 return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA)
129 + "/core.art";
130 }
131
132 std::string GetDexSrc1() {
133 return GetTestDexFileName("Main");
134 }
135
136 // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex
137 // file stripped.
138 std::string GetStrippedDexSrc1() {
139 return GetTestDexFileName("MainStripped");
140 }
141
142 std::string GetMultiDexSrc1() {
143 return GetTestDexFileName("MultiDex");
144 }
145
146 std::string GetDexSrc2() {
147 return GetTestDexFileName("Nested");
148 }
149
150 // Scratch directory, for dex and odex files (oat files will go in the
151 // dalvik cache).
152 std::string GetScratchDir() {
153 return scratch_dir_;
154 }
155
156 // ISA directory is the subdirectory in the scratch directory where odex
157 // files should be located.
158 std::string GetISADir() {
159 return isa_dir_;
160 }
161
162 // Generate an odex file for the purposes of test.
163 // If pic is true, generates a PIC odex.
164 void GenerateOdexForTest(const std::string& dex_location,
165 const std::string& odex_location,
166 bool pic = false) {
167 // For this operation, we temporarily redirect the dalvik cache so dex2oat
168 // doesn't find the relocated image file.
169 std::string android_data_tmp = GetScratchDir() + "AndroidDataTmp";
170 setenv("ANDROID_DATA", android_data_tmp.c_str(), 1);
171 std::vector<std::string> args;
172 args.push_back("--dex-file=" + dex_location);
173 args.push_back("--oat-file=" + odex_location);
174 if (pic) {
175 args.push_back("--compile-pic");
176 } else {
177 args.push_back("--include-patch-information");
Richard Uhler05dd8a62015-03-10 10:02:23 -0700178
179 // We need to use the quick compiler to generate non-PIC code, because
180 // the optimizing compiler always generates PIC.
181 args.push_back("--compiler-backend=Quick");
Richard Uhler66d874d2015-01-15 09:37:19 -0800182 }
183 args.push_back("--runtime-arg");
184 args.push_back("-Xnorelocate");
185 std::string error_msg;
186 ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
187 setenv("ANDROID_DATA", android_data_.c_str(), 1);
188 }
189
190 void GeneratePicOdexForTest(const std::string& dex_location,
191 const std::string& odex_location) {
192 GenerateOdexForTest(dex_location, odex_location, true);
193 }
194
195 private:
196 // Reserve memory around where the image will be loaded so other memory
197 // won't conflict when it comes time to load the image.
198 // This can be called with an already loaded image to reserve the space
199 // around it.
200 void ReserveImageSpace() {
201 MemMap::Init();
202
203 // Ensure a chunk of memory is reserved for the image space.
204 uintptr_t reservation_start = ART_BASE_ADDRESS + ART_BASE_ADDRESS_MIN_DELTA;
205 uintptr_t reservation_end = ART_BASE_ADDRESS + ART_BASE_ADDRESS_MAX_DELTA
Hiroshi Yamauchi3dbf2342015-03-17 16:01:11 -0700206 // Include the main space that has to come right after the
207 // image in case of the GSS collector.
208 + 384 * MB;
Richard Uhler66d874d2015-01-15 09:37:19 -0800209
210 std::string error_msg;
211 std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
212 ASSERT_TRUE(map.get() != nullptr) << "Failed to build process map";
213 for (BacktraceMap::const_iterator it = map->begin();
214 reservation_start < reservation_end && it != map->end(); ++it) {
215 if (it->end <= reservation_start) {
216 continue;
217 }
218
219 if (it->start < reservation_start) {
220 reservation_start = std::min(reservation_end, it->end);
221 }
222
223 image_reservation_.push_back(std::unique_ptr<MemMap>(
224 MemMap::MapAnonymous("image reservation",
225 reinterpret_cast<uint8_t*>(reservation_start),
226 std::min(it->start, reservation_end) - reservation_start,
227 PROT_NONE, false, false, &error_msg)));
228 ASSERT_TRUE(image_reservation_.back().get() != nullptr) << error_msg;
229 LOG(INFO) << "Reserved space for image " <<
230 reinterpret_cast<void*>(image_reservation_.back()->Begin()) << "-" <<
231 reinterpret_cast<void*>(image_reservation_.back()->End());
232 reservation_start = it->end;
233 }
234 }
235
236
237 // Unreserve any memory reserved by ReserveImageSpace. This should be called
238 // before the image is loaded.
239 void UnreserveImageSpace() {
240 image_reservation_.clear();
241 }
242
243 std::string scratch_dir_;
244 std::string isa_dir_;
245 std::vector<std::unique_ptr<MemMap>> image_reservation_;
246};
247
248class OatFileAssistantNoDex2OatTest : public OatFileAssistantTest {
249 public:
250 virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
251 OatFileAssistantTest::SetUpRuntimeOptions(options);
252 options->push_back(std::make_pair("-Xnodex2oat", nullptr));
253 }
254};
255
256// Generate an oat file for the purposes of test, as opposed to testing
257// generation of oat files.
258static void GenerateOatForTest(const char* dex_location) {
259 OatFileAssistant oat_file_assistant(dex_location, kRuntimeISA, false);
260
261 std::string error_msg;
262 ASSERT_TRUE(oat_file_assistant.GenerateOatFile(&error_msg)) << error_msg;
263}
264
265// Case: We have a DEX file, but no OAT file for it.
266// Expect: The oat file status is kOutOfDate.
267TEST_F(OatFileAssistantTest, DexNoOat) {
268 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
269 Copy(GetDexSrc1(), dex_location);
270
271 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
272
273 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
274
275 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
276 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
277 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
278 EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
279 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
280 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.OdexFileStatus());
281 EXPECT_FALSE(oat_file_assistant.OatFileExists());
282 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
283 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
284 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
285 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.OatFileStatus());
286}
287
288// Case: We have no DEX file and no OAT file.
289// Expect: Status is out of date. Loading should fail, but not crash.
290TEST_F(OatFileAssistantTest, NoDexNoOat) {
291 std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
292
293 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
294
295 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
296 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
297 EXPECT_EQ(nullptr, oat_file.get());
298}
299
300// Case: We have a DEX file and up-to-date OAT file for it.
301// Expect: The oat file status is kUpToDate.
302TEST_F(OatFileAssistantTest, OatUpToDate) {
303 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
304 Copy(GetDexSrc1(), dex_location);
305 GenerateOatForTest(dex_location.c_str());
306
307 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
308
309 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
310 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
311 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
312 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
313 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
314 EXPECT_TRUE(oat_file_assistant.OatFileExists());
315 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
316 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
317 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
318 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.OatFileStatus());
319}
320
321// Case: We have a MultiDEX file and up-to-date OAT file for it.
322// Expect: The oat file status is kUpToDate.
323TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
324 std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
325 Copy(GetMultiDexSrc1(), dex_location);
326 GenerateOatForTest(dex_location.c_str());
327
328 // Verify we can load both dex files.
Richard Uhlere5fed032015-03-18 08:21:11 -0700329 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
330 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
Richard Uhler66d874d2015-01-15 09:37:19 -0800331 ASSERT_TRUE(oat_file.get() != nullptr);
332 EXPECT_TRUE(oat_file->IsExecutable());
333 std::vector<std::unique_ptr<const DexFile>> dex_files;
Richard Uhlere5fed032015-03-18 08:21:11 -0700334 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
335 EXPECT_EQ(2u, dex_files.size());
336}
337
338// Case: We have a MultiDEX file and up-to-date OAT file for it with relative
339// encoded dex locations.
340// Expect: The oat file status is kUpToDate.
341TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
342 std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
343 std::string oat_location = GetISADir() + "/RelativeEncodedDexLocation.oat";
344
345 // Create the dex file
346 Copy(GetMultiDexSrc1(), dex_location);
347
348 // Create the oat file with relative encoded dex location.
349 std::vector<std::string> args;
350 args.push_back("--dex-file=" + dex_location);
351 args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar"));
352 args.push_back("--oat-file=" + oat_location);
353
354 std::string error_msg;
355 ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
356
357 // Verify we can load both dex files.
358 OatFileAssistant oat_file_assistant(dex_location.c_str(),
359 oat_location.c_str(),
360 kRuntimeISA, true);
361 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
362 ASSERT_TRUE(oat_file.get() != nullptr);
363 EXPECT_TRUE(oat_file->IsExecutable());
364 std::vector<std::unique_ptr<const DexFile>> dex_files;
365 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
Richard Uhler66d874d2015-01-15 09:37:19 -0800366 EXPECT_EQ(2u, dex_files.size());
367}
368
369// Case: We have a DEX file and out of date OAT file.
370// Expect: The oat file status is kOutOfDate.
371TEST_F(OatFileAssistantTest, OatOutOfDate) {
372 std::string dex_location = GetScratchDir() + "/OatOutOfDate.jar";
373
374 // We create a dex, generate an oat for it, then overwrite the dex with a
375 // different dex to make the oat out of date.
376 Copy(GetDexSrc1(), dex_location);
377 GenerateOatForTest(dex_location.c_str());
378 Copy(GetDexSrc2(), dex_location);
379
380 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
381 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
382
383 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
384 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
385 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
386 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
387 EXPECT_TRUE(oat_file_assistant.OatFileExists());
388 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
389 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
390}
391
392// Case: We have a DEX file and an ODEX file, but no OAT file.
393// Expect: The oat file status is kNeedsRelocation.
394TEST_F(OatFileAssistantTest, DexOdexNoOat) {
395 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
396 std::string odex_location = GetISADir() + "/DexOdexNoOat.odex";
397
398 // Create the dex and odex files
399 Copy(GetDexSrc1(), dex_location);
400 GenerateOdexForTest(dex_location, odex_location);
401
402 // Verify the status.
403 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
404
405 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
406
407 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
408 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
409 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
410 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
411 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
412 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.OdexFileNeedsRelocation());
413 EXPECT_FALSE(oat_file_assistant.OatFileExists());
414 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
415 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
416}
417
418// Case: We have a stripped DEX file and an ODEX file, but no OAT file.
419// Expect: The oat file status is kNeedsRelocation.
420TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
421 std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
422 std::string odex_location = GetISADir() + "/StrippedDexOdexNoOat.odex";
423
424 // Create the dex and odex files
425 Copy(GetDexSrc1(), dex_location);
426 GenerateOdexForTest(dex_location, odex_location);
427
428 // Strip the dex file
429 Copy(GetStrippedDexSrc1(), dex_location);
430
431 // Verify the status.
432 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
433
434 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
435
436 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
437 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
438 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
439 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
440 EXPECT_FALSE(oat_file_assistant.OatFileExists());
441 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
442 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
443
444 // Make the oat file up to date.
445 std::string error_msg;
446 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
447
448 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
449
450 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
451 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
452 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
453 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
454 EXPECT_TRUE(oat_file_assistant.OatFileExists());
455 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
456 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
457
458 // Verify we can load the dex files from it.
459 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
460 ASSERT_TRUE(oat_file.get() != nullptr);
461 EXPECT_TRUE(oat_file->IsExecutable());
462 std::vector<std::unique_ptr<const DexFile>> dex_files;
463 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
464 EXPECT_EQ(1u, dex_files.size());
465}
466
467// Case: We have a stripped DEX file, an ODEX file, and an out of date OAT file.
468// Expect: The oat file status is kNeedsRelocation.
469TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
470 std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
471 std::string odex_location = GetISADir() + "/StrippedDexOdexOat.odex";
472
473 // Create the oat file from a different dex file so it looks out of date.
474 Copy(GetDexSrc2(), dex_location);
475 GenerateOatForTest(dex_location.c_str());
476
477 // Create the odex file
478 Copy(GetDexSrc1(), dex_location);
479 GenerateOdexForTest(dex_location, odex_location);
480
481 // Strip the dex file.
482 Copy(GetStrippedDexSrc1(), dex_location);
483
484 // Verify the status.
485 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
486
487 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
488
489 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
490 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
491 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
492 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
493 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
494 EXPECT_TRUE(oat_file_assistant.OatFileExists());
495 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
496 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
497
498 // Make the oat file up to date.
499 std::string error_msg;
500 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
501
502 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
503
504 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
505 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
506 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
507 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
508 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
509 EXPECT_TRUE(oat_file_assistant.OatFileExists());
510 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
511 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
512 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
513
514 // Verify we can load the dex files from it.
515 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
516 ASSERT_TRUE(oat_file.get() != nullptr);
517 EXPECT_TRUE(oat_file->IsExecutable());
518 std::vector<std::unique_ptr<const DexFile>> dex_files;
519 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
520 EXPECT_EQ(1u, dex_files.size());
521}
522
523// Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
524// OAT files both have patch delta of 0.
525// Expect: It shouldn't crash.
526TEST_F(OatFileAssistantTest, OdexOatOverlap) {
527 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
528 std::string odex_location = GetISADir() + "/OdexOatOverlap.odex";
529 std::string oat_location = GetISADir() + "/OdexOatOverlap.oat";
530
531 // Create the dex and odex files
532 Copy(GetDexSrc1(), dex_location);
533 GenerateOdexForTest(dex_location, odex_location);
534
535 // Create the oat file by copying the odex so they are located in the same
536 // place in memory.
537 Copy(odex_location, oat_location);
538
539 // Verify things don't go bad.
540 OatFileAssistant oat_file_assistant(dex_location.c_str(),
541 oat_location.c_str(), kRuntimeISA, true);
542
543 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
544
545 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
546 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
547 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
548 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
549 EXPECT_TRUE(oat_file_assistant.OatFileExists());
550 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
551 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
552
553 // Things aren't relocated, so it should fall back to interpreted.
554 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
555 ASSERT_TRUE(oat_file.get() != nullptr);
556 EXPECT_FALSE(oat_file->IsExecutable());
557 std::vector<std::unique_ptr<const DexFile>> dex_files;
558 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
559 EXPECT_EQ(1u, dex_files.size());
560}
561
562// Case: We have a DEX file and a PIC ODEX file, but no OAT file.
563// Expect: The oat file status is kUpToDate, because PIC needs no relocation.
564TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
565 std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar";
566 std::string odex_location = GetISADir() + "/DexPicOdexNoOat.odex";
567
568 // Create the dex and odex files
569 Copy(GetDexSrc1(), dex_location);
570 GeneratePicOdexForTest(dex_location, odex_location);
571
572 // Verify the status.
573 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
574
575 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
576
577 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
578 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
579 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
580 EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
581 EXPECT_FALSE(oat_file_assistant.OatFileExists());
582 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
583 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
584}
585
586// Case: We have a DEX file and up-to-date OAT file for it.
587// Expect: We should load an executable dex file.
588TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
589 std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
590
591 Copy(GetDexSrc1(), dex_location);
592 GenerateOatForTest(dex_location.c_str());
593
594 // Load the oat using an oat file assistant.
595 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
596
597 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
598 ASSERT_TRUE(oat_file.get() != nullptr);
599 EXPECT_TRUE(oat_file->IsExecutable());
600 std::vector<std::unique_ptr<const DexFile>> dex_files;
601 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
602 EXPECT_EQ(1u, dex_files.size());
603}
604
605// Case: We have a DEX file and up-to-date OAT file for it.
606// Expect: Loading non-executable should load the oat non-executable.
607TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
608 std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
609
610 Copy(GetDexSrc1(), dex_location);
611 GenerateOatForTest(dex_location.c_str());
612
613 // Load the oat using an oat file assistant.
614 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
615
616 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
617 ASSERT_TRUE(oat_file.get() != nullptr);
618 EXPECT_FALSE(oat_file->IsExecutable());
619 std::vector<std::unique_ptr<const DexFile>> dex_files;
620 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
621 EXPECT_EQ(1u, dex_files.size());
622}
623
624// Case: We have a DEX file.
625// Expect: We should load an executable dex file from an alternative oat
626// location.
627TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) {
628 std::string dex_location = GetScratchDir() + "/LoadDexNoAlternateOat.jar";
629 std::string oat_location = GetScratchDir() + "/LoadDexNoAlternateOat.oat";
630
631 Copy(GetDexSrc1(), dex_location);
632
633 OatFileAssistant oat_file_assistant(
634 dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true);
635 std::string error_msg;
636 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
637
638 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
639 ASSERT_TRUE(oat_file.get() != nullptr);
640 EXPECT_TRUE(oat_file->IsExecutable());
641 std::vector<std::unique_ptr<const DexFile>> dex_files;
642 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
643 EXPECT_EQ(1u, dex_files.size());
644
645 EXPECT_TRUE(OS::FileExists(oat_location.c_str()));
646
647 // Verify it didn't create an oat in the default location.
648 OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
649 EXPECT_FALSE(ofm.OatFileExists());
650}
651
652// Case: Non-existent Dex location.
653// Expect: The dex code is out of date, and trying to update it fails.
654TEST_F(OatFileAssistantTest, NonExsistentDexLocation) {
655 std::string dex_location = GetScratchDir() + "/BadDexLocation.jar";
656
657 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
658
659 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
660 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
661 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
662 EXPECT_FALSE(oat_file_assistant.OatFileExists());
663 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
664 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
665 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
666 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
667
668 std::string error_msg;
669 EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
670 EXPECT_FALSE(error_msg.empty());
671}
672
673// Turn an absolute path into a path relative to the current working
674// directory.
675static std::string MakePathRelative(std::string target) {
676 char buf[MAXPATHLEN];
677 std::string cwd = getcwd(buf, MAXPATHLEN);
678
679 // Split the target and cwd paths into components.
680 std::vector<std::string> target_path;
681 std::vector<std::string> cwd_path;
682 Split(target, '/', &target_path);
683 Split(cwd, '/', &cwd_path);
684
685 // Reverse the path components, so we can use pop_back().
686 std::reverse(target_path.begin(), target_path.end());
687 std::reverse(cwd_path.begin(), cwd_path.end());
688
689 // Drop the common prefix of the paths. Because we reversed the path
690 // components, this becomes the common suffix of target_path and cwd_path.
691 while (!target_path.empty() && !cwd_path.empty()
692 && target_path.back() == cwd_path.back()) {
693 target_path.pop_back();
694 cwd_path.pop_back();
695 }
696
697 // For each element of the remaining cwd_path, add '..' to the beginning
698 // of the target path. Because we reversed the path components, we add to
699 // the end of target_path.
700 for (unsigned int i = 0; i < cwd_path.size(); i++) {
701 target_path.push_back("..");
702 }
703
704 // Reverse again to get the right path order, and join to get the result.
705 std::reverse(target_path.begin(), target_path.end());
706 return Join(target_path, '/');
707}
708
709// Case: Non-absolute path to Dex location.
710// Expect: Not sure, but it shouldn't crash.
711TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
712 std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
713 Copy(GetDexSrc1(), abs_dex_location);
714
715 std::string dex_location = MakePathRelative(abs_dex_location);
716 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
717
718 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
719 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
720 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
721 EXPECT_FALSE(oat_file_assistant.OatFileExists());
722 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
723 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
724 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
725 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
726}
727
728// Case: Very short, non-existent Dex location.
729// Expect: Dex code is out of date, and trying to update it fails.
730TEST_F(OatFileAssistantTest, ShortDexLocation) {
731 std::string dex_location = "/xx";
732
733 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
734
735 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
736 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
737 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
738 EXPECT_FALSE(oat_file_assistant.OatFileExists());
739 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
740 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
741 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
742 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
743
744 std::string error_msg;
745 EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
746 EXPECT_FALSE(error_msg.empty());
747}
748
749// Case: Non-standard extension for dex file.
750// Expect: The oat file status is kOutOfDate.
751TEST_F(OatFileAssistantTest, LongDexExtension) {
752 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
753 Copy(GetDexSrc1(), dex_location);
754
755 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
756
757 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
758
759 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
760 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
761 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
762 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
763 EXPECT_FALSE(oat_file_assistant.OatFileExists());
764 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
765 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
766}
767
768// A task to generate a dex location. Used by the RaceToGenerate test.
769class RaceGenerateTask : public Task {
770 public:
771 explicit RaceGenerateTask(const std::string& dex_location, const std::string& oat_location)
772 : dex_location_(dex_location), oat_location_(oat_location),
773 loaded_oat_file_(nullptr)
774 {}
775
776 void Run(Thread* self) {
777 UNUSED(self);
778
779 // Load the dex files, and save a pointer to the loaded oat file, so that
780 // we can verify only one oat file was loaded for the dex location.
781 ClassLinker* linker = Runtime::Current()->GetClassLinker();
782 std::vector<std::unique_ptr<const DexFile>> dex_files;
783 std::vector<std::string> error_msgs;
784 dex_files = linker->OpenDexFilesFromOat(dex_location_.c_str(), oat_location_.c_str(), &error_msgs);
785 CHECK(!dex_files.empty()) << Join(error_msgs, '\n');
786 loaded_oat_file_ = dex_files[0]->GetOatFile();
787 }
788
789 const OatFile* GetLoadedOatFile() const {
790 return loaded_oat_file_;
791 }
792
793 private:
794 std::string dex_location_;
795 std::string oat_location_;
796 const OatFile* loaded_oat_file_;
797};
798
799// Test the case where multiple processes race to generate an oat file.
800// This simulates multiple processes using multiple threads.
801//
802// We want only one Oat file to be loaded when there is a race to load, to
803// avoid using up the virtual memory address space.
804TEST_F(OatFileAssistantTest, RaceToGenerate) {
805 std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
806 std::string oat_location = GetISADir() + "/RaceToGenerate.oat";
807
808 // We use the lib core dex file, because it's large, and hopefully should
809 // take a while to generate.
810 Copy(GetLibCoreDexFileName(), dex_location);
811
812 const int kNumThreads = 32;
813 Thread* self = Thread::Current();
814 ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads);
815 std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
816 for (int i = 0; i < kNumThreads; i++) {
817 std::unique_ptr<RaceGenerateTask> task(new RaceGenerateTask(dex_location, oat_location));
818 thread_pool.AddTask(self, task.get());
819 tasks.push_back(std::move(task));
820 }
821 thread_pool.StartWorkers(self);
822 thread_pool.Wait(self, true, false);
823
824 // Verify every task got the same pointer.
825 const OatFile* expected = tasks[0]->GetLoadedOatFile();
826 for (auto& task : tasks) {
827 EXPECT_EQ(expected, task->GetLoadedOatFile());
828 }
829}
830
831// Case: We have a DEX file and an ODEX file, no OAT file, and dex2oat is
832// disabled.
833// Expect: We should load the odex file non-executable.
834TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
835 std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
836 std::string odex_location = GetISADir() + "/LoadDexOdexNoOat.odex";
837
838 // Create the dex and odex files
839 Copy(GetDexSrc1(), dex_location);
840 GenerateOdexForTest(dex_location, odex_location);
841
842 // Load the oat using an executable oat file assistant.
843 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
844
845 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
846 ASSERT_TRUE(oat_file.get() != nullptr);
847 EXPECT_FALSE(oat_file->IsExecutable());
848 std::vector<std::unique_ptr<const DexFile>> dex_files;
849 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
850 EXPECT_EQ(1u, dex_files.size());
851}
852
853// Case: We have a MultiDEX file and an ODEX file, no OAT file, and dex2oat is
854// disabled.
855// Expect: We should load the odex file non-executable.
856TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
857 std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
858 std::string odex_location = GetISADir() + "/LoadMultiDexOdexNoOat.odex";
859
860 // Create the dex and odex files
861 Copy(GetMultiDexSrc1(), dex_location);
862 GenerateOdexForTest(dex_location, odex_location);
863
864 // Load the oat using an executable oat file assistant.
865 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
866
867 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
868 ASSERT_TRUE(oat_file.get() != nullptr);
869 EXPECT_FALSE(oat_file->IsExecutable());
870 std::vector<std::unique_ptr<const DexFile>> dex_files;
871 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
872 EXPECT_EQ(2u, dex_files.size());
873}
874
875TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) {
876 std::string error_msg;
877 std::string odex_file;
878
879 EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
880 "/foo/bar/baz.jar", kArm, &odex_file, &error_msg)) << error_msg;
881 EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
882
883 EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
884 "/foo/bar/baz.funnyext", kArm, &odex_file, &error_msg)) << error_msg;
885 EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
886
887 EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
888 "nopath.jar", kArm, &odex_file, &error_msg));
889 EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
890 "/foo/bar/baz_noext", kArm, &odex_file, &error_msg));
891}
892
893
894// TODO: More Tests:
895// * Test class linker falls back to unquickened dex for DexNoOat
896// * Test class linker falls back to unquickened dex for MultiDexNoOat
897// * Test multidex files:
898// - Multidex with only classes2.dex out of date should have status
899// kOutOfDate
900// * Test using secondary isa
901// * Test with profiling info?
902// * Test for status of oat while oat is being generated (how?)
903// * Test case where 32 and 64 bit boot class paths differ,
904// and we ask IsInBootClassPath for a class in exactly one of the 32 or
905// 64 bit boot class paths.
906// * Test unexpected scenarios (?):
907// - Dex is stripped, don't have odex.
908// - Oat file corrupted after status check, before reload unexecutable
909// because it's unrelocated and no dex2oat
910
911} // namespace art