Add --dex-fd to dex2oat

Bug: 187327262
Test: odrefresh --force-compile
      (also, no longer seeing openat(2) BCP extension jars via strace)
Test: atest art_odrefresh_tests

Change-Id: Icac9ed522eae307e8e4391ba9cc59927c57c0d68
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 77b0f6e..7b38b8e 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -375,6 +375,28 @@
   static const char* DescribeType() { return "string value"; }
 };
 
+template <>
+struct CmdlineType<std::vector<int>> : CmdlineTypeParser<std::vector<int>> {
+  Result Parse(const std::string& args) {
+    assert(false && "Use AppendValues() for a int vector type");
+    return Result::Failure("Unconditional failure: string vector must be appended: " + args);
+  }
+
+  Result ParseAndAppend(const std::string& args,
+                        std::vector<int>& existing_value) {
+    auto result = ParseNumeric<int>(args);
+    if (result.IsSuccess()) {
+      existing_value.push_back(result.GetValue());
+    } else {
+      return Result::CastError(result);
+    }
+    return Result::SuccessNoValue();
+  }
+
+  static const char* Name() { return "std::vector<int>"; }
+  static const char* DescribeType() { return "int values"; }
+};
+
 template <typename ArgType, char Separator>
 struct ParseList {
   explicit ParseList(std::vector<ArgType>&& list) : list_(list) {}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index bbb94ea..e7391c5 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -742,6 +742,10 @@
       }
     }
 
+    if (!dex_fds_.empty() && dex_fds_.size() != dex_filenames_.size()) {
+      Usage("--dex-fd arguments do not match --dex-file arguments");
+    }
+
     if (zip_fd_ != -1 && zip_location_.empty()) {
       Usage("--zip-location should be supplied with --zip-fd");
     }
@@ -1031,6 +1035,7 @@
     AssignIfExists(args, M::CompactDexLevel, &compact_dex_level_);
     AssignIfExists(args, M::DexFiles, &dex_filenames_);
     AssignIfExists(args, M::DexLocations, &dex_locations_);
+    AssignIfExists(args, M::DexFds, &dex_fds_);
     AssignIfExists(args, M::OatFile, &oat_filenames_);
     AssignIfExists(args, M::OatSymbols, &parser_options->oat_symbols);
     AssignTrueIfExists(args, M::Strip, &strip_);
@@ -2565,6 +2570,11 @@
       DCHECK_EQ(dex_filenames_.size(), dex_locations_.size());
       DCHECK_GE(oat_writers_.size(), 1u);
 
+      bool use_dex_fds = !dex_fds_.empty();
+      if (use_dex_fds) {
+        DCHECK_EQ(dex_fds_.size(), dex_filenames_.size());
+      }
+
       bool is_multi_image = oat_writers_.size() > 1u;
       if (is_multi_image) {
         DCHECK_EQ(oat_writers_.size(), dex_filenames_.size());
@@ -2572,9 +2582,18 @@
 
       for (size_t i = 0; i != dex_filenames_.size(); ++i) {
         int oat_index = is_multi_image ? i : 0;
-        if (!oat_writers_[oat_index]->AddDexFileSource(dex_filenames_[i].c_str(),
-                                                       dex_locations_[i].c_str())) {
-          return false;
+        auto oat_writer = oat_writers_[oat_index].get();
+
+        if (use_dex_fds) {
+          if (!oat_writer->AddDexFileSource(File(dex_fds_[i], /* check_usage */ false),
+                                            dex_locations_[i].c_str())) {
+            return false;
+          }
+        } else {
+          if (!oat_writer->AddDexFileSource(dex_filenames_[i].c_str(),
+                                            dex_locations_[i].c_str())) {
+            return false;
+          }
         }
       }
     }
@@ -2879,6 +2898,7 @@
   std::unique_ptr<ZipArchive> dm_file_;
   std::vector<std::string> dex_filenames_;
   std::vector<std::string> dex_locations_;
+  std::vector<int> dex_fds_;
   int zip_fd_;
   std::string zip_location_;
   std::string boot_image_filename_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 24bb55a..e0524ac 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -71,6 +71,11 @@
                     "Eg: --dex-file=/home/build/out/system/framework/core.jar\n"
                     "    --dex-location=/system/framework/core.jar")
           .IntoKey(M::DexLocations)
+      .Define("--dex-fd=_")
+          .WithType<std::vector<int>>().AppendValues()
+          .WithHelp("Specifies a file descriptor of a dex file. It can be specified for multiple\n"
+                    "times, but the number must match the number of --dex-file. Eg: --dex-fd=5")
+          .IntoKey(M::DexFds)
       .Define("--zip-fd=_")
           .WithType<int>()
           .WithHelp("specifies a file descriptor of a zip file containing a classes.dex file to\n"
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 8aedc5f..1c1a9d7 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -37,6 +37,7 @@
 DEX2OAT_OPTIONS_KEY (CompactDexLevel,                CompactDexLevel)
 DEX2OAT_OPTIONS_KEY (std::vector<std::string>,       DexFiles)
 DEX2OAT_OPTIONS_KEY (std::vector<std::string>,       DexLocations)
+DEX2OAT_OPTIONS_KEY (std::vector<int>,               DexFds)
 DEX2OAT_OPTIONS_KEY (int,                            ZipFd)
 DEX2OAT_OPTIONS_KEY (std::string,                    ZipLocation)
 DEX2OAT_OPTIONS_KEY (int,                            InputVdexFd)
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index f78802d..d05a668 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -1019,8 +1019,12 @@
     }
 
     // Add boot extensions to compile.
+    std::vector<std::unique_ptr<File>> readonly_files_raii;
     for (const std::string& component : boot_extension_compilable_jars_) {
       args.emplace_back("--dex-file=" + component);
+      std::unique_ptr<File> file(OS::OpenFileForReading(component.c_str()));
+      args.emplace_back(android::base::StringPrintf("--dex-fd=%d", file->Fd()));
+      readonly_files_raii.push_back(std::move(file));
     }
 
     args.emplace_back("--runtime-arg");
@@ -1108,11 +1112,16 @@
 
     const std::string dex2oat = config_.GetDex2Oat();
     const InstructionSet isa = config_.GetSystemServerIsa();
+    std::vector<std::unique_ptr<File>> readonly_files_raii;
     for (const std::string& jar : systemserver_compilable_jars_) {
       std::vector<std::string> args;
       args.emplace_back(dex2oat);
       args.emplace_back("--dex-file=" + jar);
 
+      std::unique_ptr<File> dex_file(OS::OpenFileForReading(jar.c_str()));
+      args.emplace_back(android::base::StringPrintf("--dex-fd=%d", dex_file->Fd()));
+      readonly_files_raii.push_back(std::move(dex_file));
+
       AddDex2OatCommonOptions(args);
       AddDex2OatConcurrencyArguments(args);
       AddDex2OatDebugInfo(args);