ART: Add support for patching and loading OAT files compiled with PIC

* Images (.art) compiled with pic now have a new field added.
* isDexOptNeeded will now skip patch-ing for apps compiled PIC
* First-boot patching now only copies boot.art, boot.oat is linked

As a result, all system preopted dex files (with --compile-pic) no
longer take up any space in /data/dalvik-cache/<isa>.

Bug: 18035729
Change-Id: Ie1acad81a0fd8b2f24e1f3f07a06e6fdb548be62
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index fd36ad5..0ceef64 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -30,6 +30,7 @@
 namespace art {
 
 class ImageHeader;
+class OatHeader;
 
 namespace mirror {
 class Object;
@@ -40,14 +41,21 @@
 
 class PatchOat {
  public:
-  static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings);
+  // Patch only the oat file
+  static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings,
+                    bool output_oat_opened_from_fd,  // Was this using --oatput-oat-fd ?
+                    bool new_oat_out);               // Output oat was a new file created by us?
 
+  // Patch only the image (art file)
   static bool Patch(const std::string& art_location, off_t delta, File* art_out, InstructionSet isa,
                     TimingLogger* timings);
 
-  static bool Patch(const File* oat_in, const std::string& art_location,
+  // Patch both the image and the oat file
+  static bool Patch(File* oat_in, const std::string& art_location,
                     off_t delta, File* oat_out, File* art_out, InstructionSet isa,
-                    TimingLogger* timings);
+                    TimingLogger* timings,
+                    bool output_oat_opened_from_fd,  // Was this using --oatput-oat-fd ?
+                    bool new_oat_out);               // Output oat was a new file created by us?
 
  private:
   // Takes ownership only of the ElfFile. All other pointers are only borrowed.
@@ -64,6 +72,26 @@
         delta_(delta), timings_(timings) {}
   ~PatchOat() {}
 
+  // Was the .art image at image_path made with --compile-pic ?
+  static bool IsImagePic(const ImageHeader& image_header, const std::string& image_path);
+
+  enum MaybePic {
+      NOT_PIC,            // Code not pic. Patch as usual.
+      PIC,                // Code was pic. Create symlink; skip OAT patching.
+      ERROR_OAT_FILE,     // Failed to symlink oat file
+      ERROR_FIRST = ERROR_OAT_FILE,
+  };
+
+  // Was the .oat image at oat_in made with --compile-pic ?
+  static MaybePic IsOatPic(const ElfFile* oat_in);
+
+  // Attempt to replace the file with a symlink
+  // Returns false if it fails
+  static bool ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
+                                        const std::string& output_oat_filename,
+                                        bool output_oat_opened_from_fd,
+                                        bool new_oat_out);  // Output oat was newly created?
+
   static void BitmapCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     reinterpret_cast<PatchOat*>(arg)->VisitObject(obj);
@@ -95,6 +123,13 @@
   mirror::Object* RelocatedCopyOf(mirror::Object*);
   mirror::Object* RelocatedAddressOf(mirror::Object* obj);
 
+  // Look up the oat header from any elf file.
+  static const OatHeader* GetOatHeader(const ElfFile* elf_file);
+
+  // Templatized version to actually look up the oat header
+  template <typename ElfFileImpl>
+  static const OatHeader* GetOatHeader(const ElfFileImpl* elf_file);
+
   // Walks through the old image and patches the mmap'd copy of it to the new offset. It does not
   // change the heap.
   class PatchVisitor {