Implement LOCAL_COMPRESSED_MODULE.

- Prebuilts with LOCAL_MODULE_CLASS == APPS and BUILD_PACKAGE that
  define LOCAL_COMPRESSED_MODULE := true will be installed compressed
  in the system partition.
- The compression algorithm is simple gzip for now.

In addition :
- Compressed modules are not dex-preopted.
- JNI shared libraries are always embedded inside compressed modules,
  they are never installed as separate files on the FS.

Test: Manual
Bug: 63802184

Change-Id: Id12b1ff0b1d68791ec1178783f7e78910e122a33
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 1fba952..a687866 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -34,6 +34,7 @@
 LOCAL_CLASSPATH:=
 LOCAL_COMPATIBILITY_SUITE:=
 LOCAL_COMPATIBILITY_SUPPORT_FILES:=
+LOCAL_COMPRESSED_MODULE:=
 LOCAL_CONLYFLAGS:=
 LOCAL_COPY_HEADERS:=
 LOCAL_COPY_HEADERS_TO:=
diff --git a/core/definitions.mk b/core/definitions.mk
index 330d360..95e9a02 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2723,6 +2723,15 @@
   fi
 endef
 
+# Compress a package using the standard gzip algorithm.
+define compress-package
+$(hide) \
+  mv $@ $@.uncompressed; \
+  $(MINIGZIP) -c $@.uncompressed > $@.compressed; \
+  rm -f $@.uncompressed; \
+  mv $@.compressed $@;
+endef
+
 # Remove dynamic timestamps from packages
 #
 define remove-timestamps-from-package
diff --git a/core/install_jni_libs.mk b/core/install_jni_libs.mk
index 6b550c1..e88db40 100644
--- a/core/install_jni_libs.mk
+++ b/core/install_jni_libs.mk
@@ -32,6 +32,11 @@
     my_embed_jni := true
   endif
 endif
+# If we're installing this APP as a compressed module, we include all JNI libraries
+# in the compressed artifact, rather than as separate files on the partition in question.
+ifdef LOCAL_COMPRESSED_MODULE
+my_embed_jni := true
+endif
 
 jni_shared_libraries :=
 jni_shared_libraries_abis :=
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 74dd15e..28c3a08 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -215,8 +215,19 @@
 LOCAL_INTERMEDIATE_TARGETS += $(R_file_stamp)
 endif
 
+ifdef LOCAL_COMPRESSED_MODULE
+ifneq (true,$(LOCAL_COMPRESSED_MODULE))
+$(call pretty-error, Unknown value for LOCAL_COMPRESSED_MODULE $(LOCAL_COMPRESSED_MODULE))
+endif
+endif
+
+ifdef LOCAL_COMPRESSED_MODULE
+LOCAL_BUILT_MODULE_STEM := package.apk.gz
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk.gz
+else  # !LOCAL_COMPRESSED_MODULE
 LOCAL_BUILT_MODULE_STEM := package.apk
 LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk
+endif
 
 LOCAL_PROGUARD_ENABLED:=$(strip $(LOCAL_PROGUARD_ENABLED))
 ifndef LOCAL_PROGUARD_ENABLED
@@ -307,6 +318,12 @@
 LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.databinding.library
 endif  # LOCAL_DATA_BINDING
 
+# If the module is a compressed module, we don't pre-opt it because its final
+# installation location will be the data partition.
+ifdef LOCAL_COMPRESSED_MODULE
+LOCAL_DEX_PREOPT := false
+endif
+
 include $(BUILD_SYSTEM)/android_manifest.mk
 
 #################################
@@ -358,6 +375,10 @@
 my_apk_split_configs :=
 
 ifdef LOCAL_PACKAGE_SPLITS
+ifdef LOCAL_COMPRESSED_MODULE
+$(error $(LOCAL_MODULE): LOCAL_COMPRESSED_MODULE is not currently supported for split installs)
+endif  # LOCAL_COMPRESSED_MODULE
+
 my_apk_split_configs := $(LOCAL_PACKAGE_SPLITS)
 my_split_suffixes := $(subst $(comma),_,$(my_apk_split_configs))
 built_apk_splits := $(foreach s,$(my_split_suffixes),$(intermediates)/package_$(s).apk)
@@ -571,6 +592,9 @@
 else
 $(LOCAL_BUILT_MODULE) : $(all_res_assets) $(full_android_manifest) $(AAPT)
 endif
+ifdef LOCAL_COMPRESSED_MODULE
+$(LOCAL_BUILT_MODULE) : $(MINIGZIP)
+endif
 	@echo "target Package: $(PRIVATE_MODULE) ($@)"
 ifdef LOCAL_USE_AAPT2
 	$(call copy-file-to-new-target)
@@ -606,6 +630,9 @@
 endif
 endif
 	$(sign-package)
+ifdef LOCAL_COMPRESSED_MODULE
+	$(compress-package)
+endif  # LOCAL_COMPRESSED_MODULE
 
 ###############################
 ## Build dpi-specific apks, if it's apps_only build.
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index de71111..edda97e 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -105,13 +105,33 @@
   prebuilt_module_is_dex_javalib :=
 endif
 
-ifeq ($(LOCAL_MODULE_CLASS),APPS)
-LOCAL_BUILT_MODULE_STEM := package.apk
-ifndef LOCAL_INSTALLED_MODULE_STEM
-LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk
+ifdef LOCAL_COMPRESSED_MODULE
+ifneq (true,$(LOCAL_COMPRESSED_MODULE))
+$(call pretty-error, Unknown value for LOCAL_COMPRESSED_MODULE $(LOCAL_COMPRESSED_MODULE))
 endif
 endif
 
+ifeq ($(LOCAL_MODULE_CLASS),APPS)
+ifdef LOCAL_COMPRESSED_MODULE
+LOCAL_BUILT_MODULE_STEM := package.apk.gz
+else
+LOCAL_BUILT_MODULE_STEM := package.apk
+endif  # LOCAL_COMPRESSED_MODULE
+
+ifndef LOCAL_INSTALLED_MODULE_STEM
+ifdef LOCAL_COMPRESSED_MODULE
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk.gz
+else
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE).apk
+endif  # LOCAL_COMPRESSED_MODULE
+endif  # LOCAL_INSTALLED_MODULE_STEM
+
+else  # $(LOCAL_MODULE_CLASS) != APPS)
+ifdef LOCAL_COMPRESSED_MODULE
+$(error $(LOCAL_MODULE) : LOCAL_COMPRESSED_MODULE can only be defined for module class APPS)
+endif  # LOCAL_COMPRESSED_MODULE
+endif
+
 ifneq ($(filter true keep_symbols no_debuglink mini-debug-info,$(my_strip_module) $(my_pack_module_relocations)),)
   ifdef LOCAL_IS_HOST_MODULE
     $(error Cannot strip/pack host module LOCAL_PATH=$(LOCAL_PATH))
@@ -314,6 +334,12 @@
 endif
 endif
 
+# If the module is a compressed module, we don't pre-opt it because its final
+# installation location will be the data partition.
+ifdef LOCAL_COMPRESSED_MODULE
+LOCAL_DEX_PREOPT := false
+endif
+
 #######################################
 # defines built_odex along with rule to install odex
 include $(BUILD_SYSTEM)/dex_preopt_odex_install.mk
@@ -338,6 +364,10 @@
 endif
 $(built_module): PRIVATE_EMBEDDED_JNI_LIBS := $(embedded_prebuilt_jni_libs)
 
+ifdef LOCAL_COMPRESSED_MODULE
+$(built_module) : $(MINIGZIP)
+endif
+
 $(built_module) : $(my_prebuilt_src_file) | $(ZIPALIGN) $(SIGNAPK_JAR)
 	$(transform-prebuilt-to-target)
 	$(uncompress-shared-libs)
@@ -359,6 +389,9 @@
 else  # LOCAL_CERTIFICATE == PRESIGNED
 	$(align-package)
 endif  # LOCAL_CERTIFICATE
+ifdef LOCAL_COMPRESSED_MODULE
+	$(compress-package)
+endif  # LOCAL_COMPRESSED_MODULE
 endif  # ! LOCAL_REPLACE_PREBUILT_APK_INSTALLED
 
 ###############################
@@ -371,6 +404,10 @@
 ###############################
 ## Install split apks.
 ifdef LOCAL_PACKAGE_SPLITS
+ifdef LOCAL_COMPRESSED_MODULE
+$(error $(LOCAL_MODULE): LOCAL_COMPRESSED_MODULE is not currently supported for split installs)
+endif  # LOCAL_COMPRESSED_MODULE
+
 # LOCAL_PACKAGE_SPLITS is a list of apks to be installed.
 built_apk_splits := $(addprefix $(intermediates)/,$(notdir $(LOCAL_PACKAGE_SPLITS)))
 installed_apk_splits := $(addprefix $(my_module_path)/,$(notdir $(LOCAL_PACKAGE_SPLITS)))