Extract dex file if it is uncompressed but unaligned

A dex file would normally only be left in the zip file if it was both
uncompressed and unaligned, but explicitly setting CopyOptions::kNever
through --copy-dex-file=false would only check if the dex file was
uncompressed, not if it was aligned.  Add a required alignment
argument to ZipEntry::MapDirectlyOrExtract so that the contents
will be extracted into memory if they don't meet the alignment
requirement.

Bug: 119412419
Test: m test-art-host-gtest-oat_writer_test
Change-Id: I4587e22165ee0a951ffca7db9a6f5c0d1ed2e56a
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 12a8354..904ed7f 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1400,7 +1400,8 @@
         MemMap input_file = zip_entry->MapDirectlyOrExtract(
             VdexFile::kVdexNameInDmFile,
             kDexMetadata,
-            &error_msg);
+            &error_msg,
+            alignof(VdexFile));
         if (!input_file.IsValid()) {
           LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg;
         } else {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 7f2877f..fd3b95a 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -3667,7 +3667,7 @@
     for (OatDexFile& oat_dex_file : oat_dex_files_) {
       std::string error_msg;
       maps.emplace_back(oat_dex_file.source_.GetZipEntry()->MapDirectlyOrExtract(
-          oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg));
+          oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg, alignof(DexFile)));
       MemMap* map = &maps.back();
       if (!map->IsValid()) {
         LOG(ERROR) << error_msg;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index af02bfc..89c8ec8 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -119,7 +119,8 @@
         return false;
       }
     }
-    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
+    return DoWriteElf(
+        vdex_file, oat_file, oat_writer, key_value_store, verify, CopyOption::kOnlyIfCompressed);
   }
 
   bool WriteElf(File* vdex_file,
@@ -127,6 +128,7 @@
                 const std::vector<const char*>& dex_filenames,
                 SafeMap<std::string, std::string>& key_value_store,
                 bool verify,
+                CopyOption copy,
                 ProfileCompilationInfo* profile_compilation_info) {
     TimingLogger timings("WriteElf", false, false);
     ClearBootImageOption();
@@ -139,7 +141,7 @@
         return false;
       }
     }
-    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
+    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy);
   }
 
   bool WriteElf(File* vdex_file,
@@ -147,7 +149,8 @@
                 File&& zip_fd,
                 const char* location,
                 SafeMap<std::string, std::string>& key_value_store,
-                bool verify) {
+                bool verify,
+                CopyOption copy) {
     TimingLogger timings("WriteElf", false, false);
     ClearBootImageOption();
     OatWriter oat_writer(*compiler_options_,
@@ -157,14 +160,15 @@
     if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) {
       return false;
     }
-    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
+    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy);
   }
 
   bool DoWriteElf(File* vdex_file,
                   File* oat_file,
                   OatWriter& oat_writer,
                   SafeMap<std::string, std::string>& key_value_store,
-                  bool verify) {
+                  bool verify,
+                  CopyOption copy) {
     std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick(
         compiler_driver_->GetCompilerOptions(),
         oat_file);
@@ -178,7 +182,7 @@
         &key_value_store,
         verify,
         /*update_input_vdex=*/ false,
-        CopyOption::kOnlyIfCompressed,
+        copy,
         &opened_dex_files_maps,
         &opened_dex_files)) {
       return false;
@@ -258,7 +262,7 @@
   }
 
   void TestDexFileInput(bool verify, bool low_4gb, bool use_profile);
-  void TestZipFileInput(bool verify);
+  void TestZipFileInput(bool verify, CopyOption copy);
   void TestZipFileInputWithEmptyDex();
 
   std::unique_ptr<QuickCompilerCallbacks> callbacks_;
@@ -588,6 +592,7 @@
                      input_filenames,
                      key_value_store,
                      verify,
+                     CopyOption::kOnlyIfCompressed,
                      profile_compilation_info.get());
 
   // In verify mode, we expect failure.
@@ -664,7 +669,7 @@
   TestDexFileInput(/*verify*/true, /*low_4gb*/false, /*use_profile*/true);
 }
 
-void OatTest::TestZipFileInput(bool verify) {
+void OatTest::TestZipFileInput(bool verify, CopyOption copy) {
   TimingLogger timings("OatTest::DexFileInput", false, false);
 
   ScratchFile zip_file;
@@ -720,6 +725,7 @@
                        input_filenames,
                        key_value_store,
                        verify,
+                       copy,
                        /*profile_compilation_info=*/ nullptr);
 
     if (verify) {
@@ -770,7 +776,8 @@
                        std::move(zip_fd),
                        zip_file.GetFilename().c_str(),
                        key_value_store,
-                       verify);
+                       verify,
+                       copy);
     if (verify) {
       ASSERT_FALSE(success);
     } else {
@@ -810,11 +817,15 @@
 }
 
 TEST_F(OatTest, ZipFileInputCheckOutput) {
-  TestZipFileInput(false);
+  TestZipFileInput(false, CopyOption::kOnlyIfCompressed);
+}
+
+TEST_F(OatTest, ZipFileInputCheckOutputWithoutCopy) {
+  TestZipFileInput(false, CopyOption::kNever);
 }
 
 TEST_F(OatTest, ZipFileInputCheckVerifier) {
-  TestZipFileInput(true);
+  TestZipFileInput(true, CopyOption::kOnlyIfCompressed);
 }
 
 void OatTest::TestZipFileInputWithEmptyDex() {
@@ -834,6 +845,7 @@
                      input_filenames,
                      key_value_store,
                      /*verify=*/ false,
+                     CopyOption::kOnlyIfCompressed,
                      profile_compilation_info.get());
   ASSERT_FALSE(success);
 }
diff --git a/libartbase/base/zip_archive.cc b/libartbase/base/zip_archive.cc
index 8ceea83..a7f4b28 100644
--- a/libartbase/base/zip_archive.cc
+++ b/libartbase/base/zip_archive.cc
@@ -189,8 +189,9 @@
 
 MemMap ZipEntry::MapDirectlyOrExtract(const char* zip_filename,
                                       const char* entry_filename,
-                                      std::string* error_msg) {
-  if (IsUncompressed() && GetFileDescriptor(handle_) >= 0) {
+                                      std::string* error_msg,
+                                      size_t alignment) {
+  if (IsUncompressed() && IsAlignedTo(alignment) && GetFileDescriptor(handle_) >= 0) {
     std::string local_error_msg;
     MemMap ret = MapDirectlyFromFile(zip_filename, &local_error_msg);
     if (ret.IsValid()) {
diff --git a/libartbase/base/zip_archive.h b/libartbase/base/zip_archive.h
index d326a9e..fc04ec1 100644
--- a/libartbase/base/zip_archive.h
+++ b/libartbase/base/zip_archive.h
@@ -59,7 +59,8 @@
 
   MemMap MapDirectlyOrExtract(const char* zip_filename,
                               const char* entry_filename,
-                              std::string* error_msg);
+                              std::string* error_msg,
+                              size_t alignment);
 
   uint32_t GetUncompressedLength();
   uint32_t GetCrc32();
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index 6bd49a4..02f6344 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -1197,7 +1197,8 @@
     }
 
     // TODO(calin) pass along file names to assist with debugging.
-    MemMap map = zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry, "profile file", error);
+    MemMap map = zip_entry->MapDirectlyOrExtract(
+        kDexMetadataProfileEntry, "profile file", error, alignof(ProfileSource));
 
     if (map.IsValid()) {
       source->reset(ProfileSource::Create(std::move(map)));