Merge "Fix typo in MODULE_BUILD_FROM_SOURCE variable."
diff --git a/core/Makefile b/core/Makefile
index aaefacd..b44d1d7 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -4010,25 +4010,16 @@
 endif # BOARD_KERNEL_CONFIG_FILE
 
 ifneq ($(my_board_extracted_kernel),true)
-ifndef INSTALLED_KERNEL_TARGET
-$(warning No INSTALLED_KERNEL_TARGET is defined when PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \
-    is true. Information about the updated kernel cannot be built into OTA update package. \
-    You can fix this by: (1) setting TARGET_NO_KERNEL to false and installing the built kernel \
-    to $(PRODUCT_OUT)/kernel, so that kernel information will be extracted from the built kernel; \
-    or (2) extracting kernel configuration and defining BOARD_KERNEL_CONFIG_FILE and \
-    BOARD_KERNEL_VERSION manually; or (3) unsetting PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \
-    manually.)
-# Clear their values to indicate that these two files does not exist.
-BUILT_KERNEL_CONFIGS_FILE :=
-BUILT_KERNEL_VERSION_FILE :=
-else
-
 # Tools for decompression that is not in PATH.
 # Check $(EXTRACT_KERNEL) for decompression algorithms supported by the script.
 # Algorithms that are in the script but not in this list will be found in PATH.
 my_decompress_tools := \
     lz4:$(HOST_OUT_EXECUTABLES)/lz4 \
 
+endif # my_board_extracted_kernel
+
+ifneq ($(my_board_extracted_kernel),true)
+ifdef INSTALLED_KERNEL_TARGET
 $(BUILT_KERNEL_CONFIGS_FILE): .KATI_IMPLICIT_OUTPUTS := $(BUILT_KERNEL_VERSION_FILE)
 $(BUILT_KERNEL_CONFIGS_FILE): PRIVATE_DECOMPRESS_TOOLS := $(my_decompress_tools)
 $(BUILT_KERNEL_CONFIGS_FILE): $(foreach pair,$(my_decompress_tools),$(call word-colon,2,$(pair)))
@@ -4037,12 +4028,46 @@
 	  --output-configs $@ \
 	  --output-release $(BUILT_KERNEL_VERSION_FILE)
 
-my_decompress_tools :=
-
-endif # my_board_extracted_kernel
-my_board_extracted_kernel :=
-
+my_board_extracted_kernel := true
 endif # INSTALLED_KERNEL_TARGET
+endif # my_board_extracted_kernel
+
+ifneq ($(my_board_extracted_kernel),true)
+ifdef INSTALLED_BOOTIMAGE_TARGET
+$(BUILT_KERNEL_CONFIGS_FILE): .KATI_IMPLICIT_OUTPUTS := $(BUILT_KERNEL_VERSION_FILE)
+$(BUILT_KERNEL_CONFIGS_FILE): PRIVATE_DECOMPRESS_TOOLS := $(my_decompress_tools)
+$(BUILT_KERNEL_CONFIGS_FILE): $(foreach pair,$(my_decompress_tools),$(call word-colon,2,$(pair)))
+$(BUILT_KERNEL_CONFIGS_FILE): PRIVATE_UNPACKED_BOOTIMG := $(intermediates)/unpacked_bootimage
+$(BUILT_KERNEL_CONFIGS_FILE): \
+        $(HOST_OUT_EXECUTABLES)/unpack_bootimg \
+        $(EXTRACT_KERNEL) \
+        $(INSTALLED_BOOTIMAGE_TARGET)
+	$(HOST_OUT_EXECUTABLES)/unpack_bootimg --boot_img $(INSTALLED_BOOTIMAGE_TARGET) --out $(PRIVATE_UNPACKED_BOOTIMG)
+	$(EXTRACT_KERNEL) --tools $(PRIVATE_DECOMPRESS_TOOLS) --input $(PRIVATE_UNPACKED_BOOTIMG)/kernel \
+	  --output-configs $@ \
+	  --output-release $(BUILT_KERNEL_VERSION_FILE)
+
+my_board_extracted_kernel := true
+endif # INSTALLED_BOOTIMAGE_TARGET
+endif # my_board_extracted_kernel
+
+ifneq ($(my_board_extracted_kernel),true)
+$(warning Neither INSTALLED_KERNEL_TARGET nor INSTALLED_BOOTIMAGE_TARGET is defined when \
+    PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS  is true. Information about the updated kernel \
+    cannot be built into OTA update package. You can fix this by: \
+    (1) setting TARGET_NO_KERNEL to false and installing the built kernel to $(PRODUCT_OUT)/kernel,\
+        so that kernel information will be extracted from the built kernel; or \
+    (2) Add a prebuilt boot image and specify it in BOARD_PREBUILT_BOOTIMAGE; or \
+    (3) extracting kernel configuration and defining BOARD_KERNEL_CONFIG_FILE and \
+        BOARD_KERNEL_VERSION manually; or \
+    (4) unsetting PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS manually.)
+# Clear their values to indicate that these two files does not exist.
+BUILT_KERNEL_CONFIGS_FILE :=
+BUILT_KERNEL_VERSION_FILE :=
+endif
+
+my_decompress_tools :=
+my_board_extracted_kernel :=
 
 endif # PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS
 
@@ -4210,13 +4235,22 @@
   ifeq ($(TARGET_PRODUCT),sdk)
     build_ota_package := false
   endif
+  # A target without a kernel may be one of the following:
+  # - A generic target. In this case, the OTA package usually isn't built.
+  #   PRODUCT_BUILD_GENERIC_OTA_PACKAGE may be set to true to force OTA package
+  #   generation.
+  # - A real device target, with TARGET_NO_KERNEL set to true and
+  #   BOARD_PREBUILT_BOOTIMAGE set. In this case, it is valid to generate
+  #   an OTA package.
   ifneq ($(PRODUCT_BUILD_GENERIC_OTA_PACKAGE),true)
     ifneq ($(filter generic%,$(TARGET_DEVICE)),)
       build_ota_package := false
     endif
-    ifeq ($(TARGET_NO_KERNEL),true)
-      build_ota_package := false
-    endif
+    ifeq ($(INSTALLED_BOOTIMAGE_TARGET),)
+      ifeq ($(TARGET_NO_KERNEL),true)
+        build_ota_package := false
+      endif
+    endif # INSTALLED_BOOTIMAGE_TARGET == ""
     ifeq ($(recovery_fstab),)
       build_ota_package := false
     endif
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 8c25086..bb1aa1e 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -293,8 +293,11 @@
 #################################################################
 # Set up minimal BOOTCLASSPATH list of jars to build/execute
 # java code with dalvikvm/art.
-# Jars present in the ART apex. These should match exactly the list of
-# Java libraries in the ART apex build rule.
+# Jars present in the ART apex. These should match exactly the list of Java
+# libraries in art-bootclasspath-fragment. The APEX variant name
+# (com.android.art) is the same regardless which Soong module provides the ART
+# APEX. See the long comment in build/soong/java/dexprepopt_bootjars.go for
+# details.
 ART_APEX_JARS := \
     com.android.art:core-oj \
     com.android.art:core-libart \
diff --git a/core/product.mk b/core/product.mk
index 015fe44..7e8445e 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -213,12 +213,18 @@
 # The list of product-specific kernel header dirs
 _product_list_vars += PRODUCT_VENDOR_KERNEL_HEADERS
 
-# A list of module names of BOOTCLASSPATH (jar files)
+# A list of module names in BOOTCLASSPATH (jar files). Each module may be
+# prefixed with "<apex>:", which identifies the APEX that provides it. APEXes
+# are identified by their "variant" names, i.e. their `apex_name` values in
+# Soong, which default to the `name` values. The prefix can also be "platform:"
+# or "system_ext:", and defaults to "platform:" if left out. See the long
+# comment in build/soong/java/dexprepopt_bootjars.go for details.
 _product_list_vars += PRODUCT_BOOT_JARS
 
-# A list of extra BOOTCLASSPATH jars (to be appended after common jars).
-# Products that include device-specific makefiles before AOSP makefiles should use this
-# instead of PRODUCT_BOOT_JARS, so that device-specific jars go after common jars.
+# A list of extra BOOTCLASSPATH jars (to be appended after common jars),
+# following the same format as PRODUCT_BOOT_JARS. Products that include
+# device-specific makefiles before AOSP makefiles should use this instead of
+# PRODUCT_BOOT_JARS, so that device-specific jars go after common jars.
 _product_list_vars += PRODUCT_BOOT_JARS_EXTRA
 
 _product_single_value_vars += PRODUCT_SUPPORTS_BOOT_SIGNER
@@ -389,7 +395,8 @@
 _product_single_value_vars += PRODUCT_BUILD_VBMETA_IMAGE
 _product_single_value_vars += PRODUCT_BUILD_SUPER_EMPTY_IMAGE
 
-# List of boot jars delivered via apex
+# List of boot jars delivered via updatable APEXes, following the same format as
+# PRODUCT_BOOT_JARS.
 _product_list_vars += PRODUCT_UPDATABLE_BOOT_JARS
 
 # If set, device uses virtual A/B.
diff --git a/core/product_config.mk b/core/product_config.mk
index 5c85fb8..53bc9dd 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -249,6 +249,15 @@
 
 PRODUCT_BOOT_JARS := $(call qualify-platform-jars,$(PRODUCT_BOOT_JARS))
 
+# b/191127295: force core-icu4j onto boot image. It comes from a non-updatable APEX jar, but has
+# historically been part of the boot image; even though APEX jars are not meant to be part of the
+# boot image.
+# TODO(b/191686720): remove PRODUCT_UPDATABLE_BOOT_JARS to avoid a special handling of core-icu4j
+# in make rules.
+PRODUCT_UPDATABLE_BOOT_JARS := $(filter-out com.android.i18n:core-icu4j,$(PRODUCT_UPDATABLE_BOOT_JARS))
+# All APEX jars come after /system and /system_ext jars, so adding core-icu4j at the end of the list
+PRODUCT_BOOT_JARS += com.android.i18n:core-icu4j
+
 # Replaces references to overridden boot jar modules in a boot jars variable.
 # $(1): Name of a boot jars variable with <apex>:<jar> pairs.
 define replace-boot-jar-module-overrides
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index f0916f9..8c249b2 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -44,13 +44,11 @@
     voip-common \
     ims-common
 
-# Non-updatable APEX jars. Keep the list sorted.
-PRODUCT_BOOT_JARS += \
-    com.android.i18n:core-icu4j
-
-# Updatable APEX boot jars. Keep the list sorted by module names and then library names.
+# APEX boot jars. Keep the list sorted by module names and then library names.
+# Note: core-icu4j is moved back to PRODUCT_BOOT_JARS in product_config.mk at a later stage.
 PRODUCT_UPDATABLE_BOOT_JARS := \
     com.android.conscrypt:conscrypt \
+    com.android.i18n:core-icu4j \
     com.android.ipsec:android.net.ipsec.ike \
     com.android.media:updatable-media \
     com.android.mediaprovider:framework-mediaprovider \
@@ -60,7 +58,7 @@
     com.android.tethering:framework-tethering \
     com.android.wifi:framework-wifi
 
-# Updatable APEX system server jars. Keep the list sorted by module names and then library names.
+# APEX system server jars. Keep the list sorted by module names and then library names.
 PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS := \
     com.android.art:service-art \
     com.android.permission:service-permission \
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index c1fa9e7..7086f21 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -1000,8 +1000,15 @@
   # Copy the combined SEPolicy file and framework hashes to the image that is
   # being rebuilt.
   def copy_selinux_file(input_path, output_filename):
+    input_filename = os.path.join(target_files_dir, input_path)
+    if not os.path.exists(input_filename):
+      input_filename = input_filename.replace('SYSTEM_EXT/', 'SYSTEM/system_ext/') \
+          .replace('PRODUCT/', 'SYSTEM/product/')
+      if not os.path.exists(input_filename):
+        logger.info('Skipping copy_selinux_file for %s', input_filename)
+        return
     shutil.copy(
-        os.path.join(target_files_dir, input_path),
+        input_filename,
         os.path.join(target_files_dir, partition.upper(), 'etc/selinux',
                      output_filename))
 
@@ -1041,7 +1048,8 @@
     shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper()))
     shutil.copytree(
         os.path.join(target_files_dir, partition.upper()),
-        os.path.join(vendor_target_files_dir, partition.upper()))
+        os.path.join(vendor_target_files_dir, partition.upper()),
+        symlinks=True)
 
     # Delete then rebuild the partition.
     os.remove(os.path.join(vendor_target_files_dir, 'IMAGES', partition_img))
@@ -1056,6 +1064,8 @@
     common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
 
     # Move the newly-created image to the merged target files dir.
+    if not os.path.exists(os.path.join(target_files_dir, 'IMAGES')):
+      os.makedirs(os.path.join(target_files_dir, 'IMAGES'))
     shutil.move(
         os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
         os.path.join(target_files_dir, 'IMAGES', partition_img))
diff --git a/tools/zipalign/ZipAlignMain.cpp b/tools/zipalign/ZipAlignMain.cpp
index 47ebd12..53fc8d4 100644
--- a/tools/zipalign/ZipAlignMain.cpp
+++ b/tools/zipalign/ZipAlignMain.cpp
@@ -20,6 +20,7 @@
 
 #include "ZipAlign.h"
 
+#include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -60,69 +61,53 @@
     int alignment;
     char* endp;
 
-    if (argc < 4) {
-        wantUsage = true;
-        goto bail;
-    }
-
-    argc--;
-    argv++;
-
-    while (argc && argv[0][0] == '-') {
-        const char* cp = argv[0] +1;
-
-        while (*cp != '\0') {
-            switch (*cp) {
-            case 'c':
-                check = true;
-                break;
-            case 'f':
-                force = true;
-                break;
-            case 'v':
-                verbose = true;
-                break;
-            case 'z':
-                zopfli = true;
-                break;
-            case 'p':
-                pageAlignSharedLibs = true;
-                break;
-            default:
-                fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
-                wantUsage = true;
-                goto bail;
-            }
-
-            cp++;
+    int opt;
+    while ((opt = getopt(argc, argv, "fcpvz")) != -1) {
+        switch (opt) {
+        case 'c':
+            check = true;
+            break;
+        case 'f':
+            force = true;
+            break;
+        case 'v':
+            verbose = true;
+            break;
+        case 'z':
+            zopfli = true;
+            break;
+        case 'p':
+            pageAlignSharedLibs = true;
+            break;
+        default:
+            fprintf(stderr, "ERROR: unknown flag -%c\n", opt);
+            wantUsage = true;
+            goto bail;
         }
-
-        argc--;
-        argv++;
     }
 
-    if (!((check && argc == 2) || (!check && argc == 3))) {
+    if (!((check && (argc - optind) == 2) || (!check && (argc - optind) == 3))) {
         wantUsage = true;
         goto bail;
     }
 
-    alignment = strtol(argv[0], &endp, 10);
+    alignment = strtol(argv[optind], &endp, 10);
     if (*endp != '\0' || alignment <= 0) {
-        fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]);
+        fprintf(stderr, "Invalid value for alignment: %s\n", argv[optind]);
         wantUsage = true;
         goto bail;
     }
 
     if (check) {
         /* check existing archive for correct alignment */
-        result = verify(argv[1], alignment, verbose, pageAlignSharedLibs);
+        result = verify(argv[optind + 1], alignment, verbose, pageAlignSharedLibs);
     } else {
         /* create the new archive */
-        result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs);
+        result = process(argv[optind + 1], argv[optind + 2], alignment, force, zopfli, pageAlignSharedLibs);
 
         /* trust, but verify */
         if (result == 0) {
-            result = verify(argv[2], alignment, verbose, pageAlignSharedLibs);
+            result = verify(argv[optind + 2], alignment, verbose, pageAlignSharedLibs);
         }
     }