Add support for oat_process for use as a wrap.* launcher

Add test support for running Calculator

Change-Id: I7ec0681febe6f6c836452e8afb4c12a2ebfa0ea8
diff --git a/Android.mk b/Android.mk
index 49e0706..5801447 100644
--- a/Android.mk
+++ b/Android.mk
@@ -59,6 +59,11 @@
 ART_HOST_TEST_DEPENDENCIES   := $(ART_HOST_TEST_EXECUTABLES)   $(ANDROID_HOST_OUT)/framework/core-hostdex.jar   $(ART_TEST_OAT_FILES)
 ART_TARGET_TEST_DEPENDENCIES := $(ART_TARGET_TEST_EXECUTABLES) $(ANDROID_PRODUCT_OUT)/system/framework/core.jar $(ART_TEST_OAT_FILES)
 
+ART_TARGET_TEST_DEPENDENCIES += $(TARGET_OUT_EXECUTABLES)/oat_process $(TARGET_OUT_EXECUTABLES)/oat_processd
+
+########################################################################
+# host test targets
+
 # "mm test-art-host" to build and run all host tests
 .PHONY: test-art-host
 test-art-host: $(ART_HOST_TEST_DEPENDENCIES)
@@ -74,7 +79,10 @@
 tsan-art-host: $(ART_HOST_TEST_DEPENDENCIES)
 	$(call run-host-tests-with,"tsan")
 
-# "mm test-art-device" to build and run all target tests
+########################################################################
+# target test targets
+
+# "mm test-art-target" to build and run all target tests
 .PHONY: test-art-target
 test-art-target: test-art-target-gtest test-art-target-oat
 
@@ -94,20 +102,47 @@
 .PHONY: test-art-target-oat
 test-art-target-oat: $(ART_TEST_OAT_TARGETS)
 
+########################################################################
+# oat_process test targets
+
 # $(1): name
 define build-art-framework-oat
   $(call build-art-oat,$(1),$(TARGET_BOOT_OAT),$(TARGET_BOOT_DEX))
 endef
 
-$(eval $(call build-art-framework-oat,am))
-
 .PHONY: test-art-target-oat-process
-test-art-target-oat-process: $(TARGET_OUT_JAVA_LIBRARIES)/am.oat
+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))
+
+.PHONY: test-art-target-oat-process-am
+test-art-target-oat-process-am: $(TARGET_OUT_JAVA_LIBRARIES)/am.oat test-art-target-sync
 	adb remount
 	adb sync
-	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_process -Xbootimage:/system/framework/boot.oat -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am && touch /sdcard/test-art-target-process"
-	$(hide) (adb pull /sdcard/test-art-target-process /tmp/ && echo test-art-target-process PASSED) || echo test-art-target-process FAILED
-	$(hide) rm /tmp/test-art-target-process
+	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Xbootimage:/system/framework/boot.oat -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am start http://android.com && touch /sdcard/test-art-target-process-am"
+	$(hide) (adb pull /sdcard/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 test-art-target-sync
+	mkdir -p $(TARGET_OUT_DATA)/art-cache
+	unzip $(TARGET_OUT_APPS)/Calculator.apk classes.dex -d $(TARGET_OUT_DATA)/art-cache
+	mv $(TARGET_OUT_DATA)/art-cache/classes.dex $(TARGET_OUT_DATA)/art-cache/system@app@Calculator.apk@classes.dex.c96b4ebb # crc32 from "unzip -lv $(TARGET_OUT_APPS)/Calculator.apk"
+	adb remount
+	adb sync
+	adb shell setprop wrap.com.android.calculator2 "oat_processd"
+	adb shell stop
+	adb shell start
+	sleep 15 # sleep 30
+	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Xbootimage:/system/framework/boot.oat -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am start -a android.intent.action.MAIN -n com.android.calculator2/.Calculator && touch /sdcard/test-art-target-process-Calculator"
+	$(hide) (adb pull /sdcard/test-art-target-process-Calculator /tmp/ && echo test-art-target-process-Calculator PASSED) || echo test-art-target-process-Calculator FAILED
+	$(hide) rm /tmp/test-art-target-process-Calculator
+
+########################################################################
+# oatdump targets
 
 .PHONY: dump-core-oat
 dump-core-oat: $(TARGET_CORE_OAT) $(OATDUMP)
@@ -119,9 +154,14 @@
 	$(OATDUMP) $(addprefix --dex-file=,$(TARGET_BOOT_DEX)) --image=$(TARGET_BOOT_OAT) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/boot.oatdump.txt
 	@echo Output in /tmp/boot.oatdump.txt
 
+########################################################################
+# cpplint target
+
 # "mm cpplint-art" to style check art source files
 .PHONY: cpplint-art
 cpplint-art:
 	$(LOCAL_PATH)/tools/cpplint.py $(LOCAL_PATH)/src/*.h $(LOCAL_PATH)/src/*.cc
 
+########################################################################
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index 4605583..5942fcf 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -33,12 +33,12 @@
 
 ########################################################################
 
-# $(1): module
+# $(1): input jar or apk filename
 # $(2): boot oat
 # $(3): boot dex files
 define build-art-oat
-# TODO: change DEX2OATD to order-only prerequisite when output is stable
-$(TARGET_OUT_JAVA_LIBRARIES)/$(1).oat: $(TARGET_OUT_JAVA_LIBRARIES)/$(1).jar $(2) $(DEX2OAT)
+# 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)
 	@echo "target dex2oat: $$@ ($$<)"
 	$(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --boot-dex-file=,$(3)) --boot=$(2) $(addprefix --dex-file=,$$<) --image=$$@ --strip-prefix=$(PRODUCT_OUT)
 endef
@@ -48,7 +48,7 @@
 
 # $(1): directory
 define build-art-test-oat
-  $(call build-art-oat,art-test-dex-$(1),$(TARGET_CORE_OAT),$(TARGET_CORE_DEX))
+  $(call build-art-oat,$(TARGET_OUT_JAVA_LIBRARIES)/art-test-dex-$(1).jar,$(TARGET_CORE_OAT),$(TARGET_CORE_DEX))
   ART_TEST_OAT_FILES += $(TARGET_OUT_JAVA_LIBRARIES)/art-test-dex-$(1).oat
 endef
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-oat,$(dir))))
diff --git a/oat_process/app_main.cpp b/oat_process/app_main.cpp
index bf827a8..92ede6d 100644
--- a/oat_process/app_main.cpp
+++ b/oat_process/app_main.cpp
@@ -148,6 +148,45 @@
     argc--;
     argv++;
 
+    // ignore /system/bin/app_process when invoked via WrapperInit
+    if (strcmp(argv[0], "/system/bin/app_process") == 0) {
+        LOGI("Removing /system/bin/app_process argument");
+        argc--;
+        argv++;
+        for (int i = 0; i < argc; i++) {
+            LOGI("argv[%d]=%s", i, argv[i]);
+        }
+    }
+
+    // TODO: remove Calculator special case
+    int oatArgc = argc + 2;
+    const char* oatArgv[oatArgc];
+    if (strcmp(argv[0], "-Xbootimage:/system/framework/boot.oat") != 0) {
+        LOGI("Adding oat arguments");
+        oatArgv[0] = "-Xbootimage:/system/framework/boot.oat";
+        oatArgv[1] = "-Ximage:/system/app/Calculator.oat";
+        setenv("CLASSPATH", "/system/app/Calculator.apk", 1);
+        memcpy(oatArgv + (oatArgc - argc), argv, argc * sizeof(*argv));
+        argv = oatArgv;
+        argc = oatArgc;
+        for (int i = 0; i < argc; i++) {
+            LOGI("argv[%d]=%s", i, argv[i]);
+        }
+    }
+
+    // TODO: remove the heap arguments when implicit garbage collection enabled
+    LOGI("Adding heap arguments");
+    int heapArgc = argc + 2;
+    const char* heapArgv[heapArgc];
+    heapArgv[0] = "-Xms64m";
+    heapArgv[1] = "-Xmx64m";
+    memcpy(heapArgv + (heapArgc - argc), argv, argc * sizeof(*argv));
+    argv = heapArgv;
+    argc = heapArgc;
+    for (int i = 0; i < argc; i++) {
+        LOGI("argv[%d]=%s", i, argv[i]);
+    }
+
     // Everything up to '--' or first non '-' arg goes to the vm
 
     int i = runtime.addVmArguments(argc, argv);
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index ec0b0ed..c334f04 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -227,13 +227,6 @@
   return c->IsPrimitive();
 }
 
-bool CheckClassAccess(const Class* access_from, const Class* klass) {
-  if (klass->IsPublic()) {
-    return true;
-  }
-  return access_from->IsInSamePackage(klass);
-}
-
 // Validate method/field access.
 bool CheckMemberAccess(const Class* access_from, const Class* access_to, uint32_t member_flags) {
   // quick accept for public access */
@@ -293,7 +286,7 @@
   Method* caller_caller = frame.GetMethod();
   Class* caller_class = caller_caller->GetDeclaringClass();
 
-  if (!CheckClassAccess(c, caller_class)) {
+  if (!caller_class->CanAccess(c)) {
     Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
                                          "Class %s is not accessible from class %s",
                                          PrettyDescriptor(c->GetDescriptor()).c_str(),
diff --git a/src/thread.cc b/src/thread.cc
index 22495be..8005072 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -301,7 +301,7 @@
   obj->MonitorEnter(thread);
   DCHECK(thread->HoldsLock(obj));
   // Only possible exception is NPE and is handled before entry
-  DCHECK(thread->GetException() == NULL);
+  DCHECK(!thread->IsExceptionPending());
 }
 
 extern "C" void artCheckSuspendFromCode(Thread* thread) {
@@ -358,10 +358,14 @@
   Method* interface_method = class_linker->ResolveMethod(method_idx, caller_method, false);
   if (interface_method == NULL) {
     // Could not resolve interface method. Throw error and unwind
-    CHECK(thread->GetException() != NULL);
+    CHECK(thread->IsExceptionPending());
     return 0;
   }
   Method* method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
+  if (method == NULL) {
+    CHECK(thread->IsExceptionPending());
+    return 0;
+  }
   const void* code = method->GetCode();
 
   uint32_t method_uint = reinterpret_cast<uint32_t>(method);
@@ -1372,6 +1376,7 @@
   CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
   int rc = env->ThrowNew(exception_class, msg.c_str());
   CHECK_EQ(rc, JNI_OK);
+  env->DeleteLocalRef(exception_class);
 }
 
 void Thread::ThrowOutOfMemoryError() {