Improve profile processing

- allow file descriptors in addition to file names for profiles
- fix some minor issues (wrong comparison signs, unhandled errors)
- added gtests for profile_compilation_info, profile_assistant
and compiler_driver

Bug: 26080105
Change-Id: I136039fa1f25858399000049e48b01eafae54eb1
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 32a237a..178d606 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -341,6 +341,12 @@
   UsageError("      --profile-file will be merged into --reference-profile-file. Valid only when");
   UsageError("      specified together with --profile-file.");
   UsageError("");
+  UsageError("  --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor.");
+  UsageError("      Cannot be used together with --profile-file.");
+  UsageError("");
+  UsageError("  --reference-profile-file-fd=<number>: same as --reference-profile-file but");
+  UsageError("      accepts a file descriptor. Cannot be used together with");
+  UsageError("       --reference-profile-file.");
   UsageError("  --print-pass-names: print a list of pass names");
   UsageError("");
   UsageError("  --disable-passes=<pass-names>:  disable one or more passes separated by comma.");
@@ -498,6 +504,14 @@
   return dex_files_size >= kMinDexFileCumulativeSizeForSwap;
 }
 
+static void CloseAllFds(const std::vector<uint32_t>& fds, const char* descriptor) {
+  for (size_t i = 0; i < fds.size(); i++) {
+    if (close(fds[i]) < 0) {
+      PLOG(WARNING) << "Failed to close descriptor for " << descriptor << " at index " << i;
+    }
+  }
+}
+
 class Dex2Oat FINAL {
  public:
   explicit Dex2Oat(TimingLogger* timings) :
@@ -576,6 +590,14 @@
     ParseUintOption(option, "--oat-fd", &oat_fd_, Usage);
   }
 
+  void ParseFdForCollection(const StringPiece& option,
+                            const char* arg_name,
+                            std::vector<uint32_t>* fds) {
+    uint32_t fd;
+    ParseUintOption(option, arg_name, &fd, Usage);
+    fds->push_back(fd);
+  }
+
   void ParseJ(const StringPiece& option) {
     ParseUintOption(option, "-j", &thread_count_, Usage, /* is_long_option */ false);
   }
@@ -779,11 +801,25 @@
       }
     }
 
+    if (!profile_files_.empty() && !profile_files_fd_.empty()) {
+      Usage("Profile files should not be specified with both --profile-file-fd and --profile-file");
+    }
     if (!profile_files_.empty()) {
       if (!reference_profile_files_.empty() &&
           (reference_profile_files_.size() != profile_files_.size())) {
         Usage("If specified, --reference-profile-file should match the number of --profile-file.");
       }
+    } else if (!reference_profile_files_.empty()) {
+      Usage("--reference-profile-file should only be supplied with --profile-file");
+    }
+    if (!profile_files_fd_.empty()) {
+      if (!reference_profile_files_fd_.empty() &&
+          (reference_profile_files_fd_.size() != profile_files_fd_.size())) {
+        Usage("If specified, --reference-profile-file-fd should match the number",
+              " of --profile-file-fd.");
+      }
+    } else if (!reference_profile_files_fd_.empty()) {
+      Usage("--reference-profile-file-fd should only be supplied with --profile-file-fd");
     }
 
     if (!parser_options->oat_symbols.empty()) {
@@ -1080,6 +1116,10 @@
       } else if (option.starts_with("--reference-profile-file=")) {
         reference_profile_files_.push_back(
             option.substr(strlen("--reference-profile-file=")).ToString());
+      } else if (option.starts_with("--profile-file-fd=")) {
+        ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_);
+      } else if (option.starts_with("--reference-profile-file-fd=")) {
+        ParseFdForCollection(option, "--reference_profile-file-fd", &reference_profile_files_fd_);
       } else if (option == "--no-profile-file") {
         // No profile
       } else if (option == "--host") {
@@ -1810,17 +1850,27 @@
   }
 
   bool UseProfileGuidedCompilation() const {
-    return !profile_files_.empty();
+    return !profile_files_.empty() || !profile_files_fd_.empty();
   }
 
   bool ProcessProfiles() {
     DCHECK(UseProfileGuidedCompilation());
     ProfileCompilationInfo* info = nullptr;
-    if (ProfileAssistant::ProcessProfiles(profile_files_, reference_profile_files_, &info)) {
-      profile_compilation_info_.reset(info);
-      return true;
+    bool result = false;
+    if (profile_files_.empty()) {
+      DCHECK(!profile_files_fd_.empty());
+      result = ProfileAssistant::ProcessProfiles(
+          profile_files_fd_, reference_profile_files_fd_, &info);
+      CloseAllFds(profile_files_fd_, "profile_files_fd_");
+      CloseAllFds(reference_profile_files_fd_, "reference_profile_files_fd_");
+    } else {
+      result = ProfileAssistant::ProcessProfiles(
+          profile_files_, reference_profile_files_, &info);
     }
-    return false;
+
+    profile_compilation_info_.reset(info);
+
+    return result;
   }
 
   bool ShouldCompileBasedOnProfiles() const {
@@ -2304,6 +2354,8 @@
   int app_image_fd_;
   std::vector<std::string> profile_files_;
   std::vector<std::string> reference_profile_files_;
+  std::vector<uint32_t> profile_files_fd_;
+  std::vector<uint32_t> reference_profile_files_fd_;
   std::unique_ptr<ProfileCompilationInfo> profile_compilation_info_;
   TimingLogger* timings_;
   std::unique_ptr<CumulativeLogger> compiler_phases_timings_;