dex2oat: Move where we report end of compilation.

- Merge CompileApp and CompileImage which shared most of the logic.
- Add a scoped reporting class to report start and end of compilation.
- Dup the fds in the reporting, to not be subject to dex2oat
  refactorings.

Bug: 134558686
Test: test.py
Change-Id: I5db4b3fcb897b04aab325e7fe006e289d6f6b87d
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 0b996ec..1c63a86 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -40,6 +40,7 @@
 #include "android-base/parseint.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
+#include "android-base/unique_fd.h"
 
 #include "aot_class_linker.h"
 #include "arch/instruction_set_features.h"
@@ -517,7 +518,6 @@
       input_vdex_file_(nullptr),
       dm_fd_(-1),
       zip_fd_(-1),
-      zip_dup_fd_(-1),
       image_fd_(-1),
       have_multi_image_arg_(false),
       multi_image_(false),
@@ -1405,19 +1405,6 @@
   dex2oat::ReturnCode Setup() {
     TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
 
-    // At this point, file descriptors have been setup. Report that we're starting the compilation.
-    PaletteHooks* hooks = nullptr;
-    if (PaletteGetHooks(&hooks) == PALETTE_STATUS_OK) {
-      // We dup the zip file descriptor, as the oat writer will close it in
-      // OatWriter::CloseSources (we still want to close it there for
-      // consistency with other kinds of inputs).
-      zip_dup_fd_ = DupCloexec(zip_fd_);
-      hooks->NotifyStartDex2oatCompilation(zip_dup_fd_,
-                                           IsAppImage() ? app_image_fd_ : image_fd_,
-                                           oat_fd_,
-                                           output_vdex_fd_);
-    }
-
     if (!PrepareDirtyObjects()) {
       return dex2oat::ReturnCode::kOther;
     }
@@ -2161,17 +2148,6 @@
       }
     }
 
-    // Now that the files have been written to, report that we've ended the
-    // compilation.
-    PaletteHooks* hooks = nullptr;
-    if (PaletteGetHooks(&hooks) == PALETTE_STATUS_OK) {
-      hooks->NotifyEndDex2oatCompilation(zip_dup_fd_,
-                                         IsAppImage() ? app_image_fd_ : image_fd_,
-                                         oat_fd_,
-                                         output_vdex_fd_);
-      close(zip_dup_fd_);
-    }
-
     return true;
   }
 
@@ -2361,6 +2337,68 @@
     return true;
   }
 
+  class ScopedDex2oatReporting {
+   public:
+    explicit ScopedDex2oatReporting(const Dex2Oat& dex2oat) {
+      PaletteHooks* hooks = nullptr;
+      if (PaletteGetHooks(&hooks) == PALETTE_STATUS_OK) {
+        if (dex2oat.zip_fd_ != -1) {
+          zip_dup_fd_.reset(DupCloexecOrError(dex2oat.zip_fd_));
+          if (zip_dup_fd_ < 0) {
+            return;
+          }
+        }
+        int image_fd = dex2oat.IsAppImage() ? dex2oat.app_image_fd_ : dex2oat.image_fd_;
+        if (image_fd != -1) {
+          image_dup_fd_.reset(DupCloexecOrError(image_fd));
+          if (image_dup_fd_ < 0) {
+            return;
+          }
+        }
+        oat_dup_fd_.reset(DupCloexecOrError(dex2oat.oat_fd_));
+        if (oat_dup_fd_ < 0) {
+          return;
+        }
+        vdex_dup_fd_.reset(DupCloexecOrError(dex2oat.output_vdex_fd_));
+        if (vdex_dup_fd_ < 0) {
+          return;
+        }
+        hooks->NotifyStartDex2oatCompilation(zip_dup_fd_,
+                                             image_dup_fd_,
+                                             oat_dup_fd_,
+                                             vdex_dup_fd_);
+      }
+      error_reporting_ = false;
+    }
+
+    ~ScopedDex2oatReporting() {
+      PaletteHooks* hooks = nullptr;
+      if (!error_reporting_ && (PaletteGetHooks(&hooks) == PALETTE_STATUS_OK)) {
+        hooks->NotifyEndDex2oatCompilation(zip_dup_fd_,
+                                           image_dup_fd_,
+                                           oat_dup_fd_,
+                                           vdex_dup_fd_);
+      }
+    }
+
+    bool ErrorReporting() const { return error_reporting_; }
+
+   private:
+    int DupCloexecOrError(int fd) {
+      int dup_fd = DupCloexec(fd);
+      if (dup_fd < 0) {
+        LOG(ERROR) << "Error dup'ing a file descriptor " << strerror(errno);
+        error_reporting_ = true;
+      }
+      return dup_fd;
+    }
+    android::base::unique_fd oat_dup_fd_;
+    android::base::unique_fd vdex_dup_fd_;
+    android::base::unique_fd zip_dup_fd_;
+    android::base::unique_fd image_dup_fd_;
+    bool error_reporting_ = false;
+  };
+
  private:
   bool UseSwap(bool is_image, const std::vector<const DexFile*>& dex_files) {
     if (is_image) {
@@ -2800,7 +2838,6 @@
   std::vector<std::string> dex_filenames_;
   std::vector<std::string> dex_locations_;
   int zip_fd_;
-  int zip_dup_fd_;  // A dup of the zip fd in case we report it to Palette.
   std::string zip_location_;
   std::string boot_image_filename_;
   std::vector<const char*> runtime_args_;
@@ -2912,7 +2949,7 @@
   jobject obj_;
 };
 
-static dex2oat::ReturnCode CompileImage(Dex2Oat& dex2oat) {
+static dex2oat::ReturnCode DoCompilation(Dex2Oat& dex2oat) {
   dex2oat.LoadClassProfileDescriptors();
   jobject class_loader = dex2oat.Compile();
   // Keep the class loader that was used for compilation live for the rest of the compilation
@@ -2924,7 +2961,7 @@
     return dex2oat::ReturnCode::kOther;
   }
 
-  // Flush boot.oat.  Keep it open as we might still modify it later (strip it).
+  // Flush output files.  Keep them open as we might still modify them later (strip them).
   if (!dex2oat.FlushOutputFiles()) {
     dex2oat.EraseOutputFiles();
     return dex2oat::ReturnCode::kOther;
@@ -2944,51 +2981,13 @@
     return dex2oat::ReturnCode::kNoFailure;
   }
 
-  // Copy stripped to unstripped location, if necessary.
-  if (!dex2oat.CopyOatFilesToSymbolsDirectoryAndStrip()) {
-    return dex2oat::ReturnCode::kOther;
-  }
-
-  // FlushClose again, as stripping might have re-opened the oat files.
-  if (!dex2oat.FlushCloseOutputFiles()) {
-    return dex2oat::ReturnCode::kOther;
-  }
-
-  dex2oat.DumpTiming();
-  return dex2oat::ReturnCode::kNoFailure;
-}
-
-static dex2oat::ReturnCode CompileApp(Dex2Oat& dex2oat) {
-  jobject class_loader = dex2oat.Compile();
-  // Keep the class loader that was used for compilation live for the rest of the compilation
-  // process.
-  ScopedGlobalRef global_ref(class_loader);
-
-  if (!dex2oat.WriteOutputFiles(class_loader)) {
-    dex2oat.EraseOutputFiles();
-    return dex2oat::ReturnCode::kOther;
-  }
-
-  // Do not close the oat files here. We might have gotten the output file by file descriptor,
-  // which we would lose.
-
-  // When given --host, finish early without stripping.
-  if (dex2oat.IsHost()) {
-    if (!dex2oat.FlushCloseOutputFiles()) {
-      return dex2oat::ReturnCode::kOther;
-    }
-
-    dex2oat.DumpTiming();
-    return dex2oat::ReturnCode::kNoFailure;
-  }
-
   // Copy stripped to unstripped location, if necessary. This will implicitly flush & close the
   // stripped versions. If this is given, we expect to be able to open writable files by name.
   if (!dex2oat.CopyOatFilesToSymbolsDirectoryAndStrip()) {
     return dex2oat::ReturnCode::kOther;
   }
 
-  // Flush and close the files.
+  // FlushClose again, as stripping might have re-opened the oat files.
   if (!dex2oat.FlushCloseOutputFiles()) {
     return dex2oat::ReturnCode::kOther;
   }
@@ -3045,6 +3044,13 @@
     LOG(INFO) << StrippedCommandLine();
   }
 
+  Dex2Oat::ScopedDex2oatReporting sdr(*dex2oat.get());
+
+  if (sdr.ErrorReporting()) {
+    dex2oat->EraseOutputFiles();
+    return dex2oat::ReturnCode::kOther;
+  }
+
   dex2oat::ReturnCode setup_code = dex2oat->Setup();
   if (setup_code != dex2oat::ReturnCode::kNoFailure) {
     dex2oat->EraseOutputFiles();
@@ -3068,12 +3074,7 @@
   // instance. Used by tools/bisection_search/bisection_search.py.
   VLOG(compiler) << "Running dex2oat (parent PID = " << getppid() << ")";
 
-  dex2oat::ReturnCode result;
-  if (dex2oat->IsImage()) {
-    result = CompileImage(*dex2oat);
-  } else {
-    result = CompileApp(*dex2oat);
-  }
+  dex2oat::ReturnCode result = DoCompilation(*dex2oat);
 
   return result;
 }