Add option for not copying dex

If specified --avoid-copying-dex does not write the dex file into the
output vdex.

Added test to dex2oat_test.

Motivation: Use this for preopt on low end devices to speed
up first boot.

Bug: 70934104
Test: test-art-host

Change-Id: I181d35a923dccb0d08bb855c0a7f74af3ed1f48d
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 4ac8e6a..a627dbd 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -41,6 +41,8 @@
 #include "oat.h"
 #include "oat_file.h"
 #include "utils.h"
+#include "vdex_file.h"
+#include "ziparchive/zip_writer.h"
 
 namespace art {
 
@@ -1781,4 +1783,87 @@
   ASSERT_EQ(nullptr, odex_file->GetCompilationReason());
 }
 
+TEST_F(Dex2oatTest, DontExtract) {
+  std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
+  std::string error_msg;
+  const std::string out_dir = GetScratchDir();
+  const std::string dex_location = dex->GetLocation();
+  const std::string odex_location = out_dir + "/base.oat";
+  const std::string vdex_location = out_dir + "/base.vdex";
+  GenerateOdexForTest(dex_location,
+                      odex_location,
+                      CompilerFilter::Filter::kVerify,
+                      { "--copy-dex-files=false" },
+                      true,  // expect_success
+                      false,  // use_fd
+                      [](const OatFile&) {
+                      });
+  {
+    // Check the vdex doesn't have dex.
+    std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
+                                                  /*writable*/ false,
+                                                  /*low_4gb*/ false,
+                                                  /*unquicken*/ false,
+                                                  &error_msg));
+    ASSERT_TRUE(vdex != nullptr);
+    EXPECT_EQ(vdex->GetHeader().GetDexSize(), 0u) << output_;
+  }
+  std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                   odex_location.c_str(),
+                                                   nullptr,
+                                                   nullptr,
+                                                   false,
+                                                   /*low_4gb*/ false,
+                                                   dex_location.c_str(),
+                                                   &error_msg));
+  ASSERT_TRUE(odex_file != nullptr) << dex_location;
+  std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
+  ASSERT_EQ(oat_dex_files.size(), 1u);
+  // Verify that the oat file can still open the dex files.
+  for (const OatDexFile* oat_dex : oat_dex_files) {
+    std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
+    ASSERT_TRUE(dex_file != nullptr) << error_msg;
+  }
+  // Create a dm file and use it to verify.
+  // Add produced artifacts to a zip file that doesn't contain the classes.dex.
+  ScratchFile dm_file;
+  {
+    std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_location.c_str()));
+    ASSERT_TRUE(vdex_file != nullptr);
+    ASSERT_GT(vdex_file->GetLength(), 0u);
+    FILE* file = fdopen(dm_file.GetFd(), "w+b");
+    ZipWriter writer(file);
+    auto write_all_bytes = [&](File* file) {
+      std::unique_ptr<uint8_t[]> bytes(new uint8_t[file->GetLength()]);
+      ASSERT_TRUE(file->ReadFully(&bytes[0], file->GetLength()));
+      ASSERT_GE(writer.WriteBytes(&bytes[0], file->GetLength()), 0);
+    };
+    // Add vdex to zip.
+    writer.StartEntry(VdexFile::kVdexNameInDmFile, ZipWriter::kCompress);
+    write_all_bytes(vdex_file.get());
+    writer.FinishEntry();
+    writer.Finish();
+    ASSERT_EQ(dm_file.GetFile()->Flush(), 0);
+  }
+
+  // Generate a quickened dex by using the input dm file to verify.
+  GenerateOdexForTest(dex_location,
+                      odex_location,
+                      CompilerFilter::Filter::kQuicken,
+                      { "--dump-timings", "--dm-file=" + dm_file.GetFilename() },
+                      true,  // expect_success
+                      false,  // use_fd
+                      [](const OatFile& o) {
+                        CHECK(o.ContainsDexCode());
+                      });
+  std::istringstream iss(output_);
+  std::string line;
+  bool found_fast_verify = false;
+  const std::string kFastVerifyString = "Fast Verify";
+  while (std::getline(iss, line) && !found_fast_verify) {
+    found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos;
+  }
+  EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_;
+}
+
 }  // namespace art