1 /*
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 <sys/param.h>
20
21 #include <string>
22 #include <vector>
23 #include <fcntl.h>
24
25 #include <gtest/gtest.h>
26
27 #include "android-base/strings.h"
28
29 #include "art_field-inl.h"
30 #include "base/os.h"
31 #include "base/utils.h"
32 #include "class_linker-inl.h"
33 #include "class_loader_context.h"
34 #include "common_runtime_test.h"
35 #include "dexopt_test.h"
36 #include "hidden_api.h"
37 #include "oat_file.h"
38 #include "oat_file_manager.h"
39 #include "scoped_thread_state_change-inl.h"
40 #include "thread-current-inl.h"
41
42 namespace art {
43
44 static const std::string kSpecialSharedLibrary = "&"; // NOLINT [runtime/string] [4]
45 static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr;
46
47 static constexpr char kDex2oatCmdLineHiddenApiArg[] = " --runtime-arg -Xhidden-api-checks";
48
49 class OatFileAssistantTest : public DexoptTest {
50 public:
VerifyOptimizationStatus(const std::string & file,const std::string & expected_filter,const std::string & expected_reason)51 void VerifyOptimizationStatus(const std::string& file,
52 const std::string& expected_filter,
53 const std::string& expected_reason) {
54 std::string compilation_filter;
55 std::string compilation_reason;
56 OatFileAssistant::GetOptimizationStatus(
57 file, kRuntimeISA, &compilation_filter, &compilation_reason);
58
59 ASSERT_EQ(expected_filter, compilation_filter);
60 ASSERT_EQ(expected_reason, compilation_reason);
61 }
62
VerifyOptimizationStatus(const std::string & file,CompilerFilter::Filter expected_filter,const std::string & expected_reason)63 void VerifyOptimizationStatus(const std::string& file,
64 CompilerFilter::Filter expected_filter,
65 const std::string& expected_reason) {
66 VerifyOptimizationStatus(
67 file, CompilerFilter::NameOfFilter(expected_filter), expected_reason);
68 }
69 };
70
71 class OatFileAssistantNoDex2OatTest : public DexoptTest {
72 public:
SetUpRuntimeOptions(RuntimeOptions * options)73 virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
74 DexoptTest::SetUpRuntimeOptions(options);
75 options->push_back(std::make_pair("-Xnodex2oat", nullptr));
76 }
77 };
78
79 class ScopedNonWritable {
80 public:
ScopedNonWritable(const std::string & dex_location)81 explicit ScopedNonWritable(const std::string& dex_location) {
82 is_valid_ = false;
83 size_t pos = dex_location.rfind('/');
84 if (pos != std::string::npos) {
85 is_valid_ = true;
86 dex_parent_ = dex_location.substr(0, pos);
87 if (chmod(dex_parent_.c_str(), 0555) != 0) {
88 PLOG(ERROR) << "Could not change permissions on " << dex_parent_;
89 }
90 }
91 }
92
IsSuccessful()93 bool IsSuccessful() { return is_valid_ && (access(dex_parent_.c_str(), W_OK) != 0); }
94
~ScopedNonWritable()95 ~ScopedNonWritable() {
96 if (is_valid_) {
97 if (chmod(dex_parent_.c_str(), 0777) != 0) {
98 PLOG(ERROR) << "Could not restore permissions on " << dex_parent_;
99 }
100 }
101 }
102
103 private:
104 std::string dex_parent_;
105 bool is_valid_;
106 };
107
IsExecutedAsRoot()108 static bool IsExecutedAsRoot() {
109 return geteuid() == 0;
110 }
111
112 // Case: We have a DEX file, but no OAT file for it.
113 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,DexNoOat)114 TEST_F(OatFileAssistantTest, DexNoOat) {
115 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
116 Copy(GetDexSrc1(), dex_location);
117
118 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
119
120 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
121 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
122 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
123 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
124 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
125 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
126 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
127 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
128
129 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
130 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
131 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
132 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
133
134 VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
135 }
136
137 // Case: We have no DEX file and no OAT file.
138 // Expect: Status is kNoDexOptNeeded. Loading should fail, but not crash.
TEST_F(OatFileAssistantTest,NoDexNoOat)139 TEST_F(OatFileAssistantTest, NoDexNoOat) {
140 std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
141
142 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
143
144 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
145 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
146 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
147
148 // Trying to make the oat file up to date should not fail or crash.
149 std::string error_msg;
150 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
151 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg));
152
153 // Trying to get the best oat file should fail, but not crash.
154 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
155 EXPECT_EQ(nullptr, oat_file.get());
156 }
157
158 // Case: We have a DEX file and a PIC ODEX file, but no OAT file.
159 // Expect: The status is kNoDexOptNeeded, because PIC needs no relocation.
TEST_F(OatFileAssistantTest,OdexUpToDate)160 TEST_F(OatFileAssistantTest, OdexUpToDate) {
161 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
162 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
163 Copy(GetDexSrc1(), dex_location);
164 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
165
166 // For the use of oat location by making the dex parent not writable.
167 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
168
169 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
170 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
171 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
172 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
173 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
174 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
175 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
176 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
177
178 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
179 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
180 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
181 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
182
183 VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
184 }
185
186 // Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex
187 // file via a symlink.
188 // Expect: The status is kNoDexOptNeeded, because PIC needs no relocation.
TEST_F(OatFileAssistantTest,OdexUpToDateSymLink)189 TEST_F(OatFileAssistantTest, OdexUpToDateSymLink) {
190 std::string scratch_dir = GetScratchDir();
191 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
192 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
193
194 Copy(GetDexSrc1(), dex_location);
195 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
196
197 // Now replace the dex location with a symlink.
198 std::string link = scratch_dir + "/link";
199 ASSERT_EQ(0, symlink(scratch_dir.c_str(), link.c_str()));
200 dex_location = link + "/OdexUpToDate.jar";
201
202 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
203
204 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
205 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
206 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
207 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
208 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
209 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
210 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
211 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
212
213 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
214 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
215 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
216 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
217 }
218
219 // Case: We have a DEX file and up-to-date OAT file for it.
220 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,OatUpToDate)221 TEST_F(OatFileAssistantTest, OatUpToDate) {
222 if (IsExecutedAsRoot()) {
223 // We cannot simulate non writable locations when executed as root: b/38000545.
224 LOG(ERROR) << "Test skipped because it's running as root";
225 return;
226 }
227
228 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
229 Copy(GetDexSrc1(), dex_location);
230 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
231
232 // For the use of oat location by making the dex parent not writable.
233 ScopedNonWritable scoped_non_writable(dex_location);
234 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
235
236 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
237
238 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
239 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
240 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
241 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
242 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
243 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
244 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
245 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
246
247 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
248 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
249 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
250 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
251
252 VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown");
253 }
254
255 // Case: Passing valid file descriptors of updated odex/vdex filesalong with
256 // the dex file.
257 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithFd)258 TEST_F(OatFileAssistantTest, GetDexOptNeededWithFd) {
259 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
260 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
261 std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
262
263 Copy(GetDexSrc1(), dex_location);
264 GenerateOatForTest(dex_location.c_str(),
265 odex_location.c_str(),
266 CompilerFilter::kSpeed,
267 true,
268 false,
269 false);
270
271 android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
272 android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY));
273 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
274
275 OatFileAssistant oat_file_assistant(dex_location.c_str(),
276 kRuntimeISA,
277 false,
278 false,
279 vdex_fd.get(),
280 odex_fd.get(),
281 zip_fd.get());
282 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
283 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
284 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
285 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
286 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
287 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
288 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
289 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
290
291 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
292 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
293 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
294 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
295 }
296
297 // Case: Passing invalid odex fd and valid vdex and zip fds.
298 // Expect: The status should be kDex2OatForBootImage.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithInvalidOdexFd)299 TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexFd) {
300 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
301 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
302 std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
303
304 Copy(GetDexSrc1(), dex_location);
305 GenerateOatForTest(dex_location.c_str(),
306 odex_location.c_str(),
307 CompilerFilter::kSpeed,
308 true,
309 false,
310 false);
311
312 android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY));
313 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
314
315 OatFileAssistant oat_file_assistant(dex_location.c_str(),
316 kRuntimeISA,
317 false,
318 false,
319 vdex_fd.get(),
320 -1 /* oat_fd */,
321 zip_fd.get());
322 EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
323 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
324 EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
325 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
326
327 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
328 EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
329 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
330 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
331 }
332
333 // Case: Passing invalid vdex fd and valid odex and zip fds.
334 // Expect: The status should be kDex2OatFromScratch.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithInvalidVdexFd)335 TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) {
336 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
337 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
338
339 Copy(GetDexSrc1(), dex_location);
340 GenerateOatForTest(dex_location.c_str(),
341 odex_location.c_str(),
342 CompilerFilter::kSpeed,
343 true,
344 false,
345 false);
346
347 android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
348 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
349
350 OatFileAssistant oat_file_assistant(dex_location.c_str(),
351 kRuntimeISA,
352 false,
353 false,
354 -1 /* vdex_fd */,
355 odex_fd.get(),
356 zip_fd.get());
357
358 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
359 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
360 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
361 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
362 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
363 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
364 }
365
366 // Case: Passing invalid vdex and odex fd with valid zip fd.
367 // Expect: The status is kDex2oatFromScratch.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithInvalidOdexVdexFd)368 TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) {
369 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
370
371 Copy(GetDexSrc1(), dex_location);
372
373 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
374 OatFileAssistant oat_file_assistant(dex_location.c_str(),
375 kRuntimeISA,
376 false,
377 false,
378 -1 /* vdex_fd */,
379 -1 /* oat_fd */,
380 zip_fd);
381 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
382 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
383 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
384 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
385 }
386
387 // Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no
388 // ODEX file.
TEST_F(OatFileAssistantTest,VdexUpToDateNoOdex)389 TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) {
390 std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar";
391 std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat";
392
393 Copy(GetDexSrc1(), dex_location);
394
395 // Generating and deleting the oat file should have the side effect of
396 // creating an up-to-date vdex file.
397 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
398 ASSERT_EQ(0, unlink(odex_location.c_str()));
399
400 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
401
402 // Even though the vdex file is up to date, because we don't have the oat
403 // file, we can't know that the vdex depends on the boot image and is up to
404 // date with respect to the boot image. Instead we must assume the vdex file
405 // depends on the boot image and is out of date with respect to the boot
406 // image.
407 EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
408 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
409
410 // Make sure we don't crash in this case when we dump the status. We don't
411 // care what the actual dumped value is.
412 oat_file_assistant.GetStatusDump();
413
414 VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
415 }
416
417 // Case: We have a DEX file and empty VDEX and ODEX files.
TEST_F(OatFileAssistantTest,EmptyVdexOdex)418 TEST_F(OatFileAssistantTest, EmptyVdexOdex) {
419 std::string dex_location = GetScratchDir() + "/EmptyVdexOdex.jar";
420 std::string odex_location = GetOdexDir() + "/EmptyVdexOdex.oat";
421 std::string vdex_location = GetOdexDir() + "/EmptyVdexOdex.vdex";
422
423 Copy(GetDexSrc1(), dex_location);
424 ScratchFile vdex_file(vdex_location.c_str());
425 ScratchFile odex_file(odex_location.c_str());
426
427 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
428 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
429 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
430 }
431
432 // Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT
433 // file.
TEST_F(OatFileAssistantTest,VdexUpToDateNoOat)434 TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) {
435 if (IsExecutedAsRoot()) {
436 // We cannot simulate non writable locations when executed as root: b/38000545.
437 LOG(ERROR) << "Test skipped because it's running as root";
438 return;
439 }
440
441 std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOat.jar";
442 std::string oat_location;
443 std::string error_msg;
444 ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
445 dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
446
447 Copy(GetDexSrc1(), dex_location);
448 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
449 ASSERT_EQ(0, unlink(oat_location.c_str()));
450
451 ScopedNonWritable scoped_non_writable(dex_location);
452 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
453 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
454
455 // Even though the vdex file is up to date, because we don't have the oat
456 // file, we can't know that the vdex depends on the boot image and is up to
457 // date with respect to the boot image. Instead we must assume the vdex file
458 // depends on the boot image and is out of date with respect to the boot
459 // image.
460 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
461 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
462 }
463
464 // Case: We have a DEX file and speed-profile OAT file for it.
465 // Expect: The status is kNoDexOptNeeded if the profile hasn't changed, but
466 // kDex2Oat if the profile has changed.
TEST_F(OatFileAssistantTest,ProfileOatUpToDate)467 TEST_F(OatFileAssistantTest, ProfileOatUpToDate) {
468 if (IsExecutedAsRoot()) {
469 // We cannot simulate non writable locations when executed as root: b/38000545.
470 LOG(ERROR) << "Test skipped because it's running as root";
471 return;
472 }
473
474 std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
475 Copy(GetDexSrc1(), dex_location);
476 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
477
478 ScopedNonWritable scoped_non_writable(dex_location);
479 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
480
481 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
482
483 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
484 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, false));
485 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
486 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken, false));
487 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
488 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, true));
489 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
490 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken, true));
491
492 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
493 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
494 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
495 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
496 }
497
498 // Case: We have a MultiDEX file and up-to-date OAT file for it.
499 // Expect: The status is kNoDexOptNeeded and we load all dex files.
TEST_F(OatFileAssistantTest,MultiDexOatUpToDate)500 TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
501 if (IsExecutedAsRoot()) {
502 // We cannot simulate non writable locations when executed as root: b/38000545.
503 LOG(ERROR) << "Test skipped because it's running as root";
504 return;
505 }
506
507 std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
508 Copy(GetMultiDexSrc1(), dex_location);
509 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
510
511 ScopedNonWritable scoped_non_writable(dex_location);
512 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
513
514 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
515 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
516 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false));
517 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
518
519 // Verify we can load both dex files.
520 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
521 ASSERT_TRUE(oat_file.get() != nullptr);
522 EXPECT_TRUE(oat_file->IsExecutable());
523 std::vector<std::unique_ptr<const DexFile>> dex_files;
524 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
525 EXPECT_EQ(2u, dex_files.size());
526 }
527
528 // Case: We have a MultiDEX file where the non-main multdex entry is out of date.
529 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,MultiDexNonMainOutOfDate)530 TEST_F(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
531 if (IsExecutedAsRoot()) {
532 // We cannot simulate non writable locations when executed as root: b/38000545.
533 LOG(ERROR) << "Test skipped because it's running as root";
534 return;
535 }
536
537 std::string dex_location = GetScratchDir() + "/MultiDexNonMainOutOfDate.jar";
538
539 // Compile code for GetMultiDexSrc1.
540 Copy(GetMultiDexSrc1(), dex_location);
541 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
542
543 // Now overwrite the dex file with GetMultiDexSrc2 so the non-main checksum
544 // is out of date.
545 Copy(GetMultiDexSrc2(), dex_location);
546
547 ScopedNonWritable scoped_non_writable(dex_location);
548 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
549
550 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
551 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
552 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false));
553 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
554 }
555
556 // Case: We have a stripped MultiDEX file where the non-main multidex entry is
557 // out of date with respect to the odex file.
TEST_F(OatFileAssistantTest,StrippedMultiDexNonMainOutOfDate)558 TEST_F(OatFileAssistantTest, StrippedMultiDexNonMainOutOfDate) {
559 std::string dex_location = GetScratchDir() + "/StrippedMultiDexNonMainOutOfDate.jar";
560 std::string odex_location = GetOdexDir() + "/StrippedMultiDexNonMainOutOfDate.odex";
561
562 // Compile the oat from GetMultiDexSrc1.
563 Copy(GetMultiDexSrc1(), dex_location);
564 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
565
566 // Compile the odex from GetMultiDexSrc2, which has a different non-main
567 // dex checksum.
568 Copy(GetMultiDexSrc2(), dex_location);
569 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kQuicken);
570
571 // Strip the dex file.
572 Copy(GetStrippedDexSrc1(), dex_location);
573
574 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, /*load_executable*/false);
575
576 // Because the dex file is stripped, the odex file is considered the source
577 // of truth for the dex checksums. The oat file should be considered
578 // unusable.
579 std::unique_ptr<OatFile> best_file = oat_file_assistant.GetBestOatFile();
580 ASSERT_TRUE(best_file.get() != nullptr);
581 EXPECT_EQ(best_file->GetLocation(), odex_location);
582 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
583 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
584 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
585 }
586
587 // Case: We have a MultiDEX file and up-to-date ODEX file for it with relative
588 // encoded dex locations.
589 // Expect: The oat file status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,RelativeEncodedDexLocation)590 TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
591 std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
592 std::string odex_location = GetOdexDir() + "/RelativeEncodedDexLocation.odex";
593
594 // Create the dex file
595 Copy(GetMultiDexSrc1(), dex_location);
596
597 // Create the oat file with relative encoded dex location.
598 std::vector<std::string> args;
599 args.push_back("--dex-file=" + dex_location);
600 args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar"));
601 args.push_back("--oat-file=" + odex_location);
602 args.push_back("--compiler-filter=speed");
603
604 std::string error_msg;
605 ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
606
607 // Verify we can load both dex files.
608 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
609
610 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
611 ASSERT_TRUE(oat_file.get() != nullptr);
612 EXPECT_TRUE(oat_file->IsExecutable());
613 std::vector<std::unique_ptr<const DexFile>> dex_files;
614 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
615 EXPECT_EQ(2u, dex_files.size());
616 }
617
618 // Case: We have a DEX file and an OAT file out of date with respect to the
619 // dex checksum.
TEST_F(OatFileAssistantTest,OatDexOutOfDate)620 TEST_F(OatFileAssistantTest, OatDexOutOfDate) {
621 if (IsExecutedAsRoot()) {
622 // We cannot simulate non writable locations when executed as root: b/38000545.
623 LOG(ERROR) << "Test skipped because it's running as root";
624 return;
625 }
626
627 std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
628
629 // We create a dex, generate an oat for it, then overwrite the dex with a
630 // different dex to make the oat out of date.
631 Copy(GetDexSrc1(), dex_location);
632 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
633 Copy(GetDexSrc2(), dex_location);
634
635 ScopedNonWritable scoped_non_writable(dex_location);
636 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
637
638 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
639 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
640 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
641 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
642 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
643
644 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
645 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
646 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
647 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
648 }
649
650 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
651 // to the dex checksum, but no ODEX file.
TEST_F(OatFileAssistantTest,VdexDexOutOfDate)652 TEST_F(OatFileAssistantTest, VdexDexOutOfDate) {
653 std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar";
654 std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat";
655
656 Copy(GetDexSrc1(), dex_location);
657 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
658 ASSERT_EQ(0, unlink(odex_location.c_str()));
659 Copy(GetDexSrc2(), dex_location);
660
661 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
662
663 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
664 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
665 }
666
667 // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
668 // is out of date and there is no corresponding ODEX file.
TEST_F(OatFileAssistantTest,VdexMultiDexNonMainOutOfDate)669 TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
670 std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
671 std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex";
672
673 Copy(GetMultiDexSrc1(), dex_location);
674 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
675 ASSERT_EQ(0, unlink(odex_location.c_str()));
676 Copy(GetMultiDexSrc2(), dex_location);
677
678 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
679
680 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
681 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
682 }
683
684 // Case: We have a DEX file and an OAT file out of date with respect to the
685 // boot image.
TEST_F(OatFileAssistantTest,OatImageOutOfDate)686 TEST_F(OatFileAssistantTest, OatImageOutOfDate) {
687 if (IsExecutedAsRoot()) {
688 // We cannot simulate non writable locations when executed as root: b/38000545.
689 LOG(ERROR) << "Test skipped because it's running as root";
690 return;
691 }
692
693 std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
694
695 Copy(GetDexSrc1(), dex_location);
696 GenerateOatForTest(dex_location.c_str(),
697 CompilerFilter::kSpeed,
698 /*relocate*/true,
699 /*pic*/false,
700 /*with_alternate_image*/true);
701
702 ScopedNonWritable scoped_non_writable(dex_location);
703 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
704
705 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
706 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
707 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
708 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
709 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
710 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
711 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
712
713 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
714 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
715 EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
716 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
717 }
718
719 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with
720 // respect to the boot image.
721 // It shouldn't matter that the OAT file is out of date, because it is
722 // verify-at-runtime.
TEST_F(OatFileAssistantTest,OatVerifyAtRuntimeImageOutOfDate)723 TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) {
724 if (IsExecutedAsRoot()) {
725 // We cannot simulate non writable locations when executed as root: b/38000545.
726 LOG(ERROR) << "Test skipped because it's running as root";
727 return;
728 }
729
730 std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar";
731
732 Copy(GetDexSrc1(), dex_location);
733 GenerateOatForTest(dex_location.c_str(),
734 CompilerFilter::kExtract,
735 /*relocate*/true,
736 /*pic*/false,
737 /*with_alternate_image*/true);
738
739 ScopedNonWritable scoped_non_writable(dex_location);
740 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
741
742 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
743 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
744 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
745 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
746 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
747
748 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
749 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
750 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
751 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
752 }
753
754 // Case: We have a DEX file and an ODEX file, but no OAT file.
TEST_F(OatFileAssistantTest,DexOdexNoOat)755 TEST_F(OatFileAssistantTest, DexOdexNoOat) {
756 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
757 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
758
759 // Create the dex and odex files
760 Copy(GetDexSrc1(), dex_location);
761 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
762
763 // Verify the status.
764 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
765
766 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
767 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
768 EXPECT_EQ(-OatFileAssistant::kDex2OatForRelocation,
769 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
770
771 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
772 EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
773 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
774 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
775
776 // We should still be able to get the non-executable odex file to run from.
777 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
778 ASSERT_TRUE(oat_file.get() != nullptr);
779 }
780
781 // Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
TEST_F(OatFileAssistantTest,StrippedDexOdexNoOat)782 TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
783 std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
784 std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
785
786 // Create the dex and odex files
787 Copy(GetDexSrc1(), dex_location);
788 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
789
790 // Strip the dex file
791 Copy(GetStrippedDexSrc1(), dex_location);
792
793 // Verify the status.
794 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
795
796 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
797 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
798
799 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
800 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
801 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
802 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
803
804 // Verify we can load the dex files from it.
805 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
806 ASSERT_TRUE(oat_file.get() != nullptr);
807 EXPECT_TRUE(oat_file->IsExecutable());
808 std::vector<std::unique_ptr<const DexFile>> dex_files;
809 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
810 EXPECT_EQ(1u, dex_files.size());
811 }
812
813 // Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file.
TEST_F(OatFileAssistantTest,StrippedDexOdexOat)814 TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
815 std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
816 std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
817
818 // Create the oat file from a different dex file so it looks out of date.
819 Copy(GetDexSrc2(), dex_location);
820 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
821
822 // Create the odex file
823 Copy(GetDexSrc1(), dex_location);
824 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
825
826 // Strip the dex file.
827 Copy(GetStrippedDexSrc1(), dex_location);
828
829 // Verify the status.
830 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
831
832 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
833 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
834 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
835 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
836 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, // Compiling from the .vdex file
837 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
838
839 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
840 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
841 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
842 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
843
844 // Verify we can load the dex files from it.
845 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
846 ASSERT_TRUE(oat_file.get() != nullptr);
847 EXPECT_TRUE(oat_file->IsExecutable());
848 std::vector<std::unique_ptr<const DexFile>> dex_files;
849 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
850 EXPECT_EQ(1u, dex_files.size());
851 }
852
853 // Case: We have a stripped (or resource-only) DEX file, no ODEX file and no
854 // OAT file. Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,ResourceOnlyDex)855 TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
856 std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
857
858 Copy(GetStrippedDexSrc1(), dex_location);
859
860 // Verify the status.
861 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
862
863 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
864 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
865 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
866 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
867 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
868 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
869
870 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
871 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
872 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
873 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
874
875 // Make the oat file up to date. This should have no effect.
876 std::string error_msg;
877 Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
878 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
879 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) <<
880 error_msg;
881
882 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
883 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
884
885 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
886 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
887 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
888 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
889 }
890
891 // Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
892 // OAT files both have patch delta of 0.
893 // Expect: It shouldn't crash.
TEST_F(OatFileAssistantTest,OdexOatOverlap)894 TEST_F(OatFileAssistantTest, OdexOatOverlap) {
895 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
896 std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
897
898 // Create the dex, the odex and the oat files.
899 Copy(GetDexSrc1(), dex_location);
900 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
901 GenerateOatForTest(dex_location.c_str(),
902 CompilerFilter::kSpeed,
903 /*relocate*/false,
904 /*pic*/false,
905 /*with_alternate_image*/false);
906
907 // Verify things don't go bad.
908 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
909
910 // -kDex2OatForRelocation is expected rather than kDex2OatForRelocation
911 // based on the assumption that the odex location is more up-to-date than the oat
912 // location, even if they both need relocation.
913 EXPECT_EQ(-OatFileAssistant::kDex2OatForRelocation,
914 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
915
916 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
917 EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
918 EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus());
919 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
920
921 // Things aren't relocated, so it should fall back to interpreted.
922 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
923 ASSERT_TRUE(oat_file.get() != nullptr);
924
925 EXPECT_FALSE(oat_file->IsExecutable());
926 std::vector<std::unique_ptr<const DexFile>> dex_files;
927 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
928 EXPECT_EQ(1u, dex_files.size());
929 }
930
931 // Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file.
932 // Expect: The status is kNoDexOptNeeded, because VerifyAtRuntime contains no code.
TEST_F(OatFileAssistantTest,DexVerifyAtRuntimeOdexNoOat)933 TEST_F(OatFileAssistantTest, DexVerifyAtRuntimeOdexNoOat) {
934 std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar";
935 std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex";
936
937 // Create the dex and odex files
938 Copy(GetDexSrc1(), dex_location);
939 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
940
941 // Verify the status.
942 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
943
944 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
945 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
946 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
947 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
948
949 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
950 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
951 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
952 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
953 }
954
955 // Case: We have a DEX file and up-to-date OAT file for it.
956 // Expect: We should load an executable dex file.
TEST_F(OatFileAssistantTest,LoadOatUpToDate)957 TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
958 if (IsExecutedAsRoot()) {
959 // We cannot simulate non writable locations when executed as root: b/38000545.
960 LOG(ERROR) << "Test skipped because it's running as root";
961 return;
962 }
963
964 std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
965
966 Copy(GetDexSrc1(), dex_location);
967 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
968
969 ScopedNonWritable scoped_non_writable(dex_location);
970 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
971
972 // Load the oat using an oat file assistant.
973 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
974
975 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
976 ASSERT_TRUE(oat_file.get() != nullptr);
977 EXPECT_TRUE(oat_file->IsExecutable());
978 std::vector<std::unique_ptr<const DexFile>> dex_files;
979 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
980 EXPECT_EQ(1u, dex_files.size());
981 }
982
983 // Case: We have a DEX file and up-to-date quicken OAT file for it.
984 // Expect: We should still load the oat file as executable.
TEST_F(OatFileAssistantTest,LoadExecInterpretOnlyOatUpToDate)985 TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
986 if (IsExecutedAsRoot()) {
987 // We cannot simulate non writable locations when executed as root: b/38000545.
988 LOG(ERROR) << "Test skipped because it's running as root";
989 return;
990 }
991
992 std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar";
993
994 Copy(GetDexSrc1(), dex_location);
995 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
996
997 ScopedNonWritable scoped_non_writable(dex_location);
998 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
999
1000 // Load the oat using an oat file assistant.
1001 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1002
1003 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1004 ASSERT_TRUE(oat_file.get() != nullptr);
1005 EXPECT_TRUE(oat_file->IsExecutable());
1006 std::vector<std::unique_ptr<const DexFile>> dex_files;
1007 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1008 EXPECT_EQ(1u, dex_files.size());
1009 }
1010
1011 // Case: We have a DEX file and up-to-date OAT file for it.
1012 // Expect: Loading non-executable should load the oat non-executable.
TEST_F(OatFileAssistantTest,LoadNoExecOatUpToDate)1013 TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
1014 if (IsExecutedAsRoot()) {
1015 // We cannot simulate non writable locations when executed as root: b/38000545.
1016 LOG(ERROR) << "Test skipped because it's running as root";
1017 return;
1018 }
1019
1020 std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
1021
1022 Copy(GetDexSrc1(), dex_location);
1023
1024 ScopedNonWritable scoped_non_writable(dex_location);
1025 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1026
1027 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1028
1029 // Load the oat using an oat file assistant.
1030 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1031
1032 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1033 ASSERT_TRUE(oat_file.get() != nullptr);
1034 EXPECT_FALSE(oat_file->IsExecutable());
1035 std::vector<std::unique_ptr<const DexFile>> dex_files;
1036 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1037 EXPECT_EQ(1u, dex_files.size());
1038 }
1039
1040 // Case: We don't have a DEX file and can't write the oat file.
1041 // Expect: We should fail to generate the oat file without crashing.
TEST_F(OatFileAssistantTest,GenNoDex)1042 TEST_F(OatFileAssistantTest, GenNoDex) {
1043 if (IsExecutedAsRoot()) {
1044 // We cannot simulate non writable locations when executed as root: b/38000545.
1045 LOG(ERROR) << "Test skipped because it's running as root";
1046 return;
1047 }
1048
1049 std::string dex_location = GetScratchDir() + "/GenNoDex.jar";
1050
1051 ScopedNonWritable scoped_non_writable(dex_location);
1052 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1053
1054 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1055 std::string error_msg;
1056 Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
1057 // We should get kUpdateSucceeded from MakeUpToDate since there's nothing
1058 // that can be done in this situation.
1059 ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
1060 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg));
1061
1062 // Verify it didn't create an oat in the default location (dalvik-cache).
1063 OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
1064 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, ofm.OatFileStatus());
1065 // Verify it didn't create the odex file in the default location (../oat/isa/...odex)
1066 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, ofm.OdexFileStatus());
1067 }
1068
1069 // Turn an absolute path into a path relative to the current working
1070 // directory.
MakePathRelative(const std::string & target)1071 static std::string MakePathRelative(const std::string& target) {
1072 char buf[MAXPATHLEN];
1073 std::string cwd = getcwd(buf, MAXPATHLEN);
1074
1075 // Split the target and cwd paths into components.
1076 std::vector<std::string> target_path;
1077 std::vector<std::string> cwd_path;
1078 Split(target, '/', &target_path);
1079 Split(cwd, '/', &cwd_path);
1080
1081 // Reverse the path components, so we can use pop_back().
1082 std::reverse(target_path.begin(), target_path.end());
1083 std::reverse(cwd_path.begin(), cwd_path.end());
1084
1085 // Drop the common prefix of the paths. Because we reversed the path
1086 // components, this becomes the common suffix of target_path and cwd_path.
1087 while (!target_path.empty() && !cwd_path.empty()
1088 && target_path.back() == cwd_path.back()) {
1089 target_path.pop_back();
1090 cwd_path.pop_back();
1091 }
1092
1093 // For each element of the remaining cwd_path, add '..' to the beginning
1094 // of the target path. Because we reversed the path components, we add to
1095 // the end of target_path.
1096 for (unsigned int i = 0; i < cwd_path.size(); i++) {
1097 target_path.push_back("..");
1098 }
1099
1100 // Reverse again to get the right path order, and join to get the result.
1101 std::reverse(target_path.begin(), target_path.end());
1102 return android::base::Join(target_path, '/');
1103 }
1104
1105 // Case: Non-absolute path to Dex location.
1106 // Expect: Not sure, but it shouldn't crash.
TEST_F(OatFileAssistantTest,NonAbsoluteDexLocation)1107 TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
1108 std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
1109 Copy(GetDexSrc1(), abs_dex_location);
1110
1111 std::string dex_location = MakePathRelative(abs_dex_location);
1112 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1113
1114 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1115 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1116 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
1117 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1118 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1119 }
1120
1121 // Case: Very short, non-existent Dex location.
1122 // Expect: kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,ShortDexLocation)1123 TEST_F(OatFileAssistantTest, ShortDexLocation) {
1124 std::string dex_location = "/xx";
1125
1126 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1127
1128 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1129 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1130 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
1131 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1132 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1133 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
1134
1135 // Trying to make it up to date should have no effect.
1136 std::string error_msg;
1137 Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
1138 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
1139 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg));
1140 EXPECT_TRUE(error_msg.empty());
1141 }
1142
1143 // Case: Non-standard extension for dex file.
1144 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,LongDexExtension)1145 TEST_F(OatFileAssistantTest, LongDexExtension) {
1146 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
1147 Copy(GetDexSrc1(), dex_location);
1148
1149 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1150
1151 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1152 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
1153
1154 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1155 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1156 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1157 }
1158
1159 // A task to generate a dex location. Used by the RaceToGenerate test.
1160 class RaceGenerateTask : public Task {
1161 public:
RaceGenerateTask(const std::string & dex_location,const std::string & oat_location)1162 explicit RaceGenerateTask(const std::string& dex_location, const std::string& oat_location)
1163 : dex_location_(dex_location), oat_location_(oat_location), loaded_oat_file_(nullptr)
1164 {}
1165
Run(Thread * self ATTRIBUTE_UNUSED)1166 void Run(Thread* self ATTRIBUTE_UNUSED) {
1167 // Load the dex files, and save a pointer to the loaded oat file, so that
1168 // we can verify only one oat file was loaded for the dex location.
1169 std::vector<std::unique_ptr<const DexFile>> dex_files;
1170 std::vector<std::string> error_msgs;
1171 const OatFile* oat_file = nullptr;
1172 dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1173 dex_location_.c_str(),
1174 Runtime::Current()->GetSystemClassLoader(),
1175 /*dex_elements*/nullptr,
1176 &oat_file,
1177 &error_msgs);
1178 CHECK(!dex_files.empty()) << android::base::Join(error_msgs, '\n');
1179 CHECK(dex_files[0]->GetOatDexFile() != nullptr) << dex_files[0]->GetLocation();
1180 loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile();
1181 CHECK_EQ(loaded_oat_file_, oat_file);
1182 }
1183
GetLoadedOatFile() const1184 const OatFile* GetLoadedOatFile() const {
1185 return loaded_oat_file_;
1186 }
1187
1188 private:
1189 std::string dex_location_;
1190 std::string oat_location_;
1191 const OatFile* loaded_oat_file_;
1192 };
1193
1194 // Test the case where multiple processes race to generate an oat file.
1195 // This simulates multiple processes using multiple threads.
1196 //
1197 // We want unique Oat files to be loaded even when there is a race to load.
1198 // TODO: The test case no longer tests locking the way it was intended since we now get multiple
1199 // copies of the same Oat files mapped at different locations.
TEST_F(OatFileAssistantTest,RaceToGenerate)1200 TEST_F(OatFileAssistantTest, RaceToGenerate) {
1201 std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
1202 std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
1203
1204 // Start the runtime to initialize the system's class loader.
1205 Thread::Current()->TransitionFromSuspendedToRunnable();
1206 runtime_->Start();
1207
1208 // We use the lib core dex file, because it's large, and hopefully should
1209 // take a while to generate.
1210 Copy(GetLibCoreDexFileNames()[0], dex_location);
1211
1212 const int kNumThreads = 32;
1213 Thread* self = Thread::Current();
1214 ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads);
1215 std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
1216 for (int i = 0; i < kNumThreads; i++) {
1217 std::unique_ptr<RaceGenerateTask> task(new RaceGenerateTask(dex_location, oat_location));
1218 thread_pool.AddTask(self, task.get());
1219 tasks.push_back(std::move(task));
1220 }
1221 thread_pool.StartWorkers(self);
1222 thread_pool.Wait(self, true, false);
1223
1224 // Verify every task got a unique oat file.
1225 std::set<const OatFile*> oat_files;
1226 for (auto& task : tasks) {
1227 const OatFile* oat_file = task->GetLoadedOatFile();
1228 EXPECT_TRUE(oat_files.find(oat_file) == oat_files.end());
1229 oat_files.insert(oat_file);
1230 }
1231 }
1232
1233 // Case: We have a DEX file and an ODEX file, no OAT file, and dex2oat is
1234 // disabled.
1235 // Expect: We should load the odex file non-executable.
TEST_F(OatFileAssistantNoDex2OatTest,LoadDexOdexNoOat)1236 TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
1237 std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
1238 std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
1239
1240 // Create the dex and odex files
1241 Copy(GetDexSrc1(), dex_location);
1242 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1243
1244 // Load the oat using an executable oat file assistant.
1245 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1246
1247 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1248 ASSERT_TRUE(oat_file.get() != nullptr);
1249 EXPECT_FALSE(oat_file->IsExecutable());
1250 std::vector<std::unique_ptr<const DexFile>> dex_files;
1251 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1252 EXPECT_EQ(1u, dex_files.size());
1253 }
1254
1255 // Case: We have a MultiDEX file and an ODEX file, no OAT file, and dex2oat is
1256 // disabled.
1257 // Expect: We should load the odex file non-executable.
TEST_F(OatFileAssistantNoDex2OatTest,LoadMultiDexOdexNoOat)1258 TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
1259 std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
1260 std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
1261
1262 // Create the dex and odex files
1263 Copy(GetMultiDexSrc1(), dex_location);
1264 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1265
1266 // Load the oat using an executable oat file assistant.
1267 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1268
1269 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1270 ASSERT_TRUE(oat_file.get() != nullptr);
1271 EXPECT_FALSE(oat_file->IsExecutable());
1272 std::vector<std::unique_ptr<const DexFile>> dex_files;
1273 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1274 EXPECT_EQ(2u, dex_files.size());
1275 }
1276
TEST_F(OatFileAssistantTest,RuntimeCompilerFilterOptionUsed)1277 TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) {
1278 std::string dex_location = GetScratchDir() + "/RuntimeCompilerFilterOptionUsed.jar";
1279 Copy(GetDexSrc1(), dex_location);
1280
1281 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1282
1283 std::string error_msg;
1284 Runtime::Current()->AddCompilerOption("--compiler-filter=quicken");
1285 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
1286 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) <<
1287 error_msg;
1288 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1289 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
1290 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
1291 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
1292
1293 Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
1294 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
1295 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg))
1296 << error_msg;
1297 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1298 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
1299 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1300 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
1301
1302 Runtime::Current()->AddCompilerOption("--compiler-filter=bogus");
1303 EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted,
1304 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg));
1305 }
1306
TEST(OatFileAssistantUtilsTest,DexLocationToOdexFilename)1307 TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) {
1308 std::string error_msg;
1309 std::string odex_file;
1310
1311 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1312 "/foo/bar/baz.jar", InstructionSet::kArm, &odex_file, &error_msg)) << error_msg;
1313 EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1314
1315 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1316 "/foo/bar/baz.funnyext", InstructionSet::kArm, &odex_file, &error_msg)) << error_msg;
1317 EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1318
1319 EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1320 "nopath.jar", InstructionSet::kArm, &odex_file, &error_msg));
1321 EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1322 "/foo/bar/baz_noext", InstructionSet::kArm, &odex_file, &error_msg));
1323 }
1324
1325 // Verify the dexopt status values from dalvik.system.DexFile
1326 // match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantTest,DexOptStatusValues)1327 TEST_F(OatFileAssistantTest, DexOptStatusValues) {
1328 std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = {
1329 {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"},
1330 {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"},
1331 {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
1332 {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
1333 {OatFileAssistant::kDex2OatForRelocation, "DEX2OAT_FOR_RELOCATION"},
1334 };
1335
1336 ScopedObjectAccess soa(Thread::Current());
1337 StackHandleScope<1> hs(soa.Self());
1338 ClassLinker* linker = Runtime::Current()->GetClassLinker();
1339 Handle<mirror::Class> dexfile(
1340 hs.NewHandle(linker->FindSystemClass(soa.Self(), "Ldalvik/system/DexFile;")));
1341 ASSERT_FALSE(dexfile == nullptr);
1342 linker->EnsureInitialized(soa.Self(), dexfile, true, true);
1343
1344 for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) {
1345 ArtField* art_field = mirror::Class::FindStaticField(
1346 soa.Self(), dexfile.Get(), field.second, "I");
1347 ASSERT_FALSE(art_field == nullptr);
1348 EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
1349 EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get()));
1350 }
1351 }
1352
1353 // Verify that when no compiler filter is passed the default one from OatFileAssistant is used.
TEST_F(OatFileAssistantTest,DefaultMakeUpToDateFilter)1354 TEST_F(OatFileAssistantTest, DefaultMakeUpToDateFilter) {
1355 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1356 Copy(GetDexSrc1(), dex_location);
1357
1358 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1359
1360 const CompilerFilter::Filter default_filter =
1361 OatFileAssistant::kDefaultCompilerFilterForDexLoading;
1362 std::string error_msg;
1363 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
1364 oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) <<
1365 error_msg;
1366 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1367 oat_file_assistant.GetDexOptNeeded(default_filter));
1368 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1369 EXPECT_NE(nullptr, oat_file.get());
1370 EXPECT_EQ(default_filter, oat_file->GetCompilerFilter());
1371 }
1372
TEST_F(OatFileAssistantTest,MakeUpToDateWithSpecialSharedLibrary)1373 TEST_F(OatFileAssistantTest, MakeUpToDateWithSpecialSharedLibrary) {
1374 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1375 Copy(GetDexSrc1(), dex_location);
1376
1377 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1378
1379 const CompilerFilter::Filter default_filter =
1380 OatFileAssistant::kDefaultCompilerFilterForDexLoading;
1381 std::string error_msg;
1382 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1383 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1384 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1385 oat_file_assistant.GetDexOptNeeded(default_filter));
1386 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1387 EXPECT_NE(nullptr, oat_file.get());
1388 EXPECT_EQ(kSpecialSharedLibrary,
1389 oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
1390 }
1391
TEST_F(OatFileAssistantTest,MakeUpToDateWithContext)1392 TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) {
1393 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1394 std::string context_location = GetScratchDir() + "/ContextDex.jar";
1395 Copy(GetDexSrc1(), dex_location);
1396 Copy(GetDexSrc2(), context_location);
1397
1398 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1399
1400 const CompilerFilter::Filter default_filter =
1401 OatFileAssistant::kDefaultCompilerFilterForDexLoading;
1402 std::string error_msg;
1403 std::string context_str = "PCL[" + context_location + "]";
1404 std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
1405 ASSERT_TRUE(context != nullptr);
1406 ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
1407
1408 int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg);
1409 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1410 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1411 oat_file_assistant.GetDexOptNeeded(default_filter, false, false, context.get()));
1412
1413 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1414 EXPECT_NE(nullptr, oat_file.get());
1415 EXPECT_EQ(context->EncodeContextForOatFile(""),
1416 oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
1417 }
1418
TEST_F(OatFileAssistantTest,MakeUpToDateWithHiddenApiDisabled)1419 TEST_F(OatFileAssistantTest, MakeUpToDateWithHiddenApiDisabled) {
1420 hiddenapi::ScopedHiddenApiEnforcementPolicySetting hiddenapi_exemption(
1421 hiddenapi::EnforcementPolicy::kNoChecks);
1422
1423 std::string dex_location = GetScratchDir() + "/TestDexHiddenApiDisabled.jar";
1424 Copy(GetDexSrc1(), dex_location);
1425
1426 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1427 std::string error_msg;
1428 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1429 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1430
1431 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1432 EXPECT_NE(nullptr, oat_file.get());
1433
1434 const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey);
1435 EXPECT_NE(nullptr, cmd_line);
1436 EXPECT_EQ(nullptr, strstr(cmd_line, kDex2oatCmdLineHiddenApiArg));
1437 }
1438
TEST_F(OatFileAssistantTest,MakeUpToDateWithHiddenApiEnabled)1439 TEST_F(OatFileAssistantTest, MakeUpToDateWithHiddenApiEnabled) {
1440 hiddenapi::ScopedHiddenApiEnforcementPolicySetting hiddenapi_exemption(
1441 hiddenapi::EnforcementPolicy::kBlacklistOnly);
1442
1443 std::string dex_location = GetScratchDir() + "/TestDexHiddenApiEnabled.jar";
1444 Copy(GetDexSrc1(), dex_location);
1445
1446 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1447 std::string error_msg;
1448 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1449 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1450
1451 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1452 EXPECT_NE(nullptr, oat_file.get());
1453
1454 const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey);
1455 EXPECT_NE(nullptr, cmd_line);
1456 EXPECT_NE(nullptr, strstr(cmd_line, kDex2oatCmdLineHiddenApiArg));
1457 }
1458
TEST_F(OatFileAssistantTest,GetDexOptNeededWithOutOfDateContext)1459 TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) {
1460 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1461 std::string context_location = GetScratchDir() + "/ContextDex.jar";
1462 Copy(GetDexSrc1(), dex_location);
1463 Copy(GetDexSrc2(), context_location);
1464
1465 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1466
1467 const CompilerFilter::Filter default_filter =
1468 OatFileAssistant::kDefaultCompilerFilterForDexLoading;
1469 std::string error_msg;
1470 std::string context_str = "PCL[" + context_location + "]";
1471 std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
1472 ASSERT_TRUE(context != nullptr);
1473 ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
1474
1475 int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg);
1476 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1477 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1478 oat_file_assistant.GetDexOptNeeded(default_filter, false, false, context.get()));
1479
1480 // Update the context by overriding the jar file.
1481 Copy(GetMultiDexSrc2(), context_location);
1482 std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1483 ASSERT_TRUE(updated_context != nullptr);
1484 // DexOptNeeded should advise compilation from scratch.
1485 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1486 oat_file_assistant.GetDexOptNeeded(
1487 default_filter, false, false, updated_context.get()));
1488 }
1489
TEST_F(OatFileAssistantTest,GetDexOptNeededWithUpToDateContextRelative)1490 TEST_F(OatFileAssistantTest, GetDexOptNeededWithUpToDateContextRelative) {
1491 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1492 std::string context_location = GetScratchDir() + "/ContextDex.jar";
1493 Copy(GetDexSrc1(), dex_location);
1494 Copy(GetDexSrc2(), context_location);
1495
1496 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1497
1498 const CompilerFilter::Filter default_filter =
1499 OatFileAssistant::kDefaultCompilerFilterForDexLoading;
1500 std::string error_msg;
1501 std::string context_str = "PCL[" + context_location + "]";
1502 std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
1503 ASSERT_TRUE(context != nullptr);
1504 ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
1505
1506 int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg);
1507 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1508
1509 // A relative context simulates a dependent split context.
1510 std::unique_ptr<ClassLoaderContext> relative_context =
1511 ClassLoaderContext::Create("PCL[ContextDex.jar]");
1512 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1513 oat_file_assistant.GetDexOptNeeded(
1514 default_filter, false, false, relative_context.get()));
1515 }
1516
TEST_F(OatFileAssistantTest,SystemOdex)1517 TEST_F(OatFileAssistantTest, SystemOdex) {
1518 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
1519 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
1520 std::string system_location = GetAndroidRoot() + "/OatUpToDate.jar";
1521
1522 std::string error_msg;
1523
1524 Copy(GetDexSrc1(), dex_location);
1525 EXPECT_FALSE(LocationIsOnSystem(dex_location.c_str()));
1526
1527 {
1528 OatFileAssistant oat_file_assistant(dex_location.c_str(),
1529 kRuntimeISA,
1530 true,
1531 false);
1532 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1533 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1534 EXPECT_TRUE(oat_file_assistant.GetBestOatFile()->IsExecutable());
1535 }
1536
1537 {
1538 OatFileAssistant oat_file_assistant(dex_location.c_str(),
1539 kRuntimeISA,
1540 true,
1541 true);
1542 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1543 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1544 EXPECT_FALSE(oat_file_assistant.GetBestOatFile()->IsExecutable());
1545 }
1546
1547 Copy(GetDexSrc1(), system_location);
1548 EXPECT_TRUE(LocationIsOnSystem(system_location.c_str()));
1549
1550 {
1551 OatFileAssistant oat_file_assistant(system_location.c_str(),
1552 kRuntimeISA,
1553 true,
1554 false);
1555 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1556 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1557 EXPECT_TRUE(oat_file_assistant.GetBestOatFile()->IsExecutable());
1558 }
1559
1560 {
1561 OatFileAssistant oat_file_assistant(system_location.c_str(),
1562 kRuntimeISA,
1563 true,
1564 true);
1565 int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg);
1566 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg;
1567 EXPECT_TRUE(oat_file_assistant.GetBestOatFile()->IsExecutable());
1568 }
1569 }
1570
1571 // TODO: More Tests:
1572 // * Test class linker falls back to unquickened dex for DexNoOat
1573 // * Test class linker falls back to unquickened dex for MultiDexNoOat
1574 // * Test using secondary isa
1575 // * Test for status of oat while oat is being generated (how?)
1576 // * Test case where 32 and 64 bit boot class paths differ,
1577 // and we ask IsInBootClassPath for a class in exactly one of the 32 or
1578 // 64 bit boot class paths.
1579 // * Test unexpected scenarios (?):
1580 // - Dex is stripped, don't have odex.
1581 // - Oat file corrupted after status check, before reload unexecutable
1582 // because it's unrelocated and no dex2oat
1583 } // namespace art
1584