Merge "manifest_check.py: add uses-libraries propagaged via dexpreopt.config." am: e0862867d9

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2079358

Change-Id: I10e86a35a2d8f05122ef700bba633efeec12c480
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Ulya Trofimovich 2022-06-06 13:11:26 +00:00 committed by Automerger Merge Worker
commit f95728429f

View file

@ -20,9 +20,11 @@ from __future__ import print_function
import argparse import argparse
import json import json
import os
import re import re
import subprocess import subprocess
import sys import sys
from collections import OrderedDict
from xml.dom import minidom from xml.dom import minidom
from manifest import android_ns from manifest import android_ns
@ -43,11 +45,13 @@ def parse_args():
'--uses-library', '--uses-library',
dest='uses_libraries', dest='uses_libraries',
action='append', action='append',
default=[],
help='specify uses-library entries known to the build system') help='specify uses-library entries known to the build system')
parser.add_argument( parser.add_argument(
'--optional-uses-library', '--optional-uses-library',
dest='optional_uses_libraries', dest='optional_uses_libraries',
action='append', action='append',
default=[],
help='specify uses-library entries known to the build system with ' help='specify uses-library entries known to the build system with '
'required:false' 'required:false'
) )
@ -74,9 +78,14 @@ def parse_args():
help='print the targetSdkVersion from the manifest') help='print the targetSdkVersion from the manifest')
parser.add_argument( parser.add_argument(
'--dexpreopt-config', '--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', 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('--aapt', dest='aapt', help='path to aapt executable')
parser.add_argument( parser.add_argument(
'--output', '-o', dest='output', help='output AndroidManifest.xml file') '--output', '-o', dest='output', help='output AndroidManifest.xml file')
@ -295,25 +304,53 @@ def extract_target_sdk_version_xml(xml):
return target_attr.value 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.""" """Load dexpreopt.config files and map module names to library names."""
module_to_libname = {} module_to_libname = {}
if configs is None: # Go over dexpreopt.config files for uses-library dependencies and create
configs = [] # a mapping from module name to real library name (they may differ).
for config in args.dexpreopt_dep_configs:
for config in configs: # Empty dexpreopt.config files are expected for some dependencies.
if os.stat(config).st_size != 0:
with open(config, 'r') as f: with open(config, 'r') as f:
contents = json.load(f) contents = json.load(f)
module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary'] module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary']
return module_to_libname 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)
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 required, optional
def translate_libnames(modules, module_to_libname): def translate_libnames(modules, module_to_libname):
"""Translate module names into library names using the mapping.""" """Translate module names into library names using the mapping."""
if modules is None:
modules = []
libnames = [] libnames = []
for name in modules: for name in modules:
@ -346,10 +383,7 @@ def main():
# `optional_uses_libs`, `LOCAL_USES_LIBRARIES`, # `optional_uses_libs`, `LOCAL_USES_LIBRARIES`,
# `LOCAL_OPTIONAL_LIBRARY_NAMES` all contain module names), while # `LOCAL_OPTIONAL_LIBRARY_NAMES` all contain module names), while
# the manifest addresses libraries by their name. # the manifest addresses libraries by their name.
mod_to_lib = load_dexpreopt_configs(args.dexpreopt_configs) required, optional = load_dexpreopt_configs(args)
required = translate_libnames(args.uses_libraries, mod_to_lib)
optional = translate_libnames(args.optional_uses_libraries,
mod_to_lib)
# Check if the <uses-library> lists in the build system agree with # Check if the <uses-library> lists in the build system agree with
# those in the manifest. Raise an exception on mismatch, unless the # those in the manifest. Raise an exception on mismatch, unless the