From 8edad8f7a32197331b5aaddd2ceacad287943b3f Mon Sep 17 00:00:00 2001 From: Ulya Trafimovich Date: Thu, 11 Feb 2021 16:58:25 +0000 Subject: [PATCH] Preserve order in dexpreopt.config files. Library order is important because it is used to construct class loader context, which is then written into OAT/ODEX files and chacked against class loader context constructed by PackageManager on the device. If the orders are different, dexpreopted code is rejected. This CL fixes a few problems that caused reordering: - 'filter' function arguments are swapped so that patterns list comes first, and the library list second - JSON representation of class loader context is changed to avoid unmarshaling it to Go maps, which may reorder keys - library list is no longer sorted (it's unclear why it was sorted) Bug: 132357300 Test: lunch cf_x86_64_phone-userdebug && m && launch_cvd \ adb wait-for-device && adb root && adb logcat \ | grep -E 'ClassLoaderContext [a-z ]+ mismatch' # empty grep output, no errors Change-Id: Ie76996d497e60da0948f1879d6db589ff3e968a2 --- common/json.mk | 3 +++ core/dex_preopt_config_merger.py | 13 +++++++------ core/dex_preopt_odex_install.mk | 18 +++++++++--------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/common/json.mk b/common/json.mk index ba8ffa73ec..e376aab487 100644 --- a/common/json.mk +++ b/common/json.mk @@ -24,7 +24,10 @@ add_json_list =$= $(call add_json_val,$(1),$(call json_list,$(patsubst %,%,$(2)) add_json_csv =$= $(call add_json_val,$(1),$(call csv_to_json_list,$(strip $(2)))) add_json_bool =$= $(call add_json_val,$(1),$(if $(strip $(2)),true,false)) add_json_map =$= $(eval _json_contents := $$(_json_contents)$$(_json_indent)"$$(strip $$(1))": {$$(newline))$(json_increase_indent) +add_json_map_anon =$= $(eval _json_contents := $$(_json_contents)$$(_json_indent){$$(newline))$(json_increase_indent) end_json_map =$= $(json_decrease_indent)$(eval _json_contents := $$(_json_contents)$$(if $$(filter %$$(comma),$$(lastword $$(_json_contents))),__SV_END)$$(_json_indent)},$$(newline)) +add_json_array =$= $(eval _json_contents := $$(_json_contents)$$(_json_indent)"$$(strip $$(1))": [$$(newline))$(json_increase_indent) +end_json_array =$= $(json_decrease_indent)$(eval _json_contents := $$(_json_contents)$$(if $$(filter %$$(comma),$$(lastword $$(_json_contents))),__SV_END)$$(_json_indent)],$$(newline)) # Clears _json_contents to start a new json file json_start =$= $(eval _json_contents := {$$(newline))$(eval _json_indent := $$(4space)) diff --git a/core/dex_preopt_config_merger.py b/core/dex_preopt_config_merger.py index 1bd151982a..4efcc1745e 100755 --- a/core/dex_preopt_config_merger.py +++ b/core/dex_preopt_config_merger.py @@ -67,24 +67,25 @@ def main(): # the loop in case this changes in the future. for sdk_ver in clc_map: clcs = clc_map[sdk_ver] - clcs2 = OrderedDict() - for lib in clcs: - clc = clcs[lib] + clcs2 = [] + for clc in clcs: + lib = clc['Name'] if lib in uses_libs: ulib = uses_libs[lib] + # The real name (may be different from the module name). + clc['Name'] = ulib['ProvidesUsesLibrary'] # On-device (install) path to the dependency DEX jar file. clc['Device'] = ulib['DexLocation'] # CLC of the dependency becomes a subcontext. We only need sub-CLC for # 'any' version because all other versions are for compatibility # libraries, which exist only for apps and not for libraries. clc['Subcontexts'] = ulib['ClassLoaderContexts'].get('any') - # Patch the library name in the CLC as well. - clcs2[ulib['ProvidesUsesLibrary']] = clc else: # dexpreopt.config for this is not among the script # arguments, which may be the case with compatibility libraries that # don't need patching anyway. Just use the original CLC. - clcs2[lib] = clc + pass + clcs2.append(clc) clc_map2[sdk_ver] = clcs2 # Overwrite the original class loader context with the patched one. diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk index 6f6ac28032..f9a9ba7ca4 100644 --- a/core/dex_preopt_odex_install.mk +++ b/core/dex_preopt_odex_install.mk @@ -196,8 +196,8 @@ ifdef LOCAL_DEX_PREOPT # to load dexpreopt code on device. We should fix this, either by deferring # dependency computation until the full list of product packages is known, or # by adding product-specific lists of missing libraries. - my_filtered_optional_uses_libraries := $(filter $(my_filtered_optional_uses_libraries), \ - $(PRODUCT_PACKAGES)) + my_filtered_optional_uses_libraries := $(filter $(PRODUCT_PACKAGES), \ + $(my_filtered_optional_uses_libraries)) ifeq ($(LOCAL_MODULE_CLASS),APPS) # compatibility libraries are added to class loader context of an app only if @@ -222,10 +222,9 @@ ifdef LOCAL_DEX_PREOPT my_dexpreopt_libs_compat := endif - my_dexpreopt_libs := $(sort \ + my_dexpreopt_libs := \ $(LOCAL_USES_LIBRARIES) \ - $(my_filtered_optional_uses_libraries) \ - ) + $(my_filtered_optional_uses_libraries) # 1: SDK version # 2: list of libraries @@ -243,14 +242,15 @@ ifdef LOCAL_DEX_PREOPT # which are special and not handled by dex_preopt_config_merger.py. # add_json_class_loader_context = \ - $(call add_json_map, $(1)) \ + $(call add_json_array, $(1)) \ $(foreach lib, $(2),\ - $(call add_json_map, $(lib)) \ + $(call add_json_map_anon) \ + $(call add_json_str, Name, $(lib)) \ $(call add_json_str, Host, $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar) \ $(call add_json_str, Device, /system/framework/$(lib).jar) \ - $(call add_json_map, Subcontexts, ${$}) $(call end_json_map) \ + $(call add_json_val, Subcontexts, null) \ $(call end_json_map)) \ - $(call end_json_map) + $(call end_json_array) # Record dex-preopt config. DEXPREOPT.$(LOCAL_MODULE).DEX_PREOPT := $(LOCAL_DEX_PREOPT)