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