Store odex files in oat/<isa>/ directory.

Previously odex files were stored alongside the dex location as:
  dex location: /foo/bar/base.apk
  odex location: /foo/bar/<isa>/base.odex

This changes where odex files are stored, adding an "oat" directory:
  dex location: /foo/bar/base.apk
  odex location: /foo/bar/oat/<isa>/base.odex

See also the corresponding change in platform/build and
platform/frameworks/native.

Bug: 19550105
Change-Id: I4c6be4f0c41ff175904846db8e360c4af815b265
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 9a17b01..d92f59b 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -737,18 +737,19 @@
   CHECK(error_msg != nullptr);
 
   // The odex file name is formed by replacing the dex_location extension with
-  // .odex and inserting an isa directory. For example:
+  // .odex and inserting an oat/<isa> directory. For example:
   //   location = /foo/bar/baz.jar
-  //   odex_location = /foo/bar/<isa>/baz.odex
+  //   odex_location = /foo/bar/oat/<isa>/baz.odex
 
-  // Find the directory portion of the dex location and add the isa directory.
+  // Find the directory portion of the dex location and add the oat/<isa>
+  // directory.
   size_t pos = location.rfind('/');
   if (pos == std::string::npos) {
     *error_msg = "Dex location " + location + " has no directory.";
     return false;
   }
   std::string dir = location.substr(0, pos+1);
-  dir += std::string(GetInstructionSetString(isa));
+  dir += "oat/" + std::string(GetInstructionSetString(isa));
 
   // Find the file portion of the dex location.
   std::string file;
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 958b440..f2abcf9 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -151,11 +151,12 @@
   static std::vector<std::unique_ptr<const DexFile>> LoadDexFiles(
       const OatFile& oat_file, const char* dex_location);
 
-  // If the dex file has been pre-compiled on the host, the compiled oat file
-  // will have the extension .odex, and is referred to as the odex file.
-  // It is called odex for legacy reasons; the file is really an oat file. The
-  // odex file will typically have a patch delta of 0 and need to be relocated
-  // before use for the purposes of ASLR.
+  // If the dex file has been installed with a compiled oat file alongside
+  // it, the compiled oat file will have the extension .odex, and is referred
+  // to as the odex file. It is called odex for legacy reasons; the file is
+  // really an oat file. The odex file will often, but not always, have a
+  // patch delta of 0 and need to be relocated before use for the purposes of
+  // ASLR. The odex file is treated as if it were read-only.
   // These methods return the location and status of the odex file for the dex
   // location.
   // Notes:
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 41dc2d7..b2798d3 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -44,10 +44,13 @@
     scratch_dir_ = android_data_ + "/OatFileAssistantTest";
     ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
 
-    // Create a subdirectory in scratch for the current isa.
-    // This is the location that will be used for odex files in the tests.
-    isa_dir_ = scratch_dir_ + "/" + GetInstructionSetString(kRuntimeISA);
-    ASSERT_EQ(0, mkdir(isa_dir_.c_str(), 0700));
+    // Create a subdirectory in scratch for odex files.
+    odex_oat_dir_ = scratch_dir_ + "/oat";
+    ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
+
+    odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
+    ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+
 
     // Verify the environment is as we expect
     uint32_t checksum;
@@ -90,8 +93,11 @@
   }
 
   virtual void TearDown() {
-    ClearDirectory(isa_dir_.c_str());
-    ASSERT_EQ(0, rmdir(isa_dir_.c_str()));
+    ClearDirectory(odex_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
+
+    ClearDirectory(odex_oat_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
 
     ClearDirectory(scratch_dir_.c_str());
     ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
@@ -153,10 +159,10 @@
     return scratch_dir_;
   }
 
-  // ISA directory is the subdirectory in the scratch directory where odex
+  // Odex directory is the subdirectory in the scratch directory where odex
   // files should be located.
-  std::string GetISADir() {
-    return isa_dir_;
+  std::string GetOdexDir() {
+    return odex_dir_;
   }
 
   // Generate an odex file for the purposes of test.
@@ -241,7 +247,8 @@
   }
 
   std::string scratch_dir_;
-  std::string isa_dir_;
+  std::string odex_oat_dir_;
+  std::string odex_dir_;
   std::vector<std::unique_ptr<MemMap>> image_reservation_;
 };
 
@@ -340,7 +347,7 @@
 // Expect: The oat file status is kUpToDate.
 TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
   std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
-  std::string oat_location = GetISADir() + "/RelativeEncodedDexLocation.oat";
+  std::string oat_location = GetOdexDir() + "/RelativeEncodedDexLocation.oat";
 
   // Create the dex file
   Copy(GetMultiDexSrc1(), dex_location);
@@ -393,7 +400,7 @@
 // Expect: The oat file status is kNeedsRelocation.
 TEST_F(OatFileAssistantTest, DexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/DexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -419,7 +426,7 @@
 // Expect: The oat file status is kNeedsRelocation.
 TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/StrippedDexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -468,7 +475,7 @@
 // Expect: The oat file status is kNeedsRelocation.
 TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
   std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
-  std::string odex_location = GetISADir() + "/StrippedDexOdexOat.odex";
+  std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
 
   // Create the oat file from a different dex file so it looks out of date.
   Copy(GetDexSrc2(), dex_location);
@@ -525,8 +532,8 @@
 // Expect: It shouldn't crash.
 TEST_F(OatFileAssistantTest, OdexOatOverlap) {
   std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
-  std::string odex_location = GetISADir() + "/OdexOatOverlap.odex";
-  std::string oat_location = GetISADir() + "/OdexOatOverlap.oat";
+  std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
+  std::string oat_location = GetOdexDir() + "/OdexOatOverlap.oat";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -563,7 +570,7 @@
 // Expect: The oat file status is kUpToDate, because PIC needs no relocation.
 TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/DexPicOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/DexPicOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -803,7 +810,7 @@
 // avoid using up the virtual memory address space.
 TEST_F(OatFileAssistantTest, RaceToGenerate) {
   std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
-  std::string oat_location = GetISADir() + "/RaceToGenerate.oat";
+  std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
 
   // We use the lib core dex file, because it's large, and hopefully should
   // take a while to generate.
@@ -833,7 +840,7 @@
 // Expect: We should load the odex file non-executable.
 TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/LoadDexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -855,7 +862,7 @@
 // Expect: We should load the odex file non-executable.
 TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/LoadMultiDexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetMultiDexSrc1(), dex_location);
@@ -878,11 +885,11 @@
 
   EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
         "/foo/bar/baz.jar", kArm, &odex_file, &error_msg)) << error_msg;
-  EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
+  EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
 
   EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
         "/foo/bar/baz.funnyext", kArm, &odex_file, &error_msg)) << error_msg;
-  EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
+  EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
 
   EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
         "nopath.jar", kArm, &odex_file, &error_msg));