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