1*333d2b36SAndroid Build Coastguard Worker#!/usr/bin/env python 2*333d2b36SAndroid Build Coastguard Worker# 3*333d2b36SAndroid Build Coastguard Worker# Copyright (C) 2018 The Android Open Source Project 4*333d2b36SAndroid Build Coastguard Worker# 5*333d2b36SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*333d2b36SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*333d2b36SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*333d2b36SAndroid Build Coastguard Worker# 9*333d2b36SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*333d2b36SAndroid Build Coastguard Worker# 11*333d2b36SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*333d2b36SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*333d2b36SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*333d2b36SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*333d2b36SAndroid Build Coastguard Worker# limitations under the License. 16*333d2b36SAndroid Build Coastguard Worker# 17*333d2b36SAndroid Build Coastguard Worker"""A tool for checking that a manifest agrees with the build system.""" 18*333d2b36SAndroid Build Coastguard Worker 19*333d2b36SAndroid Build Coastguard Workerimport argparse 20*333d2b36SAndroid Build Coastguard Workerimport json 21*333d2b36SAndroid Build Coastguard Workerimport re 22*333d2b36SAndroid Build Coastguard Workerimport subprocess 23*333d2b36SAndroid Build Coastguard Workerimport sys 24*333d2b36SAndroid Build Coastguard Workerfrom xml.dom import minidom 25*333d2b36SAndroid Build Coastguard Worker 26*333d2b36SAndroid Build Coastguard Workerfrom manifest import * 27*333d2b36SAndroid Build Coastguard Worker 28*333d2b36SAndroid Build Coastguard Worker 29*333d2b36SAndroid Build Coastguard Workerclass ManifestMismatchError(Exception): 30*333d2b36SAndroid Build Coastguard Worker pass 31*333d2b36SAndroid Build Coastguard Worker 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Workerdef parse_args(): 34*333d2b36SAndroid Build Coastguard Worker """Parse commandline arguments.""" 35*333d2b36SAndroid Build Coastguard Worker 36*333d2b36SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 37*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 38*333d2b36SAndroid Build Coastguard Worker '--uses-library', 39*333d2b36SAndroid Build Coastguard Worker dest='uses_libraries', 40*333d2b36SAndroid Build Coastguard Worker action='append', 41*333d2b36SAndroid Build Coastguard Worker help='specify uses-library entries known to the build system') 42*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 43*333d2b36SAndroid Build Coastguard Worker '--optional-uses-library', 44*333d2b36SAndroid Build Coastguard Worker dest='optional_uses_libraries', 45*333d2b36SAndroid Build Coastguard Worker action='append', 46*333d2b36SAndroid Build Coastguard Worker help='specify uses-library entries known to the build system with ' 47*333d2b36SAndroid Build Coastguard Worker 'required:false' 48*333d2b36SAndroid Build Coastguard Worker ) 49*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 50*333d2b36SAndroid Build Coastguard Worker '--missing-optional-uses-library', 51*333d2b36SAndroid Build Coastguard Worker dest='missing_optional_uses_libraries', 52*333d2b36SAndroid Build Coastguard Worker action='append', 53*333d2b36SAndroid Build Coastguard Worker help='specify uses-library entries missing from the build system with ' 54*333d2b36SAndroid Build Coastguard Worker 'required:false', 55*333d2b36SAndroid Build Coastguard Worker default=[] 56*333d2b36SAndroid Build Coastguard Worker ) 57*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 58*333d2b36SAndroid Build Coastguard Worker '--enforce-uses-libraries', 59*333d2b36SAndroid Build Coastguard Worker dest='enforce_uses_libraries', 60*333d2b36SAndroid Build Coastguard Worker action='store_true', 61*333d2b36SAndroid Build Coastguard Worker help='check the uses-library entries known to the build system against ' 62*333d2b36SAndroid Build Coastguard Worker 'the manifest' 63*333d2b36SAndroid Build Coastguard Worker ) 64*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 65*333d2b36SAndroid Build Coastguard Worker '--enforce-uses-libraries-relax', 66*333d2b36SAndroid Build Coastguard Worker dest='enforce_uses_libraries_relax', 67*333d2b36SAndroid Build Coastguard Worker action='store_true', 68*333d2b36SAndroid Build Coastguard Worker help='do not fail immediately, just save the error message to file') 69*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 70*333d2b36SAndroid Build Coastguard Worker '--enforce-uses-libraries-status', 71*333d2b36SAndroid Build Coastguard Worker dest='enforce_uses_libraries_status', 72*333d2b36SAndroid Build Coastguard Worker help='output file to store check status (error message)') 73*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 74*333d2b36SAndroid Build Coastguard Worker '--extract-target-sdk-version', 75*333d2b36SAndroid Build Coastguard Worker dest='extract_target_sdk_version', 76*333d2b36SAndroid Build Coastguard Worker action='store_true', 77*333d2b36SAndroid Build Coastguard Worker help='print the targetSdkVersion from the manifest') 78*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 79*333d2b36SAndroid Build Coastguard Worker '--dexpreopt-config', 80*333d2b36SAndroid Build Coastguard Worker dest='dexpreopt_configs', 81*333d2b36SAndroid Build Coastguard Worker action='append', 82*333d2b36SAndroid Build Coastguard Worker help='a paths to a dexpreopt.config of some library') 83*333d2b36SAndroid Build Coastguard Worker parser.add_argument('--aapt', dest='aapt', help='path to aapt executable') 84*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 85*333d2b36SAndroid Build Coastguard Worker '--output', '-o', dest='output', help='output AndroidManifest.xml file') 86*333d2b36SAndroid Build Coastguard Worker parser.add_argument('input', help='input AndroidManifest.xml file') 87*333d2b36SAndroid Build Coastguard Worker return parser.parse_args() 88*333d2b36SAndroid Build Coastguard Worker 89*333d2b36SAndroid Build Coastguard Worker 90*333d2b36SAndroid Build Coastguard WorkerC_RED = "\033[1;31m" 91*333d2b36SAndroid Build Coastguard WorkerC_GREEN = "\033[1;32m" 92*333d2b36SAndroid Build Coastguard WorkerC_BLUE = "\033[1;34m" 93*333d2b36SAndroid Build Coastguard WorkerC_OFF = "\033[0m" 94*333d2b36SAndroid Build Coastguard WorkerC_BOLD = "\033[1m" 95*333d2b36SAndroid Build Coastguard Worker 96*333d2b36SAndroid Build Coastguard Worker 97*333d2b36SAndroid Build Coastguard Workerdef enforce_uses_libraries(manifest, required, optional, missing_optional, relax, is_apk, path): 98*333d2b36SAndroid Build Coastguard Worker """Verify that the <uses-library> tags in the manifest match those provided 99*333d2b36SAndroid Build Coastguard Worker 100*333d2b36SAndroid Build Coastguard Worker by the build system. 101*333d2b36SAndroid Build Coastguard Worker 102*333d2b36SAndroid Build Coastguard Worker Args: 103*333d2b36SAndroid Build Coastguard Worker manifest: manifest (either parsed XML or aapt dump of APK) 104*333d2b36SAndroid Build Coastguard Worker required: required libs known to the build system 105*333d2b36SAndroid Build Coastguard Worker optional: optional libs known to the build system 106*333d2b36SAndroid Build Coastguard Worker relax: if true, suppress error on mismatch and just write it to file 107*333d2b36SAndroid Build Coastguard Worker is_apk: if the manifest comes from an APK or an XML file 108*333d2b36SAndroid Build Coastguard Worker """ 109*333d2b36SAndroid Build Coastguard Worker if is_apk: 110*333d2b36SAndroid Build Coastguard Worker manifest_required, manifest_optional, tags = extract_uses_libs_apk( 111*333d2b36SAndroid Build Coastguard Worker manifest) 112*333d2b36SAndroid Build Coastguard Worker else: 113*333d2b36SAndroid Build Coastguard Worker manifest_required, manifest_optional, tags = extract_uses_libs_xml( 114*333d2b36SAndroid Build Coastguard Worker manifest) 115*333d2b36SAndroid Build Coastguard Worker 116*333d2b36SAndroid Build Coastguard Worker # Trim namespace component. Normally Soong does that automatically when it 117*333d2b36SAndroid Build Coastguard Worker # handles module names specified in Android.bp properties. However not all 118*333d2b36SAndroid Build Coastguard Worker # <uses-library> entries in the manifest correspond to real modules: some of 119*333d2b36SAndroid Build Coastguard Worker # the optional libraries may be missing at build time. Therefor this script 120*333d2b36SAndroid Build Coastguard Worker # accepts raw module names as spelled in Android.bp/Android.mk and trims the 121*333d2b36SAndroid Build Coastguard Worker # optional namespace part manually. 122*333d2b36SAndroid Build Coastguard Worker required = trim_namespace_parts(required) 123*333d2b36SAndroid Build Coastguard Worker optional = trim_namespace_parts(optional) 124*333d2b36SAndroid Build Coastguard Worker 125*333d2b36SAndroid Build Coastguard Worker existing_manifest_optional = [ 126*333d2b36SAndroid Build Coastguard Worker lib for lib in manifest_optional if lib not in missing_optional] 127*333d2b36SAndroid Build Coastguard Worker 128*333d2b36SAndroid Build Coastguard Worker # The order of the existing libraries matter, while the order of the missing 129*333d2b36SAndroid Build Coastguard Worker # ones doesn't. 130*333d2b36SAndroid Build Coastguard Worker if manifest_required == required and existing_manifest_optional == optional: 131*333d2b36SAndroid Build Coastguard Worker return None 132*333d2b36SAndroid Build Coastguard Worker 133*333d2b36SAndroid Build Coastguard Worker #pylint: disable=line-too-long 134*333d2b36SAndroid Build Coastguard Worker errmsg = ''.join([ 135*333d2b36SAndroid Build Coastguard Worker 'mismatch in the <uses-library> tags between the build system and the ' 136*333d2b36SAndroid Build Coastguard Worker 'manifest:\n', 137*333d2b36SAndroid Build Coastguard Worker '\t- required libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(required), C_OFF), 138*333d2b36SAndroid Build Coastguard Worker '\t vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_required), C_OFF), 139*333d2b36SAndroid Build Coastguard Worker '\t- optional libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(optional), C_OFF), 140*333d2b36SAndroid Build Coastguard Worker '\t and missing ones in build system: %s[%s]%s\n' % (C_RED, ', '.join(missing_optional), C_OFF), 141*333d2b36SAndroid Build Coastguard Worker '\t vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_optional), C_OFF), 142*333d2b36SAndroid Build Coastguard Worker '\t- tags in the manifest (%s):\n' % path, 143*333d2b36SAndroid Build Coastguard Worker '\t\t%s\n' % '\t\t'.join(tags), 144*333d2b36SAndroid Build Coastguard Worker '%snote:%s the following options are available:\n' % (C_BLUE, C_OFF), 145*333d2b36SAndroid Build Coastguard Worker '\t- to temporarily disable the check on command line, rebuild with ', 146*333d2b36SAndroid Build Coastguard Worker '%sRELAX_USES_LIBRARY_CHECK=true%s' % (C_BOLD, C_OFF), 147*333d2b36SAndroid Build Coastguard Worker ' (this will set compiler filter "verify" and disable AOT-compilation in dexpreopt)\n', 148*333d2b36SAndroid Build Coastguard Worker '\t- to temporarily disable the check for the whole product, set ', 149*333d2b36SAndroid Build Coastguard Worker '%sPRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true%s in the product makefiles\n' % (C_BOLD, C_OFF), 150*333d2b36SAndroid Build Coastguard Worker '\t- to fix the check, make build system properties coherent with the manifest\n', 151*333d2b36SAndroid Build Coastguard Worker '\t- for details, see %sbuild/make/Changes.md%s' % (C_GREEN, C_OFF), 152*333d2b36SAndroid Build Coastguard Worker ' and %shttps://source.android.com/devices/tech/dalvik/art-class-loader-context%s\n' % (C_GREEN, C_OFF) 153*333d2b36SAndroid Build Coastguard Worker ]) 154*333d2b36SAndroid Build Coastguard Worker #pylint: enable=line-too-long 155*333d2b36SAndroid Build Coastguard Worker 156*333d2b36SAndroid Build Coastguard Worker if not relax: 157*333d2b36SAndroid Build Coastguard Worker raise ManifestMismatchError(errmsg) 158*333d2b36SAndroid Build Coastguard Worker 159*333d2b36SAndroid Build Coastguard Worker return errmsg 160*333d2b36SAndroid Build Coastguard Worker 161*333d2b36SAndroid Build Coastguard Worker 162*333d2b36SAndroid Build Coastguard WorkerMODULE_NAMESPACE = re.compile('^//[^:]+:') 163*333d2b36SAndroid Build Coastguard Worker 164*333d2b36SAndroid Build Coastguard Worker 165*333d2b36SAndroid Build Coastguard Workerdef trim_namespace_parts(modules): 166*333d2b36SAndroid Build Coastguard Worker """Trim the namespace part of each module, if present. 167*333d2b36SAndroid Build Coastguard Worker 168*333d2b36SAndroid Build Coastguard Worker Leave only the name. 169*333d2b36SAndroid Build Coastguard Worker """ 170*333d2b36SAndroid Build Coastguard Worker 171*333d2b36SAndroid Build Coastguard Worker trimmed = [] 172*333d2b36SAndroid Build Coastguard Worker for module in modules: 173*333d2b36SAndroid Build Coastguard Worker trimmed.append(MODULE_NAMESPACE.sub('', module)) 174*333d2b36SAndroid Build Coastguard Worker return trimmed 175*333d2b36SAndroid Build Coastguard Worker 176*333d2b36SAndroid Build Coastguard Worker 177*333d2b36SAndroid Build Coastguard Workerdef extract_uses_libs_apk(badging): 178*333d2b36SAndroid Build Coastguard Worker """Extract <uses-library> tags from the manifest of an APK.""" 179*333d2b36SAndroid Build Coastguard Worker 180*333d2b36SAndroid Build Coastguard Worker pattern = re.compile("^uses-library(-not-required)?:'(.*)'$", re.MULTILINE) 181*333d2b36SAndroid Build Coastguard Worker 182*333d2b36SAndroid Build Coastguard Worker required = [] 183*333d2b36SAndroid Build Coastguard Worker optional = [] 184*333d2b36SAndroid Build Coastguard Worker lines = [] 185*333d2b36SAndroid Build Coastguard Worker for match in re.finditer(pattern, badging): 186*333d2b36SAndroid Build Coastguard Worker lines.append(match.group(0)) 187*333d2b36SAndroid Build Coastguard Worker libname = match.group(2) 188*333d2b36SAndroid Build Coastguard Worker if match.group(1) is None: 189*333d2b36SAndroid Build Coastguard Worker required.append(libname) 190*333d2b36SAndroid Build Coastguard Worker else: 191*333d2b36SAndroid Build Coastguard Worker optional.append(libname) 192*333d2b36SAndroid Build Coastguard Worker 193*333d2b36SAndroid Build Coastguard Worker required = first_unique_elements(required) 194*333d2b36SAndroid Build Coastguard Worker optional = first_unique_elements(optional) 195*333d2b36SAndroid Build Coastguard Worker tags = first_unique_elements(lines) 196*333d2b36SAndroid Build Coastguard Worker return required, optional, tags 197*333d2b36SAndroid Build Coastguard Worker 198*333d2b36SAndroid Build Coastguard Worker 199*333d2b36SAndroid Build Coastguard Workerdef extract_uses_libs_xml(xml): 200*333d2b36SAndroid Build Coastguard Worker """Extract <uses-library> tags from the manifest.""" 201*333d2b36SAndroid Build Coastguard Worker 202*333d2b36SAndroid Build Coastguard Worker manifest = parse_manifest(xml) 203*333d2b36SAndroid Build Coastguard Worker libs = [child 204*333d2b36SAndroid Build Coastguard Worker for application in get_or_create_applications(xml, manifest) 205*333d2b36SAndroid Build Coastguard Worker for child in get_children_with_tag(application, 'uses-library')] 206*333d2b36SAndroid Build Coastguard Worker 207*333d2b36SAndroid Build Coastguard Worker required = [uses_library_name(x) for x in libs if uses_library_required(x)] 208*333d2b36SAndroid Build Coastguard Worker optional = [ 209*333d2b36SAndroid Build Coastguard Worker uses_library_name(x) for x in libs if not uses_library_required(x) 210*333d2b36SAndroid Build Coastguard Worker ] 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Worker # render <uses-library> tags as XML for a pretty error message 213*333d2b36SAndroid Build Coastguard Worker tags = [] 214*333d2b36SAndroid Build Coastguard Worker for lib in libs: 215*333d2b36SAndroid Build Coastguard Worker tags.append(lib.toprettyxml()) 216*333d2b36SAndroid Build Coastguard Worker 217*333d2b36SAndroid Build Coastguard Worker required = first_unique_elements(required) 218*333d2b36SAndroid Build Coastguard Worker optional = first_unique_elements(optional) 219*333d2b36SAndroid Build Coastguard Worker tags = first_unique_elements(tags) 220*333d2b36SAndroid Build Coastguard Worker return required, optional, tags 221*333d2b36SAndroid Build Coastguard Worker 222*333d2b36SAndroid Build Coastguard Worker 223*333d2b36SAndroid Build Coastguard Workerdef first_unique_elements(l): 224*333d2b36SAndroid Build Coastguard Worker result = [] 225*333d2b36SAndroid Build Coastguard Worker for x in l: 226*333d2b36SAndroid Build Coastguard Worker if x not in result: 227*333d2b36SAndroid Build Coastguard Worker result.append(x) 228*333d2b36SAndroid Build Coastguard Worker return result 229*333d2b36SAndroid Build Coastguard Worker 230*333d2b36SAndroid Build Coastguard Worker 231*333d2b36SAndroid Build Coastguard Workerdef uses_library_name(lib): 232*333d2b36SAndroid Build Coastguard Worker """Extract the name attribute of a uses-library tag. 233*333d2b36SAndroid Build Coastguard Worker 234*333d2b36SAndroid Build Coastguard Worker Args: 235*333d2b36SAndroid Build Coastguard Worker lib: a <uses-library> tag. 236*333d2b36SAndroid Build Coastguard Worker """ 237*333d2b36SAndroid Build Coastguard Worker name = lib.getAttributeNodeNS(android_ns, 'name') 238*333d2b36SAndroid Build Coastguard Worker return name.value if name is not None else '' 239*333d2b36SAndroid Build Coastguard Worker 240*333d2b36SAndroid Build Coastguard Worker 241*333d2b36SAndroid Build Coastguard Workerdef uses_library_required(lib): 242*333d2b36SAndroid Build Coastguard Worker """Extract the required attribute of a uses-library tag. 243*333d2b36SAndroid Build Coastguard Worker 244*333d2b36SAndroid Build Coastguard Worker Args: 245*333d2b36SAndroid Build Coastguard Worker lib: a <uses-library> tag. 246*333d2b36SAndroid Build Coastguard Worker """ 247*333d2b36SAndroid Build Coastguard Worker required = lib.getAttributeNodeNS(android_ns, 'required') 248*333d2b36SAndroid Build Coastguard Worker return (required.value == 'true') if required is not None else True 249*333d2b36SAndroid Build Coastguard Worker 250*333d2b36SAndroid Build Coastguard Worker 251*333d2b36SAndroid Build Coastguard Workerdef extract_target_sdk_version(manifest, is_apk=False): 252*333d2b36SAndroid Build Coastguard Worker """Returns the targetSdkVersion from the manifest. 253*333d2b36SAndroid Build Coastguard Worker 254*333d2b36SAndroid Build Coastguard Worker Args: 255*333d2b36SAndroid Build Coastguard Worker manifest: manifest (either parsed XML or aapt dump of APK) 256*333d2b36SAndroid Build Coastguard Worker is_apk: if the manifest comes from an APK or an XML file 257*333d2b36SAndroid Build Coastguard Worker """ 258*333d2b36SAndroid Build Coastguard Worker if is_apk: #pylint: disable=no-else-return 259*333d2b36SAndroid Build Coastguard Worker return extract_target_sdk_version_apk(manifest) 260*333d2b36SAndroid Build Coastguard Worker else: 261*333d2b36SAndroid Build Coastguard Worker return extract_target_sdk_version_xml(manifest) 262*333d2b36SAndroid Build Coastguard Worker 263*333d2b36SAndroid Build Coastguard Worker 264*333d2b36SAndroid Build Coastguard Workerdef extract_target_sdk_version_apk(badging): 265*333d2b36SAndroid Build Coastguard Worker """Extract targetSdkVersion tags from the manifest of an APK.""" 266*333d2b36SAndroid Build Coastguard Worker 267*333d2b36SAndroid Build Coastguard Worker pattern = re.compile("^targetSdkVersion?:'(.*)'$", re.MULTILINE) 268*333d2b36SAndroid Build Coastguard Worker 269*333d2b36SAndroid Build Coastguard Worker for match in re.finditer(pattern, badging): 270*333d2b36SAndroid Build Coastguard Worker return match.group(1) 271*333d2b36SAndroid Build Coastguard Worker 272*333d2b36SAndroid Build Coastguard Worker raise RuntimeError('cannot find targetSdkVersion in the manifest') 273*333d2b36SAndroid Build Coastguard Worker 274*333d2b36SAndroid Build Coastguard Worker 275*333d2b36SAndroid Build Coastguard Workerdef extract_target_sdk_version_xml(xml): 276*333d2b36SAndroid Build Coastguard Worker """Extract targetSdkVersion tags from the manifest.""" 277*333d2b36SAndroid Build Coastguard Worker 278*333d2b36SAndroid Build Coastguard Worker manifest = parse_manifest(xml) 279*333d2b36SAndroid Build Coastguard Worker 280*333d2b36SAndroid Build Coastguard Worker # Get or insert the uses-sdk element 281*333d2b36SAndroid Build Coastguard Worker uses_sdk = get_children_with_tag(manifest, 'uses-sdk') 282*333d2b36SAndroid Build Coastguard Worker if len(uses_sdk) > 1: #pylint: disable=no-else-raise 283*333d2b36SAndroid Build Coastguard Worker raise RuntimeError('found multiple uses-sdk elements') 284*333d2b36SAndroid Build Coastguard Worker elif len(uses_sdk) == 0: 285*333d2b36SAndroid Build Coastguard Worker raise RuntimeError('missing uses-sdk element') 286*333d2b36SAndroid Build Coastguard Worker 287*333d2b36SAndroid Build Coastguard Worker uses_sdk = uses_sdk[0] 288*333d2b36SAndroid Build Coastguard Worker 289*333d2b36SAndroid Build Coastguard Worker min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion') 290*333d2b36SAndroid Build Coastguard Worker if min_attr is None: 291*333d2b36SAndroid Build Coastguard Worker raise RuntimeError('minSdkVersion is not specified') 292*333d2b36SAndroid Build Coastguard Worker 293*333d2b36SAndroid Build Coastguard Worker target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion') 294*333d2b36SAndroid Build Coastguard Worker if target_attr is None: 295*333d2b36SAndroid Build Coastguard Worker target_attr = min_attr 296*333d2b36SAndroid Build Coastguard Worker 297*333d2b36SAndroid Build Coastguard Worker return target_attr.value 298*333d2b36SAndroid Build Coastguard Worker 299*333d2b36SAndroid Build Coastguard Worker 300*333d2b36SAndroid Build Coastguard Workerdef load_dexpreopt_configs(configs): 301*333d2b36SAndroid Build Coastguard Worker """Load dexpreopt.config files and map module names to library names.""" 302*333d2b36SAndroid Build Coastguard Worker module_to_libname = {} 303*333d2b36SAndroid Build Coastguard Worker 304*333d2b36SAndroid Build Coastguard Worker if configs is None: 305*333d2b36SAndroid Build Coastguard Worker configs = [] 306*333d2b36SAndroid Build Coastguard Worker 307*333d2b36SAndroid Build Coastguard Worker for config in configs: 308*333d2b36SAndroid Build Coastguard Worker with open(config, 'r') as f: 309*333d2b36SAndroid Build Coastguard Worker contents = json.load(f) 310*333d2b36SAndroid Build Coastguard Worker module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary'] 311*333d2b36SAndroid Build Coastguard Worker 312*333d2b36SAndroid Build Coastguard Worker return module_to_libname 313*333d2b36SAndroid Build Coastguard Worker 314*333d2b36SAndroid Build Coastguard Worker 315*333d2b36SAndroid Build Coastguard Workerdef translate_libnames(modules, module_to_libname): 316*333d2b36SAndroid Build Coastguard Worker """Translate module names into library names using the mapping.""" 317*333d2b36SAndroid Build Coastguard Worker if modules is None: 318*333d2b36SAndroid Build Coastguard Worker modules = [] 319*333d2b36SAndroid Build Coastguard Worker 320*333d2b36SAndroid Build Coastguard Worker libnames = [] 321*333d2b36SAndroid Build Coastguard Worker for name in modules: 322*333d2b36SAndroid Build Coastguard Worker if name in module_to_libname: 323*333d2b36SAndroid Build Coastguard Worker name = module_to_libname[name] 324*333d2b36SAndroid Build Coastguard Worker libnames.append(name) 325*333d2b36SAndroid Build Coastguard Worker 326*333d2b36SAndroid Build Coastguard Worker return libnames 327*333d2b36SAndroid Build Coastguard Worker 328*333d2b36SAndroid Build Coastguard Worker 329*333d2b36SAndroid Build Coastguard Workerdef main(): 330*333d2b36SAndroid Build Coastguard Worker """Program entry point.""" 331*333d2b36SAndroid Build Coastguard Worker try: 332*333d2b36SAndroid Build Coastguard Worker args = parse_args() 333*333d2b36SAndroid Build Coastguard Worker 334*333d2b36SAndroid Build Coastguard Worker # The input can be either an XML manifest or an APK, they are parsed and 335*333d2b36SAndroid Build Coastguard Worker # processed in different ways. 336*333d2b36SAndroid Build Coastguard Worker is_apk = args.input.endswith('.apk') 337*333d2b36SAndroid Build Coastguard Worker if is_apk: 338*333d2b36SAndroid Build Coastguard Worker aapt = args.aapt if args.aapt is not None else 'aapt' 339*333d2b36SAndroid Build Coastguard Worker manifest = subprocess.check_output( 340*333d2b36SAndroid Build Coastguard Worker [aapt, 'dump', 'badging', args.input]).decode('utf-8') 341*333d2b36SAndroid Build Coastguard Worker else: 342*333d2b36SAndroid Build Coastguard Worker manifest = minidom.parse(args.input) 343*333d2b36SAndroid Build Coastguard Worker 344*333d2b36SAndroid Build Coastguard Worker if args.enforce_uses_libraries: 345*333d2b36SAndroid Build Coastguard Worker # Load dexpreopt.config files and build a mapping from module 346*333d2b36SAndroid Build Coastguard Worker # names to library names. This is for Make only and it's necessary 347*333d2b36SAndroid Build Coastguard Worker # because Make passes module names from `LOCAL_USES_LIBRARIES`, 348*333d2b36SAndroid Build Coastguard Worker # `LOCAL_OPTIONAL_LIBRARY_NAMES`, while the manifest addresses 349*333d2b36SAndroid Build Coastguard Worker # libraries by their name. Soong doesn't use it and doesn't need it 350*333d2b36SAndroid Build Coastguard Worker # because it converts the module names to the library names and 351*333d2b36SAndroid Build Coastguard Worker # passes the library names. There is no need to translate missing 352*333d2b36SAndroid Build Coastguard Worker # optional libs because they are missing and therefore there is no 353*333d2b36SAndroid Build Coastguard Worker # mapping for them. 354*333d2b36SAndroid Build Coastguard Worker mod_to_lib = load_dexpreopt_configs(args.dexpreopt_configs) 355*333d2b36SAndroid Build Coastguard Worker required = translate_libnames(args.uses_libraries, mod_to_lib) 356*333d2b36SAndroid Build Coastguard Worker optional = translate_libnames(args.optional_uses_libraries, 357*333d2b36SAndroid Build Coastguard Worker mod_to_lib) 358*333d2b36SAndroid Build Coastguard Worker 359*333d2b36SAndroid Build Coastguard Worker # Check if the <uses-library> lists in the build system agree with 360*333d2b36SAndroid Build Coastguard Worker # those in the manifest. Raise an exception on mismatch, unless the 361*333d2b36SAndroid Build Coastguard Worker # script was passed a special parameter to suppress exceptions. 362*333d2b36SAndroid Build Coastguard Worker errmsg = enforce_uses_libraries(manifest, required, optional, 363*333d2b36SAndroid Build Coastguard Worker args.missing_optional_uses_libraries, 364*333d2b36SAndroid Build Coastguard Worker args.enforce_uses_libraries_relax, is_apk, args.input) 365*333d2b36SAndroid Build Coastguard Worker 366*333d2b36SAndroid Build Coastguard Worker # Create a status file that is empty on success, or contains an 367*333d2b36SAndroid Build Coastguard Worker # error message on failure. When exceptions are suppressed, 368*333d2b36SAndroid Build Coastguard Worker # dexpreopt command will check file size to determine if 369*333d2b36SAndroid Build Coastguard Worker # the check has failed. 370*333d2b36SAndroid Build Coastguard Worker if args.enforce_uses_libraries_status: 371*333d2b36SAndroid Build Coastguard Worker with open(args.enforce_uses_libraries_status, 'w') as f: 372*333d2b36SAndroid Build Coastguard Worker if errmsg is not None: 373*333d2b36SAndroid Build Coastguard Worker f.write('%s\n' % errmsg) 374*333d2b36SAndroid Build Coastguard Worker 375*333d2b36SAndroid Build Coastguard Worker if args.extract_target_sdk_version: 376*333d2b36SAndroid Build Coastguard Worker try: 377*333d2b36SAndroid Build Coastguard Worker print(extract_target_sdk_version(manifest, is_apk)) 378*333d2b36SAndroid Build Coastguard Worker except: #pylint: disable=bare-except 379*333d2b36SAndroid Build Coastguard Worker # Failed; don't crash, return "any" SDK version. This will 380*333d2b36SAndroid Build Coastguard Worker # result in dexpreopt not adding any compatibility libraries. 381*333d2b36SAndroid Build Coastguard Worker print(10000) 382*333d2b36SAndroid Build Coastguard Worker 383*333d2b36SAndroid Build Coastguard Worker if args.output: 384*333d2b36SAndroid Build Coastguard Worker # XML output is supposed to be written only when this script is 385*333d2b36SAndroid Build Coastguard Worker # invoked with XML input manifest, not with an APK. 386*333d2b36SAndroid Build Coastguard Worker if is_apk: 387*333d2b36SAndroid Build Coastguard Worker raise RuntimeError('cannot save APK manifest as XML') 388*333d2b36SAndroid Build Coastguard Worker 389*333d2b36SAndroid Build Coastguard Worker with open(args.output, 'w') as f: 390*333d2b36SAndroid Build Coastguard Worker write_xml(f, manifest) 391*333d2b36SAndroid Build Coastguard Worker 392*333d2b36SAndroid Build Coastguard Worker # pylint: disable=broad-except 393*333d2b36SAndroid Build Coastguard Worker except Exception as err: 394*333d2b36SAndroid Build Coastguard Worker print('%serror:%s ' % (C_RED, C_OFF) + str(err), file=sys.stderr) 395*333d2b36SAndroid Build Coastguard Worker sys.exit(-1) 396*333d2b36SAndroid Build Coastguard Worker 397*333d2b36SAndroid Build Coastguard Worker 398*333d2b36SAndroid Build Coastguard Workerif __name__ == '__main__': 399*333d2b36SAndroid Build Coastguard Worker main() 400