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 <fcntl.h>
20 #include <gtest/gtest.h>
21 #include <sys/param.h>
22
23 #include <functional>
24 #include <iterator>
25 #include <memory>
26 #include <optional>
27 #include <string>
28 #include <type_traits>
29 #include <vector>
30
31 #include "android-base/scopeguard.h"
32 #include "android-base/strings.h"
33 #include "arch/instruction_set.h"
34 #include "art_field-inl.h"
35 #include "base/os.h"
36 #include "base/utils.h"
37 #include "class_linker.h"
38 #include "class_loader_context.h"
39 #include "common_runtime_test.h"
40 #include "dexopt_test.h"
41 #include "oat.h"
42 #include "oat_file.h"
43 #include "oat_file_assistant_context.h"
44 #include "oat_file_manager.h"
45 #include "scoped_thread_state_change.h"
46 #include "thread.h"
47
48 namespace art HIDDEN {
49
50 class OatFileAssistantBaseTest : public DexoptTest {};
51
52 class OatFileAssistantTest : public OatFileAssistantBaseTest,
53 public testing::WithParamInterface<bool> {
54 public:
SetUp()55 void SetUp() override {
56 DexoptTest::SetUp();
57 with_runtime_ = GetParam();
58 ofa_context_ = CreateOatFileAssistantContext();
59 }
60
61 // Verifies all variants of `GetOptimizationStatus`.
62 //
63 // `expected_filter` can be either a value of `CompilerFilter::Filter` or a string.
64 // If `check_context` is true, only verifies the variants that checks class loader context.
65 template <typename T>
VerifyOptimizationStatus(const std::string & file,ClassLoaderContext * context,const T & expected_filter,const std::string & expected_reason,const std::string & expected_odex_status,OatFileAssistant::Location expected_location,bool check_context=false)66 void VerifyOptimizationStatus(const std::string& file,
67 ClassLoaderContext* context,
68 const T& expected_filter,
69 const std::string& expected_reason,
70 const std::string& expected_odex_status,
71 OatFileAssistant::Location expected_location,
72 bool check_context = false) {
73 std::string expected_filter_name;
74 if constexpr (std::is_same_v<T, CompilerFilter::Filter>) {
75 expected_filter_name = CompilerFilter::NameOfFilter(expected_filter);
76 } else {
77 expected_filter_name = expected_filter;
78 }
79
80 // Verify the static method (called from PM for dumpsys).
81 // This variant does not check class loader context.
82 if (!check_context) {
83 std::string compilation_filter;
84 std::string compilation_reason;
85
86 OatFileAssistant::GetOptimizationStatus(file,
87 kRuntimeISA,
88 &compilation_filter,
89 &compilation_reason,
90 MaybeGetOatFileAssistantContext());
91
92 ASSERT_EQ(expected_filter_name, compilation_filter);
93 ASSERT_EQ(expected_reason, compilation_reason);
94 }
95
96 // Verify the instance methods (called at runtime and from artd).
97 OatFileAssistant assistant = CreateOatFileAssistant(file.c_str(), context);
98 VerifyOptimizationStatusWithInstance(
99 &assistant, expected_filter_name, expected_reason, expected_odex_status, expected_location);
100 }
101
VerifyOptimizationStatusWithInstance(OatFileAssistant * assistant,const std::string & expected_filter,const std::string & expected_reason,const std::string & expected_odex_status,OatFileAssistant::Location expected_location)102 void VerifyOptimizationStatusWithInstance(OatFileAssistant* assistant,
103 const std::string& expected_filter,
104 const std::string& expected_reason,
105 const std::string& expected_odex_status,
106 OatFileAssistant::Location expected_location) {
107 std::string odex_location; // ignored
108 std::string compilation_filter;
109 std::string compilation_reason;
110 std::string odex_status;
111 OatFileAssistant::Location location;
112
113 assistant->GetOptimizationStatus(
114 &odex_location, &compilation_filter, &compilation_reason, &odex_status, &location);
115
116 ASSERT_EQ(expected_filter, compilation_filter);
117 ASSERT_EQ(expected_reason, compilation_reason);
118 ASSERT_EQ(expected_odex_status, odex_status);
119 ASSERT_EQ(expected_location, location);
120 }
121
InsertNewBootClasspathEntry(const std::string & src,std::string * error_msg)122 bool InsertNewBootClasspathEntry(const std::string& src, std::string* error_msg) {
123 std::vector<std::unique_ptr<const DexFile>> dex_files;
124 ArtDexFileLoader dex_file_loader(src);
125 if (!dex_file_loader.Open(/*verify=*/true,
126 /*verify_checksum=*/false,
127 error_msg,
128 &dex_files)) {
129 return false;
130 }
131
132 runtime_->AppendToBootClassPath(src, src, dex_files);
133 std::move(dex_files.begin(), dex_files.end(), std::back_inserter(opened_dex_files_));
134
135 return true;
136 }
137
138 // Verifies the current version of `GetDexOptNeeded` (called from artd).
VerifyGetDexOptNeeded(OatFileAssistant * assistant,CompilerFilter::Filter compiler_filter,OatFileAssistant::DexOptTrigger dexopt_trigger,bool expected_dexopt_needed,bool expected_is_vdex_usable,OatFileAssistant::Location expected_location)139 void VerifyGetDexOptNeeded(OatFileAssistant* assistant,
140 CompilerFilter::Filter compiler_filter,
141 OatFileAssistant::DexOptTrigger dexopt_trigger,
142 bool expected_dexopt_needed,
143 bool expected_is_vdex_usable,
144 OatFileAssistant::Location expected_location) {
145 OatFileAssistant::DexOptStatus status;
146 EXPECT_EQ(
147 assistant->GetDexOptNeeded(compiler_filter, dexopt_trigger, &status),
148 expected_dexopt_needed);
149 EXPECT_EQ(status.IsVdexUsable(), expected_is_vdex_usable);
150 EXPECT_EQ(status.GetLocation(), expected_location);
151 }
152
153 // Verifies all versions of `GetDexOptNeeded` with the default dexopt trigger.
VerifyGetDexOptNeededDefault(OatFileAssistant * assistant,CompilerFilter::Filter compiler_filter,bool expected_dexopt_needed,bool expected_is_vdex_usable,OatFileAssistant::Location expected_location,int expected_legacy_result)154 void VerifyGetDexOptNeededDefault(OatFileAssistant* assistant,
155 CompilerFilter::Filter compiler_filter,
156 bool expected_dexopt_needed,
157 bool expected_is_vdex_usable,
158 OatFileAssistant::Location expected_location,
159 int expected_legacy_result) {
160 // Verify the current version (called from artd).
161 VerifyGetDexOptNeeded(assistant,
162 compiler_filter,
163 default_trigger_,
164 expected_dexopt_needed,
165 expected_is_vdex_usable,
166 expected_location);
167
168 // Verify the legacy version (called from PM).
169 EXPECT_EQ(
170 assistant->GetDexOptNeeded(compiler_filter, /*profile_changed=*/false, /*downgrade=*/false),
171 expected_legacy_result);
172 }
173
InitializeDefaultContext()174 static std::unique_ptr<ClassLoaderContext> InitializeDefaultContext() {
175 auto context = ClassLoaderContext::Default();
176 context->OpenDexFiles();
177 return context;
178 }
179
180 // Temporarily disables the pointer to the current runtime if `with_runtime_` is false.
181 // Essentially simulates an environment where there is no active runtime.
ScopedMaybeWithoutRuntime()182 android::base::ScopeGuard<std::function<void()>> ScopedMaybeWithoutRuntime() {
183 if (!with_runtime_) {
184 Runtime::TestOnlySetCurrent(nullptr);
185 }
186 return android::base::make_scope_guard(
187 [this]() { Runtime::TestOnlySetCurrent(runtime_.get()); });
188 }
189
CreateOatFileAssistantContext()190 std::unique_ptr<OatFileAssistantContext> CreateOatFileAssistantContext() {
191 return std::make_unique<OatFileAssistantContext>(
192 std::make_unique<OatFileAssistantContext::RuntimeOptions>(
193 OatFileAssistantContext::RuntimeOptions{
194 .image_locations = runtime_->GetImageLocations(),
195 .boot_class_path = runtime_->GetBootClassPath(),
196 .boot_class_path_locations = runtime_->GetBootClassPathLocations(),
197 .boot_class_path_files = !runtime_->GetBootClassPathFiles().empty() ?
198 runtime_->GetBootClassPathFiles() :
199 std::optional<ArrayRef<File>>(),
200 .deny_art_apex_data_files = runtime_->DenyArtApexDataFiles(),
201 }));
202 }
203
MaybeGetOatFileAssistantContext()204 OatFileAssistantContext* MaybeGetOatFileAssistantContext() {
205 return with_runtime_ ? nullptr : ofa_context_.get();
206 }
207
208 // A helper function to create OatFileAssistant with some default arguments.
CreateOatFileAssistant(const char * dex_location,ClassLoaderContext * context=nullptr,bool load_executable=false,int vdex_fd=-1,int oat_fd=-1,int zip_fd=-1)209 OatFileAssistant CreateOatFileAssistant(const char* dex_location,
210 ClassLoaderContext* context = nullptr,
211 bool load_executable = false,
212 int vdex_fd = -1,
213 int oat_fd = -1,
214 int zip_fd = -1) {
215 return OatFileAssistant(dex_location,
216 kRuntimeISA,
217 context != nullptr ? context : default_context_.get(),
218 load_executable,
219 /*only_load_trusted_executable=*/false,
220 MaybeGetOatFileAssistantContext(),
221 vdex_fd,
222 oat_fd,
223 zip_fd);
224 }
225
ExpectHasDexFiles(OatFileAssistant * oat_file_assistant,bool expected_value)226 void ExpectHasDexFiles(OatFileAssistant* oat_file_assistant, bool expected_value) {
227 std::string error_msg;
228 std::optional<bool> has_dex_files = oat_file_assistant->HasDexFiles(&error_msg);
229 ASSERT_TRUE(has_dex_files.has_value()) << error_msg;
230 EXPECT_EQ(*has_dex_files, expected_value);
231 }
232
233 std::unique_ptr<ClassLoaderContext> default_context_ = InitializeDefaultContext();
234 bool with_runtime_;
235 const OatFileAssistant::DexOptTrigger default_trigger_{
236 .targetFilterIsBetter = true, .primaryBootImageBecomesUsable = true, .needExtraction = true};
237 std::unique_ptr<OatFileAssistantContext> ofa_context_;
238 std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
239 };
240
241 class ScopedNonWritable {
242 public:
ScopedNonWritable(const std::string & dex_location)243 explicit ScopedNonWritable(const std::string& dex_location) {
244 is_valid_ = false;
245 size_t pos = dex_location.rfind('/');
246 if (pos != std::string::npos) {
247 is_valid_ = true;
248 dex_parent_ = dex_location.substr(0, pos);
249 if (chmod(dex_parent_.c_str(), 0555) != 0) {
250 PLOG(ERROR) << "Could not change permissions on " << dex_parent_;
251 }
252 }
253 }
254
IsSuccessful()255 bool IsSuccessful() { return is_valid_ && (access(dex_parent_.c_str(), W_OK) != 0); }
256
~ScopedNonWritable()257 ~ScopedNonWritable() {
258 if (is_valid_) {
259 if (chmod(dex_parent_.c_str(), 0777) != 0) {
260 PLOG(ERROR) << "Could not restore permissions on " << dex_parent_;
261 }
262 }
263 }
264
265 private:
266 std::string dex_parent_;
267 bool is_valid_;
268 };
269
IsExecutedAsRoot()270 static bool IsExecutedAsRoot() {
271 return geteuid() == 0;
272 }
273
274 // Case: We have a MultiDEX file and up-to-date ODEX file for it with relative
275 // encoded dex locations.
276 // Expect: The oat file status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,RelativeEncodedDexLocation)277 TEST_P(OatFileAssistantTest, RelativeEncodedDexLocation) {
278 std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
279 std::string odex_location = GetOdexDir() + "/RelativeEncodedDexLocation.odex";
280
281 // Create the dex file
282 Copy(GetMultiDexSrc1(), dex_location);
283
284 // Create the oat file with relative encoded dex location.
285 std::vector<std::string> args = {
286 "--dex-file=" + dex_location,
287 "--dex-location=" + std::string("RelativeEncodedDexLocation.jar"),
288 "--oat-file=" + odex_location,
289 "--compiler-filter=speed"
290 };
291
292 std::string error_msg;
293 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
294
295 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
296
297 // Verify we can load both dex files.
298 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
299 /*context=*/nullptr,
300 /*load_executable=*/true);
301
302 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
303 ASSERT_TRUE(oat_file.get() != nullptr);
304 if (with_runtime_) {
305 EXPECT_TRUE(oat_file->IsExecutable());
306 }
307 std::vector<std::unique_ptr<const DexFile>> dex_files;
308 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
309 EXPECT_EQ(2u, dex_files.size());
310 }
311
TEST_P(OatFileAssistantTest,MakeUpToDateWithContext)312 TEST_P(OatFileAssistantTest, MakeUpToDateWithContext) {
313 std::string dex_location = GetScratchDir() + "/TestDex.jar";
314 std::string odex_location = GetOdexDir() + "/TestDex.odex";
315 std::string context_location = GetScratchDir() + "/ContextDex.jar";
316 Copy(GetDexSrc1(), dex_location);
317 Copy(GetDexSrc2(), context_location);
318
319 std::string context_str = "PCL[" + context_location + "]";
320 std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
321 ASSERT_TRUE(context != nullptr);
322 ASSERT_TRUE(context->OpenDexFiles());
323
324 std::string error_msg;
325 std::vector<std::string> args;
326 args.push_back("--dex-file=" + dex_location);
327 args.push_back("--oat-file=" + odex_location);
328 args.push_back("--class-loader-context=" + context_str);
329 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
330
331 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
332
333 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(), context.get());
334
335 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
336 ASSERT_NE(nullptr, oat_file.get());
337 ASSERT_NE(nullptr, oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
338 EXPECT_EQ(context->EncodeContextForOatFile(""),
339 oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
340 }
341
TEST_P(OatFileAssistantTest,GetDexOptNeededWithUpToDateContextRelative)342 TEST_P(OatFileAssistantTest, GetDexOptNeededWithUpToDateContextRelative) {
343 std::string dex_location = GetScratchDir() + "/TestDex.jar";
344 std::string odex_location = GetOdexDir() + "/TestDex.odex";
345 std::string context_location = GetScratchDir() + "/ContextDex.jar";
346 Copy(GetDexSrc1(), dex_location);
347 Copy(GetDexSrc2(), context_location);
348
349 // A relative context simulates a dependent split context.
350 std::unique_ptr<ClassLoaderContext> relative_context =
351 ClassLoaderContext::Create("PCL[ContextDex.jar]");
352 ASSERT_TRUE(relative_context != nullptr);
353 std::vector<int> context_fds;
354 ASSERT_TRUE(relative_context->OpenDexFiles(GetScratchDir(), context_fds));
355
356 std::string error_msg;
357 std::vector<std::string> args;
358 args.push_back("--dex-file=" + dex_location);
359 args.push_back("--oat-file=" + odex_location);
360 args.push_back("--class-loader-context=PCL[" + context_location + "]");
361 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
362
363 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
364
365 OatFileAssistant oat_file_assistant =
366 CreateOatFileAssistant(dex_location.c_str(), relative_context.get());
367
368 VerifyGetDexOptNeededDefault(&oat_file_assistant,
369 CompilerFilter::kDefaultCompilerFilter,
370 /*expected_dexopt_needed=*/false,
371 /*expected_is_vdex_usable=*/true,
372 /*expected_location=*/OatFileAssistant::kLocationOdex,
373 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
374 }
375
376 // Case: We have a DEX file, but no OAT file for it.
377 // Expect: The status is kDex2OatNeeded.
TEST_P(OatFileAssistantTest,DexNoOat)378 TEST_P(OatFileAssistantTest, DexNoOat) {
379 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
380 Copy(GetDexSrc1(), dex_location);
381
382 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
383
384 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
385
386 VerifyGetDexOptNeededDefault(&oat_file_assistant,
387 CompilerFilter::kVerify,
388 /*expected_dexopt_needed=*/true,
389 /*expected_is_vdex_usable=*/false,
390 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
391 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
392 VerifyGetDexOptNeededDefault(&oat_file_assistant,
393 CompilerFilter::kSpeedProfile,
394 /*expected_dexopt_needed=*/true,
395 /*expected_is_vdex_usable=*/false,
396 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
397 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
398 VerifyGetDexOptNeededDefault(&oat_file_assistant,
399 CompilerFilter::kSpeed,
400 /*expected_dexopt_needed=*/true,
401 /*expected_is_vdex_usable=*/false,
402 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
403 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
404
405 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
406 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
407 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
408 ExpectHasDexFiles(&oat_file_assistant, true);
409
410 VerifyOptimizationStatus(dex_location,
411 default_context_.get(),
412 "run-from-apk",
413 "unknown",
414 "io-error-no-oat",
415 OatFileAssistant::kLocationNoneOrError);
416 }
417
418 // Case: We have no DEX file and no OAT file.
419 // Expect: Status is kNoDexOptNeeded. Loading should fail, but not crash.
TEST_P(OatFileAssistantTest,NoDexNoOat)420 TEST_P(OatFileAssistantTest, NoDexNoOat) {
421 std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
422
423 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
424
425 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
426
427 VerifyGetDexOptNeededDefault(&oat_file_assistant,
428 CompilerFilter::kSpeed,
429 /*expected_dexopt_needed=*/false,
430 /*expected_is_vdex_usable=*/false,
431 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
432 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
433 std::string error_msg_ignored;
434 EXPECT_FALSE(oat_file_assistant.HasDexFiles(&error_msg_ignored).has_value());
435
436 // Trying to get the best oat file should fail, but not crash.
437 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
438 EXPECT_EQ(nullptr, oat_file.get());
439
440 VerifyOptimizationStatusWithInstance(&oat_file_assistant,
441 "unknown",
442 "unknown",
443 "io-error-no-apk",
444 OatFileAssistant::kLocationNoneOrError);
445 }
446
447 // Case: We have a DEX file and an ODEX file, but no OAT file.
448 // Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,OdexUpToDate)449 TEST_P(OatFileAssistantTest, OdexUpToDate) {
450 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
451 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
452 Copy(GetDexSrc1(), dex_location);
453 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
454
455 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
456
457 // Force the use of oat location by making the dex parent not writable.
458 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
459
460 VerifyGetDexOptNeededDefault(&oat_file_assistant,
461 CompilerFilter::kSpeed,
462 /*expected_dexopt_needed=*/false,
463 /*expected_is_vdex_usable=*/true,
464 /*expected_location=*/OatFileAssistant::kLocationOdex,
465 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
466 VerifyGetDexOptNeededDefault(&oat_file_assistant,
467 CompilerFilter::kVerify,
468 /*expected_dexopt_needed=*/false,
469 /*expected_is_vdex_usable=*/true,
470 /*expected_location=*/OatFileAssistant::kLocationOdex,
471 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
472 VerifyGetDexOptNeededDefault(&oat_file_assistant,
473 CompilerFilter::kEverything,
474 /*expected_dexopt_needed=*/true,
475 /*expected_is_vdex_usable=*/true,
476 /*expected_location=*/OatFileAssistant::kLocationOdex,
477 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
478
479 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
480 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
481 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
482 ExpectHasDexFiles(&oat_file_assistant, true);
483
484 VerifyOptimizationStatus(dex_location,
485 default_context_.get(),
486 CompilerFilter::kSpeed,
487 "install",
488 "up-to-date",
489 OatFileAssistant::kLocationOdex);
490 }
491
492 // Case: We have an ODEX file compiled against partial boot image.
493 // Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,OdexUpToDatePartialBootImage)494 TEST_P(OatFileAssistantTest, OdexUpToDatePartialBootImage) {
495 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
496 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
497 Copy(GetDexSrc1(), dex_location);
498 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
499
500 // Insert an extra dex file to the boot class path.
501 std::string error_msg;
502 ASSERT_TRUE(InsertNewBootClasspathEntry(GetMultiDexSrc1(), &error_msg)) << error_msg;
503
504 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
505
506 // Force the use of oat location by making the dex parent not writable.
507 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
508
509 VerifyGetDexOptNeededDefault(&oat_file_assistant,
510 CompilerFilter::kSpeed,
511 /*expected_dexopt_needed=*/false,
512 /*expected_is_vdex_usable=*/true,
513 /*expected_location=*/OatFileAssistant::kLocationOdex,
514 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
515 VerifyGetDexOptNeededDefault(&oat_file_assistant,
516 CompilerFilter::kVerify,
517 /*expected_dexopt_needed=*/false,
518 /*expected_is_vdex_usable=*/true,
519 /*expected_location=*/OatFileAssistant::kLocationOdex,
520 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
521 VerifyGetDexOptNeededDefault(&oat_file_assistant,
522 CompilerFilter::kEverything,
523 /*expected_dexopt_needed=*/true,
524 /*expected_is_vdex_usable=*/true,
525 /*expected_location=*/OatFileAssistant::kLocationOdex,
526 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
527
528 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
529 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
530 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
531 ExpectHasDexFiles(&oat_file_assistant, true);
532
533 VerifyOptimizationStatus(dex_location,
534 default_context_.get(),
535 CompilerFilter::kSpeed,
536 "install",
537 "up-to-date",
538 OatFileAssistant::kLocationOdex);
539 }
540
541 // Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex
542 // file via a symlink.
543 // Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,OdexUpToDateSymLink)544 TEST_P(OatFileAssistantTest, OdexUpToDateSymLink) {
545 std::string scratch_dir = GetScratchDir();
546 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
547 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
548
549 Copy(GetDexSrc1(), dex_location);
550 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
551
552 // Now replace the dex location with a symlink.
553 std::string link = scratch_dir + "/link";
554 ASSERT_EQ(0, symlink(scratch_dir.c_str(), link.c_str()));
555 dex_location = link + "/OdexUpToDate.jar";
556
557 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
558
559 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
560
561 VerifyGetDexOptNeededDefault(&oat_file_assistant,
562 CompilerFilter::kSpeed,
563 /*expected_dexopt_needed=*/false,
564 /*expected_is_vdex_usable=*/true,
565 /*expected_location=*/OatFileAssistant::kLocationOdex,
566 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
567 VerifyGetDexOptNeededDefault(&oat_file_assistant,
568 CompilerFilter::kVerify,
569 /*expected_dexopt_needed=*/false,
570 /*expected_is_vdex_usable=*/true,
571 /*expected_location=*/OatFileAssistant::kLocationOdex,
572 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
573 VerifyGetDexOptNeededDefault(&oat_file_assistant,
574 CompilerFilter::kEverything,
575 /*expected_dexopt_needed=*/true,
576 /*expected_is_vdex_usable=*/true,
577 /*expected_location=*/OatFileAssistant::kLocationOdex,
578 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
579
580 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
581 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
582 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
583 ExpectHasDexFiles(&oat_file_assistant, true);
584 }
585
586 // Case: We have a DEX file and up-to-date OAT file for it.
587 // Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,OatUpToDate)588 TEST_P(OatFileAssistantTest, OatUpToDate) {
589 if (IsExecutedAsRoot()) {
590 // We cannot simulate non writable locations when executed as root: b/38000545.
591 LOG(ERROR) << "Test skipped because it's running as root";
592 return;
593 }
594
595 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
596 Copy(GetDexSrc1(), dex_location);
597 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
598
599 // Force the use of oat location by making the dex parent not writable.
600 ScopedNonWritable scoped_non_writable(dex_location);
601 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
602
603 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
604
605 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
606
607 VerifyGetDexOptNeededDefault(&oat_file_assistant,
608 CompilerFilter::kSpeed,
609 /*expected_dexopt_needed=*/false,
610 /*expected_is_vdex_usable=*/true,
611 /*expected_location=*/OatFileAssistant::kLocationOat,
612 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
613 VerifyGetDexOptNeededDefault(&oat_file_assistant,
614 CompilerFilter::kVerify,
615 /*expected_dexopt_needed=*/false,
616 /*expected_is_vdex_usable=*/true,
617 /*expected_location=*/OatFileAssistant::kLocationOat,
618 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
619 VerifyGetDexOptNeededDefault(&oat_file_assistant,
620 CompilerFilter::kEverything,
621 /*expected_dexopt_needed=*/true,
622 /*expected_is_vdex_usable=*/true,
623 /*expected_location=*/OatFileAssistant::kLocationOat,
624 /*expected_legacy_result=*/OatFileAssistant::kDex2OatForFilter);
625
626 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
627 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
628 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
629 ExpectHasDexFiles(&oat_file_assistant, true);
630
631 VerifyOptimizationStatus(dex_location,
632 default_context_.get(),
633 CompilerFilter::kSpeed,
634 "unknown",
635 "up-to-date",
636 OatFileAssistant::kLocationOat);
637 }
638
639 // Case: Passing valid file descriptors of updated odex/vdex files along with the dex file.
640 // Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,GetDexOptNeededWithFd)641 TEST_P(OatFileAssistantTest, GetDexOptNeededWithFd) {
642 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
643 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
644 std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
645
646 Copy(GetDexSrc1(), dex_location);
647 GenerateOatForTest(dex_location,
648 odex_location,
649 CompilerFilter::kSpeed,
650 /* with_alternate_image= */ false);
651
652 android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY | O_CLOEXEC));
653 android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY | O_CLOEXEC));
654 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
655
656 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
657
658 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
659 /*context=*/nullptr,
660 /*load_executable=*/false,
661 vdex_fd.get(),
662 odex_fd.get(),
663 zip_fd.get());
664 VerifyGetDexOptNeededDefault(&oat_file_assistant,
665 CompilerFilter::kSpeed,
666 /*expected_dexopt_needed=*/false,
667 /*expected_is_vdex_usable=*/true,
668 /*expected_location=*/OatFileAssistant::kLocationOdex,
669 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
670 VerifyGetDexOptNeededDefault(&oat_file_assistant,
671 CompilerFilter::kVerify,
672 /*expected_dexopt_needed=*/false,
673 /*expected_is_vdex_usable=*/true,
674 /*expected_location=*/OatFileAssistant::kLocationOdex,
675 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
676 VerifyGetDexOptNeededDefault(&oat_file_assistant,
677 CompilerFilter::kEverything,
678 /*expected_dexopt_needed=*/true,
679 /*expected_is_vdex_usable=*/true,
680 /*expected_location=*/OatFileAssistant::kLocationOdex,
681 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
682
683 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
684 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
685 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
686 ExpectHasDexFiles(&oat_file_assistant, true);
687 }
688
689 // Case: Passing invalid odex fd and valid vdex and zip fds.
690 // Expect: The status should be kDex2OatForBootImage.
TEST_P(OatFileAssistantTest,GetDexOptNeededWithInvalidOdexFd)691 TEST_P(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexFd) {
692 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
693 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
694 std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
695
696 Copy(GetDexSrc1(), dex_location);
697 GenerateOatForTest(dex_location,
698 odex_location,
699 CompilerFilter::kSpeed,
700 /* with_alternate_image= */ false);
701
702 android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY | O_CLOEXEC));
703 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
704
705 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
706
707 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
708 /*context=*/nullptr,
709 /*load_executable=*/false,
710 vdex_fd.get(),
711 /*oat_fd=*/-1,
712 zip_fd.get());
713 VerifyGetDexOptNeededDefault(&oat_file_assistant,
714 CompilerFilter::kVerify,
715 /*expected_dexopt_needed=*/false,
716 /*expected_is_vdex_usable=*/true,
717 /*expected_location=*/OatFileAssistant::kLocationOdex,
718 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
719 VerifyGetDexOptNeededDefault(&oat_file_assistant,
720 CompilerFilter::kSpeed,
721 /*expected_dexopt_needed=*/true,
722 /*expected_is_vdex_usable=*/true,
723 /*expected_location=*/OatFileAssistant::kLocationOdex,
724 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
725 VerifyGetDexOptNeededDefault(&oat_file_assistant,
726 CompilerFilter::kEverything,
727 /*expected_dexopt_needed=*/true,
728 /*expected_is_vdex_usable=*/true,
729 /*expected_location=*/OatFileAssistant::kLocationOdex,
730 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
731
732 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
733 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
734 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
735 ExpectHasDexFiles(&oat_file_assistant, true);
736 }
737
738 // Case: Passing invalid vdex fd and valid odex and zip fds.
739 // Expect: The status should be kDex2OatFromScratch.
TEST_P(OatFileAssistantTest,GetDexOptNeededWithInvalidVdexFd)740 TEST_P(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) {
741 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
742 std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
743
744 Copy(GetDexSrc1(), dex_location);
745 GenerateOatForTest(dex_location,
746 odex_location,
747 CompilerFilter::kSpeed,
748 /* with_alternate_image= */ false);
749
750 android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY | O_CLOEXEC));
751 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
752
753 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
754
755 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
756 /*context=*/nullptr,
757 /*load_executable=*/false,
758 /*vdex_fd=*/-1,
759 odex_fd.get(),
760 zip_fd.get());
761
762 VerifyGetDexOptNeededDefault(&oat_file_assistant,
763 CompilerFilter::kSpeed,
764 /*expected_dexopt_needed=*/true,
765 /*expected_is_vdex_usable=*/false,
766 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
767 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
768 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
769 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
770 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
771 ExpectHasDexFiles(&oat_file_assistant, true);
772 }
773
774 // Case: Passing invalid vdex and odex fd with valid zip fd.
775 // Expect: The status is kDex2oatFromScratch.
TEST_P(OatFileAssistantTest,GetDexOptNeededWithInvalidOdexVdexFd)776 TEST_P(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) {
777 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
778
779 Copy(GetDexSrc1(), dex_location);
780
781 android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
782
783 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
784
785 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
786 /*context=*/nullptr,
787 /*load_executable=*/false,
788 /*vdex_fd=*/-1,
789 /*oat_fd=*/-1,
790 zip_fd);
791 VerifyGetDexOptNeededDefault(&oat_file_assistant,
792 CompilerFilter::kSpeed,
793 /*expected_dexopt_needed=*/true,
794 /*expected_is_vdex_usable=*/false,
795 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
796 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
797 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
798 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
799 }
800
801 // Case: We have a DEX file and up-to-date VDEX file for it, but no ODEX file, and the DEX file is
802 // compressed.
TEST_P(OatFileAssistantTest,VdexUpToDateNoOdex)803 TEST_P(OatFileAssistantTest, VdexUpToDateNoOdex) {
804 std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar";
805 std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat";
806
807 Copy(GetDexSrc1(), dex_location);
808
809 // Generating and deleting the oat file should have the side effect of
810 // creating an up-to-date vdex file.
811 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
812 ASSERT_EQ(0, unlink(odex_location.c_str()));
813
814 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
815
816 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
817
818 VerifyGetDexOptNeededDefault(&oat_file_assistant,
819 CompilerFilter::kVerify,
820 /*expected_dexopt_needed=*/false,
821 /*expected_is_vdex_usable=*/true,
822 /*expected_location=*/OatFileAssistant::kLocationOdex,
823 /*expected_legacy_result=*/-OatFileAssistant::kNoDexOptNeeded);
824 VerifyGetDexOptNeededDefault(&oat_file_assistant,
825 CompilerFilter::kSpeed,
826 /*expected_dexopt_needed=*/true,
827 /*expected_is_vdex_usable=*/true,
828 /*expected_location=*/OatFileAssistant::kLocationOdex,
829 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
830
831 // Make sure we don't crash in this case when we dump the status. We don't
832 // care what the actual dumped value is.
833 oat_file_assistant.GetStatusDump();
834
835 VerifyOptimizationStatus(dex_location,
836 default_context_.get(),
837 "verify",
838 "vdex",
839 "up-to-date",
840 OatFileAssistant::kLocationOdex);
841 }
842
843 // Case: We have a DEX file and empty VDEX and ODEX files.
TEST_P(OatFileAssistantTest,EmptyVdexOdex)844 TEST_P(OatFileAssistantTest, EmptyVdexOdex) {
845 std::string dex_location = GetScratchDir() + "/EmptyVdexOdex.jar";
846 std::string odex_location = GetOdexDir() + "/EmptyVdexOdex.oat";
847 std::string vdex_location = GetOdexDir() + "/EmptyVdexOdex.vdex";
848
849 Copy(GetDexSrc1(), dex_location);
850 ScratchFile vdex_file(vdex_location);
851 ScratchFile odex_file(odex_location);
852
853 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
854
855 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
856 VerifyGetDexOptNeededDefault(&oat_file_assistant,
857 CompilerFilter::kSpeed,
858 /*expected_dexopt_needed=*/true,
859 /*expected_is_vdex_usable=*/false,
860 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
861 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
862 }
863
864 // Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT
865 // file.
TEST_P(OatFileAssistantTest,VdexUpToDateNoOat)866 TEST_P(OatFileAssistantTest, VdexUpToDateNoOat) {
867 if (IsExecutedAsRoot()) {
868 // We cannot simulate non writable locations when executed as root: b/38000545.
869 LOG(ERROR) << "Test skipped because it's running as root";
870 return;
871 }
872
873 std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOat.jar";
874 std::string oat_location;
875 std::string error_msg;
876 ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
877 dex_location, kRuntimeISA, /* deny_art_apex_data_files= */false, &oat_location, &error_msg))
878 << error_msg;
879
880 Copy(GetDexSrc1(), dex_location);
881 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
882 ASSERT_EQ(0, unlink(oat_location.c_str()));
883
884 ScopedNonWritable scoped_non_writable(dex_location);
885 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
886
887 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
888
889 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
890
891 VerifyGetDexOptNeededDefault(&oat_file_assistant,
892 CompilerFilter::kSpeed,
893 /*expected_dexopt_needed=*/true,
894 /*expected_is_vdex_usable=*/true,
895 /*expected_location=*/OatFileAssistant::kLocationOat,
896 /*expected_legacy_result=*/OatFileAssistant::kDex2OatForFilter);
897 }
898
899 // Case: We have a DEX file and speed-profile OAT file for it.
900 // Expect: The status is kNoDexOptNeeded if the profile hasn't changed, but
901 // kDex2Oat if the profile has changed.
TEST_P(OatFileAssistantTest,ProfileOatUpToDate)902 TEST_P(OatFileAssistantTest, ProfileOatUpToDate) {
903 if (IsExecutedAsRoot()) {
904 // We cannot simulate non writable locations when executed as root: b/38000545.
905 LOG(ERROR) << "Test skipped because it's running as root";
906 return;
907 }
908
909 std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
910 Copy(GetDexSrc1(), dex_location);
911 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
912
913 ScopedNonWritable scoped_non_writable(dex_location);
914 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
915
916 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
917
918 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
919
920 VerifyGetDexOptNeeded(&oat_file_assistant,
921 CompilerFilter::kSpeedProfile,
922 default_trigger_,
923 /*expected_dexopt_needed=*/false,
924 /*expected_is_vdex_usable=*/true,
925 /*expected_location=*/OatFileAssistant::kLocationOat);
926 EXPECT_EQ(
927 OatFileAssistant::kNoDexOptNeeded,
928 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, /*profile_changed=*/false));
929
930 VerifyGetDexOptNeeded(&oat_file_assistant,
931 CompilerFilter::kVerify,
932 default_trigger_,
933 /*expected_dexopt_needed=*/false,
934 /*expected_is_vdex_usable=*/true,
935 /*expected_location=*/OatFileAssistant::kLocationOat);
936 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
937 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify, /*profile_changed=*/false));
938
939 OatFileAssistant::DexOptTrigger profile_changed_trigger = default_trigger_;
940 profile_changed_trigger.targetFilterIsSame = true;
941
942 VerifyGetDexOptNeeded(&oat_file_assistant,
943 CompilerFilter::kSpeedProfile,
944 profile_changed_trigger,
945 /*expected_dexopt_needed=*/true,
946 /*expected_is_vdex_usable=*/true,
947 /*expected_location=*/OatFileAssistant::kLocationOat);
948 EXPECT_EQ(
949 OatFileAssistant::kDex2OatForFilter,
950 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, /*profile_changed=*/true));
951
952 // We should not recompile even if `profile_changed` is true because the compiler filter should
953 // not be downgraded.
954 VerifyGetDexOptNeeded(&oat_file_assistant,
955 CompilerFilter::kVerify,
956 profile_changed_trigger,
957 /*expected_dexopt_needed=*/false,
958 /*expected_is_vdex_usable=*/true,
959 /*expected_location=*/OatFileAssistant::kLocationOat);
960 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
961 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify, /*profile_changed=*/true));
962
963 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
964 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
965 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
966 ExpectHasDexFiles(&oat_file_assistant, true);
967 }
968
969 // Case: We have a MultiDEX file and up-to-date OAT file for it.
970 // Expect: The status is kNoDexOptNeeded and we load all dex files.
TEST_P(OatFileAssistantTest,MultiDexOatUpToDate)971 TEST_P(OatFileAssistantTest, MultiDexOatUpToDate) {
972 if (IsExecutedAsRoot()) {
973 // We cannot simulate non writable locations when executed as root: b/38000545.
974 LOG(ERROR) << "Test skipped because it's running as root";
975 return;
976 }
977
978 std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
979 Copy(GetMultiDexSrc1(), dex_location);
980 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
981
982 ScopedNonWritable scoped_non_writable(dex_location);
983 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
984
985 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
986
987 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
988 /*context=*/nullptr,
989 /*load_executable=*/true);
990 VerifyGetDexOptNeededDefault(&oat_file_assistant,
991 CompilerFilter::kSpeed,
992 /*expected_dexopt_needed=*/false,
993 /*expected_is_vdex_usable=*/true,
994 /*expected_location=*/OatFileAssistant::kLocationOat,
995 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
996 ExpectHasDexFiles(&oat_file_assistant, true);
997
998 // Verify we can load both dex files.
999 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1000 ASSERT_TRUE(oat_file.get() != nullptr);
1001 if (with_runtime_) {
1002 EXPECT_TRUE(oat_file->IsExecutable());
1003 }
1004 std::vector<std::unique_ptr<const DexFile>> dex_files;
1005 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1006 EXPECT_EQ(2u, dex_files.size());
1007 }
1008
1009 // Case: We have a MultiDEX file where the non-main multdex entry is out of date.
1010 // Expect: The status is kDex2OatNeeded.
TEST_P(OatFileAssistantTest,MultiDexNonMainOutOfDate)1011 TEST_P(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
1012 if (IsExecutedAsRoot()) {
1013 // We cannot simulate non writable locations when executed as root: b/38000545.
1014 LOG(ERROR) << "Test skipped because it's running as root";
1015 return;
1016 }
1017
1018 std::string dex_location = GetScratchDir() + "/MultiDexNonMainOutOfDate.jar";
1019
1020 // Compile code for GetMultiDexSrc1.
1021 Copy(GetMultiDexSrc1(), dex_location);
1022 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1023
1024 // Now overwrite the dex file with GetMultiDexSrc2 so the non-main checksum
1025 // is out of date.
1026 Copy(GetMultiDexSrc2(), dex_location);
1027
1028 ScopedNonWritable scoped_non_writable(dex_location);
1029 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1030
1031 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1032
1033 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1034 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1035 CompilerFilter::kSpeed,
1036 /*expected_dexopt_needed=*/true,
1037 /*expected_is_vdex_usable=*/false,
1038 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1039 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
1040 ExpectHasDexFiles(&oat_file_assistant, true);
1041 }
1042
1043 // Case: We have a DEX file and an OAT file out of date with respect to the
1044 // dex checksum.
TEST_P(OatFileAssistantTest,OatDexOutOfDate)1045 TEST_P(OatFileAssistantTest, OatDexOutOfDate) {
1046 if (IsExecutedAsRoot()) {
1047 // We cannot simulate non writable locations when executed as root: b/38000545.
1048 LOG(ERROR) << "Test skipped because it's running as root";
1049 return;
1050 }
1051
1052 std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
1053
1054 // We create a dex, generate an oat for it, then overwrite the dex with a
1055 // different dex to make the oat out of date.
1056 Copy(GetDexSrc1(), dex_location);
1057 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1058 Copy(GetDexSrc2(), dex_location);
1059
1060 ScopedNonWritable scoped_non_writable(dex_location);
1061 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1062
1063 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1064
1065 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1066 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1067 CompilerFilter::kSpeed,
1068 /*expected_dexopt_needed=*/true,
1069 /*expected_is_vdex_usable=*/false,
1070 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1071 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
1072
1073 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1074 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1075 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
1076 ExpectHasDexFiles(&oat_file_assistant, true);
1077
1078 VerifyOptimizationStatus(dex_location,
1079 default_context_.get(),
1080 "run-from-apk-fallback",
1081 "unknown",
1082 "apk-more-recent",
1083 OatFileAssistant::kLocationNoneOrError);
1084 }
1085
1086 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
1087 // to the dex checksum, but no ODEX file.
TEST_P(OatFileAssistantTest,VdexDexOutOfDate)1088 TEST_P(OatFileAssistantTest, VdexDexOutOfDate) {
1089 std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar";
1090 std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat";
1091
1092 Copy(GetDexSrc1(), dex_location);
1093 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1094 ASSERT_EQ(0, unlink(odex_location.c_str()));
1095 Copy(GetDexSrc2(), dex_location);
1096
1097 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1098
1099 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1100
1101 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1102 CompilerFilter::kSpeed,
1103 /*expected_dexopt_needed=*/true,
1104 /*expected_is_vdex_usable=*/false,
1105 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1106 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
1107 }
1108
1109 // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
1110 // is out of date and there is no corresponding ODEX file.
TEST_P(OatFileAssistantTest,VdexMultiDexNonMainOutOfDate)1111 TEST_P(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
1112 std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
1113 std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex";
1114
1115 Copy(GetMultiDexSrc1(), dex_location);
1116 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1117 ASSERT_EQ(0, unlink(odex_location.c_str()));
1118 Copy(GetMultiDexSrc2(), dex_location);
1119
1120 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1121
1122 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1123
1124 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1125 CompilerFilter::kSpeed,
1126 /*expected_dexopt_needed=*/true,
1127 /*expected_is_vdex_usable=*/false,
1128 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1129 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
1130 }
1131
1132 // Case: We have a DEX file and an OAT file out of date with respect to the
1133 // boot image.
TEST_P(OatFileAssistantTest,OatImageOutOfDate)1134 TEST_P(OatFileAssistantTest, OatImageOutOfDate) {
1135 if (IsExecutedAsRoot()) {
1136 // We cannot simulate non writable locations when executed as root: b/38000545.
1137 LOG(ERROR) << "Test skipped because it's running as root";
1138 return;
1139 }
1140
1141 std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
1142
1143 Copy(GetDexSrc1(), dex_location);
1144 GenerateOatForTest(dex_location.c_str(),
1145 CompilerFilter::kSpeed,
1146 /* with_alternate_image= */ true);
1147
1148 ScopedNonWritable scoped_non_writable(dex_location);
1149 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1150
1151 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1152
1153 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1154 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1155 CompilerFilter::kVerify,
1156 /*expected_dexopt_needed=*/false,
1157 /*expected_is_vdex_usable=*/true,
1158 /*expected_location=*/OatFileAssistant::kLocationOat,
1159 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1160 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1161 CompilerFilter::kSpeed,
1162 /*expected_dexopt_needed=*/true,
1163 /*expected_is_vdex_usable=*/true,
1164 /*expected_location=*/OatFileAssistant::kLocationOat,
1165 /*expected_legacy_result=*/OatFileAssistant::kDex2OatForFilter);
1166
1167 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1168 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1169 EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
1170 ExpectHasDexFiles(&oat_file_assistant, true);
1171
1172 VerifyOptimizationStatus(dex_location,
1173 default_context_.get(),
1174 "verify",
1175 "vdex",
1176 "up-to-date",
1177 OatFileAssistant::kLocationOat);
1178 }
1179
TEST_P(OatFileAssistantTest,OatContextOutOfDate)1180 TEST_P(OatFileAssistantTest, OatContextOutOfDate) {
1181 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1182 std::string odex_location = GetOdexDir() + "/TestDex.odex";
1183
1184 std::string context_location = GetScratchDir() + "/ContextDex.jar";
1185 Copy(GetDexSrc1(), dex_location);
1186 Copy(GetDexSrc2(), context_location);
1187
1188 std::string error_msg;
1189 std::vector<std::string> args;
1190 args.push_back("--dex-file=" + dex_location);
1191 args.push_back("--oat-file=" + odex_location);
1192 args.push_back("--class-loader-context=PCL[" + context_location + "]");
1193 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1194
1195 // Update the context by overriding the jar file.
1196 Copy(GetMultiDexSrc2(), context_location);
1197
1198 std::unique_ptr<ClassLoaderContext> context =
1199 ClassLoaderContext::Create("PCL[" + context_location + "]");
1200 ASSERT_TRUE(context != nullptr);
1201 ASSERT_TRUE(context->OpenDexFiles());
1202
1203 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1204
1205 VerifyOptimizationStatus(dex_location,
1206 context.get(),
1207 "verify",
1208 "vdex",
1209 "up-to-date",
1210 OatFileAssistant::kLocationOdex,
1211 /*check_context=*/true);
1212 }
1213
1214 // Case: We have a DEX file and an ODEX file, but no OAT file.
TEST_P(OatFileAssistantTest,DexOdexNoOat)1215 TEST_P(OatFileAssistantTest, DexOdexNoOat) {
1216 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
1217 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
1218
1219 // Create the dex and odex files
1220 Copy(GetDexSrc1(), dex_location);
1221 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1222
1223 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1224
1225 // Verify the status.
1226 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1227
1228 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1229 CompilerFilter::kSpeed,
1230 /*expected_dexopt_needed=*/false,
1231 /*expected_is_vdex_usable=*/true,
1232 /*expected_location=*/OatFileAssistant::kLocationOdex,
1233 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1234
1235 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1236 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
1237 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1238 ExpectHasDexFiles(&oat_file_assistant, true);
1239
1240 // We should still be able to get the non-executable odex file to run from.
1241 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1242 ASSERT_TRUE(oat_file.get() != nullptr);
1243 }
1244
1245 // Case: We have a resource-only DEX file, no ODEX file and no
1246 // OAT file. Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,ResourceOnlyDex)1247 TEST_P(OatFileAssistantTest, ResourceOnlyDex) {
1248 std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
1249
1250 Copy(GetResourceOnlySrc1(), dex_location);
1251
1252 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1253
1254 // Verify the status.
1255 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1256
1257 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1258 CompilerFilter::kSpeed,
1259 /*expected_dexopt_needed=*/false,
1260 /*expected_is_vdex_usable=*/false,
1261 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1262 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1263 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1264 CompilerFilter::kVerify,
1265 /*expected_dexopt_needed=*/false,
1266 /*expected_is_vdex_usable=*/false,
1267 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1268 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1269
1270 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1271 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1272 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1273 ExpectHasDexFiles(&oat_file_assistant, false);
1274
1275 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1276 CompilerFilter::kSpeed,
1277 /*expected_dexopt_needed=*/false,
1278 /*expected_is_vdex_usable=*/false,
1279 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1280 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1281
1282 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1283 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1284 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1285 ExpectHasDexFiles(&oat_file_assistant, false);
1286
1287 VerifyOptimizationStatusWithInstance(&oat_file_assistant,
1288 "unknown",
1289 "unknown",
1290 "no-dex-code",
1291 OatFileAssistant::kLocationNoneOrError);
1292 }
1293
1294 // Case: We have a DEX file, an ODEX file and an OAT file.
1295 // Expect: It shouldn't crash. We should load the odex file executable.
TEST_P(OatFileAssistantTest,OdexOatOverlap)1296 TEST_P(OatFileAssistantTest, OdexOatOverlap) {
1297 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
1298 std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
1299
1300 // Create the dex, the odex and the oat files.
1301 Copy(GetDexSrc1(), dex_location);
1302 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1303 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1304
1305 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1306
1307 // Verify things don't go bad.
1308 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
1309 /*context=*/nullptr,
1310 /*load_executable=*/true);
1311
1312 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1313 CompilerFilter::kSpeed,
1314 /*expected_dexopt_needed=*/false,
1315 /*expected_is_vdex_usable=*/true,
1316 /*expected_location=*/OatFileAssistant::kLocationOdex,
1317 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1318
1319 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1320 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
1321 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
1322 ExpectHasDexFiles(&oat_file_assistant, true);
1323
1324 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1325 ASSERT_TRUE(oat_file.get() != nullptr);
1326
1327 if (with_runtime_) {
1328 EXPECT_TRUE(oat_file->IsExecutable());
1329 }
1330 std::vector<std::unique_ptr<const DexFile>> dex_files;
1331 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1332 EXPECT_EQ(1u, dex_files.size());
1333 }
1334
1335 // Case: We have a DEX file and up-to-date OAT file for it.
1336 // Expect: We should load an executable dex file.
TEST_P(OatFileAssistantTest,LoadOatUpToDate)1337 TEST_P(OatFileAssistantTest, LoadOatUpToDate) {
1338 if (IsExecutedAsRoot()) {
1339 // We cannot simulate non writable locations when executed as root: b/38000545.
1340 LOG(ERROR) << "Test skipped because it's running as root";
1341 return;
1342 }
1343
1344 std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
1345
1346 Copy(GetDexSrc1(), dex_location);
1347 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1348
1349 ScopedNonWritable scoped_non_writable(dex_location);
1350 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1351
1352 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1353
1354 // Load the oat using an oat file assistant.
1355 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
1356 /*context=*/nullptr,
1357 /*load_executable=*/true);
1358
1359 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1360 ASSERT_TRUE(oat_file.get() != nullptr);
1361 if (with_runtime_) {
1362 EXPECT_TRUE(oat_file->IsExecutable());
1363 }
1364 std::vector<std::unique_ptr<const DexFile>> dex_files;
1365 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1366 EXPECT_EQ(1u, dex_files.size());
1367 }
1368
1369 // Case: We have a DEX file and up-to-date quicken OAT file for it.
1370 // Expect: We should still load the oat file as executable.
TEST_P(OatFileAssistantTest,LoadExecInterpretOnlyOatUpToDate)1371 TEST_P(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
1372 if (IsExecutedAsRoot()) {
1373 // We cannot simulate non writable locations when executed as root: b/38000545.
1374 LOG(ERROR) << "Test skipped because it's running as root";
1375 return;
1376 }
1377
1378 std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar";
1379
1380 Copy(GetDexSrc1(), dex_location);
1381 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kVerify);
1382
1383 ScopedNonWritable scoped_non_writable(dex_location);
1384 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1385
1386 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1387
1388 // Load the oat using an oat file assistant.
1389 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
1390 /*context=*/nullptr,
1391 /*load_executable=*/true);
1392
1393 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1394 ASSERT_TRUE(oat_file.get() != nullptr);
1395 if (with_runtime_) {
1396 EXPECT_TRUE(oat_file->IsExecutable());
1397 }
1398 std::vector<std::unique_ptr<const DexFile>> dex_files;
1399 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1400 EXPECT_EQ(1u, dex_files.size());
1401 }
1402
1403 // Case: We have a DEX file and up-to-date OAT file for it.
1404 // Expect: Loading non-executable should load the oat non-executable.
TEST_P(OatFileAssistantTest,LoadNoExecOatUpToDate)1405 TEST_P(OatFileAssistantTest, LoadNoExecOatUpToDate) {
1406 if (IsExecutedAsRoot()) {
1407 // We cannot simulate non writable locations when executed as root: b/38000545.
1408 LOG(ERROR) << "Test skipped because it's running as root";
1409 return;
1410 }
1411
1412 std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
1413
1414 Copy(GetDexSrc1(), dex_location);
1415
1416 ScopedNonWritable scoped_non_writable(dex_location);
1417 ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1418
1419 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1420
1421 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1422
1423 // Load the oat using an oat file assistant.
1424 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
1425 /*context=*/nullptr,
1426 /*load_executable=*/true);
1427
1428 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1429 ASSERT_TRUE(oat_file.get() != nullptr);
1430 if (with_runtime_) {
1431 EXPECT_TRUE(oat_file->IsExecutable());
1432 }
1433 std::vector<std::unique_ptr<const DexFile>> dex_files;
1434 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1435 EXPECT_EQ(1u, dex_files.size());
1436 }
1437
1438 // Turn an absolute path into a path relative to the current working
1439 // directory.
MakePathRelative(const std::string & target)1440 static std::string MakePathRelative(const std::string& target) {
1441 char buf[MAXPATHLEN];
1442 std::string cwd = getcwd(buf, MAXPATHLEN);
1443
1444 // Split the target and cwd paths into components.
1445 std::vector<std::string> target_path;
1446 std::vector<std::string> cwd_path;
1447 Split(target, '/', &target_path);
1448 Split(cwd, '/', &cwd_path);
1449
1450 // Reverse the path components, so we can use pop_back().
1451 std::reverse(target_path.begin(), target_path.end());
1452 std::reverse(cwd_path.begin(), cwd_path.end());
1453
1454 // Drop the common prefix of the paths. Because we reversed the path
1455 // components, this becomes the common suffix of target_path and cwd_path.
1456 while (!target_path.empty() && !cwd_path.empty()
1457 && target_path.back() == cwd_path.back()) {
1458 target_path.pop_back();
1459 cwd_path.pop_back();
1460 }
1461
1462 // For each element of the remaining cwd_path, add '..' to the beginning
1463 // of the target path. Because we reversed the path components, we add to
1464 // the end of target_path.
1465 for (unsigned int i = 0; i < cwd_path.size(); i++) {
1466 target_path.push_back("..");
1467 }
1468
1469 // Reverse again to get the right path order, and join to get the result.
1470 std::reverse(target_path.begin(), target_path.end());
1471 return android::base::Join(target_path, '/');
1472 }
1473
1474 // Case: Non-absolute path to Dex location.
1475 // Expect: Not sure, but it shouldn't crash.
TEST_P(OatFileAssistantTest,NonAbsoluteDexLocation)1476 TEST_P(OatFileAssistantTest, NonAbsoluteDexLocation) {
1477 std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
1478 Copy(GetDexSrc1(), abs_dex_location);
1479
1480 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1481
1482 std::string dex_location = MakePathRelative(abs_dex_location);
1483 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1484
1485 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1486 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1487 CompilerFilter::kSpeed,
1488 /*expected_dexopt_needed=*/true,
1489 /*expected_is_vdex_usable=*/false,
1490 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1491 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
1492 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1493 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1494 }
1495
1496 // Case: Very short, non-existent Dex location.
1497 // Expect: kNoDexOptNeeded.
TEST_P(OatFileAssistantTest,ShortDexLocation)1498 TEST_P(OatFileAssistantTest, ShortDexLocation) {
1499 std::string dex_location = "/xx";
1500
1501 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1502
1503 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1504
1505 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1506 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1507 CompilerFilter::kSpeed,
1508 /*expected_dexopt_needed=*/false,
1509 /*expected_is_vdex_usable=*/false,
1510 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1511 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1512 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1513 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1514 std::string error_msg_ignored;
1515 EXPECT_FALSE(oat_file_assistant.HasDexFiles(&error_msg_ignored).has_value());
1516 }
1517
1518 // Case: Non-standard extension for dex file.
1519 // Expect: The status is kDex2OatNeeded.
TEST_P(OatFileAssistantTest,LongDexExtension)1520 TEST_P(OatFileAssistantTest, LongDexExtension) {
1521 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
1522 Copy(GetDexSrc1(), dex_location);
1523
1524 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1525
1526 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1527
1528 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1529 CompilerFilter::kSpeed,
1530 /*expected_dexopt_needed=*/true,
1531 /*expected_is_vdex_usable=*/false,
1532 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
1533 /*expected_legacy_result=*/OatFileAssistant::kDex2OatFromScratch);
1534
1535 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1536 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1537 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1538 }
1539
1540 // A task to generate a dex location. Used by the RaceToGenerate test.
1541 class RaceGenerateTask : public Task {
1542 public:
RaceGenerateTask(OatFileAssistantBaseTest & test,const std::string & dex_location,const std::string & oat_location,Mutex * lock)1543 RaceGenerateTask(OatFileAssistantBaseTest& test,
1544 const std::string& dex_location,
1545 const std::string& oat_location,
1546 Mutex* lock)
1547 : test_(test),
1548 dex_location_(dex_location),
1549 oat_location_(oat_location),
1550 lock_(lock),
1551 loaded_oat_file_(nullptr) {}
1552
Run(Thread * self)1553 void Run([[maybe_unused]] Thread* self) override {
1554 // Load the dex files, and save a pointer to the loaded oat file, so that
1555 // we can verify only one oat file was loaded for the dex location.
1556 std::vector<std::unique_ptr<const DexFile>> dex_files;
1557 std::vector<std::string> error_msgs;
1558 const OatFile* oat_file = nullptr;
1559 {
1560 MutexLock mu(Thread::Current(), *lock_);
1561 // Create the oat file.
1562 std::vector<std::string> args;
1563 args.push_back("--dex-file=" + dex_location_);
1564 args.push_back("--oat-file=" + oat_location_);
1565 std::string error_msg;
1566 ASSERT_TRUE(test_.Dex2Oat(args, &error_msg)) << error_msg;
1567 }
1568
1569 dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1570 dex_location_.c_str(),
1571 Runtime::Current()->GetSystemClassLoader(),
1572 /*dex_elements=*/nullptr,
1573 &oat_file,
1574 &error_msgs);
1575 CHECK(!dex_files.empty()) << android::base::Join(error_msgs, '\n');
1576 if (dex_files[0]->GetOatDexFile() != nullptr) {
1577 loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile();
1578 }
1579 CHECK_EQ(loaded_oat_file_, oat_file);
1580 }
1581
GetLoadedOatFile() const1582 const OatFile* GetLoadedOatFile() const {
1583 return loaded_oat_file_;
1584 }
1585
1586 private:
1587 OatFileAssistantBaseTest& test_;
1588 std::string dex_location_;
1589 std::string oat_location_;
1590 Mutex* lock_;
1591 const OatFile* loaded_oat_file_;
1592 };
1593
1594 // Test the case where dex2oat invocations race with multiple processes trying to
1595 // load the oat file.
TEST_F(OatFileAssistantBaseTest,RaceToGenerate)1596 TEST_F(OatFileAssistantBaseTest, RaceToGenerate) {
1597 std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
1598 std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
1599
1600 // Start the runtime to initialize the system's class loader.
1601 Thread::Current()->TransitionFromSuspendedToRunnable();
1602 runtime_->Start();
1603
1604 // We use the lib core dex file, because it's large, and hopefully should
1605 // take a while to generate.
1606 Copy(GetLibCoreDexFileNames()[0], dex_location);
1607
1608 const size_t kNumThreads = 16;
1609 Thread* self = Thread::Current();
1610 std::unique_ptr<ThreadPool> thread_pool(
1611 ThreadPool::Create("Oat file assistant test thread pool", kNumThreads));
1612 std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
1613 Mutex lock("RaceToGenerate");
1614 for (size_t i = 0; i < kNumThreads; i++) {
1615 std::unique_ptr<RaceGenerateTask> task(
1616 new RaceGenerateTask(*this, dex_location, oat_location, &lock));
1617 thread_pool->AddTask(self, task.get());
1618 tasks.push_back(std::move(task));
1619 }
1620 thread_pool->StartWorkers(self);
1621 thread_pool->Wait(self, /* do_work= */ true, /* may_hold_locks= */ false);
1622
1623 // Verify that tasks which got an oat file got a unique one.
1624 std::set<const OatFile*> oat_files;
1625 for (auto& task : tasks) {
1626 const OatFile* oat_file = task->GetLoadedOatFile();
1627 if (oat_file != nullptr) {
1628 EXPECT_TRUE(oat_files.find(oat_file) == oat_files.end());
1629 oat_files.insert(oat_file);
1630 }
1631 }
1632 }
1633
1634 // Case: We have a DEX file and an ODEX file, and no OAT file,
1635 // Expect: We should load the odex file executable.
TEST_P(OatFileAssistantTest,LoadDexOdexNoOat)1636 TEST_P(OatFileAssistantTest, LoadDexOdexNoOat) {
1637 std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
1638 std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
1639
1640 // Create the dex and odex files
1641 Copy(GetDexSrc1(), dex_location);
1642 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1643
1644 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1645
1646 // Load the oat using an executable oat file assistant.
1647 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
1648 /*context=*/nullptr,
1649 /*load_executable=*/true);
1650
1651 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1652 ASSERT_TRUE(oat_file.get() != nullptr);
1653 if (with_runtime_) {
1654 EXPECT_TRUE(oat_file->IsExecutable());
1655 }
1656 std::vector<std::unique_ptr<const DexFile>> dex_files;
1657 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1658 EXPECT_EQ(1u, dex_files.size());
1659 }
1660
1661 // Case: We have a MultiDEX file and an ODEX file, and no OAT file.
1662 // Expect: We should load the odex file executable.
TEST_P(OatFileAssistantTest,LoadMultiDexOdexNoOat)1663 TEST_P(OatFileAssistantTest, LoadMultiDexOdexNoOat) {
1664 std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
1665 std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
1666
1667 // Create the dex and odex files
1668 Copy(GetMultiDexSrc1(), dex_location);
1669 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1670
1671 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1672
1673 // Load the oat using an executable oat file assistant.
1674 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
1675 /*context=*/nullptr,
1676 /*load_executable=*/true);
1677
1678 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1679 ASSERT_TRUE(oat_file.get() != nullptr);
1680 if (with_runtime_) {
1681 EXPECT_TRUE(oat_file->IsExecutable());
1682 }
1683 std::vector<std::unique_ptr<const DexFile>> dex_files;
1684 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1685 EXPECT_EQ(2u, dex_files.size());
1686 }
1687
TEST(OatFileAssistantUtilsTest,DexLocationToOdexFilename)1688 TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) {
1689 std::string error_msg;
1690 std::string odex_file;
1691
1692 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1693 "/foo/bar/baz.jar", InstructionSet::kArm, &odex_file, &error_msg))
1694 << error_msg;
1695 EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1696
1697 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1698 "/foo/bar/baz.funnyext", InstructionSet::kArm, &odex_file, &error_msg))
1699 << error_msg;
1700 EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1701
1702 EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1703 "nopath.jar", InstructionSet::kArm, &odex_file, &error_msg));
1704
1705 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1706 "/foo/bar/baz_noext", InstructionSet::kArm, &odex_file, &error_msg));
1707 EXPECT_EQ("/foo/bar/oat/arm/baz_noext.odex", odex_file);
1708 }
1709
1710 // Verify the dexopt status values from dalvik.system.DexFile
1711 // match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantBaseTest,DexOptStatusValues)1712 TEST_F(OatFileAssistantBaseTest, DexOptStatusValues) {
1713 std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = {
1714 {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"},
1715 {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"},
1716 {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
1717 {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
1718 };
1719
1720 ScopedObjectAccess soa(Thread::Current());
1721 StackHandleScope<1> hs(soa.Self());
1722 ClassLinker* linker = Runtime::Current()->GetClassLinker();
1723 Handle<mirror::Class> dexfile(
1724 hs.NewHandle(linker->FindSystemClass(soa.Self(), "Ldalvik/system/DexFile;")));
1725 ASSERT_FALSE(dexfile == nullptr);
1726 linker->EnsureInitialized(soa.Self(), dexfile, true, true);
1727
1728 for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) {
1729 ArtField* art_field = dexfile->FindStaticField(field.second, "I");
1730 ASSERT_FALSE(art_field == nullptr);
1731 EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
1732 EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get()));
1733 }
1734 }
1735
TEST_P(OatFileAssistantTest,GetDexOptNeededWithOutOfDateContext)1736 TEST_P(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) {
1737 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1738 std::string odex_location = GetOdexDir() + "/TestDex.odex";
1739
1740 std::string context_location = GetScratchDir() + "/ContextDex.jar";
1741 Copy(GetDexSrc1(), dex_location);
1742 Copy(GetDexSrc2(), context_location);
1743
1744 std::string context_str = "PCL[" + context_location + "]";
1745
1746 std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
1747 ASSERT_TRUE(context != nullptr);
1748 ASSERT_TRUE(context->OpenDexFiles());
1749
1750 std::string error_msg;
1751 std::vector<std::string> args;
1752 args.push_back("--dex-file=" + dex_location);
1753 args.push_back("--oat-file=" + odex_location);
1754 args.push_back("--class-loader-context=" + context_str);
1755 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1756
1757 // Update the context by overriding the jar file.
1758 Copy(GetMultiDexSrc2(), context_location);
1759
1760 {
1761 std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1762 ASSERT_TRUE(updated_context != nullptr);
1763 std::vector<int> context_fds;
1764 ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
1765
1766 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1767
1768 OatFileAssistant oat_file_assistant =
1769 CreateOatFileAssistant(dex_location.c_str(), updated_context.get());
1770 // DexOptNeeded should advise compilation for filter when the context changes.
1771 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1772 CompilerFilter::kDefaultCompilerFilter,
1773 /*expected_dexopt_needed=*/true,
1774 /*expected_is_vdex_usable=*/true,
1775 /*expected_location=*/OatFileAssistant::kLocationOdex,
1776 /*expected_legacy_result=*/-OatFileAssistant::kDex2OatForFilter);
1777 }
1778 {
1779 std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1780 ASSERT_TRUE(updated_context != nullptr);
1781 std::vector<int> context_fds;
1782 ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
1783 args.push_back("--compiler-filter=verify");
1784 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1785
1786 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1787
1788 OatFileAssistant oat_file_assistant =
1789 CreateOatFileAssistant(dex_location.c_str(), updated_context.get());
1790 // Now check that DexOptNeeded does not advise compilation if we only verify the file.
1791 VerifyGetDexOptNeededDefault(&oat_file_assistant,
1792 CompilerFilter::kVerify,
1793 /*expected_dexopt_needed=*/false,
1794 /*expected_is_vdex_usable=*/true,
1795 /*expected_location=*/OatFileAssistant::kLocationOdex,
1796 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
1797 }
1798 }
1799
1800 // Case: We have a DEX file and speed-profile ODEX file for it. The caller's intention is to
1801 // downgrade the compiler filter.
1802 // Expect: Dexopt should be performed only if the target compiler filter is worse than the current
1803 // one.
TEST_P(OatFileAssistantTest,Downgrade)1804 TEST_P(OatFileAssistantTest, Downgrade) {
1805 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1806 std::string odex_location = GetOdexDir() + "/TestDex.odex";
1807 Copy(GetDexSrc1(), dex_location);
1808 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeedProfile);
1809
1810 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1811
1812 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1813 OatFileAssistant::DexOptTrigger downgrade_trigger{.targetFilterIsWorse = true};
1814
1815 VerifyGetDexOptNeeded(&oat_file_assistant,
1816 CompilerFilter::kSpeed,
1817 downgrade_trigger,
1818 /*expected_dexopt_needed=*/false,
1819 /*expected_is_vdex_usable=*/true,
1820 /*expected_location=*/OatFileAssistant::kLocationOdex);
1821 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1822 oat_file_assistant.GetDexOptNeeded(
1823 CompilerFilter::kSpeed, /*profile_changed=*/false, /*downgrade=*/true));
1824
1825 VerifyGetDexOptNeeded(&oat_file_assistant,
1826 CompilerFilter::kSpeedProfile,
1827 downgrade_trigger,
1828 /*expected_dexopt_needed=*/false,
1829 /*expected_is_vdex_usable=*/true,
1830 /*expected_location=*/OatFileAssistant::kLocationOdex);
1831 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1832 oat_file_assistant.GetDexOptNeeded(
1833 CompilerFilter::kSpeedProfile, /*profile_changed=*/false, /*downgrade=*/true));
1834
1835 VerifyGetDexOptNeeded(&oat_file_assistant,
1836 CompilerFilter::kVerify,
1837 downgrade_trigger,
1838 /*expected_dexopt_needed=*/true,
1839 /*expected_is_vdex_usable=*/true,
1840 /*expected_location=*/OatFileAssistant::kLocationOdex);
1841 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
1842 oat_file_assistant.GetDexOptNeeded(
1843 CompilerFilter::kVerify, /*profile_changed=*/false, /*downgrade=*/true));
1844 }
1845
1846 // Case: We have a DEX file but we don't have an ODEX file for it. The caller's intention is to
1847 // downgrade the compiler filter.
1848 // Expect: Dexopt should never be performed regardless of the target compiler filter.
TEST_P(OatFileAssistantTest,DowngradeNoOdex)1849 TEST_P(OatFileAssistantTest, DowngradeNoOdex) {
1850 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1851 Copy(GetDexSrc1(), dex_location);
1852
1853 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1854
1855 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1856 OatFileAssistant::DexOptTrigger downgrade_trigger{.targetFilterIsWorse = true};
1857
1858 VerifyGetDexOptNeeded(&oat_file_assistant,
1859 CompilerFilter::kSpeed,
1860 downgrade_trigger,
1861 /*expected_dexopt_needed=*/false,
1862 /*expected_is_vdex_usable=*/false,
1863 /*expected_location=*/OatFileAssistant::kLocationNoneOrError);
1864 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1865 oat_file_assistant.GetDexOptNeeded(
1866 CompilerFilter::kSpeed, /*profile_changed=*/false, /*downgrade=*/true));
1867
1868 VerifyGetDexOptNeeded(&oat_file_assistant,
1869 CompilerFilter::kSpeedProfile,
1870 downgrade_trigger,
1871 /*expected_dexopt_needed=*/false,
1872 /*expected_is_vdex_usable=*/false,
1873 /*expected_location=*/OatFileAssistant::kLocationNoneOrError);
1874 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1875 oat_file_assistant.GetDexOptNeeded(
1876 CompilerFilter::kSpeedProfile, /*profile_changed=*/false, /*downgrade=*/true));
1877
1878 VerifyGetDexOptNeeded(&oat_file_assistant,
1879 CompilerFilter::kVerify,
1880 downgrade_trigger,
1881 /*expected_dexopt_needed=*/false,
1882 /*expected_is_vdex_usable=*/false,
1883 /*expected_location=*/OatFileAssistant::kLocationNoneOrError);
1884 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1885 oat_file_assistant.GetDexOptNeeded(
1886 CompilerFilter::kVerify, /*profile_changed=*/false, /*downgrade=*/true));
1887 }
1888
1889 // Case: We have a DEX file and speed-profile ODEX file for it. The legacy version is called with
1890 // both `profile_changed` and `downgrade` being true. This won't happen in the real case. Just to be
1891 // complete.
1892 // Expect: The behavior should be as `profile_changed` is false and `downgrade` is true.
TEST_P(OatFileAssistantTest,ProfileChangedDowngrade)1893 TEST_P(OatFileAssistantTest, ProfileChangedDowngrade) {
1894 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1895 std::string odex_location = GetOdexDir() + "/TestDex.odex";
1896 Copy(GetDexSrc1(), dex_location);
1897 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeedProfile);
1898
1899 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1900
1901 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1902
1903 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1904 oat_file_assistant.GetDexOptNeeded(
1905 CompilerFilter::kSpeed, /*profile_changed=*/true, /*downgrade=*/true));
1906
1907 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
1908 oat_file_assistant.GetDexOptNeeded(
1909 CompilerFilter::kSpeedProfile, /*profile_changed=*/true, /*downgrade=*/true));
1910
1911 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
1912 oat_file_assistant.GetDexOptNeeded(
1913 CompilerFilter::kVerify, /*profile_changed=*/true, /*downgrade=*/true));
1914 }
1915
1916 // Case: We have a DEX file and speed-profile ODEX file for it. The caller's intention is to force
1917 // the compilation.
1918 // Expect: Dexopt should be performed regardless of the target compiler filter. The VDEX file is
1919 // usable.
1920 //
1921 // The legacy version does not support this case. Historically, Package Manager does not take the
1922 // result from OatFileAssistant for forced compilation. It uses an arbitrary non-zero value instead.
1923 // Therefore, we don't test the legacy version here.
TEST_P(OatFileAssistantTest,Force)1924 TEST_P(OatFileAssistantTest, Force) {
1925 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1926 std::string odex_location = GetOdexDir() + "/TestDex.odex";
1927 Copy(GetDexSrc1(), dex_location);
1928 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeedProfile);
1929
1930 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1931
1932 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1933 OatFileAssistant::DexOptTrigger force_trigger{.targetFilterIsBetter = true,
1934 .targetFilterIsSame = true,
1935 .targetFilterIsWorse = true,
1936 .primaryBootImageBecomesUsable = true};
1937
1938 VerifyGetDexOptNeeded(&oat_file_assistant,
1939 CompilerFilter::kSpeed,
1940 force_trigger,
1941 /*expected_dexopt_needed=*/true,
1942 /*expected_is_vdex_usable=*/true,
1943 /*expected_location=*/OatFileAssistant::kLocationOdex);
1944
1945 VerifyGetDexOptNeeded(&oat_file_assistant,
1946 CompilerFilter::kSpeedProfile,
1947 force_trigger,
1948 /*expected_dexopt_needed=*/true,
1949 /*expected_is_vdex_usable=*/true,
1950 /*expected_location=*/OatFileAssistant::kLocationOdex);
1951
1952 VerifyGetDexOptNeeded(&oat_file_assistant,
1953 CompilerFilter::kVerify,
1954 force_trigger,
1955 /*expected_dexopt_needed=*/true,
1956 /*expected_is_vdex_usable=*/true,
1957 /*expected_location=*/OatFileAssistant::kLocationOdex);
1958 }
1959
1960 // Case: We have a DEX file but we don't have an ODEX file for it. The caller's intention is to
1961 // force the compilation.
1962 // Expect: Dexopt should be performed regardless of the target compiler filter. No VDEX file is
1963 // usable.
1964 //
1965 // The legacy version does not support this case. Historically, Package Manager does not take the
1966 // result from OatFileAssistant for forced compilation. It uses an arbitrary non-zero value instead.
1967 // Therefore, we don't test the legacy version here.
TEST_P(OatFileAssistantTest,ForceNoOdex)1968 TEST_P(OatFileAssistantTest, ForceNoOdex) {
1969 std::string dex_location = GetScratchDir() + "/TestDex.jar";
1970 Copy(GetDexSrc1(), dex_location);
1971
1972 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
1973
1974 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
1975 OatFileAssistant::DexOptTrigger force_trigger{.targetFilterIsBetter = true,
1976 .targetFilterIsSame = true,
1977 .targetFilterIsWorse = true,
1978 .primaryBootImageBecomesUsable = true};
1979
1980 VerifyGetDexOptNeeded(&oat_file_assistant,
1981 CompilerFilter::kSpeed,
1982 force_trigger,
1983 /*expected_dexopt_needed=*/true,
1984 /*expected_is_vdex_usable=*/false,
1985 /*expected_location=*/OatFileAssistant::kLocationNoneOrError);
1986
1987 VerifyGetDexOptNeeded(&oat_file_assistant,
1988 CompilerFilter::kSpeedProfile,
1989 force_trigger,
1990 /*expected_dexopt_needed=*/true,
1991 /*expected_is_vdex_usable=*/false,
1992 /*expected_location=*/OatFileAssistant::kLocationNoneOrError);
1993
1994 VerifyGetDexOptNeeded(&oat_file_assistant,
1995 CompilerFilter::kVerify,
1996 force_trigger,
1997 /*expected_dexopt_needed=*/true,
1998 /*expected_is_vdex_usable=*/false,
1999 /*expected_location=*/OatFileAssistant::kLocationNoneOrError);
2000 }
2001
2002 // Case: We have a DEX file and a DM file for it, and the DEX file is uncompressed.
2003 // Expect: Dexopt should be performed if the compiler filter is better than "verify". The location
2004 // should be kLocationDm.
2005 //
2006 // The legacy version should return kDex2OatFromScratch if the target compiler filter is better than
2007 // "verify".
TEST_P(OatFileAssistantTest,DmUpToDateDexUncompressed)2008 TEST_P(OatFileAssistantTest, DmUpToDateDexUncompressed) {
2009 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2010 std::string dm_location = GetScratchDir() + "/TestDex.dm";
2011 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2012 std::string vdex_location = GetOdexDir() + "/TestDex.vdex";
2013 Copy(GetMultiDexUncompressedAlignedSrc1(), dex_location);
2014
2015 // Generate temporary ODEX and VDEX files in order to create the DM file from.
2016 GenerateOdexForTest(
2017 dex_location, odex_location, CompilerFilter::kVerify, "install", {"--copy-dex-files=false"});
2018
2019 CreateDexMetadata(vdex_location, dm_location);
2020
2021 // Cleanup the temporary files.
2022 ASSERT_EQ(0, unlink(odex_location.c_str()));
2023 ASSERT_EQ(0, unlink(vdex_location.c_str()));
2024
2025 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2026
2027 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2028
2029 VerifyGetDexOptNeeded(&oat_file_assistant,
2030 CompilerFilter::kSpeed,
2031 default_trigger_,
2032 /*expected_dexopt_needed=*/true,
2033 /*expected_is_vdex_usable=*/true,
2034 /*expected_location=*/OatFileAssistant::kLocationDm);
2035 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
2036 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
2037
2038 VerifyGetDexOptNeeded(&oat_file_assistant,
2039 CompilerFilter::kSpeedProfile,
2040 default_trigger_,
2041 /*expected_dexopt_needed=*/true,
2042 /*expected_is_vdex_usable=*/true,
2043 /*expected_location=*/OatFileAssistant::kLocationDm);
2044 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
2045 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
2046
2047 VerifyGetDexOptNeeded(&oat_file_assistant,
2048 CompilerFilter::kVerify,
2049 default_trigger_,
2050 /*expected_dexopt_needed=*/false,
2051 /*expected_is_vdex_usable=*/true,
2052 /*expected_location=*/OatFileAssistant::kLocationDm);
2053 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
2054 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify));
2055 }
2056
2057 // Case: We have a DEX file and a DM file for it, and the DEX file is compressed.
2058 // Expect: Dexopt should be performed regardless of the compiler filter. The location
2059 // should be kLocationDm.
TEST_P(OatFileAssistantTest,DmUpToDateDexCompressed)2060 TEST_P(OatFileAssistantTest, DmUpToDateDexCompressed) {
2061 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2062 std::string dm_location = GetScratchDir() + "/TestDex.dm";
2063 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2064 std::string vdex_location = GetOdexDir() + "/TestDex.vdex";
2065 Copy(GetMultiDexSrc1(), dex_location);
2066
2067 // Generate temporary ODEX and VDEX files in order to create the DM file from.
2068 GenerateOdexForTest(
2069 dex_location, odex_location, CompilerFilter::kVerify, "install", {"--copy-dex-files=false"});
2070
2071 CreateDexMetadata(vdex_location, dm_location);
2072
2073 // Cleanup the temporary files.
2074 ASSERT_EQ(0, unlink(odex_location.c_str()));
2075 ASSERT_EQ(0, unlink(vdex_location.c_str()));
2076
2077 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2078
2079 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2080
2081 VerifyGetDexOptNeeded(&oat_file_assistant,
2082 CompilerFilter::kSpeed,
2083 default_trigger_,
2084 /*expected_dexopt_needed=*/true,
2085 /*expected_is_vdex_usable=*/true,
2086 /*expected_location=*/OatFileAssistant::kLocationDm);
2087 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
2088 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
2089
2090 VerifyGetDexOptNeeded(&oat_file_assistant,
2091 CompilerFilter::kSpeedProfile,
2092 default_trigger_,
2093 /*expected_dexopt_needed=*/true,
2094 /*expected_is_vdex_usable=*/true,
2095 /*expected_location=*/OatFileAssistant::kLocationDm);
2096 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
2097 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
2098
2099 VerifyGetDexOptNeeded(&oat_file_assistant,
2100 CompilerFilter::kVerify,
2101 default_trigger_,
2102 /*expected_dexopt_needed=*/true,
2103 /*expected_is_vdex_usable=*/true,
2104 /*expected_location=*/OatFileAssistant::kLocationDm);
2105 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
2106 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify));
2107 }
2108
2109 // Case: We have an ODEX file, but the DEX file is gone.
2110 // Expect: No dexopt is needed, as there's nothing we can do.
TEST_P(OatFileAssistantTest,OdexNoDex)2111 TEST_P(OatFileAssistantTest, OdexNoDex) {
2112 std::string dex_location = GetScratchDir() + "/OdexNoDex.jar";
2113 std::string odex_location = GetOdexDir() + "/OdexNoDex.oat";
2114
2115 Copy(GetDexSrc1(), dex_location);
2116 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
2117 ASSERT_EQ(0, unlink(dex_location.c_str()));
2118
2119 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2120
2121 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2122
2123 VerifyGetDexOptNeededDefault(&oat_file_assistant,
2124 CompilerFilter::kSpeed,
2125 /*expected_dexopt_needed=*/false,
2126 /*expected_is_vdex_usable=*/false,
2127 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
2128 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
2129
2130 VerifyOptimizationStatusWithInstance(&oat_file_assistant,
2131 "unknown",
2132 "unknown",
2133 "io-error-no-apk",
2134 OatFileAssistant::kLocationNoneOrError);
2135 }
2136
2137 // Case: We have a VDEX file, but the DEX file is gone.
2138 // Expect: No dexopt is needed, as there's nothing we can do.
TEST_P(OatFileAssistantTest,VdexNoDex)2139 TEST_P(OatFileAssistantTest, VdexNoDex) {
2140 std::string dex_location = GetScratchDir() + "/VdexNoDex.jar";
2141 std::string odex_location = GetOdexDir() + "/VdexNoDex.oat";
2142
2143 Copy(GetDexSrc1(), dex_location);
2144 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
2145 ASSERT_EQ(0, unlink(odex_location.c_str()));
2146 ASSERT_EQ(0, unlink(dex_location.c_str()));
2147
2148 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2149
2150 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2151
2152 VerifyGetDexOptNeededDefault(&oat_file_assistant,
2153 CompilerFilter::kSpeed,
2154 /*expected_dexopt_needed=*/false,
2155 /*expected_is_vdex_usable=*/false,
2156 /*expected_location=*/OatFileAssistant::kLocationNoneOrError,
2157 /*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
2158
2159 VerifyOptimizationStatusWithInstance(&oat_file_assistant,
2160 "unknown",
2161 "unknown",
2162 "io-error-no-apk",
2163 OatFileAssistant::kLocationNoneOrError);
2164 }
2165
2166 // Case: We have a VDEX file, generated without a boot image, and we now have a boot image.
2167 // Expect: Dexopt only if the target compiler filter >= "speed-profile".
TEST_P(OatFileAssistantTest,ShouldRecompileForImageFromVdex)2168 TEST_P(OatFileAssistantTest, ShouldRecompileForImageFromVdex) {
2169 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2170 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2171 std::string vdex_location = GetOdexDir() + "/TestDex.vdex";
2172 Copy(GetMultiDexSrc1(), dex_location);
2173
2174 // Compile without a boot image.
2175 GenerateOdexForTest(dex_location,
2176 odex_location,
2177 CompilerFilter::kVerify,
2178 "install",
2179 {"--boot-image=/nonx/boot.art"});
2180
2181 // Delete the odex file and only keep the vdex.
2182 ASSERT_EQ(0, unlink(odex_location.c_str()));
2183
2184 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2185
2186 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2187
2188 VerifyGetDexOptNeeded(&oat_file_assistant,
2189 CompilerFilter::kSpeed,
2190 default_trigger_,
2191 /*expected_dexopt_needed=*/true,
2192 /*expected_is_vdex_usable=*/true,
2193 /*expected_location=*/OatFileAssistant::kLocationOdex);
2194 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
2195 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
2196
2197 VerifyGetDexOptNeeded(&oat_file_assistant,
2198 CompilerFilter::kSpeedProfile,
2199 default_trigger_,
2200 /*expected_dexopt_needed=*/true,
2201 /*expected_is_vdex_usable=*/true,
2202 /*expected_location=*/OatFileAssistant::kLocationOdex);
2203 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
2204 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
2205
2206 VerifyGetDexOptNeeded(&oat_file_assistant,
2207 CompilerFilter::kVerify,
2208 default_trigger_,
2209 /*expected_dexopt_needed=*/false,
2210 /*expected_is_vdex_usable=*/true,
2211 /*expected_location=*/OatFileAssistant::kLocationOdex);
2212 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
2213 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify));
2214 }
2215
2216 // Case: We have an ODEX file, generated without a boot image (filter: "verify"), and we now have a
2217 // boot image.
2218 // Expect: Dexopt only if the target compiler filter >= "speed-profile".
TEST_P(OatFileAssistantTest,ShouldRecompileForImageFromVerify)2219 TEST_P(OatFileAssistantTest, ShouldRecompileForImageFromVerify) {
2220 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2221 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2222 std::string vdex_location = GetOdexDir() + "/TestDex.vdex";
2223 Copy(GetMultiDexSrc1(), dex_location);
2224
2225 // Compile without a boot image.
2226 GenerateOdexForTest(dex_location,
2227 odex_location,
2228 CompilerFilter::kVerify,
2229 "install",
2230 {"--boot-image=/nonx/boot.art"});
2231
2232 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2233
2234 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2235
2236 VerifyGetDexOptNeeded(&oat_file_assistant,
2237 CompilerFilter::kSpeed,
2238 default_trigger_,
2239 /*expected_dexopt_needed=*/true,
2240 /*expected_is_vdex_usable=*/true,
2241 /*expected_location=*/OatFileAssistant::kLocationOdex);
2242 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
2243 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
2244
2245 VerifyGetDexOptNeeded(&oat_file_assistant,
2246 CompilerFilter::kSpeedProfile,
2247 default_trigger_,
2248 /*expected_dexopt_needed=*/true,
2249 /*expected_is_vdex_usable=*/true,
2250 /*expected_location=*/OatFileAssistant::kLocationOdex);
2251 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
2252 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
2253
2254 VerifyGetDexOptNeeded(&oat_file_assistant,
2255 CompilerFilter::kVerify,
2256 default_trigger_,
2257 /*expected_dexopt_needed=*/false,
2258 /*expected_is_vdex_usable=*/true,
2259 /*expected_location=*/OatFileAssistant::kLocationOdex);
2260 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
2261 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify));
2262 }
2263
2264 // Case: We have an ODEX file, generated without a boot image (filter: "speed-profile"), and we now
2265 // have a boot image.
2266 // Expect: Dexopt only if the target compiler filter >= "speed-profile".
TEST_P(OatFileAssistantTest,ShouldRecompileForImageFromSpeedProfile)2267 TEST_P(OatFileAssistantTest, ShouldRecompileForImageFromSpeedProfile) {
2268 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2269 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2270 std::string vdex_location = GetOdexDir() + "/TestDex.vdex";
2271 Copy(GetMultiDexSrc1(), dex_location);
2272
2273 // Compile without a boot image.
2274 GenerateOdexForTest(dex_location,
2275 odex_location,
2276 CompilerFilter::kSpeedProfile,
2277 "install",
2278 {"--boot-image=/nonx/boot.art"});
2279
2280 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2281
2282 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2283
2284 VerifyGetDexOptNeeded(&oat_file_assistant,
2285 CompilerFilter::kSpeed,
2286 default_trigger_,
2287 /*expected_dexopt_needed=*/true,
2288 /*expected_is_vdex_usable=*/true,
2289 /*expected_location=*/OatFileAssistant::kLocationOdex);
2290 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
2291 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
2292
2293 VerifyGetDexOptNeeded(&oat_file_assistant,
2294 CompilerFilter::kSpeedProfile,
2295 default_trigger_,
2296 /*expected_dexopt_needed=*/true,
2297 /*expected_is_vdex_usable=*/true,
2298 /*expected_location=*/OatFileAssistant::kLocationOdex);
2299 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
2300 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
2301
2302 VerifyGetDexOptNeeded(&oat_file_assistant,
2303 CompilerFilter::kVerify,
2304 default_trigger_,
2305 /*expected_dexopt_needed=*/false,
2306 /*expected_is_vdex_usable=*/true,
2307 /*expected_location=*/OatFileAssistant::kLocationOdex);
2308 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
2309 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerify));
2310 }
2311
2312 // Test that GetLocation of a dex file is the same whether the dex
2313 // filed is backed by an oat file or not.
TEST_F(OatFileAssistantBaseTest,GetDexLocation)2314 TEST_F(OatFileAssistantBaseTest, GetDexLocation) {
2315 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2316 std::string oat_location = GetOdexDir() + "/TestDex.odex";
2317 std::string art_location = GetOdexDir() + "/TestDex.art";
2318
2319 // Start the runtime to initialize the system's class loader.
2320 Thread::Current()->TransitionFromSuspendedToRunnable();
2321 runtime_->Start();
2322
2323 Copy(GetDexSrc1(), dex_location);
2324
2325 std::vector<std::unique_ptr<const DexFile>> dex_files;
2326 std::vector<std::string> error_msgs;
2327 const OatFile* oat_file = nullptr;
2328
2329 dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
2330 dex_location.c_str(),
2331 Runtime::Current()->GetSystemClassLoader(),
2332 /*dex_elements=*/nullptr,
2333 &oat_file,
2334 &error_msgs);
2335 ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
2336 EXPECT_EQ(oat_file, nullptr);
2337 std::string stored_dex_location = dex_files[0]->GetLocation();
2338 {
2339 // Create the oat file.
2340 std::vector<std::string> args;
2341 args.push_back("--dex-file=" + dex_location);
2342 args.push_back("--dex-location=TestDex.jar");
2343 args.push_back("--oat-file=" + oat_location);
2344 args.push_back("--app-image-file=" + art_location);
2345 std::string error_msg;
2346 ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
2347 }
2348 dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
2349 dex_location.c_str(),
2350 Runtime::Current()->GetSystemClassLoader(),
2351 /*dex_elements=*/nullptr,
2352 &oat_file,
2353 &error_msgs);
2354 ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
2355 ASSERT_NE(oat_file, nullptr);
2356 std::string oat_stored_dex_location = dex_files[0]->GetLocation();
2357 EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
2358 }
2359
2360 // Test that a dex file on the platform location gets the right hiddenapi domain,
2361 // regardless of whether it has a backing oat file.
TEST_F(OatFileAssistantBaseTest,SystemFrameworkDir)2362 TEST_F(OatFileAssistantBaseTest, SystemFrameworkDir) {
2363 std::string filebase = "OatFileAssistantTestSystemFrameworkDir";
2364 std::string dex_location = GetAndroidRoot() + "/framework/" + filebase + ".jar";
2365 Copy(GetDexSrc1(), dex_location);
2366
2367 std::string odex_dir = GetAndroidRoot() + "/framework/oat/";
2368 mkdir(odex_dir.c_str(), 0700);
2369 odex_dir = odex_dir + std::string(GetInstructionSetString(kRuntimeISA));
2370 mkdir(odex_dir.c_str(), 0700);
2371 std::string oat_location = odex_dir + "/" + filebase + ".odex";
2372 std::string vdex_location = odex_dir + "/" + filebase + ".vdex";
2373 std::string art_location = odex_dir + "/" + filebase + ".art";
2374 // Clean up in case previous run crashed.
2375 remove(oat_location.c_str());
2376 remove(vdex_location.c_str());
2377 remove(art_location.c_str());
2378
2379 // Start the runtime to initialize the system's class loader.
2380 Thread::Current()->TransitionFromSuspendedToRunnable();
2381 runtime_->Start();
2382
2383 std::vector<std::unique_ptr<const DexFile>> dex_files_first;
2384 std::vector<std::unique_ptr<const DexFile>> dex_files_second;
2385 std::vector<std::string> error_msgs;
2386 const OatFile* oat_file = nullptr;
2387
2388 dex_files_first = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
2389 dex_location.c_str(),
2390 Runtime::Current()->GetSystemClassLoader(),
2391 /*dex_elements=*/nullptr,
2392 &oat_file,
2393 &error_msgs);
2394 ASSERT_EQ(dex_files_first.size(), 1u) << android::base::Join(error_msgs, "\n");
2395 EXPECT_EQ(oat_file, nullptr) << dex_location;
2396 EXPECT_EQ(dex_files_first[0]->GetOatDexFile(), nullptr);
2397
2398 // Register the dex file to get a domain.
2399 {
2400 ScopedObjectAccess soa(Thread::Current());
2401 Runtime::Current()->GetClassLinker()->RegisterDexFile(
2402 *dex_files_first[0],
2403 soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader()));
2404 }
2405 std::string stored_dex_location = dex_files_first[0]->GetLocation();
2406 EXPECT_EQ(dex_files_first[0]->GetHiddenapiDomain(), hiddenapi::Domain::kPlatform);
2407 {
2408 // Create the oat file.
2409 std::vector<std::string> args;
2410 args.push_back("--dex-file=" + dex_location);
2411 args.push_back("--dex-location=" + filebase + ".jar");
2412 args.push_back("--oat-file=" + oat_location);
2413 args.push_back("--app-image-file=" + art_location);
2414 std::string error_msg;
2415 ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
2416 }
2417 dex_files_second = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
2418 dex_location.c_str(),
2419 Runtime::Current()->GetSystemClassLoader(),
2420 /*dex_elements=*/nullptr,
2421 &oat_file,
2422 &error_msgs);
2423 ASSERT_EQ(dex_files_second.size(), 1u) << android::base::Join(error_msgs, "\n");
2424 ASSERT_NE(oat_file, nullptr);
2425 EXPECT_NE(dex_files_second[0]->GetOatDexFile(), nullptr);
2426 EXPECT_NE(dex_files_second[0]->GetOatDexFile()->GetOatFile(), nullptr);
2427
2428 // Register the dex file to get a domain.
2429 {
2430 ScopedObjectAccess soa(Thread::Current());
2431 Runtime::Current()->GetClassLinker()->RegisterDexFile(
2432 *dex_files_second[0],
2433 soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader()));
2434 }
2435 std::string oat_stored_dex_location = dex_files_second[0]->GetLocation();
2436 EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
2437 EXPECT_EQ(dex_files_second[0]->GetHiddenapiDomain(), hiddenapi::Domain::kPlatform);
2438 EXPECT_EQ(0, remove(oat_location.c_str()));
2439 }
2440
2441 // Make sure OAT files that require app images are not loaded as executable.
TEST_F(OatFileAssistantBaseTest,LoadOatNoArt)2442 TEST_F(OatFileAssistantBaseTest, LoadOatNoArt) {
2443 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2444 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2445 std::string art_location = GetOdexDir() + "/TestDex.art";
2446 Copy(GetDexSrc1(), dex_location);
2447 GenerateOdexForTest(dex_location,
2448 odex_location,
2449 CompilerFilter::kSpeed,
2450 "install",
2451 {
2452 "--app-image-file=" + art_location,
2453 });
2454
2455 unlink(art_location.c_str());
2456
2457 std::vector<std::string> error_msgs;
2458 const OatFile* oat_file = nullptr;
2459
2460 // Start the runtime to initialize the system's class loader.
2461 Thread::Current()->TransitionFromSuspendedToRunnable();
2462 runtime_->Start();
2463
2464 const auto dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
2465 dex_location.c_str(),
2466 Runtime::Current()->GetSystemClassLoader(),
2467 /*dex_elements=*/nullptr,
2468 &oat_file,
2469 &error_msgs);
2470
2471 EXPECT_FALSE(dex_files.empty());
2472 ASSERT_NE(oat_file, nullptr);
2473 EXPECT_FALSE(oat_file->IsExecutable());
2474 }
2475
TEST_P(OatFileAssistantTest,GetDexOptNeededWithApexVersions)2476 TEST_P(OatFileAssistantTest, GetDexOptNeededWithApexVersions) {
2477 std::string dex_location = GetScratchDir() + "/TestDex.jar";
2478 std::string odex_location = GetOdexDir() + "/TestDex.odex";
2479 Copy(GetDexSrc1(), dex_location);
2480
2481 // Test that using the current's runtime apex versions works.
2482 {
2483 std::string error_msg;
2484 std::vector<std::string> args;
2485 args.push_back("--dex-file=" + dex_location);
2486 args.push_back("--oat-file=" + odex_location);
2487 args.push_back("--apex-versions=" + Runtime::Current()->GetApexVersions());
2488 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
2489
2490 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2491
2492 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2493 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
2494 }
2495
2496 // Test that a subset of apex versions works.
2497 {
2498 std::string error_msg;
2499 std::vector<std::string> args;
2500 args.push_back("--dex-file=" + dex_location);
2501 args.push_back("--oat-file=" + odex_location);
2502 args.push_back("--apex-versions=" + Runtime::Current()->GetApexVersions().substr(0, 1));
2503 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
2504
2505 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2506
2507 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2508 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
2509 }
2510
2511 // Test that different apex versions require to recompile.
2512 {
2513 std::string error_msg;
2514 std::vector<std::string> args;
2515 args.push_back("--dex-file=" + dex_location);
2516 args.push_back("--oat-file=" + odex_location);
2517 args.push_back("--apex-versions=/1/2/3/4");
2518 ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
2519
2520 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2521
2522 OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
2523 EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
2524 }
2525 }
2526
TEST_P(OatFileAssistantTest,Create)2527 TEST_P(OatFileAssistantTest, Create) {
2528 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
2529 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
2530 Copy(GetDexSrc1(), dex_location);
2531 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
2532
2533 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2534
2535 std::unique_ptr<ClassLoaderContext> context;
2536 std::string error_msg;
2537 std::unique_ptr<OatFileAssistant> oat_file_assistant =
2538 OatFileAssistant::Create(dex_location,
2539 GetInstructionSetString(kRuntimeISA),
2540 default_context_->EncodeContextForDex2oat(/*base_dir=*/""),
2541 /*load_executable=*/false,
2542 /*only_load_trusted_executable=*/true,
2543 MaybeGetOatFileAssistantContext(),
2544 &context,
2545 &error_msg);
2546 ASSERT_NE(oat_file_assistant, nullptr);
2547
2548 // Verify that the created instance is usable.
2549 VerifyOptimizationStatusWithInstance(
2550 oat_file_assistant.get(), "speed", "install", "up-to-date", OatFileAssistant::kLocationOdex);
2551 }
2552
TEST_P(OatFileAssistantTest,CreateWithNullContext)2553 TEST_P(OatFileAssistantTest, CreateWithNullContext) {
2554 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
2555 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
2556 Copy(GetDexSrc1(), dex_location);
2557 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
2558
2559 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2560
2561 std::unique_ptr<ClassLoaderContext> context;
2562 std::string error_msg;
2563 std::unique_ptr<OatFileAssistant> oat_file_assistant =
2564 OatFileAssistant::Create(dex_location,
2565 GetInstructionSetString(kRuntimeISA),
2566 /*context_str=*/std::nullopt,
2567 /*load_executable=*/false,
2568 /*only_load_trusted_executable=*/true,
2569 MaybeGetOatFileAssistantContext(),
2570 &context,
2571 &error_msg);
2572 ASSERT_NE(oat_file_assistant, nullptr);
2573 ASSERT_EQ(context, nullptr);
2574
2575 // Verify that the created instance is usable.
2576 VerifyOptimizationStatusWithInstance(
2577 oat_file_assistant.get(), "speed", "install", "up-to-date", OatFileAssistant::kLocationOdex);
2578 }
2579
TEST_P(OatFileAssistantTest,ErrorOnInvalidIsaString)2580 TEST_P(OatFileAssistantTest, ErrorOnInvalidIsaString) {
2581 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
2582 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
2583 Copy(GetDexSrc1(), dex_location);
2584 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
2585
2586 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2587
2588 std::unique_ptr<ClassLoaderContext> context;
2589 std::string error_msg;
2590 EXPECT_EQ(OatFileAssistant::Create(dex_location,
2591 /*isa_str=*/"foo",
2592 default_context_->EncodeContextForDex2oat(/*base_dir=*/""),
2593 /*load_executable=*/false,
2594 /*only_load_trusted_executable=*/true,
2595 MaybeGetOatFileAssistantContext(),
2596 &context,
2597 &error_msg),
2598 nullptr);
2599 EXPECT_EQ(error_msg, "Instruction set 'foo' is invalid");
2600 }
2601
TEST_P(OatFileAssistantTest,ErrorOnInvalidContextString)2602 TEST_P(OatFileAssistantTest, ErrorOnInvalidContextString) {
2603 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
2604 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
2605 Copy(GetDexSrc1(), dex_location);
2606 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
2607
2608 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2609
2610 std::unique_ptr<ClassLoaderContext> context;
2611 std::string error_msg;
2612 EXPECT_EQ(OatFileAssistant::Create(dex_location,
2613 GetInstructionSetString(kRuntimeISA),
2614 /*context_str=*/"foo",
2615 /*load_executable=*/false,
2616 /*only_load_trusted_executable=*/true,
2617 MaybeGetOatFileAssistantContext(),
2618 &context,
2619 &error_msg),
2620 nullptr);
2621 EXPECT_EQ(error_msg, "Class loader context 'foo' is invalid");
2622 }
2623
TEST_P(OatFileAssistantTest,ErrorOnInvalidContextFile)2624 TEST_P(OatFileAssistantTest, ErrorOnInvalidContextFile) {
2625 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
2626 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
2627 Copy(GetDexSrc1(), dex_location);
2628 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
2629
2630 // Create a broken context file.
2631 std::string context_location = GetScratchDir() + "/BrokenContext.jar";
2632 std::ofstream output(context_location);
2633 output.close();
2634
2635 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2636
2637 std::unique_ptr<ClassLoaderContext> context;
2638 std::string error_msg;
2639 EXPECT_EQ(OatFileAssistant::Create(dex_location,
2640 GetInstructionSetString(kRuntimeISA),
2641 /*context_str=*/"PCL[" + context_location + "]",
2642 /*load_executable=*/false,
2643 /*only_load_trusted_executable=*/true,
2644 MaybeGetOatFileAssistantContext(),
2645 &context,
2646 &error_msg),
2647 nullptr);
2648 EXPECT_EQ(error_msg,
2649 "Failed to load class loader context files for '" + dex_location +
2650 "' with context 'PCL[" + context_location + "]'");
2651 }
2652
2653 // Verifies that `OatFileAssistant::ValidateBootClassPathChecksums` accepts the checksum string
2654 // produced by `gc::space::ImageSpace::GetBootClassPathChecksums`.
TEST_P(OatFileAssistantTest,ValidateBootClassPathChecksums)2655 TEST_P(OatFileAssistantTest, ValidateBootClassPathChecksums) {
2656 std::string error_msg;
2657 auto create_and_verify = [&]() {
2658 std::string checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
2659 ArrayRef<gc::space::ImageSpace* const>(runtime_->GetHeap()->GetBootImageSpaces()),
2660 ArrayRef<const DexFile* const>(runtime_->GetClassLinker()->GetBootClassPath()));
2661 std::string bcp_locations = android::base::Join(runtime_->GetBootClassPathLocations(), ':');
2662
2663 ofa_context_ = CreateOatFileAssistantContext();
2664 auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
2665 return OatFileAssistant::ValidateBootClassPathChecksums(
2666 ofa_context_.get(), kRuntimeISA, checksums, bcp_locations, &error_msg);
2667 };
2668
2669 ASSERT_TRUE(create_and_verify()) << error_msg;
2670
2671 for (const std::string& src : {GetDexSrc1(), GetDexSrc2()}) {
2672 ASSERT_TRUE(InsertNewBootClasspathEntry(src, &error_msg)) << error_msg;
2673 ASSERT_TRUE(create_and_verify()) << error_msg;
2674 }
2675 }
2676
2677 // TODO: More Tests:
2678 // * Test class linker falls back to unquickened dex for DexNoOat
2679 // * Test class linker falls back to unquickened dex for MultiDexNoOat
2680 // * Test using secondary isa
2681 // * Test for status of oat while oat is being generated (how?)
2682 // * Test case where 32 and 64 bit boot class paths differ,
2683 // and we ask IsInBootClassPath for a class in exactly one of the 32 or
2684 // 64 bit boot class paths.
2685 // * Test unexpected scenarios (?):
2686 // - Dex is stripped, don't have odex.
2687 // - Oat file corrupted after status check, before reload unexecutable
2688 // because it's unrelocated and no dex2oat
2689
2690 INSTANTIATE_TEST_SUITE_P(WithOrWithoutRuntime, OatFileAssistantTest, testing::Values(true, false));
2691
2692 } // namespace art
2693