Tweaks to patchoat and other related things.

Removed some flags from patchoat that were poorly specified and fixed
some other issues with the relocation system.

Bug: 15358152

Change-Id: Ia6d47b1a008f02373307d833ba45f00ea408d76f
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d6501a1..a78d3f7 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -849,7 +849,6 @@
   bool dump_timing = false;
   bool dump_passes = false;
   bool include_patch_information = CompilerOptions::kDefaultIncludePatchInformation;
-  bool explicit_include_patch_information = false;
   bool include_debug_symbols = kIsDebugBuild;
   bool dump_slow_timing = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
@@ -1037,10 +1036,8 @@
       PassDriverMEOpts::SetDumpPassList(dump_passes);
     } else if (option == "--include-patch-information") {
       include_patch_information = true;
-      explicit_include_patch_information = true;
     } else if (option == "--no-include-patch-information") {
       include_patch_information = false;
-      explicit_include_patch_information = true;
     } else {
       Usage("Unknown argument %s", option.data());
     }
@@ -1167,11 +1164,6 @@
     Usage("Unknown --compiler-filter value %s", compiler_filter_string);
   }
 
-  if (!explicit_include_patch_information) {
-    include_patch_information =
-        (compiler_kind == Compiler::kQuick && CompilerOptions::kDefaultIncludePatchInformation);
-  }
-
   // Set the compilation target's implicit checks options.
   switch (instruction_set) {
     case kArm:
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 4c88c9e..72189c3 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -66,6 +66,47 @@
   }
 }
 
+static bool LocationToFilename(const std::string& location, InstructionSet isa,
+                               std::string* filename) {
+  bool has_system = false;
+  bool has_cache = false;
+  // image_location = /system/framework/boot.art
+  // system_image_location = /system/framework/<image_isa>/boot.art
+  std::string system_filename(GetSystemImageFilename(location.c_str(), isa));
+  if (OS::FileExists(system_filename.c_str())) {
+    has_system = true;
+  }
+
+  bool have_android_data = false;
+  bool dalvik_cache_exists = false;
+  std::string dalvik_cache;
+  GetDalvikCache(GetInstructionSetString(isa), false, &dalvik_cache,
+                 &have_android_data, &dalvik_cache_exists);
+
+  std::string cache_filename;
+  if (have_android_data && dalvik_cache_exists) {
+    // Always set output location even if it does not exist,
+    // so that the caller knows where to create the image.
+    //
+    // image_location = /system/framework/boot.art
+    // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
+    std::string error_msg;
+    if (GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(),
+                               &cache_filename, &error_msg)) {
+      has_cache = true;
+    }
+  }
+  if (has_system) {
+    *filename = system_filename;
+    return true;
+  } else if (has_cache) {
+    *filename = cache_filename;
+    return true;
+  } else {
+    return false;
+  }
+}
+
 bool PatchOat::Patch(const std::string& image_location, off_t delta,
                      File* output_image, InstructionSet isa,
                      TimingLogger* timings) {
@@ -77,10 +118,15 @@
 
   TimingLogger::ScopedTiming t("Runtime Setup", timings);
   const char *isa_name = GetInstructionSetString(isa);
-  std::string image_filename(GetSystemImageFilename(image_location.c_str(), isa));
+  std::string image_filename;
+  if (!LocationToFilename(image_location, isa, &image_filename)) {
+    LOG(ERROR) << "Unable to find image at location " << image_location;
+    return false;
+  }
   std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str()));
   if (input_image.get() == nullptr) {
-    LOG(ERROR) << "unable to open input image file.";
+    LOG(ERROR) << "unable to open input image file at " << image_filename
+               << " for location " << image_location;
     return false;
   }
   int64_t image_len = input_image->GetLength();
@@ -162,10 +208,15 @@
     isa = ElfISAToInstructionSet(elf_hdr.e_machine);
   }
   const char* isa_name = GetInstructionSetString(isa);
-  std::string image_filename(GetSystemImageFilename(image_location.c_str(), isa));
+  std::string image_filename;
+  if (!LocationToFilename(image_location, isa, &image_filename)) {
+    LOG(ERROR) << "Unable to find image at location " << image_location;
+    return false;
+  }
   std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str()));
   if (input_image.get() == nullptr) {
-    LOG(ERROR) << "unable to open input image file.";
+    LOG(ERROR) << "unable to open input image file at " << image_filename
+               << " for location " << image_location;
     return false;
   }
   int64_t image_len = input_image->GetLength();
@@ -239,11 +290,6 @@
 
 bool PatchOat::WriteElf(File* out) {
   TimingLogger::ScopedTiming t("Writing Elf File", timings_);
-  std::string error_msg;
-
-  // Lock the output file.
-  ScopedFlock flock;
-  flock.Init(out, &error_msg);
 
   CHECK(oat_file_.get() != nullptr);
   CHECK(out != nullptr);
@@ -261,9 +307,8 @@
   TimingLogger::ScopedTiming t("Writing image File", timings_);
   std::string error_msg;
 
-  // Lock the output file.
-  ScopedFlock flock;
-  flock.Init(out, &error_msg);
+  ScopedFlock img_flock;
+  img_flock.Init(out, &error_msg);
 
   CHECK(image_ != nullptr);
   CHECK(out != nullptr);
@@ -625,9 +670,6 @@
   UsageError("  --output-oat-file=<file.oat>: Specifies the exact file to write the patched oat");
   UsageError("      file to.");
   UsageError("");
-  UsageError("  --output-oat-location=<file.oat>: Specifies the 'location' to write the patched");
-  UsageError("      oat file to. If used one must also specify the --instruction-set");
-  UsageError("");
   UsageError("  --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the");
   UsageError("      the patched oat file to.");
   UsageError("");
@@ -637,9 +679,6 @@
   UsageError("  --output-image-fd=<file-descriptor>: Specifies the file-descriptor to write the");
   UsageError("      the patched image file to.");
   UsageError("");
-  UsageError("  --output-image-location=<file.art>: Specifies the 'location' to write the patched");
-  UsageError("      image file to. If used one must also specify the --instruction-set");
-  UsageError("");
   UsageError("  --orig-base-offset=<original-base-offset>: Specify the base offset the input file");
   UsageError("      was compiled with. This is needed if one is specifying a --base-offset");
   UsageError("");
@@ -657,6 +696,10 @@
   UsageError("      --instruction-set flag. It will search for this image in the same way that");
   UsageError("      is done when loading one.");
   UsageError("");
+  UsageError("  --lock-output: Obtain a flock on output oat file before starting.");
+  UsageError("");
+  UsageError("  --no-lock-output: Do not attempt to obtain a flock on output oat file.");
+  UsageError("");
   UsageError("  --dump-timings: dump out patch timing information");
   UsageError("");
   UsageError("  --no-dump-timings: do not dump out patch timing information");
@@ -699,7 +742,15 @@
     return OS::OpenFileReadWrite(name);
   } else {
     *created = true;
-    return OS::CreateEmptyFile(name);
+    std::unique_ptr<File> f(OS::CreateEmptyFile(name));
+    if (f.get() != nullptr) {
+      if (fchmod(f->Fd(), 0644) != 0) {
+        PLOG(ERROR) << "Unable to make " << name << " world readable";
+        unlink(name);
+        return nullptr;
+      }
+    }
+    return f.release();
   }
 }
 
@@ -731,11 +782,9 @@
   bool have_input_oat = false;
   std::string input_image_location;
   std::string output_oat_filename;
-  std::string output_oat_location;
   int output_oat_fd = -1;
   bool have_output_oat = false;
   std::string output_image_filename;
-  std::string output_image_location;
   int output_image_fd = -1;
   bool have_output_image = false;
   uintptr_t base_offset = 0;
@@ -747,6 +796,7 @@
   std::string patched_image_filename;
   std::string patched_image_location;
   bool dump_timings = kIsDebugBuild;
+  bool lock_output = true;
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
@@ -797,24 +847,15 @@
       }
     } else if (option.starts_with("--input-image-location=")) {
       input_image_location = option.substr(strlen("--input-image-location=")).data();
-    } else if (option.starts_with("--output-oat-location=")) {
-      if (have_output_oat) {
-        Usage("Only one of --output-oat-file, --output-oat-location and --output-oat-fd may "
-              "be used.");
-      }
-      have_output_oat = true;
-      output_oat_location = option.substr(strlen("--output-oat-location=")).data();
     } else if (option.starts_with("--output-oat-file=")) {
       if (have_output_oat) {
-        Usage("Only one of --output-oat-file, --output-oat-location and --output-oat-fd may "
-              "be used.");
+        Usage("Only one of --output-oat-file, and --output-oat-fd may be used.");
       }
       have_output_oat = true;
       output_oat_filename = option.substr(strlen("--output-oat-file=")).data();
     } else if (option.starts_with("--output-oat-fd=")) {
       if (have_output_oat) {
-        Usage("Only one of --output-oat-file, --output-oat-location and --output-oat-fd may "
-              "be used.");
+        Usage("Only one of --output-oat-file, --output-oat-fd may be used.");
       }
       have_output_oat = true;
       const char* oat_fd_str = option.substr(strlen("--output-oat-fd=")).data();
@@ -824,24 +865,15 @@
       if (output_oat_fd < 0) {
         Usage("--output-oat-fd pass a negative value %d", output_oat_fd);
       }
-    } else if (option.starts_with("--output-image-location=")) {
-      if (have_output_image) {
-        Usage("Only one of --output-image-file, --output-image-location and --output-image-fd may "
-              "be used.");
-      }
-      have_output_image = true;
-      output_image_location= option.substr(strlen("--output-image-location=")).data();
     } else if (option.starts_with("--output-image-file=")) {
       if (have_output_image) {
-        Usage("Only one of --output-image-file, --output-image-location and --output-image-fd may "
-              "be used.");
+        Usage("Only one of --output-image-file, and --output-image-fd may be used.");
       }
       have_output_image = true;
       output_image_filename = option.substr(strlen("--output-image-file=")).data();
     } else if (option.starts_with("--output-image-fd=")) {
       if (have_output_image) {
-        Usage("Only one of --output-image-file, --output-image-location and --output-image-fd "
-              "may be used.");
+        Usage("Only one of --output-image-file, and --output-image-fd may be used.");
       }
       have_output_image = true;
       const char* image_fd_str = option.substr(strlen("--output-image-fd=")).data();
@@ -874,6 +906,10 @@
       patched_image_location = option.substr(strlen("--patched-image-location=")).data();
     } else if (option.starts_with("--patched-image-file=")) {
       patched_image_filename = option.substr(strlen("--patched-image-file=")).data();
+    } else if (option == "--lock-output") {
+      lock_output = true;
+    } else if (option == "--no-lock-output") {
+      lock_output = false;
     } else if (option == "--dump-timings") {
       dump_timings = true;
     } else if (option == "--no-dump-timings") {
@@ -923,29 +959,13 @@
     if (!isa_set) {
       Usage("specifying a location requires specifying an instruction set");
     }
-    input_oat_filename = GetSystemImageFilename(input_oat_location.c_str(), isa);
+    if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) {
+      Usage("Unable to find filename for input oat location %s", input_oat_location.c_str());
+    }
     if (debug) {
       LOG(INFO) << "Using input-oat-file " << input_oat_filename;
     }
   }
-  if (!output_oat_location.empty()) {
-    if (!isa_set) {
-      Usage("specifying a location requires specifying an instruction set");
-    }
-    output_oat_filename = GetSystemImageFilename(output_oat_location.c_str(), isa);
-    if (debug) {
-      LOG(INFO) << "Using output-oat-file " << output_oat_filename;
-    }
-  }
-  if (!output_image_location.empty()) {
-    if (!isa_set) {
-      Usage("specifying a location requires specifying an instruction set");
-    }
-    output_image_filename = GetSystemImageFilename(output_image_location.c_str(), isa);
-    if (debug) {
-      LOG(INFO) << "Using output-image-file " << output_image_filename;
-    }
-  }
   if (!patched_image_location.empty()) {
     if (!isa_set) {
       Usage("specifying a location requires specifying an instruction set");
@@ -1009,6 +1029,9 @@
     CHECK(!input_image_location.empty());
 
     if (output_image_fd != -1) {
+      if (output_image_filename.empty()) {
+        output_image_filename = "output-image-file";
+      }
       output_image.reset(new File(output_image_fd, output_image_filename));
     } else {
       CHECK(!output_image_filename.empty());
@@ -1020,6 +1043,9 @@
 
   if (have_oat_files) {
     if (input_oat_fd != -1) {
+      if (input_oat_filename.empty()) {
+        input_oat_filename = "input-oat-file";
+      }
       input_oat.reset(new File(input_oat_fd, input_oat_filename));
     } else {
       CHECK(!input_oat_filename.empty());
@@ -1030,15 +1056,10 @@
     }
 
     if (output_oat_fd != -1) {
-      output_oat.reset(new File(output_oat_fd, output_oat_filename));
-    } else if (output_oat_filename == input_oat_filename) {
-      // This could be a wierd situation, since we'd be writting from an mmap'd copy of this file.
-      // Lets just unlink it.
-      if (0 != unlink(input_oat_filename.c_str())) {
-        PLOG(ERROR) << "Could not unlink " << input_oat_filename << " to make room for output";
-        return false;
+      if (output_oat_filename.empty()) {
+        output_oat_filename = "output-oat-file";
       }
-      output_oat.reset(OS::CreateEmptyFile(output_oat_filename.c_str()));
+      output_oat.reset(new File(output_oat_fd, output_oat_filename));
     } else {
       CHECK(!output_oat_filename.empty());
       output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
@@ -1063,6 +1084,22 @@
     }
   };
 
+  if ((have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) ||
+      (have_image_files && output_image.get() == nullptr)) {
+    cleanup(false);
+    return EXIT_FAILURE;
+  }
+
+  ScopedFlock output_oat_lock;
+  if (lock_output) {
+    std::string error_msg;
+    if (have_oat_files && !output_oat_lock.Init(output_oat.get(), &error_msg)) {
+      LOG(ERROR) << "Unable to lock output oat " << output_image->GetPath() << ": " << error_msg;
+      cleanup(false);
+      return EXIT_FAILURE;
+    }
+  }
+
   if (debug) {
     LOG(INFO) << "moving offset by " << base_delta
               << " (0x" << std::hex << base_delta << ") bytes or "
@@ -1083,7 +1120,6 @@
     ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings);
   }
   cleanup(ret);
-  sync();
   return (ret) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 7a3cbf3..883e1c1f 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -45,6 +45,26 @@
   live_bitmap_.reset(live_bitmap);
 }
 
+static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
+  CHECK_ALIGNED(min_delta, kPageSize);
+  CHECK_ALIGNED(max_delta, kPageSize);
+  CHECK_LT(min_delta, max_delta);
+
+  std::default_random_engine generator;
+  generator.seed(NanoTime() * getpid());
+  std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
+  int32_t r = distribution(generator);
+  if (r % 2 == 0) {
+    r = RoundUp(r, kPageSize);
+  } else {
+    r = RoundDown(r, kPageSize);
+  }
+  CHECK_LE(min_delta, r);
+  CHECK_GE(max_delta, r);
+  CHECK_ALIGNED(r, kPageSize);
+  return r;
+}
+
 static bool GenerateImage(const std::string& image_filename, std::string* error_msg) {
   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
   std::vector<std::string> boot_class_path;
@@ -75,7 +95,11 @@
 
   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
 
-  arg_vector.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS));
+  int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
+                                                    ART_BASE_ADDRESS_MAX_DELTA);
+  LOG(INFO) << "Using an offset of 0x" << std::hex << base_offset << " from default "
+            << "art base address of 0x" << std::hex << ART_BASE_ADDRESS;
+  arg_vector.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset));
 
   if (kIsTargetBuild) {
     arg_vector.push_back("--image-classes-zip=/system/framework/framework.jar");
@@ -145,26 +169,6 @@
     return true;
 }
 
-static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
-  CHECK_ALIGNED(min_delta, kPageSize);
-  CHECK_ALIGNED(max_delta, kPageSize);
-  CHECK_LT(min_delta, max_delta);
-
-  std::default_random_engine generator;
-  generator.seed(NanoTime() * getpid());
-  std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
-  int32_t r = distribution(generator);
-  if (r % 2 == 0) {
-    r = RoundUp(r, kPageSize);
-  } else {
-    r = RoundDown(r, kPageSize);
-  }
-  CHECK_LE(min_delta, r);
-  CHECK_GE(max_delta, r);
-  CHECK_ALIGNED(r, kPageSize);
-  return r;
-}
-
 bool ImageSpace::RelocateImage(const char* image_location, const char* dest_filename,
                                InstructionSet isa, std::string* error_msg) {
   std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
@@ -376,13 +380,6 @@
   CHECK(dalvik_cache_exists) << "No place to put generated image.";
   CHECK(GenerateImage(cache_filename, &error_msg))
       << "Failed to generate image '" << cache_filename << "': " << error_msg;
-  // TODO Should I relocate this image? Sure
-  if (relocate) {
-    if (!RelocateImage(cache_filename.c_str(), cache_filename.c_str(), image_isa, &error_msg)) {
-      LOG(FATAL) << "Failed to relocate newly created image " << cache_filename.c_str();
-      return nullptr;
-    }
-  }
   {
     // Note that we must not use the file descriptor associated with
     // ScopedFlock::GetFile to Init the image file. We want the file