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

Also implement Zygote_nativeForkAndSpecialize

Change-Id: I7dfb257b2897279a4cdac4b1ca194c1ac84eb047
diff --git a/Android.mk b/Android.mk
index 282dd3b..b909c98 100644
--- a/Android.mk
+++ b/Android.mk
@@ -122,29 +122,37 @@
 ########################################################################
 # oat_process test targets
 
+# $(1): jar or apk name
+define art-cache-oat
+  $(ART_CACHE_OUT)/$(subst /,@,$(patsubst %.apk,%.oat,$(patsubst %.jar,%.oat,$(1))))
+endef
+
+ART_CACHE_OATS :=
 # $(1): name
-define build-art-framework-oat
-  $(call build-art-oat,$(1),$(TARGET_BOOT_OAT),$(TARGET_BOOT_DEX))
+define build-art-cache-oat
+  $(call build-art-oat,$(PRODUCT_OUT)/$(1),$(call art-cache-oat,$(1)),$(TARGET_BOOT_IMG))
+  ART_CACHE_OATS += $(call art-cache-oat,$(1))
 endef
 
 .PHONY: test-art-target-oat-process
 test-art-target-oat-process: test-art-target-oat-process-am # test-art-target-oat-process-Calculator
 
-$(eval $(call build-art-framework-oat,$(TARGET_OUT_JAVA_LIBRARIES)/am.jar))
+$(eval $(call build-art-cache-oat,system/framework/am.jar))
+$(eval $(call build-art-cache-oat,system/app/Calculator.apk))
+$(eval $(call build-art-cache-oat,system/app/SettingsProvider.apk))
+$(eval $(call build-art-cache-oat,system/app/SystemUI.apk))
 
 .PHONY: test-art-target-oat-process-am
-test-art-target-oat-process-am: $(TARGET_OUT_JAVA_LIBRARIES)/am.oat test-art-target-sync
+test-art-target-oat-process-am: $(call art-cache-oat,system/framework/am.jar) test-art-target-sync
 	adb remount
 	adb sync
 	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Ximage:$(ART_CACHE_DIR)/boot.art /system/bin com.android.commands.am.Am start http://android.com && touch $(ART_TEST_DIR)/test-art-target-process-am"
 	$(hide) (adb pull $(ART_TEST_DIR)/test-art-target-process-am /tmp/ && echo test-art-target-process-am PASSED) || echo test-art-target-process-am FAILED
 	$(hide) rm /tmp/test-art-target-process-am
 
-$(eval $(call build-art-framework-oat,$(TARGET_OUT_APPS)/Calculator.apk))
-
 .PHONY: test-art-target-oat-process-Calculator
 # Note that using this instead of "adb shell am start" make sure that the /data/art-cache is up-to-date
-test-art-target-oat-process-Calculator: $(TARGET_OUT_APPS)/Calculator.oat $(TARGET_OUT_JAVA_LIBRARIES)/am.oat test-art-target-sync
+test-art-target-oat-process-Calculator: $(call art-cache-oat,system/app/Calculator.oat) $(call art-cache-oat,system/framework/am.jar) test-art-target-sync
 	mkdir -p $(ART_CACHE_OUT)
 	unzip $(TARGET_OUT_APPS)/Calculator.apk classes.dex -d $(TARGET_OUT_DATA)/art-cache
 	mv $(TARGET_OUT_DATA)/art-cache/classes.dex $(ART_CACHE_OUT)/system@app@Calculator.apk@classes.dex.`unzip -lv $(TARGET_OUT_APPS)/Calculator.apk classes.dex | grep classes.dex | sed -E 's/.* ([0-9a-f]+)  classes.dex/\1/'` # note this is extracting the crc32 that is needed as the file extension
@@ -175,14 +183,14 @@
 # zygote-art-target-sync will just push a new art in place of dvm
 
 .PHONY: zygote-artd-target-sync
-zygote-artd-target-sync: $(ART_TARGET_DEPENDENCIES)
+zygote-artd-target-sync: $(ART_TARGET_DEPENDENCIES) $(TARGET_BOOT_OAT) $(ART_CACHE_OATS)
 	cp $(TARGET_OUT_SHARED_LIBRARIES)/libartd.so $(TARGET_OUT_SHARED_LIBRARIES)/libdvm.so
 	cp $(TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)/libartd.so $(TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)/libdvm.so
 	adb remount
 	adb sync
 
 .PHONY: zygote-artd
-zygote-artd: $(TARGET_BOOT_OAT) zygote-artd-target-sync
+zygote-artd: zygote-artd-target-sync
 	sed 's/--start-system-server/--start-system-server --no-preload/' < system/core/rootdir/init.rc > $(ANDROID_PRODUCT_OUT)/root/init.rc
 	rm -f $(ANDROID_PRODUCT_OUT)/boot.img
 	unset ONE_SHOT_MAKEFILE && $(MAKE) showcommands bootimage
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index 8125df1..27a4646 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -35,13 +35,13 @@
 ########################################################################
 
 # $(1): input jar or apk filename
-# $(2): boot oat
-# $(3): boot dex files
+# $(2): output oat filename
+# $(3): boot image
 define build-art-oat
 # TODO: change DEX2OATD (and perhaps $(2) boot oat) to order-only prerequisite when output is stable
-$(patsubst %.apk,%.oat,$(patsubst %.jar,%.oat,$(1))): $(1) $(2) $(DEX2OAT)
+$(2): $(1) $(3) $(DEX2OAT)
 	@echo "target dex2oat: $$@ ($$<)"
-	$(hide) $(DEX2OAT) -Xms16m -Xmx16m --boot-image=$(patsubst %.oat,%.art,$(2)) $(addprefix --dex-file=,$$<) --oat=$$@ --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) -Xms16m -Xmx16m --boot-image=$(3) $(addprefix --dex-file=,$$<) --oat=$$@ --host-prefix=$(PRODUCT_OUT)
 endef
 
 ########################################################################
@@ -49,7 +49,7 @@
 
 # $(1): directory
 define build-art-test-oat
-  $(call build-art-oat,$(ART_TEST_OUT)/art-test-dex-$(1).jar,$(TARGET_CORE_OAT),$(TARGET_CORE_DEX))
+  $(call build-art-oat,$(ART_TEST_OUT)/art-test-dex-$(1).jar,$(ART_TEST_OUT)/art-test-dex-$(1).oat,$(TARGET_CORE_IMG))
   ART_TEST_OAT_FILES += $(ART_TEST_OUT)/art-test-dex-$(1).oat
 endef
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-oat,$(dir))))
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_