blob: be8652cec5720dc8dfe7c9442cef23ae81c65510 [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.
329 OatFileAssistant executable_oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
330 std::unique_ptr<OatFile> oat_file = executable_oat_file_assistant.GetBestOatFile();
331 ASSERT_TRUE(oat_file.get() != nullptr);
332 EXPECT_TRUE(oat_file->IsExecutable());
333 std::vector<std::unique_ptr<const DexFile>> dex_files;
334 dex_files = executable_oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
335 EXPECT_EQ(2u, dex_files.size());
336}
337
338// Case: We have a DEX file and out of date OAT file.
339// Expect: The oat file status is kOutOfDate.
340TEST_F(OatFileAssistantTest, OatOutOfDate) {
341 std::string dex_location = GetScratchDir() + "/OatOutOfDate.jar";
342
343 // We create a dex, generate an oat for it, then overwrite the dex with a
344 // different dex to make the oat out of date.
345 Copy(GetDexSrc1(), dex_location);
346 GenerateOatForTest(dex_location.c_str());
347 Copy(GetDexSrc2(), dex_location);
348
349 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
350 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
351
352 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
353 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
354 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
355 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
356 EXPECT_TRUE(oat_file_assistant.OatFileExists());
357 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
358 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
359}
360
361// Case: We have a DEX file and an ODEX file, but no OAT file.
362// Expect: The oat file status is kNeedsRelocation.
363TEST_F(OatFileAssistantTest, DexOdexNoOat) {
364 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
365 std::string odex_location = GetISADir() + "/DexOdexNoOat.odex";
366
367 // Create the dex and odex files
368 Copy(GetDexSrc1(), dex_location);
369 GenerateOdexForTest(dex_location, odex_location);
370
371 // Verify the status.
372 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
373
374 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
375
376 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
377 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
378 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
379 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
380 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
381 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.OdexFileNeedsRelocation());
382 EXPECT_FALSE(oat_file_assistant.OatFileExists());
383 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
384 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
385}
386
387// Case: We have a stripped DEX file and an ODEX file, but no OAT file.
388// Expect: The oat file status is kNeedsRelocation.
389TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
390 std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
391 std::string odex_location = GetISADir() + "/StrippedDexOdexNoOat.odex";
392
393 // Create the dex and odex files
394 Copy(GetDexSrc1(), dex_location);
395 GenerateOdexForTest(dex_location, odex_location);
396
397 // Strip the dex file
398 Copy(GetStrippedDexSrc1(), dex_location);
399
400 // Verify the status.
401 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
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_FALSE(oat_file_assistant.OatFileExists());
410 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
411 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
412
413 // Make the oat file up to date.
414 std::string error_msg;
415 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
416
417 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
418
419 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
420 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
421 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
422 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
423 EXPECT_TRUE(oat_file_assistant.OatFileExists());
424 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
425 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
426
427 // Verify we can load the dex files from it.
428 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
429 ASSERT_TRUE(oat_file.get() != nullptr);
430 EXPECT_TRUE(oat_file->IsExecutable());
431 std::vector<std::unique_ptr<const DexFile>> dex_files;
432 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
433 EXPECT_EQ(1u, dex_files.size());
434}
435
436// Case: We have a stripped DEX file, an ODEX file, and an out of date OAT file.
437// Expect: The oat file status is kNeedsRelocation.
438TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
439 std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
440 std::string odex_location = GetISADir() + "/StrippedDexOdexOat.odex";
441
442 // Create the oat file from a different dex file so it looks out of date.
443 Copy(GetDexSrc2(), dex_location);
444 GenerateOatForTest(dex_location.c_str());
445
446 // Create the odex file
447 Copy(GetDexSrc1(), dex_location);
448 GenerateOdexForTest(dex_location, odex_location);
449
450 // Strip the dex file.
451 Copy(GetStrippedDexSrc1(), dex_location);
452
453 // Verify the status.
454 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
455
456 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
457
458 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
459 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
460 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
461 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
462 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
463 EXPECT_TRUE(oat_file_assistant.OatFileExists());
464 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
465 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
466
467 // Make the oat file up to date.
468 std::string error_msg;
469 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
470
471 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
472
473 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
474 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
475 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
476 EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
477 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
478 EXPECT_TRUE(oat_file_assistant.OatFileExists());
479 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
480 EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
481 EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
482
483 // Verify we can load the dex files from it.
484 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
485 ASSERT_TRUE(oat_file.get() != nullptr);
486 EXPECT_TRUE(oat_file->IsExecutable());
487 std::vector<std::unique_ptr<const DexFile>> dex_files;
488 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
489 EXPECT_EQ(1u, dex_files.size());
490}
491
492// Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
493// OAT files both have patch delta of 0.
494// Expect: It shouldn't crash.
495TEST_F(OatFileAssistantTest, OdexOatOverlap) {
496 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
497 std::string odex_location = GetISADir() + "/OdexOatOverlap.odex";
498 std::string oat_location = GetISADir() + "/OdexOatOverlap.oat";
499
500 // Create the dex and odex files
501 Copy(GetDexSrc1(), dex_location);
502 GenerateOdexForTest(dex_location, odex_location);
503
504 // Create the oat file by copying the odex so they are located in the same
505 // place in memory.
506 Copy(odex_location, oat_location);
507
508 // Verify things don't go bad.
509 OatFileAssistant oat_file_assistant(dex_location.c_str(),
510 oat_location.c_str(), kRuntimeISA, true);
511
512 EXPECT_EQ(OatFileAssistant::kNeedsRelocation, oat_file_assistant.GetStatus());
513
514 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
515 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
516 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
517 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
518 EXPECT_TRUE(oat_file_assistant.OatFileExists());
519 EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
520 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
521
522 // Things aren't relocated, so it should fall back to interpreted.
523 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
524 ASSERT_TRUE(oat_file.get() != nullptr);
525 EXPECT_FALSE(oat_file->IsExecutable());
526 std::vector<std::unique_ptr<const DexFile>> dex_files;
527 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
528 EXPECT_EQ(1u, dex_files.size());
529}
530
531// Case: We have a DEX file and a PIC ODEX file, but no OAT file.
532// Expect: The oat file status is kUpToDate, because PIC needs no relocation.
533TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
534 std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar";
535 std::string odex_location = GetISADir() + "/DexPicOdexNoOat.odex";
536
537 // Create the dex and odex files
538 Copy(GetDexSrc1(), dex_location);
539 GeneratePicOdexForTest(dex_location, odex_location);
540
541 // Verify the status.
542 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
543
544 EXPECT_EQ(OatFileAssistant::kUpToDate, oat_file_assistant.GetStatus());
545
546 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
547 EXPECT_TRUE(oat_file_assistant.OdexFileExists());
548 EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
549 EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
550 EXPECT_FALSE(oat_file_assistant.OatFileExists());
551 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
552 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
553}
554
555// Case: We have a DEX file and up-to-date OAT file for it.
556// Expect: We should load an executable dex file.
557TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
558 std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
559
560 Copy(GetDexSrc1(), dex_location);
561 GenerateOatForTest(dex_location.c_str());
562
563 // Load the oat using an oat file assistant.
564 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
565
566 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
567 ASSERT_TRUE(oat_file.get() != nullptr);
568 EXPECT_TRUE(oat_file->IsExecutable());
569 std::vector<std::unique_ptr<const DexFile>> dex_files;
570 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
571 EXPECT_EQ(1u, dex_files.size());
572}
573
574// Case: We have a DEX file and up-to-date OAT file for it.
575// Expect: Loading non-executable should load the oat non-executable.
576TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
577 std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
578
579 Copy(GetDexSrc1(), dex_location);
580 GenerateOatForTest(dex_location.c_str());
581
582 // Load the oat using an oat file assistant.
583 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
584
585 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
586 ASSERT_TRUE(oat_file.get() != nullptr);
587 EXPECT_FALSE(oat_file->IsExecutable());
588 std::vector<std::unique_ptr<const DexFile>> dex_files;
589 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
590 EXPECT_EQ(1u, dex_files.size());
591}
592
593// Case: We have a DEX file.
594// Expect: We should load an executable dex file from an alternative oat
595// location.
596TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) {
597 std::string dex_location = GetScratchDir() + "/LoadDexNoAlternateOat.jar";
598 std::string oat_location = GetScratchDir() + "/LoadDexNoAlternateOat.oat";
599
600 Copy(GetDexSrc1(), dex_location);
601
602 OatFileAssistant oat_file_assistant(
603 dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true);
604 std::string error_msg;
605 ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
606
607 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
608 ASSERT_TRUE(oat_file.get() != nullptr);
609 EXPECT_TRUE(oat_file->IsExecutable());
610 std::vector<std::unique_ptr<const DexFile>> dex_files;
611 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
612 EXPECT_EQ(1u, dex_files.size());
613
614 EXPECT_TRUE(OS::FileExists(oat_location.c_str()));
615
616 // Verify it didn't create an oat in the default location.
617 OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
618 EXPECT_FALSE(ofm.OatFileExists());
619}
620
621// Case: Non-existent Dex location.
622// Expect: The dex code is out of date, and trying to update it fails.
623TEST_F(OatFileAssistantTest, NonExsistentDexLocation) {
624 std::string dex_location = GetScratchDir() + "/BadDexLocation.jar";
625
626 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
627
628 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
629 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
630 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
631 EXPECT_FALSE(oat_file_assistant.OatFileExists());
632 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
633 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
634 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
635 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
636
637 std::string error_msg;
638 EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
639 EXPECT_FALSE(error_msg.empty());
640}
641
642// Turn an absolute path into a path relative to the current working
643// directory.
644static std::string MakePathRelative(std::string target) {
645 char buf[MAXPATHLEN];
646 std::string cwd = getcwd(buf, MAXPATHLEN);
647
648 // Split the target and cwd paths into components.
649 std::vector<std::string> target_path;
650 std::vector<std::string> cwd_path;
651 Split(target, '/', &target_path);
652 Split(cwd, '/', &cwd_path);
653
654 // Reverse the path components, so we can use pop_back().
655 std::reverse(target_path.begin(), target_path.end());
656 std::reverse(cwd_path.begin(), cwd_path.end());
657
658 // Drop the common prefix of the paths. Because we reversed the path
659 // components, this becomes the common suffix of target_path and cwd_path.
660 while (!target_path.empty() && !cwd_path.empty()
661 && target_path.back() == cwd_path.back()) {
662 target_path.pop_back();
663 cwd_path.pop_back();
664 }
665
666 // For each element of the remaining cwd_path, add '..' to the beginning
667 // of the target path. Because we reversed the path components, we add to
668 // the end of target_path.
669 for (unsigned int i = 0; i < cwd_path.size(); i++) {
670 target_path.push_back("..");
671 }
672
673 // Reverse again to get the right path order, and join to get the result.
674 std::reverse(target_path.begin(), target_path.end());
675 return Join(target_path, '/');
676}
677
678// Case: Non-absolute path to Dex location.
679// Expect: Not sure, but it shouldn't crash.
680TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
681 std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
682 Copy(GetDexSrc1(), abs_dex_location);
683
684 std::string dex_location = MakePathRelative(abs_dex_location);
685 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
686
687 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
688 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
689 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
690 EXPECT_FALSE(oat_file_assistant.OatFileExists());
691 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
692 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
693 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
694 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
695}
696
697// Case: Very short, non-existent Dex location.
698// Expect: Dex code is out of date, and trying to update it fails.
699TEST_F(OatFileAssistantTest, ShortDexLocation) {
700 std::string dex_location = "/xx";
701
702 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
703
704 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
705 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
706 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
707 EXPECT_FALSE(oat_file_assistant.OatFileExists());
708 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
709 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
710 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
711 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
712
713 std::string error_msg;
714 EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
715 EXPECT_FALSE(error_msg.empty());
716}
717
718// Case: Non-standard extension for dex file.
719// Expect: The oat file status is kOutOfDate.
720TEST_F(OatFileAssistantTest, LongDexExtension) {
721 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
722 Copy(GetDexSrc1(), dex_location);
723
724 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
725
726 EXPECT_EQ(OatFileAssistant::kOutOfDate, oat_file_assistant.GetStatus());
727
728 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
729 EXPECT_FALSE(oat_file_assistant.OdexFileExists());
730 EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
731 EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
732 EXPECT_FALSE(oat_file_assistant.OatFileExists());
733 EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
734 EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
735}
736
737// A task to generate a dex location. Used by the RaceToGenerate test.
738class RaceGenerateTask : public Task {
739 public:
740 explicit RaceGenerateTask(const std::string& dex_location, const std::string& oat_location)
741 : dex_location_(dex_location), oat_location_(oat_location),
742 loaded_oat_file_(nullptr)
743 {}
744
745 void Run(Thread* self) {
746 UNUSED(self);
747
748 // Load the dex files, and save a pointer to the loaded oat file, so that
749 // we can verify only one oat file was loaded for the dex location.
750 ClassLinker* linker = Runtime::Current()->GetClassLinker();
751 std::vector<std::unique_ptr<const DexFile>> dex_files;
752 std::vector<std::string> error_msgs;
753 dex_files = linker->OpenDexFilesFromOat(dex_location_.c_str(), oat_location_.c_str(), &error_msgs);
754 CHECK(!dex_files.empty()) << Join(error_msgs, '\n');
755 loaded_oat_file_ = dex_files[0]->GetOatFile();
756 }
757
758 const OatFile* GetLoadedOatFile() const {
759 return loaded_oat_file_;
760 }
761
762 private:
763 std::string dex_location_;
764 std::string oat_location_;
765 const OatFile* loaded_oat_file_;
766};
767
768// Test the case where multiple processes race to generate an oat file.
769// This simulates multiple processes using multiple threads.
770//
771// We want only one Oat file to be loaded when there is a race to load, to
772// avoid using up the virtual memory address space.
773TEST_F(OatFileAssistantTest, RaceToGenerate) {
774 std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
775 std::string oat_location = GetISADir() + "/RaceToGenerate.oat";
776
777 // We use the lib core dex file, because it's large, and hopefully should
778 // take a while to generate.
779 Copy(GetLibCoreDexFileName(), dex_location);
780
781 const int kNumThreads = 32;
782 Thread* self = Thread::Current();
783 ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads);
784 std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
785 for (int i = 0; i < kNumThreads; i++) {
786 std::unique_ptr<RaceGenerateTask> task(new RaceGenerateTask(dex_location, oat_location));
787 thread_pool.AddTask(self, task.get());
788 tasks.push_back(std::move(task));
789 }
790 thread_pool.StartWorkers(self);
791 thread_pool.Wait(self, true, false);
792
793 // Verify every task got the same pointer.
794 const OatFile* expected = tasks[0]->GetLoadedOatFile();
795 for (auto& task : tasks) {
796 EXPECT_EQ(expected, task->GetLoadedOatFile());
797 }
798}
799
800// Case: We have a DEX file and an ODEX file, no OAT file, and dex2oat is
801// disabled.
802// Expect: We should load the odex file non-executable.
803TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
804 std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
805 std::string odex_location = GetISADir() + "/LoadDexOdexNoOat.odex";
806
807 // Create the dex and odex files
808 Copy(GetDexSrc1(), dex_location);
809 GenerateOdexForTest(dex_location, odex_location);
810
811 // Load the oat using an executable oat file assistant.
812 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
813
814 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
815 ASSERT_TRUE(oat_file.get() != nullptr);
816 EXPECT_FALSE(oat_file->IsExecutable());
817 std::vector<std::unique_ptr<const DexFile>> dex_files;
818 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
819 EXPECT_EQ(1u, dex_files.size());
820}
821
822// Case: We have a MultiDEX file and an ODEX file, no OAT file, and dex2oat is
823// disabled.
824// Expect: We should load the odex file non-executable.
825TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
826 std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
827 std::string odex_location = GetISADir() + "/LoadMultiDexOdexNoOat.odex";
828
829 // Create the dex and odex files
830 Copy(GetMultiDexSrc1(), dex_location);
831 GenerateOdexForTest(dex_location, odex_location);
832
833 // Load the oat using an executable oat file assistant.
834 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
835
836 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
837 ASSERT_TRUE(oat_file.get() != nullptr);
838 EXPECT_FALSE(oat_file->IsExecutable());
839 std::vector<std::unique_ptr<const DexFile>> dex_files;
840 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
841 EXPECT_EQ(2u, dex_files.size());
842}
843
844TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) {
845 std::string error_msg;
846 std::string odex_file;
847
848 EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
849 "/foo/bar/baz.jar", kArm, &odex_file, &error_msg)) << error_msg;
850 EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
851
852 EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
853 "/foo/bar/baz.funnyext", kArm, &odex_file, &error_msg)) << error_msg;
854 EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
855
856 EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
857 "nopath.jar", kArm, &odex_file, &error_msg));
858 EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
859 "/foo/bar/baz_noext", kArm, &odex_file, &error_msg));
860}
861
862
863// TODO: More Tests:
864// * Test class linker falls back to unquickened dex for DexNoOat
865// * Test class linker falls back to unquickened dex for MultiDexNoOat
866// * Test multidex files:
867// - Multidex with only classes2.dex out of date should have status
868// kOutOfDate
869// * Test using secondary isa
870// * Test with profiling info?
871// * Test for status of oat while oat is being generated (how?)
872// * Test case where 32 and 64 bit boot class paths differ,
873// and we ask IsInBootClassPath for a class in exactly one of the 32 or
874// 64 bit boot class paths.
875// * Test unexpected scenarios (?):
876// - Dex is stripped, don't have odex.
877// - Oat file corrupted after status check, before reload unexecutable
878// because it's unrelocated and no dex2oat
879
880} // namespace art