hiddenapi: Refactor before new features are added

Refactor the hiddenapi build tool to take a command name as its
first argument and create a notion of a "class path" group of dex
files. These changes will be needed for creating a new command
that resolves SDK stubs against the boot class path.

Bug: 79409988
Test: m hiddenapi
Test: m test-art-host-gtest-hiddenapi_test
Test: art/test.py -r -t 674-hiddenapi -t 999-redefine-hiddenapi
Change-Id: I93c36154cc8c5e8c0e9414cf02e2c6ea298ae0e8
diff --git a/test/etc/default-build b/test/etc/default-build
index 073ae2c..8542ad0 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -321,7 +321,7 @@
 }
 
 function make_hiddenapi() {
-  local args=()
+  local args=( "encode" )
   while [[ $# -gt 0 ]]; do
     args+=("--dex=$1")
     shift
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index 97e7f4c..2e1ec5a 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -61,18 +61,16 @@
   va_end(ap);
 
   UsageError("Command: %s", CommandLine().c_str());
-  UsageError("Usage: hiddenapi [options]...");
+  UsageError("Usage: hiddenapi [command_name] [options]...");
   UsageError("");
-  UsageError("  --dex=<filename>: specify dex file whose members' access flags are to be set.");
-  UsageError("      At least one --dex parameter must be specified.");
+  UsageError("  Command \"encode\": encode API list membership in boot dex files");
+  UsageError("    --dex=<filename>: dex file which belongs to boot class path,");
+  UsageError("                      the file will be overwritten");
   UsageError("");
-  UsageError("  --light-greylist=<filename>:");
-  UsageError("  --dark-greylist=<filename>:");
-  UsageError("  --blacklist=<filename>: text files with signatures of methods/fields to be marked");
-  UsageError("      greylisted/blacklisted respectively. At least one list must be provided.");
-  UsageError("");
-  UsageError("  --print-hidden-api: dump a list of marked methods/fields to the standard output.");
-  UsageError("      There is no indication which API category they belong to.");
+  UsageError("    --light-greylist=<filename>:");
+  UsageError("    --dark-greylist=<filename>:");
+  UsageError("    --blacklist=<filename>:");
+  UsageError("        text files with signatures of methods/fields to be annotated");
   UsageError("");
 
   exit(EXIT_FAILURE);
@@ -128,11 +126,6 @@
     UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags);
   }
 
-  // Returns true if this member's API entry is in `list`.
-  bool IsOnApiList(const std::unordered_set<std::string>& list) const {
-    return list.find(GetApiEntry()) != list.end();
-  }
-
   // Constructs a string with a unique signature of this class member.
   std::string GetApiEntry() const {
     std::stringstream ss;
@@ -164,174 +157,23 @@
   const ClassDataItemIterator& it_;
 };
 
-class HiddenApi FINAL {
+class ClassPath FINAL {
  public:
-  HiddenApi() : print_hidden_api_(false) {}
-
-  void ParseArgs(int argc, char** argv) {
-    original_argc = argc;
-    original_argv = argv;
-
-    android::base::InitLogging(argv);
-
-    // Skip over the command name.
-    argv++;
-    argc--;
-
-    if (argc == 0) {
-      Usage("No arguments specified");
-    }
-
-    for (int i = 0; i < argc; ++i) {
-      const StringPiece option(argv[i]);
-      const bool log_options = false;
-      if (log_options) {
-        LOG(INFO) << "hiddenapi: option[" << i << "]=" << argv[i];
-      }
-      if (option == "--print-hidden-api") {
-        print_hidden_api_ = true;
-      } else if (option.starts_with("--dex=")) {
-        dex_paths_.push_back(option.substr(strlen("--dex=")).ToString());
-      } else if (option.starts_with("--light-greylist=")) {
-        light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString();
-      } else if (option.starts_with("--dark-greylist=")) {
-        dark_greylist_path_ = option.substr(strlen("--dark-greylist=")).ToString();
-      } else if (option.starts_with("--blacklist=")) {
-        blacklist_path_ = option.substr(strlen("--blacklist=")).ToString();
-      } else {
-        Usage("Unknown argument '%s'", option.data());
-      }
-    }
+  explicit ClassPath(const std::vector<std::string>& dex_paths) {
+    OpenDexFiles(dex_paths);
   }
 
-  bool ProcessDexFiles() {
-    if (dex_paths_.empty()) {
-      Usage("No DEX files specified");
-    }
-
-    if (light_greylist_path_.empty() && dark_greylist_path_.empty() && blacklist_path_.empty()) {
-      Usage("No API file specified");
-    }
-
-    if (!light_greylist_path_.empty() && !OpenApiFile(light_greylist_path_, &light_greylist_)) {
-      return false;
-    }
-
-    if (!dark_greylist_path_.empty() && !OpenApiFile(dark_greylist_path_, &dark_greylist_)) {
-      return false;
-    }
-
-    if (!blacklist_path_.empty() && !OpenApiFile(blacklist_path_, &blacklist_)) {
-      return false;
-    }
-
-    MemMap::Init();
-    if (!OpenDexFiles()) {
-      return false;
-    }
-
-    DCHECK(!dex_files_.empty());
+  template<typename Fn>
+  void ForEachDexMember(Fn fn) {
     for (auto& dex_file : dex_files_) {
-      CategorizeAllClasses(*dex_file.get());
-    }
-
-    UpdateDexChecksums();
-    return true;
-  }
-
- private:
-  bool OpenApiFile(const std::string& path, std::unordered_set<std::string>* list) {
-    DCHECK(list->empty());
-    DCHECK(!path.empty());
-
-    std::ifstream api_file(path, std::ifstream::in);
-    if (api_file.fail()) {
-      LOG(ERROR) << "Unable to open file '" << path << "' " << strerror(errno);
-      return false;
-    }
-
-    for (std::string line; std::getline(api_file, line);) {
-      list->insert(line);
-    }
-
-    api_file.close();
-    return true;
-  }
-
-  bool OpenDexFiles() {
-    ArtDexFileLoader dex_loader;
-    DCHECK(dex_files_.empty());
-
-    for (const std::string& filename : dex_paths_) {
-      std::string error_msg;
-
-      File fd(filename.c_str(), O_RDWR, /* check_usage */ false);
-      if (fd.Fd() == -1) {
-        LOG(ERROR) << "Unable to open file '" << filename << "': " << strerror(errno);
-        return false;
-      }
-
-      // Memory-map the dex file with MAP_SHARED flag so that changes in memory
-      // propagate to the underlying file. We run dex file verification as if
-      // the dex file was not in boot claass path to check basic assumptions,
-      // such as that at most one of public/private/protected flag is set.
-      // We do those checks here and skip them when loading the processed file
-      // into boot class path.
-      std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(fd.Release(),
-                                                                 /* location */ filename,
-                                                                 /* verify */ true,
-                                                                 /* verify_checksum */ true,
-                                                                 /* mmap_shared */ true,
-                                                                 &error_msg));
-      if (dex_file.get() == nullptr) {
-        LOG(ERROR) << "Open failed for '" << filename << "' " << error_msg;
-        return false;
-      }
-
-      if (!dex_file->IsStandardDexFile()) {
-        LOG(ERROR) << "Expected a standard dex file '" << filename << "'";
-        return false;
-      }
-
-      // Change the protection of the memory mapping to read-write.
-      if (!dex_file->EnableWrite()) {
-        LOG(ERROR) << "Failed to enable write permission for '" << filename << "'";
-        return false;
-      }
-
-      dex_files_.push_back(std::move(dex_file));
-    }
-    return true;
-  }
-
-  void CategorizeAllClasses(const DexFile& dex_file) {
-    for (uint32_t class_idx = 0; class_idx < dex_file.NumClassDefs(); ++class_idx) {
-      DexClass klass(dex_file, class_idx);
-      const uint8_t* klass_data = klass.GetData();
-      if (klass_data == nullptr) {
-        continue;
-      }
-
-      for (ClassDataItemIterator it(klass.GetDexFile(), klass_data); it.HasNext(); it.Next()) {
-        DexMember member(klass, it);
-
-        // Catagorize member and overwrite its access flags.
-        // Note that if a member appears on multiple API lists, it will be categorized
-        // as the strictest.
-        bool is_hidden = true;
-        if (member.IsOnApiList(blacklist_)) {
-          member.SetHidden(HiddenApiAccessFlags::kBlacklist);
-        } else if (member.IsOnApiList(dark_greylist_)) {
-          member.SetHidden(HiddenApiAccessFlags::kDarkGreylist);
-        } else if (member.IsOnApiList(light_greylist_)) {
-          member.SetHidden(HiddenApiAccessFlags::kLightGreylist);
-        } else {
-          member.SetHidden(HiddenApiAccessFlags::kWhitelist);
-          is_hidden = false;
-        }
-
-        if (print_hidden_api_ && is_hidden) {
-          std::cout << member.GetApiEntry() << std::endl;
+      for (uint32_t class_idx = 0; class_idx < dex_file->NumClassDefs(); ++class_idx) {
+        DexClass klass(*dex_file, class_idx);
+        const uint8_t* klass_data = klass.GetData();
+        if (klass_data != nullptr) {
+          for (ClassDataItemIterator it(*dex_file, klass_data); it.HasNext(); it.Next()) {
+            DexMember member(klass, it);
+            fn(member);
+          }
         }
       }
     }
@@ -346,33 +188,147 @@
     }
   }
 
-  // Print signatures of APIs which have been grey-/blacklisted.
-  bool print_hidden_api_;
+ private:
+  void OpenDexFiles(const std::vector<std::string>& dex_paths) {
+    ArtDexFileLoader dex_loader;
+    std::string error_msg;
+    for (const std::string& filename : dex_paths) {
+      File fd(filename.c_str(), O_RDWR, /* check_usage */ false);
+      CHECK_NE(fd.Fd(), -1) << "Unable to open file '" << filename << "': " << strerror(errno);
+
+      // Memory-map the dex file with MAP_SHARED flag so that changes in memory
+      // propagate to the underlying file. We run dex file verification as if
+      // the dex file was not in boot claass path to check basic assumptions,
+      // such as that at most one of public/private/protected flag is set.
+      // We do those checks here and skip them when loading the processed file
+      // into boot class path.
+      std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(fd.Release(),
+                                                                 /* location */ filename,
+                                                                 /* verify */ true,
+                                                                 /* verify_checksum */ true,
+                                                                 /* mmap_shared */ true,
+                                                                 &error_msg));
+      CHECK(dex_file.get() != nullptr) << "Open failed for '" << filename << "' " << error_msg;
+      CHECK(dex_file->IsStandardDexFile()) << "Expected a standard dex file '" << filename << "'";
+      CHECK(dex_file->EnableWrite())
+          << "Failed to enable write permission for '" << filename << "'";
+      dex_files_.push_back(std::move(dex_file));
+    }
+  }
+
+  // Opened DEX files. Note that these are opened as `const` but may be written into.
+  std::vector<std::unique_ptr<const DexFile>> dex_files_;
+};
+
+class HiddenApi FINAL {
+ public:
+  HiddenApi() {}
+
+  void Run(int argc, char** argv) {
+    switch (ParseArgs(argc, argv)) {
+    case Command::kEncode:
+      EncodeAccessFlags();
+      break;
+    }
+  }
+
+ private:
+  enum class Command {
+    // Currently just one command. A "list" command will be added for generating
+    // a full list of boot class members.
+    kEncode,
+  };
+
+  Command ParseArgs(int argc, char** argv) {
+    // Skip over the binary's path.
+    argv++;
+    argc--;
+
+    if (argc > 0) {
+      const StringPiece command(argv[0]);
+      if (command == "encode") {
+        for (int i = 1; i < argc; ++i) {
+          const StringPiece option(argv[i]);
+          if (option.starts_with("--dex=")) {
+            boot_dex_paths_.push_back(option.substr(strlen("--dex=")).ToString());
+          } else if (option.starts_with("--light-greylist=")) {
+            light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString();
+          } else if (option.starts_with("--dark-greylist=")) {
+            dark_greylist_path_ = option.substr(strlen("--dark-greylist=")).ToString();
+          } else if (option.starts_with("--blacklist=")) {
+            blacklist_path_ = option.substr(strlen("--blacklist=")).ToString();
+          } else {
+            Usage("Unknown argument '%s'", option.data());
+          }
+        }
+        return Command::kEncode;
+      } else {
+        Usage("Unknown command '%s'", command.data());
+      }
+    } else {
+      Usage("No command specified");
+    }
+  }
+
+  void EncodeAccessFlags() {
+    if (boot_dex_paths_.empty()) {
+      Usage("No boot DEX files specified");
+    }
+
+    // Load dex signatures.
+    std::map<std::string, HiddenApiAccessFlags::ApiList> api_list;
+    OpenApiFile(light_greylist_path_, api_list, HiddenApiAccessFlags::kLightGreylist);
+    OpenApiFile(dark_greylist_path_, api_list, HiddenApiAccessFlags::kDarkGreylist);
+    OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist);
+
+    // Open all dex files.
+    ClassPath boot_class_path(boot_dex_paths_);
+
+    // Set access flags of all members.
+    boot_class_path.ForEachDexMember([&api_list](DexMember& boot_member) {
+      auto it = api_list.find(boot_member.GetApiEntry());
+      if (it == api_list.end()) {
+        boot_member.SetHidden(HiddenApiAccessFlags::kWhitelist);
+      } else {
+        boot_member.SetHidden(it->second);
+      }
+    });
+
+    boot_class_path.UpdateDexChecksums();
+  }
+
+  void OpenApiFile(const std::string& path,
+                   std::map<std::string, HiddenApiAccessFlags::ApiList>& api_list,
+                   HiddenApiAccessFlags::ApiList membership) {
+    if (path.empty()) {
+      return;
+    }
+
+    std::ifstream api_file(path, std::ifstream::in);
+    CHECK(!api_file.fail()) << "Unable to open file '" << path << "' " << strerror(errno);
+
+    for (std::string line; std::getline(api_file, line);) {
+      CHECK(api_list.find(line) == api_list.end())
+          << "Duplicate entry: " << line << " (" << api_list[line] << " and " << membership << ")";
+      api_list.emplace(line, membership);
+    }
+    api_file.close();
+  }
 
   // Paths to DEX files which should be processed.
-  std::vector<std::string> dex_paths_;
+  std::vector<std::string> boot_dex_paths_;
 
   // Paths to text files which contain the lists of API members.
   std::string light_greylist_path_;
   std::string dark_greylist_path_;
   std::string blacklist_path_;
-
-  // Opened DEX files. Note that these are opened as `const` but eventually will be written into.
-  std::vector<std::unique_ptr<const DexFile>> dex_files_;
-
-  // Signatures of DEX members loaded from `light_greylist_path_`, `dark_greylist_path_`,
-  // `blacklist_path_`.
-  std::unordered_set<std::string> light_greylist_;
-  std::unordered_set<std::string> dark_greylist_;
-  std::unordered_set<std::string> blacklist_;
 };
 
 }  // namespace art
 
 int main(int argc, char** argv) {
-  art::HiddenApi hiddenapi;
-
-  // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError.
-  hiddenapi.ParseArgs(argc, argv);
-  return hiddenapi.ProcessDexFiles() ? EXIT_SUCCESS : EXIT_FAILURE;
+  android::base::InitLogging(argv);
+  art::MemMap::Init();
+  art::HiddenApi().Run(argc, argv);
+  return EXIT_SUCCESS;
 }
diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc
index ed880e0..aa87f21 100644
--- a/tools/hiddenapi/hiddenapi_test.cc
+++ b/tools/hiddenapi/hiddenapi_test.cc
@@ -66,15 +66,18 @@
     std::vector<std::string> argv_str;
     argv_str.push_back(GetHiddenApiCmd());
     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
+    argv_str.push_back("encode");
     argv_str.push_back("--dex=" + out_dex->GetFilename());
     argv_str.push_back("--light-greylist=" + light_greylist.GetFilename());
     argv_str.push_back("--dark-greylist=" + dark_greylist.GetFilename());
     argv_str.push_back("--blacklist=" + blacklist.GetFilename());
     int return_code = ExecAndReturnCode(argv_str, &error);
-    if (return_code != 0) {
-      LOG(FATAL) << "HiddenApi binary exited with unexpected return code " << return_code;
+    if (return_code == 0) {
+      return OpenDex(*out_dex);
+    } else {
+      LOG(ERROR) << "HiddenApi binary exited with unexpected return code " << return_code;
+      return nullptr;
     }
-    return OpenDex(*out_dex);
   }
 
   std::unique_ptr<const DexFile> OpenDex(const ScratchFile& file) {
@@ -226,6 +229,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetIFieldHiddenFlags(*dex_file));
 }
 
@@ -235,6 +239,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetIFieldHiddenFlags(*dex_file));
 }
 
@@ -244,6 +249,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIFieldHiddenFlags(*dex_file));
 }
 
@@ -253,6 +259,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:I" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file));
 }
 
@@ -262,7 +269,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:I" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch2) {
@@ -271,7 +278,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:I" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch3) {
@@ -280,7 +287,7 @@
   OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl;
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticFieldNoMatch) {
@@ -289,6 +296,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSFieldHiddenFlags(*dex_file));
 }
 
@@ -298,6 +306,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSFieldHiddenFlags(*dex_file));
 }
 
@@ -307,6 +316,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSFieldHiddenFlags(*dex_file));
 }
 
@@ -316,6 +326,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file));
 }
 
@@ -325,7 +336,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch2) {
@@ -334,7 +345,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch3) {
@@ -343,7 +354,7 @@
   OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceMethodNoMatch) {
@@ -352,6 +363,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetIMethodHiddenFlags(*dex_file));
 }
 
@@ -361,6 +373,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetIMethodHiddenFlags(*dex_file));
 }
 
@@ -370,6 +383,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIMethodHiddenFlags(*dex_file));
 }
 
@@ -379,6 +393,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file));
 }
 
@@ -388,7 +403,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch2) {
@@ -397,7 +412,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch3) {
@@ -406,7 +421,7 @@
   OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl;
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticMethodNoMatch) {
@@ -415,6 +430,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSMethodHiddenFlags(*dex_file));
 }
 
@@ -424,6 +440,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSMethodHiddenFlags(*dex_file));
 }
 
@@ -433,6 +450,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSMethodHiddenFlags(*dex_file));
 }
 
@@ -442,6 +460,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file));
 }
 
@@ -451,7 +470,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch2) {
@@ -460,7 +479,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch3) {
@@ -469,7 +488,7 @@
   OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodNoMatch) {
@@ -478,6 +497,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetINMethodHiddenFlags(*dex_file));
 }
 
@@ -487,6 +507,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetINMethodHiddenFlags(*dex_file));
 }
 
@@ -496,6 +517,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetINMethodHiddenFlags(*dex_file));
 }
 
@@ -505,6 +527,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file));
 }
 
@@ -514,7 +537,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch2) {
@@ -523,7 +546,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch3) {
@@ -532,7 +555,7 @@
   OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl;
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodNoMatch) {
@@ -541,6 +564,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSNMethodHiddenFlags(*dex_file));
 }
 
@@ -550,6 +574,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSNMethodHiddenFlags(*dex_file));
 }
 
@@ -559,6 +584,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSNMethodHiddenFlags(*dex_file));
 }
 
@@ -568,6 +594,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
+  ASSERT_NE(dex_file.get(), nullptr);
   ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file));
 }
 
@@ -577,7 +604,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch2) {
@@ -586,7 +613,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch3) {
@@ -595,7 +622,7 @@
   OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(dex_file.get(), nullptr);
 }
 
 }  // namespace art