Integrate dexpreopt into the build system.

Change-Id: Id67f85d0f5c8674f5bc22e431114ca73625811ef
diff --git a/core/Makefile b/core/Makefile
index ad964c1..f27b5c1 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -737,7 +737,8 @@
 
 ifdef WITH_DEXPREOPT
   ifndef DISABLE_DEXPREOPT
-    with_dexpreopt := true
+# TODO: remove the unnecessary code.
+#  with_dexpreopt := true
   endif
 endif
 ifdef with_dexpreopt
diff --git a/core/base_rules.mk b/core/base_rules.mk
index db05e00..f372748 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -492,6 +492,16 @@
 	$(copy-file-to-target-with-cp)
 endif
 
+ifeq ($(LOCAL_DEX_PREOPT),true)
+installed_odex := $(basename $(LOCAL_INSTALLED_MODULE)).odex
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(installed_odex) : $(built_odex) | $(ACP)
+	@echo "Install: $@"
+	$(copy-file-to-target)
+
+$(LOCAL_INSTALLED_MODULE): $(installed_odex)
+endif
+
 endif # !LOCAL_UNINSTALLABLE_MODULE
 
 
diff --git a/core/cleanbuild.mk b/core/cleanbuild.mk
index 24a3565..dbc64ff 100644
--- a/core/cleanbuild.mk
+++ b/core/cleanbuild.mk
@@ -186,7 +186,11 @@
 	./$(PRODUCT_OUT)/obj/PACKAGING \
 	./$(PRODUCT_OUT)/recovery \
 	./$(PRODUCT_OUT)/root \
-	./$(PRODUCT_OUT)/system
+	./$(PRODUCT_OUT)/system \
+	./$(PRODUCT_OUT)/dex_bootjars
+
+# TODO: move the dex-preopt files to a product-specific directory
+installclean_files += ./$(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/*/javalib.jar
 
 # The files/dirs to delete during a dataclean, which removes any files
 # in the staging and emulator data partitions.
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index c046c69..9681364 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -97,6 +97,7 @@
 LOCAL_EMMA_COVERAGE_FILTER:=
 LOCAL_MANIFEST_FILE:=
 LOCAL_BUILD_HOST_DEX:=
+LOCAL_DEX_PREOPT:=
 
 # Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to
 # iterate over thousands of entries every time.
diff --git a/core/config.mk b/core/config.mk
index 897af83..a3bcbf1 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -215,6 +215,8 @@
 JARJAR := $(HOST_OUT_JAVA_LIBRARIES)/jarjar.jar
 PROGUARD := external/proguard/bin/proguard.sh
 JAVATAGS := build/tools/java-event-log-tags.py
+DEXOPT := $(HOST_OUT_EXECUTABLES)/dexopt$(HOST_EXECUTABLE_SUFFIX)
+DEXPREOPT := dalvik/tools/dex-preopt
 
 # ACP is always for the build OS, not for the host OS
 ACP := $(BUILD_OUT_EXECUTABLES)/acp$(BUILD_EXECUTABLE_SUFFIX)
diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk
new file mode 100644
index 0000000..b036443
--- /dev/null
+++ b/core/dex_preopt.mk
@@ -0,0 +1,73 @@
+####################################
+# Dexpreopt on the boot jars
+#
+####################################
+
+# TODO: replace it with device's BOOTCLASSPATH
+DEXPREOPT_BOOT_JARS := core:bouncycastle:ext:framework:android.policy:services:core-junit
+DEXPREOPT_BOOT_JARS_MODULES := $(subst :, ,$(DEXPREOPT_BOOT_JARS))
+
+DEXPREOPT_BUILD_DIR := $(OUT_DIR)
+DEXPREOPT_PRODUCT_DIR := $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(PRODUCT_OUT))/dex_bootjars
+DEXPREOPT_BOOT_JAR_DIR := system/framework
+DEXPREOPT_DEXOPT := $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(DEXOPT))
+
+DEXPREOPT_BOOT_JAR_DIR_FULL_PATH := $(DEXPREOPT_BUILD_DIR)/$(DEXPREOPT_PRODUCT_DIR)/$(DEXPREOPT_BOOT_JAR_DIR)
+
+DEXPREOPT_BOOT_ODEXS := $(foreach b,$(DEXPREOPT_BOOT_JARS_MODULES),\
+    $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(b).odex)
+
+# $(1): the .jar or .apk to remove classes.dex
+define dexpreopt-remove-classes.dex
+$(hide) $(AAPT) remove $(1) classes.dex
+endef
+
+# $(1): the input .jar or .apk file
+# $(2): the output .odex file
+define dexpreopt-one-file
+$(hide) $(DEXPREOPT) --dexopt=$(DEXPREOPT_DEXOPT) --build-dir=$(DEXPREOPT_BUILD_DIR) \
+	--product-dir=$(DEXPREOPT_PRODUCT_DIR) --boot-dir=$(DEXPREOPT_BOOT_JAR_DIR) \
+	--boot-jars=$(DEXPREOPT_BOOT_JARS) \
+	$(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(1)) \
+	$(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(2))
+endef
+
+# $(1): boot jar module name
+define _dexpreopt-boot-jar
+$(eval _dbj_jar := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1).jar)
+$(eval _dbj_odex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1).odex)
+$(eval _dbj_jar_no_dex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1)_nodex.jar)
+$(eval _dbj_src_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,$(1),,COMMON)/javalib.dex.jar)
+$(eval $(_dbj_odex): PRIVATE_DBJ_JAR := $(_dbj_jar))
+$(_dbj_odex) : $(_dbj_src_jar) | $(ACP) $(DEXPREOPT) $(DEXOPT)
+	@echo "Dexpreopt Boot Jar: $$@"
+	$(hide) rm -f $$@
+	$(hide) mkdir -p $$(dir $$@)
+	$(hide) $(ACP) -fpt $$< $$(PRIVATE_DBJ_JAR)
+	$$(call dexpreopt-one-file,$$(PRIVATE_DBJ_JAR),$$@)
+
+$(_dbj_jar_no_dex) : $(_dbj_src_jar) | $(ACP) $(AAPT)
+	$$(call copy-file-to-target)
+	$$(call dexpreopt-remove-classes.dex,$$@)
+
+$(eval _dbj_jar :=)
+$(eval _dbj_odex :=)
+$(eval _dbj_src_jar :=)
+endef
+
+$(foreach b,$(DEXPREOPT_BOOT_JARS_MODULES),$(eval $(call _dexpreopt-boot-jar,$(b))))
+
+# $(1): the rest list of boot jars
+define _build-dexpreopt-boot-jar-dependency-pair
+$(if $(filter 1,$(words $(1)))$(filter 0,$(words $(1))),,\
+	$(eval _bdbjdp_target := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(word 2,$(1)).odex) \
+	$(eval _bdbjdp_dep := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(word 1,$(1)).odex) \
+	$(eval $(call add-dependency,$(_bdbjdp_target),$(_bdbjdp_dep))) \
+	$(eval $(call _build-dexpreopt-boot-jar-dependency-pair,$(wordlist 2,999,$(1)))))
+endef
+
+define _build-dexpreopt-boot-jar-dependency
+$(call _build-dexpreopt-boot-jar-dependency-pair,$(DEXPREOPT_BOOT_JARS_MODULES))
+endef
+
+$(eval $(call _build-dexpreopt-boot-jar-dependency))
diff --git a/core/java_library.mk b/core/java_library.mk
index a33bf2e..3e670a9 100644
--- a/core/java_library.mk
+++ b/core/java_library.mk
@@ -23,6 +23,14 @@
 
 LOCAL_BUILT_MODULE_STEM := javalib.jar
 
+ifndef LOCAL_IS_HOST_MODULE
+ifeq (true,$(WITH_DEXPREOPT))
+ifndef LOCAL_DEX_PREOPT
+LOCAL_DEX_PREOPT := true
+endif
+endif
+endif
+
 #################################
 include $(BUILD_SYSTEM)/java.mk
 #################################
@@ -35,8 +43,10 @@
 
 else # !LOCAL_IS_STATIC_JAVA_LIBRARY
 
-$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(built_dex)
-$(LOCAL_BUILT_MODULE): $(built_dex) $(java_resource_sources) | $(AAPT)
+ifeq ($(LOCAL_DEX_PREOPT),true)
+jar_with_dex := $(intermediates.COMMON)/javalib.dex.jar
+$(jar_with_dex): PRIVATE_DEX_FILE := $(built_dex)
+$(jar_with_dex) : $(built_dex) $(java_resource_sources) | $(AAPT)
 	@echo "target Jar: $(PRIVATE_MODULE) ($@)"
 	$(create-empty-package)
 	$(add-dex-to-package)
@@ -44,4 +54,43 @@
 	$(add-java-resources-to-package)
 endif
 
+dexpreopt_boot_jar_module := $(filter $(LOCAL_MODULE),$(DEXPREOPT_BOOT_JARS_MODULES))
+ifneq ($(dexpreopt_boot_jar_module),)
+# boot jar's rules are defined in dex_preopt.mk
+dexpreopted_boot_jar := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(dexpreopt_boot_jar_module)_nodex.jar
+$(LOCAL_BUILT_MODULE) : $(dexpreopted_boot_jar) | $(ACP)
+	$(call copy-file-to-target)
+
+dexpreopted_boot_odex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(dexpreopt_boot_jar_module).odex
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(built_odex) : $(dexpreopted_boot_odex) | $(ACP)
+	$(call copy-file-to-target)
+
+else # dexpreopt_boot_jar_module
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(built_odex): PRIVATE_MODULE := $(LOCAL_MODULE)
+# Make sure the boot jars get dex-preopt-ed first
+$(built_odex) : $(DEXPREOPT_BOOT_ODEXS)
+$(built_odex) : $(jar_with_dex) | $(DEXPREOPT) $(DEXOPT)
+	@echo "Dexpreopt Jar: $(PRIVATE_MODULE) ($@)"
+	$(hide) rm -f $@
+	$(call dexpreopt-one-file,$<,$@)
+
+$(LOCAL_BUILT_MODULE) : $(jar_with_dex) | $(ACP) $(AAPT)
+	$(call copy-file-to-target)
+	$(call dexpreopt-remove-classes.dex,$@)
+
+endif # dexpreopt_boot_jar_module
+
+else # LOCAL_DEX_PREOPT
+$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(built_dex)
+$(LOCAL_BUILT_MODULE) : $(built_dex) $(java_resource_sources) | $(AAPT)
+	@echo "target Jar: $(PRIVATE_MODULE) ($@)"
+	$(create-empty-package)
+	$(add-dex-to-package)
+ifneq ($(extra_jar_args),)
+	$(add-java-resources-to-package)
+endif
+endif # LOCAL_DEX_PREOPT
+
 endif # !LOCAL_IS_STATIC_JAVA_LIBRARY
diff --git a/core/main.mk b/core/main.mk
index be74e38..8a70489 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -157,6 +157,9 @@
 # Bring in standard build system definitions.
 include $(BUILD_SYSTEM)/definitions.mk
 
+# Bring in dex_preopt.mk
+include $(BUILD_SYSTEM)/dex_preopt.mk
+
 ifneq ($(filter eng user userdebug tests,$(MAKECMDGOALS)),)
 $(info ***************************************************************)
 $(info ***************************************************************)
diff --git a/core/package.mk b/core/package.mk
index 8254bae..6834995 100644
--- a/core/package.mk
+++ b/core/package.mk
@@ -154,6 +154,14 @@
 endif # !custom
 LOCAL_PROGUARD_FLAGS := $(addprefix -include ,$(proguard_options_file)) $(LOCAL_PROGUARD_FLAGS)
 
+ifeq (true,$(WITH_DEXPREOPT))
+ifneq (,$(LOCAL_SRC_FILES))
+ifndef LOCAL_DEX_PREOPT
+LOCAL_DEX_PREOPT := true
+endif
+endif
+endif
+
 # The dex files go in the package, so we don't
 # want to install them separately for this module.
 old_DONT_INSTALL_DEX_FILES := $(DONT_INSTALL_DEX_FILES)
@@ -314,6 +322,10 @@
 
 # Define the rule to build the actual package.
 $(LOCAL_BUILT_MODULE): $(AAPT) | $(ZIPALIGN)
+ifeq ($(LOCAL_DEX_PREOPT),true)
+# Make sure the boot jars get dexpreopt-ed first
+$(LOCAL_BUILT_MODULE): $(DEXPREOPT_BOOT_ODEXS) | $(DEXPREOPT) $(DEXOPT)
+endif
 $(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES := $(jni_shared_libraries)
 ifneq ($(TARGET_BUILD_APPS),)
     # Include all resources for unbundled apps.
@@ -332,6 +344,14 @@
 	$(sign-package)
 	@# Alignment must happen after all other zip operations.
 	$(align-package)
+ifeq ($(LOCAL_DEX_PREOPT),true)
+	$(hide) rm -f $(patsubst %.apk,%.odex,$@)
+	$(call dexpreopt-one-file,$@,$(patsubst %.apk,%.odex,$@))
+	$(call dexpreopt-remove-classes.dex,$@)
+
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(built_odex): $(LOCAL_BUILT_MODULE)
+endif
 
 # Save information about this package
 PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))