blob: 637789b4cd494590a566eb3d18f0906e76b4221f [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
206 + 100 * 1024 * 1024;
207
208 std::string error_msg;
209 std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
210 ASSERT_TRUE(map.get() != nullptr) << "Failed to build process map";
211 for (BacktraceMap::const_iterator it = map->begin();
212 reservation_start < reservation_end && it != map->end(); ++it) {
213 if (it->end <= reservation_start) {
214 continue;
215 }
216
217 if (it->start < reservation_start) {
218 reservation_start = std::min(reservation_end, it->end);
219 }
220
221 image_reservation_.push_back(std::unique_ptr<MemMap>(
222 MemMap::MapAnonymous("image reservation",
223 reinterpret_cast<uint8_t*>(reservation_start),
224 std::min(it->start, reservation_end) - reservation_start,
225 PROT_NONE, false, false, &error_msg)));
226 ASSERT_TRUE(image_reservation_.back().get() != nullptr) << error_msg;
227 LOG(INFO) << "Reserved space for image " <<
228 reinterpret_cast<void*>(image_reservation_.back()->Begin()) << "-" <<
229 reinterpret_cast<void*>(image_reservation_.back()->End());
230 reservation_start = it->end;
231 }
232 }
233
234
235 // Unreserve any memory reserved by ReserveImageSpace. This should be called
236 // before the image is loaded.
237 void UnreserveImageSpace() {
238 image_reservation_.clear();
239 }
240
241 std::string scratch_dir_;
242 std::string isa_dir_;
243 std::vector<std::unique_ptr<MemMap>> image_reservation_;
244};
245
246class OatFileAssistantNoDex2OatTest : public OatFileAssistantTest {
247 public:
248 virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
249 OatFileAssistantTest::SetUpRuntimeOptions(options);
250 options->push_back(std::make_pair("-Xnodex2oat", nullptr));
251 }
252};
253
254// Generate an oat file for the purposes of test, as opposed to testing
255// generation of oat files.
256static void GenerateOatForTest(const char* dex_location) {
257 OatFileAssistant oat_file_assistant(dex_location, kRuntimeISA, false);
258
259 std::string error_msg;
260 ASSERT_TRUE(oat_file_assistant.GenerateOatFile(&error_msg)) << error_msg;
261}
262
263// Case: We have a DEX file, but no OAT file for it.
264// Expect: The oat file status is kOutOfDate.
265TEST_F(OatFileAssistantTest, DexNoOat) {
266 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
267 Copy(GetDexSrc1(), dex_location);
268
269 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
270
271 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
272
273 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
274 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
275 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
276 EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
277 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
278 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.OdexFileStatus());
279 EXPECT_FALSE(oat_file_assistant.OatFileExists());
280 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
281 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
282 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
283 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.OatFileStatus());
284}
285
286// Case: We have no DEX file and no OAT file.
287// Expect: Status is out of date. Loading should fail, but not crash.
288TEST_F(OatFileAssistantTest, NoDexNoOat) {
289 std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
290
291 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
292
293 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
294 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
295 EXPECT_EQ(nullptr, oat_file.get());
296}
297
298// Case: We have a DEX file and up-to-date OAT file for it.
299// Expect: The oat file status is kUpToDate.
300TEST_F(OatFileAssistantTest, OatUpToDate) {
301 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
302 Copy(GetDexSrc1(), dex_location);
303 GenerateOatForTest(dex_location.c_str());
304
305 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
306
307 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
308 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
309 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
310 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
311 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
312 EXPECT_TRUE(oat_file_assistant.OatFileExists());
313 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
314 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
315 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
316 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.OatFileStatus());
317}
318
319// Case: We have a MultiDEX file and up-to-date OAT file for it.
320// Expect: The oat file status is kUpToDate.
321TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
322 std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
323 Copy(GetMultiDexSrc1(), dex_location);
324 GenerateOatForTest(dex_location.c_str());
325
326 // Verify we can load both dex files.
Richard Uhlere5fed032015-03-18 08:21:11 -0700327 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
328 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
Richard Uhler66d874d2015-01-15 09:37:19 -0800329 ASSERT_TRUE(oat_file.get() != nullptr);
330 EXPECT_TRUE(oat_file->IsExecutable());
331 std::vector<std::unique_ptr<const DexFile>> dex_files;
Richard Uhlere5fed032015-03-18 08:21:11 -0700332 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
333 EXPECT_EQ(2u, dex_files.size());
334}
335
336// Case: We have a MultiDEX file and up-to-date OAT file for it with relative
337// encoded dex locations.
338// Expect: The oat file status is kUpToDate.
339TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
340 std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
341 std::string oat_location = GetISADir() + "/RelativeEncodedDexLocation.oat";
342
343 // Create the dex file
344 Copy(GetMultiDexSrc1(), dex_location);
345
346 // Create the oat file with relative encoded dex location.
347 std::vector<std::string> args;
348 args.push_back("--dex-file=" + dex_location);
349 args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar"));
350 args.push_back("--oat-file=" + oat_location);
351
352 std::string error_msg;
353 ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
354
355 // Verify we can load both dex files.
356 OatFileAssistant oat_file_assistant(dex_location.c_str(),
357 oat_location.c_str(),
358 kRuntimeISA, true);
359 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
360 ASSERT_TRUE(oat_file.get() != nullptr);
361 EXPECT_TRUE(oat_file->IsExecutable());
362 std::vector<std::unique_ptr<const DexFile>> dex_files;
363 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
Richard Uhler66d874d2015-01-15 09:37:19 -0800364 EXPECT_EQ(2u, dex_files.size());
365}
366
367// Case: We have a DEX file and out of date OAT file.
368// Expect: The oat file status is kOutOfDate.
369TEST_F(OatFileAssistantTest, OatOutOfDate) {
370 std::string dex_location = GetScratchDir() + "/OatOutOfDate.jar";
371
372 // We create a dex, generate an oat for it, then overwrite the dex with a
373 // different dex to make the oat out of date.
374 Copy(GetDexSrc1(), dex_location);
375 GenerateOatForTest(dex_location.c_str());
376 Copy(GetDexSrc2(), dex_location);
377
378 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
379 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
380
381 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
382 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
383 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
384 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
385 EXPECT_TRUE(oat_file_assistant.OatFileExists());
386 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
387 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
388}
389
390// Case: We have a DEX file and an ODEX file, but no OAT file.
391// Expect: The oat file status is kNeedsRelocation.
392TEST_F(OatFileAssistantTest, DexOdexNoOat) {
393 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
394 std::string odex_location = GetISADir() + "/DexOdexNoOat.odex";
395
396 // Create the dex and odex files
397 Copy(GetDexSrc1(), dex_location);
398 GenerateOdexForTest(dex_location, odex_location);
399
400 // Verify the status.
401 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
402
403 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
404
405 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
406 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
407 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
408 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
409 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
410 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.OdexFileNeedsRelocation());
411 EXPECT_FALSE(oat_file_assistant.OatFileExists());
412 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
413 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
414}
415
416// Case: We have a stripped DEX file and an ODEX file, but no OAT file.
417// Expect: The oat file status is kNeedsRelocation.
418TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
419 std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
420 std::string odex_location = GetISADir() + "/StrippedDexOdexNoOat.odex";
421
422 // Create the dex and odex files
423 Copy(GetDexSrc1(), dex_location);
424 GenerateOdexForTest(dex_location, odex_location);
425
426 // Strip the dex file
427 Copy(GetStrippedDexSrc1(), dex_location);
428
429 // Verify the status.
430 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
431
432 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
433
434 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
435 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
436 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
437 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
438 EXPECT_FALSE(oat_file_assistant.OatFileExists());
439 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
440 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
441
442 // Make the oat file up to date.
443 std::string error_msg;
444 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
445
446 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
447
448 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
449 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
450 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
451 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
452 EXPECT_TRUE(oat_file_assistant.OatFileExists());
453 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
454 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
455
456 // Verify we can load the dex files from it.
457 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
458 ASSERT_TRUE(oat_file.get() != nullptr);
459 EXPECT_TRUE(oat_file->IsExecutable());
460 std::vector<std::unique_ptr<const DexFile>> dex_files;
461 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
462 EXPECT_EQ(1u, dex_files.size());
463}
464
465// Case: We have a stripped DEX file, an ODEX file, and an out of date OAT file.
466// Expect: The oat file status is kNeedsRelocation.
467TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
468 std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
469 std::string odex_location = GetISADir() + "/StrippedDexOdexOat.odex";
470
471 // Create the oat file from a different dex file so it looks out of date.
472 Copy(GetDexSrc2(), dex_location);
473 GenerateOatForTest(dex_location.c_str());
474
475 // Create the odex file
476 Copy(GetDexSrc1(), dex_location);
477 GenerateOdexForTest(dex_location, odex_location);
478
479 // Strip the dex file.
480 Copy(GetStrippedDexSrc1(), dex_location);
481
482 // Verify the status.
483 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
484
485 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
486
487 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
488 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
489 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
490 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
491 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
492 EXPECT_TRUE(oat_file_assistant.OatFileExists());
493 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
494 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
495
496 // Make the oat file up to date.
497 std::string error_msg;
498 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
499
500 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
501
502 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
503 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
504 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
505 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
506 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
507 EXPECT_TRUE(oat_file_assistant.OatFileExists());
508 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
509 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
510 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
511
512 // Verify we can load the dex files from it.
513 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
514 ASSERT_TRUE(oat_file.get() != nullptr);
515 EXPECT_TRUE(oat_file->IsExecutable());
516 std::vector<std::unique_ptr<const DexFile>> dex_files;
517 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
518 EXPECT_EQ(1u, dex_files.size());
519}
520
521// Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
522// OAT files both have patch delta of 0.
523// Expect: It shouldn't crash.
524TEST_F(OatFileAssistantTest, OdexOatOverlap) {
525 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
526 std::string odex_location = GetISADir() + "/OdexOatOverlap.odex";
527 std::string oat_location = GetISADir() + "/OdexOatOverlap.oat";
528
529 // Create the dex and odex files
530 Copy(GetDexSrc1(), dex_location);
531 GenerateOdexForTest(dex_location, odex_location);
532
533 // Create the oat file by copying the odex so they are located in the same
534 // place in memory.
535 Copy(odex_location, oat_location);
536
537 // Verify things don't go bad.
538 OatFileAssistant oat_file_assistant(dex_location.c_str(),
539 oat_location.c_str(), kRuntimeISA, true);
540
541 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
542
543 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
544 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
545 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
546 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
547 EXPECT_TRUE(oat_file_assistant.OatFileExists());
548 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
549 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
550
551 // Things aren't relocated, so it should fall back to interpreted.
552 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
553 ASSERT_TRUE(oat_file.get() != nullptr);
554 EXPECT_FALSE(oat_file->IsExecutable());
555 std::vector<std::unique_ptr<const DexFile>> dex_files;
556 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
557 EXPECT_EQ(1u, dex_files.size());
558}
559
560// Case: We have a DEX file and a PIC ODEX file, but no OAT file.
561// Expect: The oat file status is kUpToDate, because PIC needs no relocation.
562TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
563 std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar";
564 std::string odex_location = GetISADir() + "/DexPicOdexNoOat.odex";
565
566 // Create the dex and odex files
567 Copy(GetDexSrc1(), dex_location);
568 GeneratePicOdexForTest(dex_location, odex_location);
569
570 // Verify the status.
571 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
572
573 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
574
575 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
576 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
577 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
578 EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
579 EXPECT_FALSE(oat_file_assistant.OatFileExists());
580 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
581 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
582}
583
584// Case: We have a DEX file and up-to-date OAT file for it.
585// Expect: We should load an executable dex file.
586TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
587 std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
588
589 Copy(GetDexSrc1(), dex_location);
590 GenerateOatForTest(dex_location.c_str());
591
592 // Load the oat using an oat file assistant.
593 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
594
595 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
596 ASSERT_TRUE(oat_file.get() != nullptr);
597 EXPECT_TRUE(oat_file->IsExecutable());
598 std::vector<std::unique_ptr<const DexFile>> dex_files;
599 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
600 EXPECT_EQ(1u, dex_files.size());
601}
602
603// Case: We have a DEX file and up-to-date OAT file for it.
604// Expect: Loading non-executable should load the oat non-executable.
605TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
606 std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
607
608 Copy(GetDexSrc1(), dex_location);
609 GenerateOatForTest(dex_location.c_str());
610
611 // Load the oat using an oat file assistant.
612 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
613
614 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
615 ASSERT_TRUE(oat_file.get() != nullptr);
616 EXPECT_FALSE(oat_file->IsExecutable());
617 std::vector<std::unique_ptr<const DexFile>> dex_files;
618 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
619 EXPECT_EQ(1u, dex_files.size());
620}
621
622// Case: We have a DEX file.
623// Expect: We should load an executable dex file from an alternative oat
624// location.
625TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) {
626 std::string dex_location = GetScratchDir() + "/LoadDexNoAlternateOat.jar";
627 std::string oat_location = GetScratchDir() + "/LoadDexNoAlternateOat.oat";
628
629 Copy(GetDexSrc1(), dex_location);
630
631 OatFileAssistant oat_file_assistant(
632 dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true);
633 std::string error_msg;
634 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
635
636 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
637 ASSERT_TRUE(oat_file.get() != nullptr);
638 EXPECT_TRUE(oat_file->IsExecutable());
639 std::vector<std::unique_ptr<const DexFile>> dex_files;
640 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
641 EXPECT_EQ(1u, dex_files.size());
642
643 EXPECT_TRUE(OS::FileExists(oat_location.c_str()));
644
645 // Verify it didn't create an oat in the default location.
646 OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
647 EXPECT_FALSE(ofm.OatFileExists());
648}
649
650// Case: Non-existent Dex location.
651// Expect: The dex code is out of date, and trying to update it fails.
652TEST_F(OatFileAssistantTest, NonExsistentDexLocation) {
653 std::string dex_location = GetScratchDir() + "/BadDexLocation.jar";
654
655 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
656
657 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
658 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
659 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
660 EXPECT_FALSE(oat_file_assistant.OatFileExists());
661 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
662 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
663 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
664 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
665
666 std::string error_msg;
667 EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
668 EXPECT_FALSE(error_msg.empty());
669}
670
671// Turn an absolute path into a path relative to the current working
672// directory.
673static std::string MakePathRelative(std::string target) {
674 char buf[MAXPATHLEN];
675 std::string cwd = getcwd(buf, MAXPATHLEN);
676
677 // Split the target and cwd paths into components.
678 std::vector<std::string> target_path;
679 std::vector<std::string> cwd_path;
680 Split(target, '/', &target_path);
681 Split(cwd, '/', &cwd_path);
682
683 // Reverse the path components, so we can use pop_back().
684 std::reverse(target_path.begin(), target_path.end());
685 std::reverse(cwd_path.begin(), cwd_path.end());
686
687 // Drop the common prefix of the paths. Because we reversed the path
688 // components, this becomes the common suffix of target_path and cwd_path.
689 while (!target_path.empty() && !cwd_path.empty()
690 && target_path.back() == cwd_path.back()) {
691 target_path.pop_back();
692 cwd_path.pop_back();
693 }
694
695 // For each element of the remaining cwd_path, add '..' to the beginning
696 // of the target path. Because we reversed the path components, we add to
697 // the end of target_path.
698 for (unsigned int i = 0; i < cwd_path.size(); i++) {
699 target_path.push_back("..");
700 }
701
702 // Reverse again to get the right path order, and join to get the result.
703 std::reverse(target_path.begin(), target_path.end());
704 return Join(target_path, '/');
705}
706
707// Case: Non-absolute path to Dex location.
708// Expect: Not sure, but it shouldn't crash.
709TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
710 std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
711 Copy(GetDexSrc1(), abs_dex_location);
712
713 std::string dex_location = MakePathRelative(abs_dex_location);
714 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
715
716 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
717 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
718 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
719 EXPECT_FALSE(oat_file_assistant.OatFileExists());
720 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
721 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
722 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
723 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
724}
725
726// Case: Very short, non-existent Dex location.
727// Expect: Dex code is out of date, and trying to update it fails.
728TEST_F(OatFileAssistantTest, ShortDexLocation) {
729 std::string dex_location = "/xx";
730
731 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
732
733 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
734 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
735 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
736 EXPECT_FALSE(oat_file_assistant.OatFileExists());
737 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
738 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
739 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
740 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
741
742 std::string error_msg;
743 EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
744 EXPECT_FALSE(error_msg.empty());
745}
746
747// Case: Non-standard extension for dex file.
748// Expect: The oat file status is kOutOfDate.
749TEST_F(OatFileAssistantTest, LongDexExtension) {
750 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
751 Copy(GetDexSrc1(), dex_location);
752
753 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
754
755 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
756
757 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
758 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
759 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
760 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
761 EXPECT_FALSE(oat_file_assistant.OatFileExists());
762 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
763 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
764}
765
766// A task to generate a dex location. Used by the RaceToGenerate test.
767class RaceGenerateTask : public Task {
768 public:
769 explicit RaceGenerateTask(const std::string& dex_location, const std::string& oat_location)
770 : dex_location_(dex_location), oat_location_(oat_location),
771 loaded_oat_file_(nullptr)
772 {}
773
774 void Run(Thread* self) {
775 UNUSED(self);
776
777 // Load the dex files, and save a pointer to the loaded oat file, so that
778 // we can verify only one oat file was loaded for the dex location.
779 ClassLinker* linker = Runtime::Current()->GetClassLinker();
780 std::vector<std::unique_ptr<const DexFile>> dex_files;
781 std::vector<std::string> error_msgs;
782 dex_files = linker->OpenDexFilesFromOat(dex_location_.c_str(), oat_location_.c_str(), &error_msgs);
783 CHECK(!dex_files.empty()) << Join(error_msgs, '\n');
784 loaded_oat_file_ = dex_files[0]->GetOatFile();
785 }
786
787 const OatFile* GetLoadedOatFile() const {
788 return loaded_oat_file_;
789 }
790
791 private:
792 std::string dex_location_;
793 std::string oat_location_;
794 const OatFile* loaded_oat_file_;
795};
796
797// Test the case where multiple processes race to generate an oat file.
798// This simulates multiple processes using multiple threads.
799//
800// We want only one Oat file to be loaded when there is a race to load, to
801// avoid using up the virtual memory address space.
802TEST_F(OatFileAssistantTest, RaceToGenerate) {
803 std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
804 std::string oat_location = GetISADir() + "/RaceToGenerate.oat";
805
806 // We use the lib core dex file, because it's large, and hopefully should
807 // take a while to generate.
808 Copy(GetLibCoreDexFileName(), dex_location);
809
810 const int kNumThreads = 32;
811 Thread* self = Thread::Current();
812 ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads);
813 std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
814 for (int i = 0; i < kNumThreads; i++) {
815 std::unique_ptr<RaceGenerateTask> task(new RaceGenerateTask(dex_location, oat_location));
816 thread_pool.AddTask(self, task.get());
817 tasks.push_back(std::move(task));
818 }
819 thread_pool.StartWorkers(self);
820 thread_pool.Wait(self, true, false);
821
822 // Verify every task got the same pointer.
823 const OatFile* expected = tasks[0]->GetLoadedOatFile();
824 for (auto& task : tasks) {
825 EXPECT_EQ(expected, task->GetLoadedOatFile());
826 }
827}
828
829// Case: We have a DEX file and an ODEX file, no OAT file, and dex2oat is
830// disabled.
831// Expect: We should load the odex file non-executable.
832TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
833 std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
834 std::string odex_location = GetISADir() + "/LoadDexOdexNoOat.odex";
835
836 // Create the dex and odex files
837 Copy(GetDexSrc1(), dex_location);
838 GenerateOdexForTest(dex_location, odex_location);
839
840 // Load the oat using an executable oat file assistant.
841 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
842
843 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
844 ASSERT_TRUE(oat_file.get() != nullptr);
845 EXPECT_FALSE(oat_file->IsExecutable());
846 std::vector<std::unique_ptr<const DexFile>> dex_files;
847 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
848 EXPECT_EQ(1u, dex_files.size());
849}
850
851// Case: We have a MultiDEX file and an ODEX file, no OAT file, and dex2oat is
852// disabled.
853// Expect: We should load the odex file non-executable.
854TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
855 std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
856 std::string odex_location = GetISADir() + "/LoadMultiDexOdexNoOat.odex";
857
858 // Create the dex and odex files
859 Copy(GetMultiDexSrc1(), dex_location);
860 GenerateOdexForTest(dex_location, odex_location);
861
862 // Load the oat using an executable oat file assistant.
863 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
864
865 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
866 ASSERT_TRUE(oat_file.get() != nullptr);
867 EXPECT_FALSE(oat_file->IsExecutable());
868 std::vector<std::unique_ptr<const DexFile>> dex_files;
869 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
870 EXPECT_EQ(2u, dex_files.size());
871}
872
873TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) {
874 std::string error_msg;
875 std::string odex_file;
876
877 EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
878 "/foo/bar/baz.jar", kArm, &odex_file, &error_msg)) << error_msg;
879 EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
880
881 EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
882 "/foo/bar/baz.funnyext", kArm, &odex_file, &error_msg)) << error_msg;
883 EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
884
885 EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
886 "nopath.jar", kArm, &odex_file, &error_msg));
887 EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
888 "/foo/bar/baz_noext", kArm, &odex_file, &error_msg));
889}
890
891
892// TODO: More Tests:
893// * Test class linker falls back to unquickened dex for DexNoOat
894// * Test class linker falls back to unquickened dex for MultiDexNoOat
895// * Test multidex files:
896// - Multidex with only classes2.dex out of date should have status
897// kOutOfDate
898// * Test using secondary isa
899// * Test with profiling info?
900// * Test for status of oat while oat is being generated (how?)
901// * Test case where 32 and 64 bit boot class paths differ,
902// and we ask IsInBootClassPath for a class in exactly one of the 32 or
903// 64 bit boot class paths.
904// * Test unexpected scenarios (?):
905// - Dex is stripped, don't have odex.
906// - Oat file corrupted after status check, before reload unexecutable
907// because it's unrelocated and no dex2oat
908
909} // namespace art