Merge "Revert "Generate care map after merging target_files""
diff --git a/Changes.md b/Changes.md
index 0a6adc4..1ab005f 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,49 @@
 # Build System Changes for Android.mk Writers
 
+## Dexpreopt starts enforcing `<uses-library>` checks (for Java modules)
+
+In order to construct correct class loader context for dexpreopt, build system
+needs to know about the shared library dependencies of Java modules listed in
+the `<uses-library>` tags in the manifest. Since the build system does not have
+access to the manifest contents, that information must be present in the build
+files. In simple cases Soong is able to infer it from its knowledge of Java SDK
+libraries and the `libs` property in Android.bp, but in more complex cases it is
+necessary to add the missing information in Android.bp/Android.mk manually.
+
+To specify a list of libraries for a given modules, use:
+
+* Android.bp properties: `uses_libs`, `optional_uses_libs`
+* Android.mk variables: `LOCAL_USES_LIBRARIES`, `LOCAL_OPTIONAL_USES_LIBRARIES`
+
+If a library is in `libs`, it usually should *not* be added to the above
+properties, and Soong should be able to infer the `<uses-library>` tag. But
+sometimes a library also needs additional information in its
+Android.bp/Android.mk file (e.g. when it is a `java_library` rather than a
+`java_sdk_library`, or when the library name is different from its module name,
+or when the module is defined in Android.mk rather than Android.bp). In such
+cases it is possible to tell the build system that the library provides a
+`<uses-library>` with a given name (however, this is discouraged and will be
+deprecated in the future, and it is recommended to fix the underlying problem):
+
+* Android.bp property: `provides_uses_lib`
+* Android.mk variable: `LOCAL_PROVIDES_USES_LIBRARY`
+
+It is possible to disable the check on a per-module basis. When doing that it is
+also recommended to disable dexpreopt, as disabling a failed check will result
+in incorrect class loader context recorded in the .odex file, which will cause
+class loader context mismatch and dexopt at first boot.
+
+* Android.bp property: `enforce_uses_lib`
+* Android.mk variable: `LOCAL_ENFORCE_USES_LIBRARIES`
+
+Finally, it is possible to globally disable the check:
+
+* For a given product: `PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true`
+* On the command line: `RELAX_USES_LIBRARY_CHECK=true`
+
+The environment variable overrides the product variable, so it is possible to
+disable the check for a product, but quickly re-enable it for a local build.
+
 ## `LOCAL_REQUIRED_MODULES` requires listed modules to exist {#BUILD_BROKEN_MISSING_REQUIRED_MODULES}
 
 Modules listed in `LOCAL_REQUIRED_MODULES`, `LOCAL_HOST_REQUIRED_MODULES` and
diff --git a/core/binary.mk b/core/binary.mk
index 2c20eed..0d7206f 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -266,10 +266,7 @@
       endif
     endif
 
-    ifneq (,$(filter armeabi armeabi-v7a,$(my_cpu_variant)))
-      my_ndk_stl_static_lib += $(my_libcxx_libdir)/libunwind.a
-    endif
-
+    my_ndk_stl_static_lib += $(my_libcxx_libdir)/libunwind.a
     my_ldlibs += -ldl
   else # LOCAL_NDK_STL_VARIANT must be none
     # Do nothing.
diff --git a/core/cxx_stl_setup.mk b/core/cxx_stl_setup.mk
index f71ef72..0d557c7 100644
--- a/core/cxx_stl_setup.mk
+++ b/core/cxx_stl_setup.mk
@@ -82,15 +82,7 @@
         endif
     endif
 else ifeq ($(my_cxx_stl),ndk)
-    # Using an NDK STL. Handled in binary.mk, except for the unwinder.
-    # TODO: Switch the NDK over to the LLVM unwinder for non-arm32 architectures.
-    ifeq (arm,$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH))
-        my_static_libraries += libunwind_llvm
-        my_ldflags += -Wl,--exclude-libs,libunwind_llvm.a
-    else
-        my_static_libraries += libgcc_stripped
-        my_ldflags += -Wl,--exclude-libs,libgcc_stripped.a
-    endif
+    # Using an NDK STL. Handled in binary.mk.
 else ifeq ($(my_cxx_stl),libstdc++)
     $(error $(LOCAL_PATH): $(LOCAL_MODULE): libstdc++ is not supported)
 else ifeq ($(my_cxx_stl),none)
diff --git a/core/envsetup.rbc b/core/envsetup.rbc
index 2924ee1..451623b 100644
--- a/core/envsetup.rbc
+++ b/core/envsetup.rbc
@@ -1,4 +1,3 @@
-
 # Copyright 2021 Google LLC
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,14 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load(":build_id.rbc|init", _build_id_init="init")
+load(":build_id.rbc|init", _build_id_init = "init")
 
 def _all_versions():
     """Returns all known versions."""
-    versions = ["OPR1", "OPD1", "OPD2","OPM1", "OPM2", "PPR1", "PPD1", "PPD2", "PPM1",  "PPM2", "QPR1" ]
+    versions = ["OPR1", "OPD1", "OPD2", "OPM1", "OPM2", "PPR1", "PPD1", "PPD2", "PPM1", "PPM2", "QPR1"]
     for v in ("Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"):
-        for e in ("P1A", "P1B", "P2A", "P2B", "D1A", "D1B", "D2A", "D2B", "Q1A", "Q1B", "Q2A", "Q2B", "Q3A",  "Q3B"):
-            versions.append(v+e)
+        for e in ("P1A", "P1B", "P2A", "P2B", "D1A", "D1B", "D2A", "D2B", "Q1A", "Q1B", "Q2A", "Q2B", "Q3A", "Q3B"):
+            versions.append(v + e)
     return versions
 
 def _allowed_versions(all_versions, min_version, max_version, default_version):
@@ -36,7 +35,7 @@
         fail("%s should come before %s in the version list" % (min_version, max_version))
     if def_i < min_i or def_i > max_i:
         fail("%s should come between % and %s" % (default_version, min_version, max_version))
-    return all_versions[min_i:max_i+1]
+    return all_versions[min_i:max_i + 1]
 
 # This function is a manual conversion of the version_defaults.mk
 def _versions_default(g, all_versions):
@@ -70,21 +69,22 @@
     g.setdefault("PLATFORM_VERSION_CODENAME", g["TARGET_PLATFORM_VERSION"])
     # TODO(asmundak): set PLATFORM_VERSION_ALL_CODENAMES
 
-    g.setdefault("PLATFORM_VERSION",
-        g["PLATFORM_VERSION_LAST_STABLE"] if g["PLATFORM_VERSION_CODENAME"] == "REL" else g["PLATFORM_VERSION_CODENAME"])
     g.setdefault("PLATFORM_SDK_VERSION", 30)
-    if g["PLATFORM_VERSION_CODENAME"] == "REL":
+    version_codename = g["PLATFORM_VERSION_CODENAME"]
+    if version_codename == "REL":
+        g.setdefault("PLATFORM_VERSION", g["PLATFORM_VERSION_LAST_STABLE"])
         g["PLATFORM_PREVIEW_SDK_VERSION"] = 0
+        g.setdefault("DEFAULT_APP_TARGET_SDK", g["PLATFORM_SDK_VERSION"])
+        g.setdefault("PLATFORM_VNDK_VERSION", g["PLATFORM_SDK_VERSION"])
     else:
+        g.setdefault("PLATFORM_VERSION", version_codename)
         g.setdefault("PLATFORM_PREVIEW_SDK_VERSION", 1)
+        g.setdefault("DEFAULT_APP_TARGET_SDK", version_codename)
+        g.setdefault("PLATFORM_VNDK_VERSION", version_codename)
 
-    g.setdefault("DEFAULT_APP_TARGET_SDK",
-        g["PLATFORM_SDK_VERSION"] if g["PLATFORM_VERSION_CODENAME"] == "REL" else g["PLATFORM_VERSION_CODENAME"])
-    g.setdefault("PLATFORM_VNDK_VERSION",
-        g["PLATFORM_SDK_VERSION"] if g["PLATFORM_VERSION_CODENAME"] == "REL" else g["PLATFORM_VERSION_CODENAME"])
     g.setdefault("PLATFORM_SYSTEMSDK_MIN_VERSION", 28)
     versions = [str(i) for i in range(g["PLATFORM_SYSTEMSDK_MIN_VERSION"], g["PLATFORM_SDK_VERSION"] + 1)]
-    versions.append(g["PLATFORM_VERSION_CODENAME"])
+    versions.append(version_codename)
     g["PLATFORM_SYSTEMSDK_VERSIONS"] = sorted(versions)
 
     #  Used to indicate the security patch that has been applied to the device.
@@ -117,6 +117,13 @@
     g.setdefault("PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION", 23)
 
 def init(g):
+    """Initializes globals.
+
+    The code is the Starlark counterpart of the contents of the
+    envsetup.mk file.
+    Args:
+        g: globals dictionary
+    """
     all_versions = _all_versions()
     _versions_default(g, all_versions)
     for v in all_versions:
@@ -168,7 +175,8 @@
     g["HOST_CROSS_2ND_ARCH_MODULE_SUFFIX"] = "_64"
     g["TARGET_2ND_ARCH_VAR_PREFIX"] = "2ND_"
 
-    # TODO(asmundak): combo-related stuff
+    # TODO(asmundak): envsetup.mk lines 216-226:
+    # convert combo-related stuff from combo/select.mk
 
     # on windows, the tools have .exe at the end, and we depend on the
     # host config stuff being done first
@@ -177,23 +185,23 @@
 
     # the host build defaults to release, and it must be release or debug
     g.setdefault("HOST_BUILD_TYPE", "release")
-    if g["HOST_BUILD_TYPE"] != "release" and g["HOST_BUILD_TYPE"] != "debug":
+    if g["HOST_BUILD_TYPE"] not in ["release", "debug"]:
         fail("HOST_BUILD_TYPE must be either release or debug, not '%s'" % g["HOST_BUILD_TYPE"])
 
-    # TODO(asmundak): a lot more, but not needed for the product configuration
+    # TODO(asmundak): there is more stuff in envsetup.mk lines 249-292, but
+    # it does not seem to affect product configuration. Revisit this.
 
     g["ART_APEX_JARS"] = [
         "com.android.art:core-oj",
         "com.android.art:core-libart",
         "com.android.art:okhttp",
         "com.android.art:bouncycastle",
-        "com.android.art:apache-xml"
+        "com.android.art:apache-xml",
     ]
 
     if g.get("TARGET_BUILD_TYPE", "") != "debug":
         g["TARGET_BUILD_TYPE"] = "release"
 
-
 v_default = "SP1A"
 v_min = "SP1A"
 v_max = "SP1A"
diff --git a/core/fuzz_test.mk b/core/fuzz_test.mk
index 4a0fcfa..8a4b8c3 100644
--- a/core/fuzz_test.mk
+++ b/core/fuzz_test.mk
@@ -19,35 +19,6 @@
 
 ifeq ($(my_fuzzer),libFuzzer)
 LOCAL_STATIC_LIBRARIES += libFuzzer
-else ifeq ($(my_fuzzer),honggfuzz)
-LOCAL_STATIC_LIBRARIES += honggfuzz_libhfuzz
-LOCAL_REQUIRED_MODULES += honggfuzz
-LOCAL_LDFLAGS += \
-        "-Wl,--wrap=strcmp" \
-        "-Wl,--wrap=strcasecmp" \
-        "-Wl,--wrap=strncmp" \
-        "-Wl,--wrap=strncasecmp" \
-        "-Wl,--wrap=strstr" \
-        "-Wl,--wrap=strcasestr" \
-        "-Wl,--wrap=memcmp" \
-        "-Wl,--wrap=bcmp" \
-        "-Wl,--wrap=memmem" \
-        "-Wl,--wrap=ap_cstr_casecmp" \
-        "-Wl,--wrap=ap_cstr_casecmpn" \
-        "-Wl,--wrap=ap_strcasestr" \
-        "-Wl,--wrap=apr_cstr_casecmp" \
-        "-Wl,--wrap=apr_cstr_casecmpn" \
-        "-Wl,--wrap=CRYPTO_memcmp" \
-        "-Wl,--wrap=OPENSSL_memcmp" \
-        "-Wl,--wrap=OPENSSL_strcasecmp" \
-        "-Wl,--wrap=OPENSSL_strncasecmp" \
-        "-Wl,--wrap=xmlStrncmp" \
-        "-Wl,--wrap=xmlStrcmp" \
-        "-Wl,--wrap=xmlStrEqual" \
-        "-Wl,--wrap=xmlStrcasecmp" \
-        "-Wl,--wrap=xmlStrncasecmp" \
-        "-Wl,--wrap=xmlStrstr" \
-        "-Wl,--wrap=xmlStrcasestr"
 else
 $(call pretty-error, Unknown fuzz engine $(my_fuzzer))
 endif
diff --git a/core/main.mk b/core/main.mk
index 56950ec..3362681 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1573,6 +1573,8 @@
     $(INSTALLED_SUPERIMAGE_EMPTY_TARGET) \
     $(INSTALLED_PRODUCTIMAGE_TARGET) \
     $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) \
+    $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET) \
+    $(INSTALLED_TEST_HARNESS_BOOTIMAGE_TARGET) \
     $(INSTALLED_FILES_FILE) \
     $(INSTALLED_FILES_JSON) \
     $(INSTALLED_FILES_FILE_VENDOR) \
@@ -1750,14 +1752,12 @@
       $(INSTALLED_FILES_JSON_VENDOR_DEBUG_RAMDISK) \
       $(INSTALLED_DEBUG_RAMDISK_TARGET) \
       $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
+      $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET) \
+      $(INSTALLED_TEST_HARNESS_BOOTIMAGE_TARGET) \
       $(INSTALLED_VENDOR_DEBUG_BOOTIMAGE_TARGET) \
       $(INSTALLED_VENDOR_RAMDISK_TARGET) \
       $(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET) \
     )
-    $(call dist-for-goals, bootimage_test_harness, \
-      $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET) \
-      $(INSTALLED_TEST_HARNESS_BOOTIMAGE_TARGET) \
-    )
   endif
 
   ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
diff --git a/core/product_config.rbc b/core/product_config.rbc
index 6e96822..111e759 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -1,4 +1,3 @@
-
 # Copyright 2021 Google LLC
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//build/make/core:envsetup.rbc", _envsetup_init="init")
+load("//build/make/core:envsetup.rbc", _envsetup_init = "init")
+
 """Runtime functions."""
 
 def _global_init():
@@ -33,10 +33,13 @@
 
     # Variables that should be defined.
     mandatory_vars = [
-        "PLATFORM_VERSION_CODENAME", "PLATFORM_VERSION",
+        "PLATFORM_VERSION_CODENAME",
+        "PLATFORM_VERSION",
         "PRODUCT_SOONG_NAMESPACES",
         # TODO(asmundak): do we need TARGET_ARCH? AOSP does not reference it
-        "TARGET_BUILD_TYPE", "TARGET_BUILD_VARIANT", "TARGET_PRODUCT",
+        "TARGET_BUILD_TYPE",
+        "TARGET_BUILD_VARIANT",
+        "TARGET_PRODUCT",
     ]
     for bv in mandatory_vars:
         if not bv in globals:
@@ -56,29 +59,26 @@
             print(attr, "=", repr(value))
         elif _options.format == "make":
             print(attr, ":=", " ".join(value))
+    elif _options.format == "pretty":
+        print(attr, "=", repr(value))
+    elif _options.format == "make":
+        print(attr, ":=", value)
     else:
-        if _options.format == "pretty":
-            print(attr, "=", repr(value))
-        elif _options.format == "make":
-            print(attr, ":=", value)
-        else:
-            fail("bad output format", _options.format)
-
+        fail("bad output format", _options.format)
 
 def _printvars(globals, cfg):
     """Prints known configuration variables."""
     for attr, val in sorted(cfg.items()):
         __print_attr(attr, val)
     if _options.print_globals:
+        print()
         for attr, val in sorted(globals.items()):
-            print()
             if attr not in _globals_base:
                 __print_attr(attr, val)
 
-
-def __printvars_rearrange_list(l):
+def __printvars_rearrange_list(value_list):
     """Rearrange value list: return only distinct elements, maybe sorted."""
-    seen = { item: 0 for item in l}
+    seen = {item: 0 for item in value_list}
     return sorted(seen.keys()) if _options.rearrange == "sort" else seen.keys()
 
 def _product_configuration(top_pcm_name, top_pcm):
@@ -97,44 +97,49 @@
 
     globals = dict(**_globals_base)
 
-    config_postfix = []     # Configs in postfix order
+    config_postfix = []  # Configs in postfix order
+
     # Each PCM is represented by a quadruple of function, config, children names
     # and readyness (that is, the configurations from inherited PCMs have been
     # substituted).
-    configs = { top_pcm_name: (top_pcm, None, [], False)}  # All known PCMs
+    configs = {top_pcm_name: (top_pcm, None, [], False)}  # All known PCMs
 
-    stash = []              # Configs to push once their descendants are done
+    stash = []  # Configs to push once their descendants are done
 
-    # Stack maintaining PCMs to be processed. An item in the stack
+    # Stack containing PCMs to be processed. An item in the stack
     # is a pair of PCMs name and its height in the product inheritance tree.
-    pcm_stack = []
-    pcm_stack.append((top_pcm_name, 0))
+    pcm_stack = [(top_pcm_name, 0)]
     pcm_count = 0
+
     # Run it until pcm_stack is exhausted, but no more than N times
     for n in range(1000):
         if not pcm_stack:
             break
         (name, height) = pcm_stack.pop()
         pcm, cfg, c, _ = configs[name]
-        # each PCM is executed once
+
+        # cfg is set only after PCM has been called, leverage this
+        # to prevent calling the same PCM twice
         if cfg != None:
             continue
+
         # Push ancestors until we reach this node's height
         config_postfix.extend([stash.pop() for i in range(len(stash) - height)])
 
         # Run this one, obtaining its configuration and child PCMs.
         if _options.trace_modules:
-            print("%s:" % n[0])
+            print("%d:" % n)
 
-        # The handle passed to the PCM consists of config and inheritance state.dict of inherited modules
-        # and a list containing the current default value of a list variable.
+        # Run PCM.
         handle = __h_new()
         pcm(globals, handle)
+
+        # Now we know everything about this PCM, record it in 'configs'.
         children = __h_inherited_modules(handle)
         if _options.trace_modules:
             print("   ", "    ".join(children.keys()))
         configs[name] = (pcm, __h_cfg(handle), children.keys(), False)
-        pcm_count = pcm_count+1
+        pcm_count = pcm_count + 1
 
         if len(children) == 0:
             # Leaf PCM goes straight to the config_postfix
@@ -143,17 +148,18 @@
 
         # Stash this PCM, process children in the sorted order
         stash.append(name)
-        for child_name in sorted(children, reverse=True):
+        for child_name in sorted(children, reverse = True):
             if child_name not in configs:
                 configs[child_name] = (children[child_name], None, [], False)
             pcm_stack.append((child_name, len(stash)))
+    if pcm_stack:
+        fail("Inheritance processing took too many iterations")
 
     # Flush the stash
     config_postfix.extend([stash.pop() for i in range(len(stash))])
     if len(config_postfix) != pcm_count:
         fail("Ran %d modules but postfix tree has only %d entries" % (pcm_count, len(config_postfix)))
 
-
     if _options.trace_modules:
         print("\n---Postfix---")
         for x in config_postfix:
@@ -162,55 +168,56 @@
     # Traverse the tree from the bottom, evaluating inherited values
     for pcm_name in config_postfix:
         pcm, cfg, children_names, ready = configs[pcm_name]
+
         # Should run
         if cfg == None:
             fail("%s: has not been run" % pcm_name)
+
         # Ready once
         if ready:
             continue
+
         # Children should be ready
         for child_name in children_names:
             if not configs[child_name][3]:
                 fail("%s: child is not ready" % child_name)
 
-        # if _options.trace_modules:
-        #     print(">%s: %s" % (pcm_name, cfg))
-
         _substitute_inherited(configs, pcm_name, cfg)
         _percolate_inherited(configs, pcm_name, cfg, children_names)
         configs[pcm_name] = pcm, cfg, children_names, True
-        # if _options.trace_modules:
-        #     print("<%s: %s" % (pcm_name, cfg))
 
     return globals, configs[top_pcm_name][1]
 
-
 def _substitute_inherited(configs, pcm_name, cfg):
-    """Substitutes inherited values in all the configuration settings."""
-    for attr, val in cfg.items():
-        trace_it = attr in _options.trace_variables
-        if trace_it:
-            old_val = val
+    """Substitutes inherited values in all the attributes.
 
+    When a value of an attribute is a list, some of its items may be
+    references to a value of a same attribute in an inherited product,
+    e.g., for a given module PRODUCT_PACKAGES can be
+      ["foo", (submodule), "bar"]
+    and for 'submodule' PRODUCT_PACKAGES may be ["baz"]
+    (we use a tuple to distinguish submodule references).
+    After the substitution the value of PRODUCT_PACKAGES for the module
+    will become ["foo", "baz", "bar"]
+    """
+    for attr, val in cfg.items():
         # TODO(asmundak): should we handle single vars?
         if type(val) != "list":
             continue
 
-        if trace_it:
+        if attr not in _options.trace_variables:
+            cfg[attr] = _value_expand(configs, attr, val)
+        else:
+            old_val = val
             new_val = _value_expand(configs, attr, val)
             if new_val != old_val:
                 print("%s(i): %s=%s (was %s)" % (pcm_name, attr, new_val, old_val))
             cfg[attr] = new_val
-            continue
-
-        cfg[attr] = _value_expand(configs, attr, val)
-
-
 
 def _value_expand(configs, attr, values_list):
     """Expands references to inherited values in a given list."""
     result = []
-    expanded={}
+    expanded = {}
     for item in values_list:
         # Inherited values are 1-tuples
         if type(item) != "tuple":
@@ -227,7 +234,6 @@
 
     return result
 
-
 def _percolate_inherited(configs, cfg_name, cfg, children_names):
     """Percolates the settings that are present only in children."""
     percolated_attrs = {}
@@ -251,19 +257,16 @@
         if attr in percolated_attrs:
             print("%s: %s^=%s" % (cfg_name, attr, cfg[attr]))
 
-
 def __move_items(to_list, from_cfg, attr):
-    l = from_cfg.get(attr, [])
-    if l:
-        to_list.extend(l)
+    value = from_cfg.get(attr, [])
+    if value:
+        to_list.extend(value)
         from_cfg[attr] = []
 
-
 def _indirect(pcm_name):
     """Returns configuration item for the inherited module."""
     return (pcm_name,)
 
-
 def _addprefix(prefix, string_or_list):
     """Adds prefix and returns a list.
 
@@ -276,8 +279,7 @@
         string_or_list
 
     """
-    return [ prefix + x for x in __words(string_or_list)]
-
+    return [prefix + x for x in __words(string_or_list)]
 
 def _addsuffix(suffix, string_or_list):
     """Adds suffix and returns a list.
@@ -290,67 +292,82 @@
       suffix
       string_or_list
     """
-    return [ x + suffix for x in __words(string_or_list)]
-
+    return [x + suffix for x in __words(string_or_list)]
 
 def __words(string_or_list):
     if type(string_or_list) == "list":
         return string_or_list
     return string_or_list.split()
 
-
+# Handle manipulation functions.
+# A handle passed to a PCM consists of:
+#   product attributes dict ("cfg")
+#   inherited modules dict (maps module name to PCM)
+#   default value list (initially empty, modified by inheriting)
 def __h_new():
     """Constructs a handle which is passed to PCM."""
     return (dict(), dict(), list())
 
 def __h_inherited_modules(handle):
+    """Returns PCM's inherited modules dict."""
     return handle[1]
 
-
 def __h_cfg(handle):
+    """Returns PCM's product configuration attributes dict.
+
+    This function is also exported as rblf.cfg, and every PCM
+    calls it at the beginning.
+    """
     return handle[0]
 
-
 def _setdefault(handle, attr):
-    """Sets given attribute's value if it has not been set."""
+    """If attribute has not been set, assigns default value to it.
+
+    This function is exported as rblf.setdefault().
+    Only list attributes are initialized this way. The default
+    value is kept in the PCM's handle. Calling inherit() updates it.
+    """
     cfg = handle[0]
     if cfg.get(attr) == None:
         cfg[attr] = list(handle[2])
     return cfg[attr]
 
 def _inherit(handle, pcm_name, pcm):
-    """Records inheritance."""
+    """Records inheritance.
+
+    This function is exported as rblf.inherit, PCM calls it when
+    a module is inherited.
+    """
     cfg, inherited, default_lv = handle
-    inherited[pcm_name]=pcm
+    inherited[pcm_name] = pcm
     default_lv.append(_indirect(pcm_name))
+
     # Add inherited module reference to all configuration values
     for attr, val in cfg.items():
         if type(val) == "list":
             val.append(_indirect(pcm_name))
 
-
 def _copy_if_exists(path_pair):
     """If from file exists, returns [from:to] pair."""
-    l = path_pair.split(":", 2)
+    value = path_pair.split(":", 2)
+
     # Check that l[0] exists
-    return [":".join(l)] if rblf_file_exists(l[0]) else []
+    return [":".join(value)] if rblf_file_exists(value[0]) else []
 
 def _enforce_product_packages_exist(pkg_string_or_list):
     """Makes including non-existent modules in PRODUCT_PACKAGES an error."""
+
     #TODO(asmundak)
     pass
 
-
 def _file_wildcard_exists(file_pattern):
     """Return True if there are files matching given bash pattern."""
     return len(rblf_wildcard(file_pattern)) > 0
 
-
 def _find_and_copy(pattern, from_dir, to_dir):
     """Return a copy list for the files matching the pattern."""
     return ["%s/%s:%s/%s" % (from_dir, f, to_dir, f) for f in rblf_wildcard(pattern, from_dir)]
 
-
 def _filter_out(pattern, text):
     """Return all the words from `text' that do not match any word in `pattern'.
 
@@ -367,7 +384,6 @@
             res.append(w)
     return res
 
-
 def _filter(pattern, text):
     """Return all the words in `text` that match `pattern`.
 
@@ -383,49 +399,39 @@
             res.append(w)
     return res
 
-
 def __mk2regex(words):
     """Returns regular expression equivalent to Make pattern."""
 
     # TODO(asmundak): this will mishandle '\%'
     return "^(" + "|".join([w.replace("%", ".*", 1) for w in words]) + ")"
 
-
 def _regex_match(regex, w):
     return rblf_regex(regex, w)
 
-
 def _require_artifacts_in_path(paths, allowed_paths):
     """TODO."""
-    #print("require_artifacts_in_path(", __words(paths), ",", __words(allowed_paths), ")")
     pass
 
-
 def _require_artifacts_in_path_relaxed(paths, allowed_paths):
     """TODO."""
     pass
 
-
 def _expand_wildcard(pattern):
     """Expands shell wildcard pattern."""
     return rblf_wildcard(pattern)
 
-
-def _mkerror(file, message=""):
+def _mkerror(file, message = ""):
     """Prints error and stops."""
     fail("%s: %s. Stop" % (file, message))
 
-
-def _mkwarning(file, message=""):
+def _mkwarning(file, message = ""):
     """Prints warning."""
     print("%s: warning: %s" % (file, message))
 
-
-def _mkinfo(file, message=""):
+def _mkinfo(file, message = ""):
     """Prints info."""
     print(message)
 
-
 def __get_options():
     """Returns struct containing runtime global settings."""
     settings = dict(
@@ -455,29 +461,29 @@
 
 # Settings used during debugging.
 _options = __get_options()
-rblf = struct(addprefix=_addprefix,
-              addsuffix=_addsuffix,
-              copy_if_exists=_copy_if_exists,
-              cfg=__h_cfg,
-              enforce_product_packages_exist=_enforce_product_packages_exist,
-              expand_wildcard=_expand_wildcard,
-              file_exists=rblf_file_exists,
-              file_wildcard_exists=_file_wildcard_exists,
-              filter=_filter,
-              filter_out=_filter_out,
-              find_and_copy=_find_and_copy,
-              global_init=_global_init,
-              inherit=_inherit,
-              indirect=_indirect,
-              mkinfo=_mkinfo,
-              mkerror=_mkerror,
-              mkwarning=_mkwarning,
-              printvars=_printvars,
-              product_configuration=_product_configuration,
-              require_artifacts_in_path=_require_artifacts_in_path,
-              require_artifacts_in_path_relaxed=_require_artifacts_in_path_relaxed,
-              setdefault=_setdefault,
-              shell=rblf_shell,
-              warning=_mkwarning,
-              )
-
+rblf = struct(
+    addprefix = _addprefix,
+    addsuffix = _addsuffix,
+    copy_if_exists = _copy_if_exists,
+    cfg = __h_cfg,
+    enforce_product_packages_exist = _enforce_product_packages_exist,
+    expand_wildcard = _expand_wildcard,
+    file_exists = rblf_file_exists,
+    file_wildcard_exists = _file_wildcard_exists,
+    filter = _filter,
+    filter_out = _filter_out,
+    find_and_copy = _find_and_copy,
+    global_init = _global_init,
+    inherit = _inherit,
+    indirect = _indirect,
+    mkinfo = _mkinfo,
+    mkerror = _mkerror,
+    mkwarning = _mkwarning,
+    printvars = _printvars,
+    product_configuration = _product_configuration,
+    require_artifacts_in_path = _require_artifacts_in_path,
+    require_artifacts_in_path_relaxed = _require_artifacts_in_path_relaxed,
+    setdefault = _setdefault,
+    shell = rblf_shell,
+    warning = _mkwarning,
+)
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index c87fb73..4fdfc88 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -385,11 +385,6 @@
     SettingsProvider \
     WallpaperBackup
 
-# Packages included only for eng/userdebug builds, when building with SANITIZE_TARGET=address
-PRODUCT_PACKAGES_DEBUG_ASAN := \
-    fuzz \
-    honggfuzz
-
 PRODUCT_PACKAGES_DEBUG_JAVA_COVERAGE := \
     libdumpcoverage
 
diff --git a/tools/rbcrun/Android.bp b/tools/rbcrun/Android.bp
index b5f7155..90173ac 100644
--- a/tools/rbcrun/Android.bp
+++ b/tools/rbcrun/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "rbcrun",
     srcs: ["cmd/rbcrun.go"],
diff --git a/tools/rbcrun/host.go b/tools/rbcrun/host.go
index f1697f1..1e43334 100644
--- a/tools/rbcrun/host.go
+++ b/tools/rbcrun/host.go
@@ -182,7 +182,7 @@
 	}
 	if shellPath == "" {
 		return starlark.None,
-			fmt.Errorf("cannot run shell, SHELL environment variable is not set (running on Windows?)")
+			fmt.Errorf("cannot run shell, /bin/sh is missing (running on Windows?)")
 	}
 	cmd := exec.Command(shellPath, "-c", command)
 	// We ignore command's status
@@ -234,8 +234,12 @@
 		"rblf_wildcard": starlark.NewBuiltin("rblf_wildcard", wildcard),
 	}
 
-	// NOTE(asmundak): OS-specific.
-	shellPath, _ = os.LookupEnv("SHELL")
+	// NOTE(asmundak): OS-specific. Behave similar to Linux `system` call,
+	// which always uses /bin/sh to run the command
+	shellPath = "/bin/sh"
+	if _, err := os.Stat(shellPath); err != nil {
+		shellPath = ""
+	}
 }
 
 // Parses, resolves, and executes a Starlark file.
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 3b0c070..65c035e 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -133,6 +133,7 @@
     required: [
         "brillo_update_payload",
         "checkvintf",
+        "minigzip",
         "lz4",
         "toybox",
         "unpack_bootimg",
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 414ab97..c550490 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -651,6 +651,9 @@
       raise KeyError(fn)
     return file
 
+class RamdiskFormat(object):
+  LZ4 = 1
+  GZ = 2
 
 def LoadInfoDict(input_file, repacking=False):
   """Loads the key/value pairs from the given input target_files.
@@ -753,13 +756,17 @@
 
   # Load recovery fstab if applicable.
   d["fstab"] = _FindAndLoadRecoveryFstab(d, input_file, read_helper)
+  if d.get('lz4_ramdisks') == 'true':
+    ramdisk_format = RamdiskFormat.LZ4
+  else:
+    ramdisk_format = RamdiskFormat.GZ
 
   # Tries to load the build props for all partitions with care_map, including
   # system and vendor.
   for partition in PARTITIONS_WITH_BUILD_PROP:
     partition_prop = "{}.build.prop".format(partition)
     d[partition_prop] = PartitionBuildProps.FromInputFile(
-        input_file, partition)
+        input_file, partition, ramdisk_format=ramdisk_format)
   d["build.prop"] = d["system.build.prop"]
 
   # Set up the salt (based on fingerprint) that will be used when adding AVB
@@ -818,6 +825,9 @@
     placeholder_values: A dict of runtime variables' values to replace the
         placeholders in the build.prop file. We expect exactly one value for
         each of the variables.
+    ramdisk_format: If name is "boot", the format of ramdisk inside the
+        boot image. Otherwise, its value is ignored.
+        Use lz4 to decompress by default. If its value is gzip, use minigzip.
   """
 
   def __init__(self, input_file, name, placeholder_values=None):
@@ -840,11 +850,11 @@
     return props
 
   @staticmethod
-  def FromInputFile(input_file, name, placeholder_values=None):
+  def FromInputFile(input_file, name, placeholder_values=None, ramdisk_format=RamdiskFormat.LZ4):
     """Loads the build.prop file and builds the attributes."""
 
     if name == "boot":
-      data = PartitionBuildProps._ReadBootPropFile(input_file)
+      data = PartitionBuildProps._ReadBootPropFile(input_file, ramdisk_format=ramdisk_format)
     else:
       data = PartitionBuildProps._ReadPartitionPropFile(input_file, name)
 
@@ -853,7 +863,7 @@
     return props
 
   @staticmethod
-  def _ReadBootPropFile(input_file):
+  def _ReadBootPropFile(input_file, ramdisk_format):
     """
     Read build.prop for boot image from input_file.
     Return empty string if not found.
@@ -863,7 +873,7 @@
     except KeyError:
       logger.warning('Failed to read IMAGES/boot.img')
       return ''
-    prop_file = GetBootImageBuildProp(boot_img)
+    prop_file = GetBootImageBuildProp(boot_img, ramdisk_format=ramdisk_format)
     if prop_file is None:
       return ''
     with open(prop_file, "r") as f:
@@ -3661,12 +3671,12 @@
         append('move %s %s' % (p, u.tgt_group))
 
 
-def GetBootImageBuildProp(boot_img):
+def GetBootImageBuildProp(boot_img, ramdisk_format=RamdiskFormat.LZ4):
   """
   Get build.prop from ramdisk within the boot image
 
   Args:
-    boot_img: the boot image file. Ramdisk must be compressed with lz4 format.
+    boot_img: the boot image file. Ramdisk must be compressed with lz4 or minigzip format.
 
   Return:
     An extracted file that stores properties in the boot image.
@@ -3679,7 +3689,16 @@
       logger.warning('Unable to get boot image timestamp: no ramdisk in boot')
       return None
     uncompressed_ramdisk = os.path.join(tmp_dir, 'uncompressed_ramdisk')
-    RunAndCheckOutput(['lz4', '-d', ramdisk, uncompressed_ramdisk])
+    if ramdisk_format == RamdiskFormat.LZ4:
+      RunAndCheckOutput(['lz4', '-d', ramdisk, uncompressed_ramdisk])
+    elif ramdisk_format == RamdiskFormat.GZ:
+      with open(ramdisk, 'rb') as input_stream:
+        with open(uncompressed_ramdisk, 'wb') as output_stream:
+          p2 = Run(['minigzip', '-d'], stdin=input_stream.fileno(), stdout=output_stream.fileno())
+          p2.wait()
+    else:
+      logger.error('Only support lz4 or minigzip ramdisk format.')
+      return None
 
     abs_uncompressed_ramdisk = os.path.abspath(uncompressed_ramdisk)
     extracted_ramdisk = MakeTempDir('extracted_ramdisk')