Add support for oat files in /data/art-cache

Also implement Zygote_nativeForkAndSpecialize

Change-Id: I7dfb257b2897279a4cdac4b1ca194c1ac84eb047
diff --git a/src/class_linker.cc b/src/class_linker.cc
index adabe97..6ad6543 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -551,9 +551,9 @@
   std::string oat_filename;
   oat_filename += runtime->GetHostPrefix();
   oat_filename += oat_location->ToModifiedUtf8();
-  OatFile* oat_file = OatFile::Open(std::string(oat_filename), "", image_header.GetOatBaseAddr());
+  OatFile* oat_file = OatFile::Open(oat_filename, "", image_header.GetOatBaseAddr());
   if (oat_file == NULL) {
-    LOG(ERROR) << "Failed to open oat file " << oat_filename << " referenced from image";
+    LOG(ERROR) << "Failed to open oat file " << oat_filename << " referenced from image.";
     return NULL;
   }
   uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
@@ -596,8 +596,22 @@
 
   const OatFile* oat_file = OatFile::Open(location, "", NULL);
   if (oat_file == NULL) {
-    LOG(ERROR) << "Failed to open oat file " << location;
-    return NULL;
+    if (location.empty() || location[0] != '/') {
+      LOG(ERROR) << "Failed to open oat file from " << location;
+      return NULL;
+    }
+    // not found in /foo/bar/baz.oat? try /data/art-cache/foo@bar@baz.oat
+    std::string art_cache = GetArtCacheOrDie();
+    std::string cache_file(location, 1); // skip leading slash
+    std::replace(cache_file.begin(), cache_file.end(), '/', '@');
+    std::string cache_location = art_cache + "/" + cache_file;
+    oat_file = OatFile::Open(cache_location, "", NULL);
+    if (oat_file  == NULL) {
+      LOG(ERROR) << "Failed to open oat file from " << location << " or " << cache_location << ".";
+      return NULL;
+    }
+
+
   }
   return oat_file;
 }
diff --git a/src/dalvik_system_Zygote.cc b/src/dalvik_system_Zygote.cc
index 2e715c7..7c0b6a6 100644
--- a/src/dalvik_system_Zygote.cc
+++ b/src/dalvik_system_Zygote.cc
@@ -277,6 +277,11 @@
   return pid;
 }
 
+jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+                                    jint debugFlags, jobjectArray rlimits) {
+  return forkAndSpecializeCommon(env, uid, gid, gids, debugFlags, rlimits, 0, 0);
+}
+
 jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
                                    jint debugFlags, jobjectArray rlimits,
                                    jlong permittedCapabilities, jlong effectiveCapabilities) {
@@ -301,7 +306,7 @@
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Zygote, nativeExecShell, "(Ljava/lang/String;)V"),
   //NATIVE_METHOD(Zygote, nativeFork, "()I"),
-  //NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[I)I"),
+  NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[I)I"),
   NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
 };
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index a84c316..fa6d9d5 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -9,7 +9,6 @@
 #include <sys/file.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/types.h>
 
 #include <map>
 
@@ -208,35 +207,8 @@
   cache_file.append(kClassesDex);
   // Example cache_file = parent@dir@foo.jar@classes.dex
 
-  const char* data_root = getenv("ANDROID_DATA");
-  if (data_root == NULL) {
-    if (OS::DirectoryExists("/data")) {
-      data_root = "/data";
-    } else {
-      data_root = "/tmp";
-    }
-  }
-  if (!OS::DirectoryExists(data_root)) {
-    LOG(ERROR) << "Failed to find ANDROID_DATA directory " << data_root;
-    return NULL;
-  }
-
-  std::string art_cache = StringPrintf("%s/art-cache", data_root);
-
-  if (!OS::DirectoryExists(art_cache.c_str())) {
-    if (StringPiece(art_cache).starts_with("/tmp/")) {
-      int result = mkdir(art_cache.c_str(), 0700);
-      if (result != 0) {
-        LOG(FATAL) << "Failed to create art-cache directory " << art_cache;
-        return NULL;
-      }
-    } else {
-      LOG(FATAL) << "Failed to find art-cache directory " << art_cache;
-      return NULL;
-    }
-  }
-
-  std::string cache_path_tmp = StringPrintf("%s/%s", art_cache.c_str(), cache_file.c_str());
+  std::string art_cache = GetArtCacheOrDie();
+  std::string cache_path_tmp = art_cache + "/" + cache_file;
   // Example cache_path_tmp = /data/art-cache/parent@dir@foo.jar@classes.dex
 
   UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename));
diff --git a/src/utils.cc b/src/utils.cc
index 3017807..bc51c2a 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -4,6 +4,7 @@
 #include "utils.h"
 
 #include <pthread.h>
+#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -482,6 +483,37 @@
 #endif
 }
 
+std::string GetArtCacheOrDie() {
+  const char* data_root = getenv("ANDROID_DATA");
+  if (data_root == NULL) {
+    if (OS::DirectoryExists("/data")) {
+      data_root = "/data";
+    } else {
+      data_root = "/tmp";
+    }
+  }
+  if (!OS::DirectoryExists(data_root)) {
+    LOG(FATAL) << "Failed to find ANDROID_DATA directory " << data_root;
+    return "";
+  }
+
+  std::string art_cache = StringPrintf("%s/art-cache", data_root);
+
+  if (!OS::DirectoryExists(art_cache.c_str())) {
+    if (StringPiece(art_cache).starts_with("/tmp/")) {
+      int result = mkdir(art_cache.c_str(), 0700);
+      if (result != 0) {
+        LOG(FATAL) << "Failed to create art-cache directory " << art_cache;
+        return "";
+      }
+    } else {
+      LOG(FATAL) << "Failed to find art-cache directory " << art_cache;
+      return "";
+    }
+  }
+  return art_cache;
+}
+
 }  // namespace art
 
 // Neither bionic nor glibc exposes gettid(2).
diff --git a/src/utils.h b/src/utils.h
index 228925d..7778918 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -212,6 +212,9 @@
 // implementation-defined limit.
 void SetThreadName(const char* name);
 
+// Returns the art-cache location or dies trying
+std::string GetArtCacheOrDie();
+
 }  // namespace art
 
 #endif  // ART_SRC_UTILS_H_