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