1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*8975f5c5SAndroid Build Coastguard Worker 3*8975f5c5SAndroid Build Coastguard Worker# Copyright 2017 The Chromium Authors 4*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 6*8975f5c5SAndroid Build Coastguard Worker 7*8975f5c5SAndroid Build Coastguard Worker"""Merges dependency Android manifests into a root manifest.""" 8*8975f5c5SAndroid Build Coastguard Worker 9*8975f5c5SAndroid Build Coastguard Workerimport argparse 10*8975f5c5SAndroid Build Coastguard Workerimport collections 11*8975f5c5SAndroid Build Coastguard Workerimport contextlib 12*8975f5c5SAndroid Build Coastguard Workerimport os 13*8975f5c5SAndroid Build Coastguard Workerimport sys 14*8975f5c5SAndroid Build Coastguard Workerimport tempfile 15*8975f5c5SAndroid Build Coastguard Workerimport xml.etree.ElementTree as ElementTree 16*8975f5c5SAndroid Build Coastguard Worker 17*8975f5c5SAndroid Build Coastguard Workerfrom util import build_utils 18*8975f5c5SAndroid Build Coastguard Workerfrom util import manifest_utils 19*8975f5c5SAndroid Build Coastguard Workerimport action_helpers # build_utils adds //build to sys.path. 20*8975f5c5SAndroid Build Coastguard Worker 21*8975f5c5SAndroid Build Coastguard Worker_MANIFEST_MERGER_MAIN_CLASS = 'com.android.manifmerger.Merger' 22*8975f5c5SAndroid Build Coastguard Worker 23*8975f5c5SAndroid Build Coastguard Worker 24*8975f5c5SAndroid Build Coastguard Worker@contextlib.contextmanager 25*8975f5c5SAndroid Build Coastguard Workerdef _ProcessMainManifest(manifest_path, min_sdk_version, target_sdk_version, 26*8975f5c5SAndroid Build Coastguard Worker max_sdk_version, manifest_package): 27*8975f5c5SAndroid Build Coastguard Worker """Patches the main Android manifest""" 28*8975f5c5SAndroid Build Coastguard Worker doc, manifest, _ = manifest_utils.ParseManifest(manifest_path) 29*8975f5c5SAndroid Build Coastguard Worker manifest_utils.SetUsesSdk(manifest, target_sdk_version, min_sdk_version, 30*8975f5c5SAndroid Build Coastguard Worker max_sdk_version) 31*8975f5c5SAndroid Build Coastguard Worker assert manifest_utils.GetPackage(manifest) or manifest_package, \ 32*8975f5c5SAndroid Build Coastguard Worker 'Must set manifest package in GN or in AndroidManifest.xml' 33*8975f5c5SAndroid Build Coastguard Worker if manifest_package: 34*8975f5c5SAndroid Build Coastguard Worker manifest.set('package', manifest_package) 35*8975f5c5SAndroid Build Coastguard Worker tmp_prefix = manifest_path.replace(os.path.sep, '-') 36*8975f5c5SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest: 37*8975f5c5SAndroid Build Coastguard Worker manifest_utils.SaveManifest(doc, patched_manifest.name) 38*8975f5c5SAndroid Build Coastguard Worker yield patched_manifest.name, manifest_utils.GetPackage(manifest) 39*8975f5c5SAndroid Build Coastguard Worker 40*8975f5c5SAndroid Build Coastguard Worker 41*8975f5c5SAndroid Build Coastguard Worker@contextlib.contextmanager 42*8975f5c5SAndroid Build Coastguard Workerdef _ProcessOtherManifest(manifest_path, min_sdk_version, target_sdk_version, 43*8975f5c5SAndroid Build Coastguard Worker seen_package_names): 44*8975f5c5SAndroid Build Coastguard Worker """Patches non-main AndroidManifest.xml if necessary.""" 45*8975f5c5SAndroid Build Coastguard Worker # 1. Ensure targetSdkVersion is set to the expected value to avoid 46*8975f5c5SAndroid Build Coastguard Worker # spurious permissions being added (b/222331337). 47*8975f5c5SAndroid Build Coastguard Worker # 2. Ensure all manifests have a unique package name so that the merger 48*8975f5c5SAndroid Build Coastguard Worker # does not fail when this happens. 49*8975f5c5SAndroid Build Coastguard Worker doc, manifest, _ = manifest_utils.ParseManifest(manifest_path) 50*8975f5c5SAndroid Build Coastguard Worker 51*8975f5c5SAndroid Build Coastguard Worker changed_api = manifest_utils.SetTargetApiIfUnset(manifest, target_sdk_version) 52*8975f5c5SAndroid Build Coastguard Worker 53*8975f5c5SAndroid Build Coastguard Worker package_name = manifest_utils.GetPackage(manifest) 54*8975f5c5SAndroid Build Coastguard Worker # Ignore minSdkVersion from androidx.pdf library. The client code will ensure 55*8975f5c5SAndroid Build Coastguard Worker # not to call into the library API on older Android versions. 56*8975f5c5SAndroid Build Coastguard Worker if package_name.startswith('androidx.pdf'): 57*8975f5c5SAndroid Build Coastguard Worker manifest_utils.OverrideMinSdkVersionIfPresent(manifest, min_sdk_version) 58*8975f5c5SAndroid Build Coastguard Worker changed_api = True 59*8975f5c5SAndroid Build Coastguard Worker package_count = seen_package_names[package_name] 60*8975f5c5SAndroid Build Coastguard Worker seen_package_names[package_name] += 1 61*8975f5c5SAndroid Build Coastguard Worker if package_count > 0: 62*8975f5c5SAndroid Build Coastguard Worker manifest.set('package', f'{package_name}_{package_count}') 63*8975f5c5SAndroid Build Coastguard Worker 64*8975f5c5SAndroid Build Coastguard Worker if package_count > 0 or changed_api: 65*8975f5c5SAndroid Build Coastguard Worker tmp_prefix = manifest_path.replace(os.path.sep, '-') 66*8975f5c5SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest: 67*8975f5c5SAndroid Build Coastguard Worker manifest_utils.SaveManifest(doc, patched_manifest.name) 68*8975f5c5SAndroid Build Coastguard Worker yield patched_manifest.name 69*8975f5c5SAndroid Build Coastguard Worker else: 70*8975f5c5SAndroid Build Coastguard Worker yield manifest_path 71*8975f5c5SAndroid Build Coastguard Worker 72*8975f5c5SAndroid Build Coastguard Worker 73*8975f5c5SAndroid Build Coastguard Workerdef main(argv): 74*8975f5c5SAndroid Build Coastguard Worker argv = build_utils.ExpandFileArgs(argv) 75*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=__doc__) 76*8975f5c5SAndroid Build Coastguard Worker action_helpers.add_depfile_arg(parser) 77*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--manifest-merger-jar', 78*8975f5c5SAndroid Build Coastguard Worker help='Path to SDK\'s manifest merger jar.', 79*8975f5c5SAndroid Build Coastguard Worker required=True) 80*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--root-manifest', 81*8975f5c5SAndroid Build Coastguard Worker help='Root manifest which to merge into', 82*8975f5c5SAndroid Build Coastguard Worker required=True) 83*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--output', help='Output manifest path', required=True) 84*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--extras', 85*8975f5c5SAndroid Build Coastguard Worker help='GN list of additional manifest to merge') 86*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 87*8975f5c5SAndroid Build Coastguard Worker '--min-sdk-version', 88*8975f5c5SAndroid Build Coastguard Worker required=True, 89*8975f5c5SAndroid Build Coastguard Worker help='android:minSdkVersion for merging.') 90*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 91*8975f5c5SAndroid Build Coastguard Worker '--target-sdk-version', 92*8975f5c5SAndroid Build Coastguard Worker required=True, 93*8975f5c5SAndroid Build Coastguard Worker help='android:targetSdkVersion for merging.') 94*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 95*8975f5c5SAndroid Build Coastguard Worker '--max-sdk-version', help='android:maxSdkVersion for merging.') 96*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 97*8975f5c5SAndroid Build Coastguard Worker '--manifest-package', 98*8975f5c5SAndroid Build Coastguard Worker help='Package name of the merged AndroidManifest.xml.') 99*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--warnings-as-errors', 100*8975f5c5SAndroid Build Coastguard Worker action='store_true', 101*8975f5c5SAndroid Build Coastguard Worker help='Treat all warnings as errors.') 102*8975f5c5SAndroid Build Coastguard Worker args = parser.parse_args(argv) 103*8975f5c5SAndroid Build Coastguard Worker 104*8975f5c5SAndroid Build Coastguard Worker with action_helpers.atomic_output(args.output) as output: 105*8975f5c5SAndroid Build Coastguard Worker cmd = build_utils.JavaCmd() + [ 106*8975f5c5SAndroid Build Coastguard Worker '-cp', 107*8975f5c5SAndroid Build Coastguard Worker args.manifest_merger_jar, 108*8975f5c5SAndroid Build Coastguard Worker _MANIFEST_MERGER_MAIN_CLASS, 109*8975f5c5SAndroid Build Coastguard Worker '--out', 110*8975f5c5SAndroid Build Coastguard Worker output.name, 111*8975f5c5SAndroid Build Coastguard Worker '--property', 112*8975f5c5SAndroid Build Coastguard Worker 'MIN_SDK_VERSION=' + args.min_sdk_version, 113*8975f5c5SAndroid Build Coastguard Worker '--property', 114*8975f5c5SAndroid Build Coastguard Worker 'TARGET_SDK_VERSION=' + args.target_sdk_version, 115*8975f5c5SAndroid Build Coastguard Worker ] 116*8975f5c5SAndroid Build Coastguard Worker 117*8975f5c5SAndroid Build Coastguard Worker if args.max_sdk_version: 118*8975f5c5SAndroid Build Coastguard Worker cmd += [ 119*8975f5c5SAndroid Build Coastguard Worker '--property', 120*8975f5c5SAndroid Build Coastguard Worker 'MAX_SDK_VERSION=' + args.max_sdk_version, 121*8975f5c5SAndroid Build Coastguard Worker ] 122*8975f5c5SAndroid Build Coastguard Worker 123*8975f5c5SAndroid Build Coastguard Worker extras = action_helpers.parse_gn_list(args.extras) 124*8975f5c5SAndroid Build Coastguard Worker 125*8975f5c5SAndroid Build Coastguard Worker with contextlib.ExitStack() as stack: 126*8975f5c5SAndroid Build Coastguard Worker root_manifest, package = stack.enter_context( 127*8975f5c5SAndroid Build Coastguard Worker _ProcessMainManifest(args.root_manifest, args.min_sdk_version, 128*8975f5c5SAndroid Build Coastguard Worker args.target_sdk_version, args.max_sdk_version, 129*8975f5c5SAndroid Build Coastguard Worker args.manifest_package)) 130*8975f5c5SAndroid Build Coastguard Worker if extras: 131*8975f5c5SAndroid Build Coastguard Worker seen_package_names = collections.Counter() 132*8975f5c5SAndroid Build Coastguard Worker extras_processed = [ 133*8975f5c5SAndroid Build Coastguard Worker stack.enter_context( 134*8975f5c5SAndroid Build Coastguard Worker _ProcessOtherManifest(e, args.min_sdk_version, 135*8975f5c5SAndroid Build Coastguard Worker args.target_sdk_version, 136*8975f5c5SAndroid Build Coastguard Worker seen_package_names)) for e in extras 137*8975f5c5SAndroid Build Coastguard Worker ] 138*8975f5c5SAndroid Build Coastguard Worker cmd += ['--libs', ':'.join(extras_processed)] 139*8975f5c5SAndroid Build Coastguard Worker cmd += [ 140*8975f5c5SAndroid Build Coastguard Worker '--main', 141*8975f5c5SAndroid Build Coastguard Worker root_manifest, 142*8975f5c5SAndroid Build Coastguard Worker '--property', 143*8975f5c5SAndroid Build Coastguard Worker 'PACKAGE=' + package, 144*8975f5c5SAndroid Build Coastguard Worker '--remove-tools-declarations', 145*8975f5c5SAndroid Build Coastguard Worker ] 146*8975f5c5SAndroid Build Coastguard Worker build_utils.CheckOutput( 147*8975f5c5SAndroid Build Coastguard Worker cmd, 148*8975f5c5SAndroid Build Coastguard Worker # https://issuetracker.google.com/issues/63514300: 149*8975f5c5SAndroid Build Coastguard Worker # The merger doesn't set a nonzero exit code for failures. 150*8975f5c5SAndroid Build Coastguard Worker fail_func=lambda returncode, stderr: returncode != 0 or build_utils. 151*8975f5c5SAndroid Build Coastguard Worker IsTimeStale(output.name, [root_manifest] + extras), 152*8975f5c5SAndroid Build Coastguard Worker fail_on_output=args.warnings_as_errors) 153*8975f5c5SAndroid Build Coastguard Worker 154*8975f5c5SAndroid Build Coastguard Worker if args.depfile: 155*8975f5c5SAndroid Build Coastguard Worker action_helpers.write_depfile(args.depfile, args.output, inputs=extras) 156*8975f5c5SAndroid Build Coastguard Worker 157*8975f5c5SAndroid Build Coastguard Worker 158*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 159*8975f5c5SAndroid Build Coastguard Worker main(sys.argv[1:]) 160