xref: /aosp_15_r20/art/runtime/oat/oat_file_assistant_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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