diff options
author | 2022-04-28 12:50:47 +0100 | |
---|---|---|
committer | 2022-05-24 16:19:13 +0100 | |
commit | 24abbe85d1f2aae1d7fc9b42c35f9bb28c0a1bb2 (patch) | |
tree | ded3bee6a6445e13fb5cf9e8ea8411b7e336f842 /scripts/manifest_check.py | |
parent | f5d91bb3b4cb907a4fbcd1ea6cf36b9d1a3094ed (diff) |
manifest_check.py: add uses-libraries propagaged via dexpreopt.config.
Some of the uses-libraries in the manifest are propagated from
dependencies (which are not necessarily uses-libraries themselves).
In makefiles this has to be done via dexpreopt.config files to ensure
topological order. This patch makes manifest_check.py add such
propagated entries before doing the check (as it might otherwise fail).
Also, the patch adds deduplication of added library entries.
Bug: 214255490
Test: lunch aosp_cf_x86_64_phone-userdebug && m && launch_cvd \
&& adb wait-for-device && adb root \
&& adb logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch'
# a few unrelated errors caused by missing optional uses-libraries
# android.net.ipsec.ike
# androidx.window.extensions
# androidx.window.sidecar
# that were present before this patch
Change-Id: Ic8528dffd47fa5818b38b912cd6b606855480e33
Diffstat (limited to 'scripts/manifest_check.py')
-rwxr-xr-x | scripts/manifest_check.py | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index c8d4f76c8..0216fc0fe 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -20,9 +20,11 @@ from __future__ import print_function import argparse import json +import os import re import subprocess import sys +from collections import OrderedDict from xml.dom import minidom from manifest import android_ns @@ -43,11 +45,13 @@ def parse_args(): '--uses-library', dest='uses_libraries', action='append', + default=[], help='specify uses-library entries known to the build system') parser.add_argument( '--optional-uses-library', dest='optional_uses_libraries', action='append', + default=[], help='specify uses-library entries known to the build system with ' 'required:false' ) @@ -74,9 +78,14 @@ def parse_args(): help='print the targetSdkVersion from the manifest') parser.add_argument( '--dexpreopt-config', - dest='dexpreopt_configs', + dest='dexpreopt_config', + help='a path to dexpreopt.config file for this library/app') + parser.add_argument( + '--dexpreopt-dep-config', + dest='dexpreopt_dep_configs', action='append', - help='a paths to a dexpreopt.config of some library') + default=[], + help='a path to dexpreopt.config file for a dependency library') parser.add_argument('--aapt', dest='aapt', help='path to aapt executable') parser.add_argument( '--output', '-o', dest='output', help='output AndroidManifest.xml file') @@ -295,25 +304,53 @@ def extract_target_sdk_version_xml(xml): return target_attr.value -def load_dexpreopt_configs(configs): +def remove_duplicates(l): + return list(OrderedDict.fromkeys(l)) + + +def load_dexpreopt_configs(args): """Load dexpreopt.config files and map module names to library names.""" module_to_libname = {} - if configs is None: - configs = [] - - for config in configs: - with open(config, 'r') as f: + # Go over dexpreopt.config files for uses-library dependencies and create + # a mapping from module name to real library name (they may differ). + for config in args.dexpreopt_dep_configs: + # Empty dexpreopt.config files are expected for some dependencies. + if os.stat(config).st_size != 0: + with open(config, 'r') as f: + contents = json.load(f) + module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary'] + + required = translate_libnames(args.uses_libraries, module_to_libname) + optional = translate_libnames(args.optional_uses_libraries, module_to_libname) + + # Add extra uses-libraries from the library/app's own dexpreopt.config. + # Extra libraries may be propagated via dependencies' dexpreopt.config files + # (not only uses-library ones, but also transitively via static libraries). + if args.dexpreopt_config: + with open(args.dexpreopt_config, 'r') as f: contents = json.load(f) - module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary'] + for clc in contents['ClassLoaderContexts']['any']: + ulib = clc['Name'] + if clc['Optional']: + optional.append(ulib) + else: + required.append(ulib) + + required = remove_duplicates(required) + optional = remove_duplicates(optional) + + # If the same library is both in optional and required, prefer required. + # This may happen for compatibility libraries, e.g. org.apache.http.legacy. + for lib in required: + if lib in optional: + optional.remove(lib) - return module_to_libname + return required, optional def translate_libnames(modules, module_to_libname): """Translate module names into library names using the mapping.""" - if modules is None: - modules = [] libnames = [] for name in modules: @@ -346,10 +383,7 @@ def main(): # `optional_uses_libs`, `LOCAL_USES_LIBRARIES`, # `LOCAL_OPTIONAL_LIBRARY_NAMES` all contain module names), while # the manifest addresses libraries by their name. - mod_to_lib = load_dexpreopt_configs(args.dexpreopt_configs) - required = translate_libnames(args.uses_libraries, mod_to_lib) - optional = translate_libnames(args.optional_uses_libraries, - mod_to_lib) + required, optional = load_dexpreopt_configs(args) # Check if the <uses-library> lists in the build system agree with # those in the manifest. Raise an exception on mismatch, unless the |