Merge <uses-library> dependency configs into dexpreopt.config files.
Since Make does not visit modules in topological order of their <uses-library> dependencies, information from dependencies to the dexpreopted module has to be passed via dexpreopt.config files. A build rule for a dexpreopt.config file depends on dexpreopt.config files for <uses-library> dependencies, and dex_preopt_config_merger.py script extracts the necessary information from dependency configs and patches the module's config. Bug: 132357300 Test: lunch aosp_cf_x86_phone-userdebug && m Change-Id: Id0b71170a4d2ab1d33059de0e9ad9d7e61f2345e
This commit is contained in:
100
core/dex_preopt_config_merger.py
Executable file
100
core/dex_preopt_config_merger.py
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2021 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
"""
|
||||
A tool for merging dexpreopt.config files for <uses-library> dependencies into
|
||||
the dexpreopt.config file of the library/app that uses them. This is needed to
|
||||
generate class loader context (CLC) for dexpreopt.
|
||||
|
||||
In Make there is no topological order when processing different modules, so a
|
||||
<uses-library> dependency module may have not been processed yet by the time the
|
||||
dependent module is processed. Therefore makefiles communicate the information
|
||||
from dependencies via dexpreopt.config files and add file-level dependencies
|
||||
from a module dexpreopt.config to its dependency configs. The actual patching
|
||||
of configs is done by this script, which is called from the makefiles.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Program entry point."""
|
||||
if len(sys.argv) < 2:
|
||||
raise SystemExit('usage: %s <main-config> [dep-config ...]' % sys.argv[0])
|
||||
|
||||
# Read all JSON configs.
|
||||
cfgs = []
|
||||
for arg in sys.argv[1:]:
|
||||
with open(arg, 'r') as f:
|
||||
cfgs.append(json.load(f, object_pairs_hook=OrderedDict))
|
||||
|
||||
# The first config is the dexpreopted library/app, the rest are its
|
||||
# <uses-library> dependencies.
|
||||
cfg0 = cfgs[0]
|
||||
|
||||
# Put dependency configs in a map keyed on module name (for easier lookup).
|
||||
uses_libs = {}
|
||||
for cfg in cfgs[1:]:
|
||||
uses_libs[cfg['Name']] = cfg
|
||||
|
||||
# Load the original CLC map.
|
||||
clc_map = cfg0['ClassLoaderContexts']
|
||||
|
||||
# Create a new CLC map that will be a copy of the original one with patched
|
||||
# fields from dependency dexpreopt.config files.
|
||||
clc_map2 = OrderedDict()
|
||||
|
||||
# Patch CLC for each SDK version. Although this should not be necessary for
|
||||
# compatibility libraries (so-called "conditional CLC"), because they all have
|
||||
# known names, known paths in system/framework, and no subcontext. But keep
|
||||
# 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]
|
||||
if lib in uses_libs:
|
||||
ulib = uses_libs[lib]
|
||||
# On-host (build) path to the dependency DEX jar file.
|
||||
clc['Host'] = ulib['BuildPath']
|
||||
# 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 <uses-library> 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
|
||||
clc_map2[sdk_ver] = clcs2
|
||||
|
||||
# Overwrite the original class loader context with the patched one.
|
||||
cfg0['ClassLoaderContexts'] = clc_map2
|
||||
|
||||
# Update dexpreopt.config file.
|
||||
with open(sys.argv[1], 'w') as f:
|
||||
f.write(json.dumps(cfgs[0], indent=4, separators=(',', ': ')))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user