Add a preloaded-classes-fds argument to dex2oat.

odrefresh passes files as fds.

Test: m
Bug: 162110941
Change-Id: I84cac774e66442268159e732e6313f8c77a061d2
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 57b81b6..f5c6bc9 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -823,6 +823,10 @@
       Usage("--dirty-image-objects and --dirty-image-objects-fd should not be both specified");
     }
 
+    if (!preloaded_classes_files_.empty() && !preloaded_classes_fds_.empty()) {
+      Usage("--preloaded-classes and --preloaded-classes-fds should not be both specified");
+    }
+
     if (!cpu_set_.empty()) {
       SetCpuAffinity(cpu_set_);
     }
@@ -1071,6 +1075,7 @@
     AssignIfExists(args, M::Profile, &profile_files_);
     AssignIfExists(args, M::ProfileFd, &profile_file_fds_);
     AssignIfExists(args, M::PreloadedClasses, &preloaded_classes_files_);
+    AssignIfExists(args, M::PreloadedClassesFds, &preloaded_classes_fds_);
     AssignIfExists(args, M::RuntimeOptions, &runtime_args_);
     AssignIfExists(args, M::SwapFile, &swap_file_name_);
     AssignIfExists(args, M::SwapFileFd, &swap_fd_);
@@ -2526,11 +2531,15 @@
   }
 
   bool PreparePreloadedClasses() {
-    preloaded_classes_.reset(new HashSet<std::string>());
-    for (const std::string& file : preloaded_classes_files_) {
-      ReadCommentedInputFromFile<HashSet<std::string>>(file.c_str(),
-                                                       nullptr,
-                                                       preloaded_classes_.get());
+    preloaded_classes_ = std::make_unique<HashSet<std::string>>();
+    if (!preloaded_classes_fds_.empty()) {
+      for (int fd : preloaded_classes_fds_) {
+        ReadCommentedInputFromFd(fd, nullptr, preloaded_classes_.get());
+      }
+    } else {
+      for (const std::string& file : preloaded_classes_files_) {
+        ReadCommentedInputFromFile(file.c_str(), nullptr, preloaded_classes_.get());
+      }
     }
     return true;
   }
@@ -2774,18 +2783,24 @@
     ReadCommentedInputStream<T>(input_file.get(), process, output);
   }
 
+  template <typename T>
+  static void ReadCommentedInputFromFd(
+      int input_fd, std::function<std::string(const char*)>* process, T* output) {
+    auto input_file = std::unique_ptr<FILE, decltype(&fclose)>{fdopen(input_fd, "r"), fclose};
+    if (!input_file) {
+      LOG(ERROR) << "Failed to re-open input fd from /prof/self/fd/" << input_fd;
+      return;
+    }
+    ReadCommentedInputStream<T>(input_file.get(), process, output);
+  }
+
   // Read lines from the given file, dropping comments and empty lines. Post-process each line with
   // the given function.
   template <typename T>
   static std::unique_ptr<T> ReadCommentedInputFromFile(
       const char* input_filename, std::function<std::string(const char*)>* process) {
-    auto input_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(input_filename, "r"), fclose};
-    if (!input_file) {
-      LOG(ERROR) << "Failed to open input file " << input_filename;
-      return nullptr;
-    }
     std::unique_ptr<T> output(new T());
-    ReadCommentedInputStream<T>(input_file.get(), process, output.get());
+    ReadCommentedInputFromFile(input_filename, process, output.get());
     return output;
   }
 
@@ -2794,13 +2809,8 @@
   template <typename T>
   static std::unique_ptr<T> ReadCommentedInputFromFd(
       int input_fd, std::function<std::string(const char*)>* process) {
-    auto input_file = std::unique_ptr<FILE, decltype(&fclose)>{fdopen(input_fd, "r"), fclose};
-    if (!input_file) {
-      LOG(ERROR) << "Failed to re-open input fd from /prof/self/fd/" << input_fd;
-      return nullptr;
-    }
     std::unique_ptr<T> output(new T());
-    ReadCommentedInputStream<T>(input_file.get(), process, output.get());
+    ReadCommentedInputFromFd(input_fd, process, output.get());
     return output;
   }
 
@@ -2950,6 +2960,7 @@
   std::vector<std::string> profile_files_;
   std::vector<int> profile_file_fds_;
   std::vector<std::string> preloaded_classes_files_;
+  std::vector<int> preloaded_classes_fds_;
   std::unique_ptr<ProfileCompilationInfo> profile_compilation_info_;
   TimingLogger* timings_;
   std::vector<std::vector<const DexFile*>> dex_files_per_oat_file_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index e8439cc..1f9138e 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -259,7 +259,11 @@
       .Define("--preloaded-classes=_")
           .WithType<std::vector<std::string>>().AppendValues()
           .WithHelp("Specify files containing list of classes preloaded in the zygote.")
-          .IntoKey(M::PreloadedClasses);
+          .IntoKey(M::PreloadedClasses)
+      .Define("--preloaded-classes-fds=_")
+          .WithType<std::vector<int>>().AppendValues()
+          .WithHelp("Specify files containing list of classes preloaded in the zygote.")
+          .IntoKey(M::PreloadedClassesFds);
 }
 
 static void AddTargetMappings(Builder& builder) {
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 2b47735..7c071dc 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -104,5 +104,6 @@
 DEX2OAT_OPTIONS_KEY (std::string,                    ApexVersions)
 DEX2OAT_OPTIONS_KEY (Unit,                           ForcePaletteCompilationHooks)
 DEX2OAT_OPTIONS_KEY (std::vector<std::string>,       PreloadedClasses)
+DEX2OAT_OPTIONS_KEY (std::vector<int>,               PreloadedClassesFds)
 
 #undef DEX2OAT_OPTIONS_KEY
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index 2455772..1d12b94 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -1348,6 +1348,15 @@
     LOG(WARNING) << "Missing dirty objects file : " << QuotePath(dirty_image_objects_file);
   }
 
+  const std::string preloaded_classes_file(GetAndroidRoot() + "/etc/preloaded-classes");
+  if (OS::FileExists(preloaded_classes_file.c_str())) {
+    std::unique_ptr<File> file(OS::OpenFileForReading(preloaded_classes_file.c_str()));
+    args.emplace_back(android::base::StringPrintf("--preloaded-classes-fds=%d", file->Fd()));
+    readonly_files_raii.push_back(std::move(file));
+  } else {
+    LOG(WARNING) << "Missing preloaded classes file : " << QuotePath(preloaded_classes_file);
+  }
+
   // Add boot classpath jars to compile.
   std::vector<std::string> jars_to_compile = boot_classpath_compilable_jars_;
   if (minimal) {