Add a public error code to DexFileLoader::OpenAll.

Some of the APKs in the build system don't contain any dex file (e.g.
they are only there to test that PackageManager can install them).
Users of this library (e.g. veridex) can now verify the error condition
to determine whether they should just skip the file or propagate the
error.

Test: m test-art-host-gtest; ran veridex on an APK without classes.dex
Bug: 110073830
Bug: 78924201
Change-Id: I65b6a5aa8abb404a77b90352dd066fb0dff36955
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 8261035..060d079 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1884,6 +1884,7 @@
     return -1;
   }
   const DexFileLoader dex_file_loader;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
@@ -1891,6 +1892,7 @@
                                fileName,
                                kVerify,
                                kVerifyChecksum,
+                               &error_code,
                                &error_msg,
                                &dex_files)) {
     // Display returned error message to user. Note that this error behavior
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 6a50258..88a74de 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -180,6 +180,7 @@
     return -1;
   }
   std::vector<std::unique_ptr<const DexFile>> dex_files;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   const DexFileLoader dex_file_loader;
   if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
@@ -187,6 +188,7 @@
                                fileName,
                                /*verify*/ true,
                                kVerifyChecksum,
+                               &error_code,
                                &error_msg,
                                &dex_files)) {
     LOG(ERROR) << error_msg;
diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc
index 392ce1e..cc7d7aa 100644
--- a/libdexfile/dex/art_dex_file_loader.cc
+++ b/libdexfile/dex/art_dex_file_loader.cc
@@ -352,17 +352,17 @@
     bool verify,
     bool verify_checksum,
     std::string* error_msg,
-    ZipOpenErrorCode* error_code) const {
+    DexFileLoaderErrorCode* error_code) const {
   ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
   CHECK(!location.empty());
   std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
   if (zip_entry == nullptr) {
-    *error_code = ZipOpenErrorCode::kEntryNotFound;
+    *error_code = DexFileLoaderErrorCode::kEntryNotFound;
     return nullptr;
   }
   if (zip_entry->GetUncompressedLength() == 0) {
     *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
-    *error_code = ZipOpenErrorCode::kDexFileError;
+    *error_code = DexFileLoaderErrorCode::kDexFileError;
     return nullptr;
   }
 
@@ -394,7 +394,7 @@
   if (map == nullptr) {
     *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
                               error_msg->c_str());
-    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+    *error_code = DexFileLoaderErrorCode::kExtractToMemoryError;
     return nullptr;
   }
   VerifyResult verify_result;
@@ -417,23 +417,23 @@
   }
   if (dex_file == nullptr) {
     if (verify_result == VerifyResult::kVerifyNotAttempted) {
-      *error_code = ZipOpenErrorCode::kDexFileError;
+      *error_code = DexFileLoaderErrorCode::kDexFileError;
     } else {
-      *error_code = ZipOpenErrorCode::kVerifyError;
+      *error_code = DexFileLoaderErrorCode::kVerifyError;
     }
     return nullptr;
   }
   if (!dex_file->DisableWrite()) {
     *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
-    *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
+    *error_code = DexFileLoaderErrorCode::kMakeReadOnlyError;
     return nullptr;
   }
   CHECK(dex_file->IsReadOnly()) << location;
   if (verify_result != VerifyResult::kVerifySucceeded) {
-    *error_code = ZipOpenErrorCode::kVerifyError;
+    *error_code = DexFileLoaderErrorCode::kVerifyError;
     return nullptr;
   }
-  *error_code = ZipOpenErrorCode::kNoError;
+  *error_code = DexFileLoaderErrorCode::kNoError;
   return dex_file;
 }
 
@@ -452,7 +452,7 @@
     std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
   ScopedTrace trace("Dex file open from Zip " + std::string(location));
   DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
-  ZipOpenErrorCode error_code;
+  DexFileLoaderErrorCode error_code;
   std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
                                                                 kClassesDex,
                                                                 location,
@@ -482,7 +482,7 @@
                                                                          error_msg,
                                                                          &error_code));
       if (next_dex_file.get() == nullptr) {
-        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+        if (error_code != DexFileLoaderErrorCode::kEntryNotFound) {
           LOG(WARNING) << "Zip open failed: " << *error_msg;
         }
         break;
diff --git a/libdexfile/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h
index a460aee..da2620f 100644
--- a/libdexfile/dex/art_dex_file_loader.h
+++ b/libdexfile/dex/art_dex_file_loader.h
@@ -119,7 +119,7 @@
                                                        bool verify,
                                                        bool verify_checksum,
                                                        std::string* error_msg,
-                                                       ZipOpenErrorCode* error_code) const;
+                                                       DexFileLoaderErrorCode* error_code) const;
 
   static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
                                              size_t size,
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 457addf..6d9ca4a 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -269,6 +269,7 @@
     const std::string& location,
     bool verify,
     bool verify_checksum,
+    DexFileLoaderErrorCode* error_code,
     std::string* error_msg,
     std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
   DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
@@ -283,6 +284,7 @@
                                   location,
                                   verify,
                                   verify_checksum,
+                                  error_code,
                                   error_msg,
                                   dex_files);
   }
@@ -387,17 +389,17 @@
     const std::string& location,
     bool verify,
     bool verify_checksum,
-    std::string* error_msg,
-    ZipOpenErrorCode* error_code) const {
+    DexFileLoaderErrorCode* error_code,
+    std::string* error_msg) const {
   CHECK(!location.empty());
   std::unique_ptr<DexZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
   if (zip_entry == nullptr) {
-    *error_code = ZipOpenErrorCode::kEntryNotFound;
+    *error_code = DexFileLoaderErrorCode::kEntryNotFound;
     return nullptr;
   }
   if (zip_entry->GetUncompressedLength() == 0) {
     *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
-    *error_code = ZipOpenErrorCode::kDexFileError;
+    *error_code = DexFileLoaderErrorCode::kDexFileError;
     return nullptr;
   }
 
@@ -405,7 +407,7 @@
   if (map.size() == 0) {
     *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
                               error_msg->c_str());
-    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+    *error_code = DexFileLoaderErrorCode::kExtractToMemoryError;
     return nullptr;
   }
   VerifyResult verify_result;
@@ -422,19 +424,15 @@
       error_msg,
       std::make_unique<VectorContainer>(std::move(map)),
       &verify_result);
-  if (dex_file == nullptr) {
+  if (verify_result != VerifyResult::kVerifySucceeded) {
     if (verify_result == VerifyResult::kVerifyNotAttempted) {
-      *error_code = ZipOpenErrorCode::kDexFileError;
+      *error_code = DexFileLoaderErrorCode::kDexFileError;
     } else {
-      *error_code = ZipOpenErrorCode::kVerifyError;
+      *error_code = DexFileLoaderErrorCode::kVerifyError;
     }
     return nullptr;
   }
-  if (verify_result != VerifyResult::kVerifySucceeded) {
-    *error_code = ZipOpenErrorCode::kVerifyError;
-    return nullptr;
-  }
-  *error_code = ZipOpenErrorCode::kNoError;
+  *error_code = DexFileLoaderErrorCode::kNoError;
   return dex_file;
 }
 
@@ -449,18 +447,18 @@
     const std::string& location,
     bool verify,
     bool verify_checksum,
+    DexFileLoaderErrorCode* error_code,
     std::string* error_msg,
     std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
   DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
-  ZipOpenErrorCode error_code;
   std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
                                                                 kClassesDex,
                                                                 location,
                                                                 verify,
                                                                 verify_checksum,
-                                                                error_msg,
-                                                                &error_code));
-  if (dex_file.get() == nullptr) {
+                                                                error_code,
+                                                                error_msg));
+  if (*error_code != DexFileLoaderErrorCode::kNoError) {
     return false;
   } else {
     // Had at least classes.dex.
@@ -479,10 +477,10 @@
                                                                          fake_location,
                                                                          verify,
                                                                          verify_checksum,
-                                                                         error_msg,
-                                                                         &error_code));
+                                                                         error_code,
+                                                                         error_msg));
       if (next_dex_file.get() == nullptr) {
-        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+        if (*error_code != DexFileLoaderErrorCode::kEntryNotFound) {
           LOG(WARNING) << "Zip open failed: " << *error_msg;
         }
         break;
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 0153220..8fc836e 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -31,6 +31,15 @@
 
 class DexZipArchive;
 
+enum class DexFileLoaderErrorCode {
+  kNoError,
+  kEntryNotFound,
+  kExtractToMemoryError,
+  kDexFileError,
+  kMakeReadOnlyError,
+  kVerifyError
+};
+
 // Class that is used to open dex files and deal with corresponding multidex and location logic.
 class DexFileLoader {
  public:
@@ -142,19 +151,11 @@
                        const std::string& location,
                        bool verify,
                        bool verify_checksum,
+                       DexFileLoaderErrorCode* error_code,
                        std::string* error_msg,
                        std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
  protected:
-  enum class ZipOpenErrorCode {
-    kNoError,
-    kEntryNotFound,
-    kExtractToMemoryError,
-    kDexFileError,
-    kMakeReadOnlyError,
-    kVerifyError
-  };
-
   enum class VerifyResult {  // private
     kVerifyNotAttempted,
     kVerifySucceeded,
@@ -180,6 +181,7 @@
                               const std::string& location,
                               bool verify,
                               bool verify_checksum,
+                              DexFileLoaderErrorCode* error_code,
                               std::string* error_msg,
                               std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
@@ -190,8 +192,8 @@
                                                        const std::string& location,
                                                        bool verify,
                                                        bool verify_checksum,
-                                                       std::string* error_msg,
-                                                       ZipOpenErrorCode* error_code) const;
+                                                       DexFileLoaderErrorCode* error_code,
+                                                       std::string* error_msg) const;
 };
 
 }  // namespace art
diff --git a/libdexfile/dex/dex_file_loader_test.cc b/libdexfile/dex/dex_file_loader_test.cc
index ab5c3f9..5bb01dd 100644
--- a/libdexfile/dex/dex_file_loader_test.cc
+++ b/libdexfile/dex/dex_file_loader_test.cc
@@ -210,6 +210,7 @@
                                const char* location,
                                std::vector<uint8_t>* dex_bytes,
                                std::vector<std::unique_ptr<const DexFile>>* dex_files,
+                               DexFileLoaderErrorCode* error_code,
                                std::string* error_msg) {
   DecodeDexFile(base64, dex_bytes);
 
@@ -222,6 +223,7 @@
                                          location,
                                          /* verify */ true,
                                          kVerifyChecksum,
+                                         error_code,
                                          error_msg,
                                          dex_files);
   return success;
@@ -231,9 +233,11 @@
                                                         const char* location,
                                                         std::vector<uint8_t>* dex_bytes) {
   // read dex files.
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  bool success = OpenDexFilesBase64(base64, location, dex_bytes, &dex_files, &error_msg);
+  bool success = OpenDexFilesBase64(base64, location, dex_bytes, &dex_files, &error_code,
+                                    &error_msg);
   CHECK(success) << error_msg;
   EXPECT_EQ(1U, dex_files.size());
   return std::move(dex_files[0]);
@@ -337,6 +341,7 @@
   DecodeDexFile(kRawDex40, &dex_bytes);
 
   static constexpr bool kVerifyChecksum = true;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   const DexFileLoader dex_file_loader;
@@ -345,6 +350,7 @@
                                        kLocationString,
                                        /* verify */ true,
                                        kVerifyChecksum,
+                                       &error_code,
                                        &error_msg,
                                        &dex_files));
 }
@@ -354,6 +360,7 @@
   DecodeDexFile(kRawDex41, &dex_bytes);
 
   static constexpr bool kVerifyChecksum = true;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   const DexFileLoader dex_file_loader;
@@ -362,6 +369,7 @@
                                        kLocationString,
                                        /* verify */ true,
                                        kVerifyChecksum,
+                                       &error_code,
                                        &error_msg,
                                        &dex_files));
 }
@@ -371,6 +379,7 @@
   DecodeDexFile(kRawDexZeroLength, &dex_bytes);
 
   static constexpr bool kVerifyChecksum = true;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   const DexFileLoader dex_file_loader;
@@ -379,6 +388,7 @@
                                        kLocationString,
                                        /* verify */ true,
                                        kVerifyChecksum,
+                                       &error_code,
                                        &error_msg,
                                        &dex_files));
 }
@@ -412,11 +422,13 @@
 TEST_F(DexFileLoaderTest, ZipOpenClassesPresent) {
   std::vector<uint8_t> dex_bytes;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   ASSERT_TRUE(OpenDexFilesBase64(kRawZipClassesDexPresent,
                                  kLocationString,
                                  &dex_bytes,
                                  &dex_files,
+                                 &error_code,
                                  &error_msg));
   EXPECT_EQ(dex_files.size(), 1u);
 }
@@ -424,23 +436,28 @@
 TEST_F(DexFileLoaderTest, ZipOpenClassesAbsent) {
   std::vector<uint8_t> dex_bytes;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   ASSERT_FALSE(OpenDexFilesBase64(kRawZipClassesDexAbsent,
                                   kLocationString,
                                   &dex_bytes,
                                   &dex_files,
+                                  &error_code,
                                   &error_msg));
+  EXPECT_EQ(error_code, DexFileLoaderErrorCode::kEntryNotFound);
   EXPECT_EQ(dex_files.size(), 0u);
 }
 
 TEST_F(DexFileLoaderTest, ZipOpenThreeDexFiles) {
   std::vector<uint8_t> dex_bytes;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
+  DexFileLoaderErrorCode error_code;
   std::string error_msg;
   ASSERT_TRUE(OpenDexFilesBase64(kRawZipThreeDexFiles,
                                  kLocationString,
                                  &dex_bytes,
                                  &dex_files,
+                                 &error_code,
                                  &error_msg));
   EXPECT_EQ(dex_files.size(), 3u);
 }
diff --git a/libdexfile/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc
index 65448ca..78b53a0 100644
--- a/libdexfile/dex/dex_file_verifier_test.cc
+++ b/libdexfile/dex/dex_file_verifier_test.cc
@@ -102,11 +102,13 @@
   // read dex
   std::vector<std::unique_ptr<const DexFile>> tmp;
   const DexFileLoader dex_file_loader;
+  DexFileLoaderErrorCode error_code;
   bool success = dex_file_loader.OpenAll(dex_bytes.get(),
                                          length,
                                          location,
                                          /* verify */ true,
                                          /* verify_checksum */ true,
+                                         &error_code,
                                          error_msg,
                                          &tmp);
   CHECK(success) << *error_msg;
diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc
index c90bb9c..d516400 100644
--- a/tools/dexanalyze/dexanalyze.cc
+++ b/tools/dexanalyze/dexanalyze.cc
@@ -185,6 +185,7 @@
       return result;
     }
 
+    DexFileLoaderErrorCode error_code;
     std::string error_msg;
     Analysis cumulative(&options);
     for (const std::string& filename : options.filenames_) {
@@ -201,6 +202,7 @@
                                    filename.c_str(),
                                    options.run_dex_file_verifier_,
                                    options.verify_checksum_,
+                                   &error_code,
                                    &error_msg,
                                    &dex_files)) {
         LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl;
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index bcd4815..1d3a4fb 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -269,6 +269,7 @@
     }
 
     const DexFileLoader dex_file_loader;
+    DexFileLoaderErrorCode error_code;
     static constexpr bool kVerifyChecksum = true;
     static constexpr bool kRunDexFileVerifier = true;
     if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
@@ -276,8 +277,13 @@
                                  filename.c_str(),
                                  kRunDexFileVerifier,
                                  kVerifyChecksum,
+                                 &error_code,
                                  error_msg,
                                  dex_files)) {
+      if (error_code == DexFileLoaderErrorCode::kEntryNotFound) {
+        LOG(INFO) << "No .dex found, skipping analysis.";
+        return true;
+      }
       return false;
     }