1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# 3*6777b538SAndroid Build Coastguard Worker# Copyright 2012 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"""Compile Android resources into an intermediate APK. 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard WorkerThis can also generate an R.txt, and an .srcjar file containing the proper 10*6777b538SAndroid Build Coastguard Workerfinal R.java class for all resource packages the APK depends on. 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard WorkerThis will crunch images with aapt2. 13*6777b538SAndroid Build Coastguard Worker""" 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Workerimport argparse 16*6777b538SAndroid Build Coastguard Workerimport collections 17*6777b538SAndroid Build Coastguard Workerimport contextlib 18*6777b538SAndroid Build Coastguard Workerimport filecmp 19*6777b538SAndroid Build Coastguard Workerimport hashlib 20*6777b538SAndroid Build Coastguard Workerimport logging 21*6777b538SAndroid Build Coastguard Workerimport os 22*6777b538SAndroid Build Coastguard Workerimport pathlib 23*6777b538SAndroid Build Coastguard Workerimport re 24*6777b538SAndroid Build Coastguard Workerimport shutil 25*6777b538SAndroid Build Coastguard Workerimport subprocess 26*6777b538SAndroid Build Coastguard Workerimport sys 27*6777b538SAndroid Build Coastguard Workerimport textwrap 28*6777b538SAndroid Build Coastguard Workerfrom xml.etree import ElementTree 29*6777b538SAndroid Build Coastguard Worker 30*6777b538SAndroid Build Coastguard Workerfrom util import build_utils 31*6777b538SAndroid Build Coastguard Workerfrom util import diff_utils 32*6777b538SAndroid Build Coastguard Workerfrom util import manifest_utils 33*6777b538SAndroid Build Coastguard Workerfrom util import parallel 34*6777b538SAndroid Build Coastguard Workerfrom util import protoresources 35*6777b538SAndroid Build Coastguard Workerfrom util import resource_utils 36*6777b538SAndroid Build Coastguard Workerimport action_helpers # build_utils adds //build to sys.path. 37*6777b538SAndroid Build Coastguard Workerimport zip_helpers 38*6777b538SAndroid Build Coastguard Worker 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker# Pngs that we shouldn't convert to webp. Please add rationale when updating. 41*6777b538SAndroid Build Coastguard Worker_PNG_WEBP_EXCLUSION_PATTERN = re.compile('|'.join([ 42*6777b538SAndroid Build Coastguard Worker # Crashes on Galaxy S5 running L (https://crbug.com/807059). 43*6777b538SAndroid Build Coastguard Worker r'.*star_gray\.png', 44*6777b538SAndroid Build Coastguard Worker # Android requires pngs for 9-patch images. 45*6777b538SAndroid Build Coastguard Worker r'.*\.9\.png', 46*6777b538SAndroid Build Coastguard Worker # Daydream requires pngs for icon files. 47*6777b538SAndroid Build Coastguard Worker r'.*daydream_icon_.*\.png' 48*6777b538SAndroid Build Coastguard Worker])) 49*6777b538SAndroid Build Coastguard Worker 50*6777b538SAndroid Build Coastguard Worker 51*6777b538SAndroid Build Coastguard Workerdef _ParseArgs(args): 52*6777b538SAndroid Build Coastguard Worker """Parses command line options. 53*6777b538SAndroid Build Coastguard Worker 54*6777b538SAndroid Build Coastguard Worker Returns: 55*6777b538SAndroid Build Coastguard Worker An options object as from argparse.ArgumentParser.parse_args() 56*6777b538SAndroid Build Coastguard Worker """ 57*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=__doc__) 58*6777b538SAndroid Build Coastguard Worker 59*6777b538SAndroid Build Coastguard Worker input_opts = parser.add_argument_group('Input options') 60*6777b538SAndroid Build Coastguard Worker output_opts = parser.add_argument_group('Output options') 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker input_opts.add_argument('--include-resources', 63*6777b538SAndroid Build Coastguard Worker action='append', 64*6777b538SAndroid Build Coastguard Worker required=True, 65*6777b538SAndroid Build Coastguard Worker help='Paths to arsc resource files used to link ' 66*6777b538SAndroid Build Coastguard Worker 'against. Can be specified multiple times.') 67*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 68*6777b538SAndroid Build Coastguard Worker '--dependencies-res-zips', 69*6777b538SAndroid Build Coastguard Worker default=[], 70*6777b538SAndroid Build Coastguard Worker help='Resources zip archives from dependents. Required to ' 71*6777b538SAndroid Build Coastguard Worker 'resolve @type/foo references into dependent libraries.') 72*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 73*6777b538SAndroid Build Coastguard Worker '--extra-res-packages', 74*6777b538SAndroid Build Coastguard Worker help='Additional package names to generate R.java files for.') 75*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 76*6777b538SAndroid Build Coastguard Worker '--aapt2-path', required=True, help='Path to the Android aapt2 tool.') 77*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 78*6777b538SAndroid Build Coastguard Worker '--android-manifest', required=True, help='AndroidManifest.xml path.') 79*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 80*6777b538SAndroid Build Coastguard Worker '--r-java-root-package-name', 81*6777b538SAndroid Build Coastguard Worker default='base', 82*6777b538SAndroid Build Coastguard Worker help='Short package name for this target\'s root R java file (ex. ' 83*6777b538SAndroid Build Coastguard Worker 'input of "base" would become gen.base_module). Defaults to "base".') 84*6777b538SAndroid Build Coastguard Worker group = input_opts.add_mutually_exclusive_group() 85*6777b538SAndroid Build Coastguard Worker group.add_argument( 86*6777b538SAndroid Build Coastguard Worker '--shared-resources', 87*6777b538SAndroid Build Coastguard Worker action='store_true', 88*6777b538SAndroid Build Coastguard Worker help='Make all resources in R.java non-final and allow the resource IDs ' 89*6777b538SAndroid Build Coastguard Worker 'to be reset to a different package index when the apk is loaded by ' 90*6777b538SAndroid Build Coastguard Worker 'another application at runtime.') 91*6777b538SAndroid Build Coastguard Worker group.add_argument( 92*6777b538SAndroid Build Coastguard Worker '--app-as-shared-lib', 93*6777b538SAndroid Build Coastguard Worker action='store_true', 94*6777b538SAndroid Build Coastguard Worker help='Same as --shared-resources, but also ensures all resource IDs are ' 95*6777b538SAndroid Build Coastguard Worker 'directly usable from the APK loaded as an application.') 96*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 97*6777b538SAndroid Build Coastguard Worker '--package-id', 98*6777b538SAndroid Build Coastguard Worker type=int, 99*6777b538SAndroid Build Coastguard Worker help='Decimal integer representing custom package ID for resources ' 100*6777b538SAndroid Build Coastguard Worker '(instead of 127==0x7f). Cannot be used with --shared-resources.') 101*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 102*6777b538SAndroid Build Coastguard Worker '--package-name', 103*6777b538SAndroid Build Coastguard Worker help='Package name that will be used to create R class.') 104*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 105*6777b538SAndroid Build Coastguard Worker '--rename-manifest-package', help='Package name to force AAPT to use.') 106*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 107*6777b538SAndroid Build Coastguard Worker '--arsc-package-name', 108*6777b538SAndroid Build Coastguard Worker help='Package name to set in manifest of resources.arsc file. This is ' 109*6777b538SAndroid Build Coastguard Worker 'only used for apks under test.') 110*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 111*6777b538SAndroid Build Coastguard Worker '--shared-resources-allowlist', 112*6777b538SAndroid Build Coastguard Worker help='An R.txt file acting as a allowlist for resources that should be ' 113*6777b538SAndroid Build Coastguard Worker 'non-final and have their package ID changed at runtime in R.java. ' 114*6777b538SAndroid Build Coastguard Worker 'Implies and overrides --shared-resources.') 115*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 116*6777b538SAndroid Build Coastguard Worker '--shared-resources-allowlist-locales', 117*6777b538SAndroid Build Coastguard Worker default='[]', 118*6777b538SAndroid Build Coastguard Worker help='Optional GN-list of locales. If provided, all strings corresponding' 119*6777b538SAndroid Build Coastguard Worker ' to this locale list will be kept in the final output for the ' 120*6777b538SAndroid Build Coastguard Worker 'resources identified through --shared-resources-allowlist, even ' 121*6777b538SAndroid Build Coastguard Worker 'if --locale-allowlist is being used.') 122*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 123*6777b538SAndroid Build Coastguard Worker '--use-resource-ids-path', 124*6777b538SAndroid Build Coastguard Worker help='Use resource IDs generated by aapt --emit-ids.') 125*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 126*6777b538SAndroid Build Coastguard Worker '--debuggable', 127*6777b538SAndroid Build Coastguard Worker action='store_true', 128*6777b538SAndroid Build Coastguard Worker help='Whether to add android:debuggable="true".') 129*6777b538SAndroid Build Coastguard Worker input_opts.add_argument('--static-library-version', 130*6777b538SAndroid Build Coastguard Worker help='Version code for static library.') 131*6777b538SAndroid Build Coastguard Worker input_opts.add_argument('--version-code', help='Version code for apk.') 132*6777b538SAndroid Build Coastguard Worker input_opts.add_argument('--version-name', help='Version name for apk.') 133*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 134*6777b538SAndroid Build Coastguard Worker '--min-sdk-version', required=True, help='android:minSdkVersion for APK.') 135*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 136*6777b538SAndroid Build Coastguard Worker '--target-sdk-version', 137*6777b538SAndroid Build Coastguard Worker required=True, 138*6777b538SAndroid Build Coastguard Worker help="android:targetSdkVersion for APK.") 139*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 140*6777b538SAndroid Build Coastguard Worker '--max-sdk-version', 141*6777b538SAndroid Build Coastguard Worker help="android:maxSdkVersion expected in AndroidManifest.xml.") 142*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 143*6777b538SAndroid Build Coastguard Worker '--manifest-package', help='Package name of the AndroidManifest.xml.') 144*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 145*6777b538SAndroid Build Coastguard Worker '--locale-allowlist', 146*6777b538SAndroid Build Coastguard Worker default='[]', 147*6777b538SAndroid Build Coastguard Worker help='GN list of languages to include. All other language configs will ' 148*6777b538SAndroid Build Coastguard Worker 'be stripped out. List may include a combination of Android locales ' 149*6777b538SAndroid Build Coastguard Worker 'or Chrome locales.') 150*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 151*6777b538SAndroid Build Coastguard Worker '--resource-exclusion-regex', 152*6777b538SAndroid Build Coastguard Worker default='', 153*6777b538SAndroid Build Coastguard Worker help='File-based filter for resources (applied before compiling)') 154*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 155*6777b538SAndroid Build Coastguard Worker '--resource-exclusion-exceptions', 156*6777b538SAndroid Build Coastguard Worker default='[]', 157*6777b538SAndroid Build Coastguard Worker help='GN list of globs that say which files to include even ' 158*6777b538SAndroid Build Coastguard Worker 'when --resource-exclusion-regex is set.') 159*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 160*6777b538SAndroid Build Coastguard Worker '--dependencies-res-zip-overlays', 161*6777b538SAndroid Build Coastguard Worker help='GN list with subset of --dependencies-res-zips to use overlay ' 162*6777b538SAndroid Build Coastguard Worker 'semantics for.') 163*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 164*6777b538SAndroid Build Coastguard Worker '--values-filter-rules', 165*6777b538SAndroid Build Coastguard Worker help='GN list of source_glob:regex for filtering resources after they ' 166*6777b538SAndroid Build Coastguard Worker 'are compiled. Use this to filter out entries within values/ files.') 167*6777b538SAndroid Build Coastguard Worker input_opts.add_argument('--png-to-webp', action='store_true', 168*6777b538SAndroid Build Coastguard Worker help='Convert png files to webp format.') 169*6777b538SAndroid Build Coastguard Worker 170*6777b538SAndroid Build Coastguard Worker input_opts.add_argument('--webp-binary', default='', 171*6777b538SAndroid Build Coastguard Worker help='Path to the cwebp binary.') 172*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 173*6777b538SAndroid Build Coastguard Worker '--webp-cache-dir', help='The directory to store webp image cache.') 174*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 175*6777b538SAndroid Build Coastguard Worker '--is-bundle-module', 176*6777b538SAndroid Build Coastguard Worker action='store_true', 177*6777b538SAndroid Build Coastguard Worker help='Whether resources are being generated for a bundle module.') 178*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 179*6777b538SAndroid Build Coastguard Worker '--uses-split', 180*6777b538SAndroid Build Coastguard Worker help='Value to set uses-split to in the AndroidManifest.xml.') 181*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 182*6777b538SAndroid Build Coastguard Worker '--verification-version-code-offset', 183*6777b538SAndroid Build Coastguard Worker help='Subtract this from versionCode for expectation files') 184*6777b538SAndroid Build Coastguard Worker input_opts.add_argument( 185*6777b538SAndroid Build Coastguard Worker '--verification-library-version-offset', 186*6777b538SAndroid Build Coastguard Worker help='Subtract this from static-library version for expectation files') 187*6777b538SAndroid Build Coastguard Worker 188*6777b538SAndroid Build Coastguard Worker action_helpers.add_depfile_arg(output_opts) 189*6777b538SAndroid Build Coastguard Worker output_opts.add_argument('--arsc-path', help='Apk output for arsc format.') 190*6777b538SAndroid Build Coastguard Worker output_opts.add_argument('--proto-path', help='Apk output for proto format.') 191*6777b538SAndroid Build Coastguard Worker output_opts.add_argument( 192*6777b538SAndroid Build Coastguard Worker '--info-path', help='Path to output info file for the partial apk.') 193*6777b538SAndroid Build Coastguard Worker output_opts.add_argument( 194*6777b538SAndroid Build Coastguard Worker '--srcjar-out', 195*6777b538SAndroid Build Coastguard Worker help='Path to srcjar to contain generated R.java.') 196*6777b538SAndroid Build Coastguard Worker output_opts.add_argument('--r-text-out', 197*6777b538SAndroid Build Coastguard Worker help='Path to store the generated R.txt file.') 198*6777b538SAndroid Build Coastguard Worker output_opts.add_argument( 199*6777b538SAndroid Build Coastguard Worker '--proguard-file', help='Path to proguard.txt generated file.') 200*6777b538SAndroid Build Coastguard Worker output_opts.add_argument( 201*6777b538SAndroid Build Coastguard Worker '--emit-ids-out', help='Path to file produced by aapt2 --emit-ids.') 202*6777b538SAndroid Build Coastguard Worker 203*6777b538SAndroid Build Coastguard Worker diff_utils.AddCommandLineFlags(parser) 204*6777b538SAndroid Build Coastguard Worker options = parser.parse_args(args) 205*6777b538SAndroid Build Coastguard Worker 206*6777b538SAndroid Build Coastguard Worker options.include_resources = action_helpers.parse_gn_list( 207*6777b538SAndroid Build Coastguard Worker options.include_resources) 208*6777b538SAndroid Build Coastguard Worker options.dependencies_res_zips = action_helpers.parse_gn_list( 209*6777b538SAndroid Build Coastguard Worker options.dependencies_res_zips) 210*6777b538SAndroid Build Coastguard Worker options.extra_res_packages = action_helpers.parse_gn_list( 211*6777b538SAndroid Build Coastguard Worker options.extra_res_packages) 212*6777b538SAndroid Build Coastguard Worker options.locale_allowlist = action_helpers.parse_gn_list( 213*6777b538SAndroid Build Coastguard Worker options.locale_allowlist) 214*6777b538SAndroid Build Coastguard Worker options.shared_resources_allowlist_locales = action_helpers.parse_gn_list( 215*6777b538SAndroid Build Coastguard Worker options.shared_resources_allowlist_locales) 216*6777b538SAndroid Build Coastguard Worker options.resource_exclusion_exceptions = action_helpers.parse_gn_list( 217*6777b538SAndroid Build Coastguard Worker options.resource_exclusion_exceptions) 218*6777b538SAndroid Build Coastguard Worker options.dependencies_res_zip_overlays = action_helpers.parse_gn_list( 219*6777b538SAndroid Build Coastguard Worker options.dependencies_res_zip_overlays) 220*6777b538SAndroid Build Coastguard Worker options.values_filter_rules = action_helpers.parse_gn_list( 221*6777b538SAndroid Build Coastguard Worker options.values_filter_rules) 222*6777b538SAndroid Build Coastguard Worker 223*6777b538SAndroid Build Coastguard Worker if not options.arsc_path and not options.proto_path: 224*6777b538SAndroid Build Coastguard Worker parser.error('One of --arsc-path or --proto-path is required.') 225*6777b538SAndroid Build Coastguard Worker 226*6777b538SAndroid Build Coastguard Worker if options.package_id and options.shared_resources: 227*6777b538SAndroid Build Coastguard Worker parser.error('--package-id and --shared-resources are mutually exclusive') 228*6777b538SAndroid Build Coastguard Worker 229*6777b538SAndroid Build Coastguard Worker if options.static_library_version and (options.static_library_version != 230*6777b538SAndroid Build Coastguard Worker options.version_code): 231*6777b538SAndroid Build Coastguard Worker assert options.static_library_version == options.version_code, ( 232*6777b538SAndroid Build Coastguard Worker f'static_library_version={options.static_library_version} must equal ' 233*6777b538SAndroid Build Coastguard Worker f'version_code={options.version_code}. Please verify the version code ' 234*6777b538SAndroid Build Coastguard Worker 'map for this target is defined correctly.') 235*6777b538SAndroid Build Coastguard Worker 236*6777b538SAndroid Build Coastguard Worker return options 237*6777b538SAndroid Build Coastguard Worker 238*6777b538SAndroid Build Coastguard Worker 239*6777b538SAndroid Build Coastguard Workerdef _IterFiles(root_dir): 240*6777b538SAndroid Build Coastguard Worker for root, _, files in os.walk(root_dir): 241*6777b538SAndroid Build Coastguard Worker for f in files: 242*6777b538SAndroid Build Coastguard Worker yield os.path.join(root, f) 243*6777b538SAndroid Build Coastguard Worker 244*6777b538SAndroid Build Coastguard Worker 245*6777b538SAndroid Build Coastguard Workerdef _RenameLocaleResourceDirs(resource_dirs, path_info): 246*6777b538SAndroid Build Coastguard Worker """Rename locale resource directories into standard names when necessary. 247*6777b538SAndroid Build Coastguard Worker 248*6777b538SAndroid Build Coastguard Worker This is necessary to deal with the fact that older Android releases only 249*6777b538SAndroid Build Coastguard Worker support ISO 639-1 two-letter codes, and sometimes even obsolete versions 250*6777b538SAndroid Build Coastguard Worker of them. 251*6777b538SAndroid Build Coastguard Worker 252*6777b538SAndroid Build Coastguard Worker In practice it means: 253*6777b538SAndroid Build Coastguard Worker * 3-letter ISO 639-2 qualifiers are renamed under a corresponding 254*6777b538SAndroid Build Coastguard Worker 2-letter one. E.g. for Filipino, strings under values-fil/ will be moved 255*6777b538SAndroid Build Coastguard Worker to a new corresponding values-tl/ sub-directory. 256*6777b538SAndroid Build Coastguard Worker 257*6777b538SAndroid Build Coastguard Worker * Modern ISO 639-1 codes will be renamed to their obsolete variant 258*6777b538SAndroid Build Coastguard Worker for Indonesian, Hebrew and Yiddish (e.g. 'values-in/ -> values-id/). 259*6777b538SAndroid Build Coastguard Worker 260*6777b538SAndroid Build Coastguard Worker * Norwegian macrolanguage strings will be renamed to Bokmal (main 261*6777b538SAndroid Build Coastguard Worker Norway language). See http://crbug.com/920960. In practice this 262*6777b538SAndroid Build Coastguard Worker means that 'values-no/ -> values-nb/' unless 'values-nb/' already 263*6777b538SAndroid Build Coastguard Worker exists. 264*6777b538SAndroid Build Coastguard Worker 265*6777b538SAndroid Build Coastguard Worker * BCP 47 langauge tags will be renamed to an equivalent ISO 639-1 266*6777b538SAndroid Build Coastguard Worker locale qualifier if possible (e.g. 'values-b+en+US/ -> values-en-rUS'). 267*6777b538SAndroid Build Coastguard Worker 268*6777b538SAndroid Build Coastguard Worker Args: 269*6777b538SAndroid Build Coastguard Worker resource_dirs: list of top-level resource directories. 270*6777b538SAndroid Build Coastguard Worker """ 271*6777b538SAndroid Build Coastguard Worker for resource_dir in resource_dirs: 272*6777b538SAndroid Build Coastguard Worker ignore_dirs = {} 273*6777b538SAndroid Build Coastguard Worker for path in _IterFiles(resource_dir): 274*6777b538SAndroid Build Coastguard Worker locale = resource_utils.FindLocaleInStringResourceFilePath(path) 275*6777b538SAndroid Build Coastguard Worker if not locale: 276*6777b538SAndroid Build Coastguard Worker continue 277*6777b538SAndroid Build Coastguard Worker cr_locale = resource_utils.ToChromiumLocaleName(locale) 278*6777b538SAndroid Build Coastguard Worker if not cr_locale: 279*6777b538SAndroid Build Coastguard Worker continue # Unsupported Android locale qualifier!? 280*6777b538SAndroid Build Coastguard Worker locale2 = resource_utils.ToAndroidLocaleName(cr_locale) 281*6777b538SAndroid Build Coastguard Worker if locale != locale2: 282*6777b538SAndroid Build Coastguard Worker path2 = path.replace('/values-%s/' % locale, '/values-%s/' % locale2) 283*6777b538SAndroid Build Coastguard Worker if path == path2: 284*6777b538SAndroid Build Coastguard Worker raise Exception('Could not substitute locale %s for %s in %s' % 285*6777b538SAndroid Build Coastguard Worker (locale, locale2, path)) 286*6777b538SAndroid Build Coastguard Worker 287*6777b538SAndroid Build Coastguard Worker # Ignore rather than rename when the destination resources config 288*6777b538SAndroid Build Coastguard Worker # already exists. 289*6777b538SAndroid Build Coastguard Worker # e.g. some libraries provide both values-nb/ and values-no/. 290*6777b538SAndroid Build Coastguard Worker # e.g. material design provides: 291*6777b538SAndroid Build Coastguard Worker # * res/values-rUS/values-rUS.xml 292*6777b538SAndroid Build Coastguard Worker # * res/values-b+es+419/values-b+es+419.xml 293*6777b538SAndroid Build Coastguard Worker config_dir = os.path.dirname(path2) 294*6777b538SAndroid Build Coastguard Worker already_has_renamed_config = ignore_dirs.get(config_dir) 295*6777b538SAndroid Build Coastguard Worker if already_has_renamed_config is None: 296*6777b538SAndroid Build Coastguard Worker # Cache the result of the first time the directory is encountered 297*6777b538SAndroid Build Coastguard Worker # since subsequent encounters will find the directory already exists 298*6777b538SAndroid Build Coastguard Worker # (due to the rename). 299*6777b538SAndroid Build Coastguard Worker already_has_renamed_config = os.path.exists(config_dir) 300*6777b538SAndroid Build Coastguard Worker ignore_dirs[config_dir] = already_has_renamed_config 301*6777b538SAndroid Build Coastguard Worker if already_has_renamed_config: 302*6777b538SAndroid Build Coastguard Worker continue 303*6777b538SAndroid Build Coastguard Worker 304*6777b538SAndroid Build Coastguard Worker build_utils.MakeDirectory(os.path.dirname(path2)) 305*6777b538SAndroid Build Coastguard Worker shutil.move(path, path2) 306*6777b538SAndroid Build Coastguard Worker path_info.RegisterRename( 307*6777b538SAndroid Build Coastguard Worker os.path.relpath(path, resource_dir), 308*6777b538SAndroid Build Coastguard Worker os.path.relpath(path2, resource_dir)) 309*6777b538SAndroid Build Coastguard Worker 310*6777b538SAndroid Build Coastguard Worker 311*6777b538SAndroid Build Coastguard Workerdef _ToAndroidLocales(locale_allowlist): 312*6777b538SAndroid Build Coastguard Worker """Converts the list of Chrome locales to Android config locale qualifiers. 313*6777b538SAndroid Build Coastguard Worker 314*6777b538SAndroid Build Coastguard Worker Args: 315*6777b538SAndroid Build Coastguard Worker locale_allowlist: A list of Chromium locale names. 316*6777b538SAndroid Build Coastguard Worker Returns: 317*6777b538SAndroid Build Coastguard Worker A set of matching Android config locale qualifier names. 318*6777b538SAndroid Build Coastguard Worker """ 319*6777b538SAndroid Build Coastguard Worker ret = set() 320*6777b538SAndroid Build Coastguard Worker for locale in locale_allowlist: 321*6777b538SAndroid Build Coastguard Worker locale = resource_utils.ToAndroidLocaleName(locale) 322*6777b538SAndroid Build Coastguard Worker if locale is None or ('-' in locale and '-r' not in locale): 323*6777b538SAndroid Build Coastguard Worker raise Exception('Unsupported Chromium locale name: %s' % locale) 324*6777b538SAndroid Build Coastguard Worker ret.add(locale) 325*6777b538SAndroid Build Coastguard Worker # Always keep non-regional fall-backs. 326*6777b538SAndroid Build Coastguard Worker language = locale.split('-')[0] 327*6777b538SAndroid Build Coastguard Worker ret.add(language) 328*6777b538SAndroid Build Coastguard Worker 329*6777b538SAndroid Build Coastguard Worker return ret 330*6777b538SAndroid Build Coastguard Worker 331*6777b538SAndroid Build Coastguard Worker 332*6777b538SAndroid Build Coastguard Workerdef _MoveImagesToNonMdpiFolders(res_root, path_info): 333*6777b538SAndroid Build Coastguard Worker """Move images from drawable-*-mdpi-* folders to drawable-* folders. 334*6777b538SAndroid Build Coastguard Worker 335*6777b538SAndroid Build Coastguard Worker Why? http://crbug.com/289843 336*6777b538SAndroid Build Coastguard Worker """ 337*6777b538SAndroid Build Coastguard Worker for src_dir_name in os.listdir(res_root): 338*6777b538SAndroid Build Coastguard Worker src_components = src_dir_name.split('-') 339*6777b538SAndroid Build Coastguard Worker if src_components[0] != 'drawable' or 'mdpi' not in src_components: 340*6777b538SAndroid Build Coastguard Worker continue 341*6777b538SAndroid Build Coastguard Worker src_dir = os.path.join(res_root, src_dir_name) 342*6777b538SAndroid Build Coastguard Worker if not os.path.isdir(src_dir): 343*6777b538SAndroid Build Coastguard Worker continue 344*6777b538SAndroid Build Coastguard Worker dst_components = [c for c in src_components if c != 'mdpi'] 345*6777b538SAndroid Build Coastguard Worker assert dst_components != src_components 346*6777b538SAndroid Build Coastguard Worker dst_dir_name = '-'.join(dst_components) 347*6777b538SAndroid Build Coastguard Worker dst_dir = os.path.join(res_root, dst_dir_name) 348*6777b538SAndroid Build Coastguard Worker build_utils.MakeDirectory(dst_dir) 349*6777b538SAndroid Build Coastguard Worker for src_file_name in os.listdir(src_dir): 350*6777b538SAndroid Build Coastguard Worker src_file = os.path.join(src_dir, src_file_name) 351*6777b538SAndroid Build Coastguard Worker dst_file = os.path.join(dst_dir, src_file_name) 352*6777b538SAndroid Build Coastguard Worker assert not os.path.lexists(dst_file) 353*6777b538SAndroid Build Coastguard Worker shutil.move(src_file, dst_file) 354*6777b538SAndroid Build Coastguard Worker path_info.RegisterRename( 355*6777b538SAndroid Build Coastguard Worker os.path.relpath(src_file, res_root), 356*6777b538SAndroid Build Coastguard Worker os.path.relpath(dst_file, res_root)) 357*6777b538SAndroid Build Coastguard Worker 358*6777b538SAndroid Build Coastguard Worker 359*6777b538SAndroid Build Coastguard Workerdef _DeterminePlatformVersion(aapt2_path, jar_candidates): 360*6777b538SAndroid Build Coastguard Worker def maybe_extract_version(j): 361*6777b538SAndroid Build Coastguard Worker try: 362*6777b538SAndroid Build Coastguard Worker return resource_utils.ExtractBinaryManifestValues(aapt2_path, j) 363*6777b538SAndroid Build Coastguard Worker except build_utils.CalledProcessError: 364*6777b538SAndroid Build Coastguard Worker return None 365*6777b538SAndroid Build Coastguard Worker 366*6777b538SAndroid Build Coastguard Worker def is_sdk_jar(jar_name): 367*6777b538SAndroid Build Coastguard Worker if jar_name in ('android.jar', 'android_system.jar'): 368*6777b538SAndroid Build Coastguard Worker return True 369*6777b538SAndroid Build Coastguard Worker # Robolectric jar looks a bit different. 370*6777b538SAndroid Build Coastguard Worker return 'android-all' in jar_name and 'robolectric' in jar_name 371*6777b538SAndroid Build Coastguard Worker 372*6777b538SAndroid Build Coastguard Worker android_sdk_jars = [ 373*6777b538SAndroid Build Coastguard Worker j for j in jar_candidates if is_sdk_jar(os.path.basename(j)) 374*6777b538SAndroid Build Coastguard Worker ] 375*6777b538SAndroid Build Coastguard Worker extract_all = [maybe_extract_version(j) for j in android_sdk_jars] 376*6777b538SAndroid Build Coastguard Worker extract_all = [x for x in extract_all if x] 377*6777b538SAndroid Build Coastguard Worker if len(extract_all) == 0: 378*6777b538SAndroid Build Coastguard Worker raise Exception( 379*6777b538SAndroid Build Coastguard Worker 'Unable to find android SDK jar among candidates: %s' 380*6777b538SAndroid Build Coastguard Worker % ', '.join(android_sdk_jars)) 381*6777b538SAndroid Build Coastguard Worker if len(extract_all) > 1: 382*6777b538SAndroid Build Coastguard Worker raise Exception( 383*6777b538SAndroid Build Coastguard Worker 'Found multiple android SDK jars among candidates: %s' 384*6777b538SAndroid Build Coastguard Worker % ', '.join(android_sdk_jars)) 385*6777b538SAndroid Build Coastguard Worker platform_version_code, platform_version_name = extract_all.pop()[:2] 386*6777b538SAndroid Build Coastguard Worker return platform_version_code, platform_version_name 387*6777b538SAndroid Build Coastguard Worker 388*6777b538SAndroid Build Coastguard Worker 389*6777b538SAndroid Build Coastguard Workerdef _FixManifest(options, temp_dir): 390*6777b538SAndroid Build Coastguard Worker """Fix the APK's AndroidManifest.xml. 391*6777b538SAndroid Build Coastguard Worker 392*6777b538SAndroid Build Coastguard Worker This adds any missing namespaces for 'android' and 'tools', and 393*6777b538SAndroid Build Coastguard Worker sets certains elements like 'platformBuildVersionCode' or 394*6777b538SAndroid Build Coastguard Worker 'android:debuggable' depending on the content of |options|. 395*6777b538SAndroid Build Coastguard Worker 396*6777b538SAndroid Build Coastguard Worker Args: 397*6777b538SAndroid Build Coastguard Worker options: The command-line arguments tuple. 398*6777b538SAndroid Build Coastguard Worker temp_dir: A temporary directory where the fixed manifest will be written to. 399*6777b538SAndroid Build Coastguard Worker Returns: 400*6777b538SAndroid Build Coastguard Worker Tuple of: 401*6777b538SAndroid Build Coastguard Worker * Manifest path within |temp_dir|. 402*6777b538SAndroid Build Coastguard Worker * Original package_name. 403*6777b538SAndroid Build Coastguard Worker * Manifest package name. 404*6777b538SAndroid Build Coastguard Worker """ 405*6777b538SAndroid Build Coastguard Worker doc, manifest_node, app_node = manifest_utils.ParseManifest( 406*6777b538SAndroid Build Coastguard Worker options.android_manifest) 407*6777b538SAndroid Build Coastguard Worker 408*6777b538SAndroid Build Coastguard Worker # merge_manifest.py also sets package & <uses-sdk>. We may want to ensure 409*6777b538SAndroid Build Coastguard Worker # manifest merger is always enabled and remove these command-line arguments. 410*6777b538SAndroid Build Coastguard Worker manifest_utils.SetUsesSdk(manifest_node, options.target_sdk_version, 411*6777b538SAndroid Build Coastguard Worker options.min_sdk_version, options.max_sdk_version) 412*6777b538SAndroid Build Coastguard Worker orig_package = manifest_node.get('package') or options.manifest_package 413*6777b538SAndroid Build Coastguard Worker fixed_package = (options.arsc_package_name or options.manifest_package 414*6777b538SAndroid Build Coastguard Worker or orig_package) 415*6777b538SAndroid Build Coastguard Worker manifest_node.set('package', fixed_package) 416*6777b538SAndroid Build Coastguard Worker 417*6777b538SAndroid Build Coastguard Worker platform_version_code, platform_version_name = _DeterminePlatformVersion( 418*6777b538SAndroid Build Coastguard Worker options.aapt2_path, options.include_resources) 419*6777b538SAndroid Build Coastguard Worker manifest_node.set('platformBuildVersionCode', platform_version_code) 420*6777b538SAndroid Build Coastguard Worker manifest_node.set('platformBuildVersionName', platform_version_name) 421*6777b538SAndroid Build Coastguard Worker if options.version_code: 422*6777b538SAndroid Build Coastguard Worker manifest_utils.NamespacedSet(manifest_node, 'versionCode', 423*6777b538SAndroid Build Coastguard Worker options.version_code) 424*6777b538SAndroid Build Coastguard Worker if options.version_name: 425*6777b538SAndroid Build Coastguard Worker manifest_utils.NamespacedSet(manifest_node, 'versionName', 426*6777b538SAndroid Build Coastguard Worker options.version_name) 427*6777b538SAndroid Build Coastguard Worker if options.debuggable: 428*6777b538SAndroid Build Coastguard Worker manifest_utils.NamespacedSet(app_node, 'debuggable', 'true') 429*6777b538SAndroid Build Coastguard Worker 430*6777b538SAndroid Build Coastguard Worker if options.uses_split: 431*6777b538SAndroid Build Coastguard Worker uses_split = ElementTree.SubElement(manifest_node, 'uses-split') 432*6777b538SAndroid Build Coastguard Worker manifest_utils.NamespacedSet(uses_split, 'name', options.uses_split) 433*6777b538SAndroid Build Coastguard Worker 434*6777b538SAndroid Build Coastguard Worker # Make sure the min-sdk condition is not less than the min-sdk of the bundle. 435*6777b538SAndroid Build Coastguard Worker for min_sdk_node in manifest_node.iter('{%s}min-sdk' % 436*6777b538SAndroid Build Coastguard Worker manifest_utils.DIST_NAMESPACE): 437*6777b538SAndroid Build Coastguard Worker dist_value = '{%s}value' % manifest_utils.DIST_NAMESPACE 438*6777b538SAndroid Build Coastguard Worker if int(min_sdk_node.get(dist_value)) < int(options.min_sdk_version): 439*6777b538SAndroid Build Coastguard Worker min_sdk_node.set(dist_value, options.min_sdk_version) 440*6777b538SAndroid Build Coastguard Worker 441*6777b538SAndroid Build Coastguard Worker debug_manifest_path = os.path.join(temp_dir, 'AndroidManifest.xml') 442*6777b538SAndroid Build Coastguard Worker manifest_utils.SaveManifest(doc, debug_manifest_path) 443*6777b538SAndroid Build Coastguard Worker return debug_manifest_path, orig_package, fixed_package 444*6777b538SAndroid Build Coastguard Worker 445*6777b538SAndroid Build Coastguard Worker 446*6777b538SAndroid Build Coastguard Workerdef _CreateKeepPredicate(resource_exclusion_regex, 447*6777b538SAndroid Build Coastguard Worker resource_exclusion_exceptions): 448*6777b538SAndroid Build Coastguard Worker """Return a predicate lambda to determine which resource files to keep. 449*6777b538SAndroid Build Coastguard Worker 450*6777b538SAndroid Build Coastguard Worker Args: 451*6777b538SAndroid Build Coastguard Worker resource_exclusion_regex: A regular expression describing all resources 452*6777b538SAndroid Build Coastguard Worker to exclude, except if they are mip-maps, or if they are listed 453*6777b538SAndroid Build Coastguard Worker in |resource_exclusion_exceptions|. 454*6777b538SAndroid Build Coastguard Worker resource_exclusion_exceptions: A list of glob patterns corresponding 455*6777b538SAndroid Build Coastguard Worker to exceptions to the |resource_exclusion_regex|. 456*6777b538SAndroid Build Coastguard Worker Returns: 457*6777b538SAndroid Build Coastguard Worker A lambda that takes a path, and returns true if the corresponding file 458*6777b538SAndroid Build Coastguard Worker must be kept. 459*6777b538SAndroid Build Coastguard Worker """ 460*6777b538SAndroid Build Coastguard Worker predicate = lambda path: os.path.basename(path)[0] != '.' 461*6777b538SAndroid Build Coastguard Worker if resource_exclusion_regex == '': 462*6777b538SAndroid Build Coastguard Worker # Do not extract dotfiles (e.g. ".gitkeep"). aapt ignores them anyways. 463*6777b538SAndroid Build Coastguard Worker return predicate 464*6777b538SAndroid Build Coastguard Worker 465*6777b538SAndroid Build Coastguard Worker # A simple predicate that only removes (returns False for) paths covered by 466*6777b538SAndroid Build Coastguard Worker # the exclusion regex or listed as exceptions. 467*6777b538SAndroid Build Coastguard Worker return lambda path: ( 468*6777b538SAndroid Build Coastguard Worker not re.search(resource_exclusion_regex, path) or 469*6777b538SAndroid Build Coastguard Worker build_utils.MatchesGlob(path, resource_exclusion_exceptions)) 470*6777b538SAndroid Build Coastguard Worker 471*6777b538SAndroid Build Coastguard Worker 472*6777b538SAndroid Build Coastguard Workerdef _ComputeSha1(path): 473*6777b538SAndroid Build Coastguard Worker with open(path, 'rb') as f: 474*6777b538SAndroid Build Coastguard Worker data = f.read() 475*6777b538SAndroid Build Coastguard Worker return hashlib.sha1(data).hexdigest() 476*6777b538SAndroid Build Coastguard Worker 477*6777b538SAndroid Build Coastguard Worker 478*6777b538SAndroid Build Coastguard Workerdef _ConvertToWebPSingle(png_path, cwebp_binary, cwebp_version, webp_cache_dir): 479*6777b538SAndroid Build Coastguard Worker sha1_hash = _ComputeSha1(png_path) 480*6777b538SAndroid Build Coastguard Worker 481*6777b538SAndroid Build Coastguard Worker # The set of arguments that will appear in the cache key. 482*6777b538SAndroid Build Coastguard Worker quality_args = ['-m', '6', '-q', '100', '-lossless'] 483*6777b538SAndroid Build Coastguard Worker 484*6777b538SAndroid Build Coastguard Worker webp_cache_path = os.path.join( 485*6777b538SAndroid Build Coastguard Worker webp_cache_dir, '{}-{}-{}'.format(sha1_hash, cwebp_version, 486*6777b538SAndroid Build Coastguard Worker ''.join(quality_args))) 487*6777b538SAndroid Build Coastguard Worker # No need to add .webp. Android can load images fine without them. 488*6777b538SAndroid Build Coastguard Worker webp_path = os.path.splitext(png_path)[0] 489*6777b538SAndroid Build Coastguard Worker 490*6777b538SAndroid Build Coastguard Worker cache_hit = os.path.exists(webp_cache_path) 491*6777b538SAndroid Build Coastguard Worker if cache_hit: 492*6777b538SAndroid Build Coastguard Worker os.link(webp_cache_path, webp_path) 493*6777b538SAndroid Build Coastguard Worker else: 494*6777b538SAndroid Build Coastguard Worker # We place the generated webp image to webp_path, instead of in the 495*6777b538SAndroid Build Coastguard Worker # webp_cache_dir to avoid concurrency issues. 496*6777b538SAndroid Build Coastguard Worker args = [cwebp_binary, png_path, '-o', webp_path, '-quiet'] + quality_args 497*6777b538SAndroid Build Coastguard Worker subprocess.check_call(args) 498*6777b538SAndroid Build Coastguard Worker 499*6777b538SAndroid Build Coastguard Worker try: 500*6777b538SAndroid Build Coastguard Worker os.link(webp_path, webp_cache_path) 501*6777b538SAndroid Build Coastguard Worker except OSError: 502*6777b538SAndroid Build Coastguard Worker # Because of concurrent run, a webp image may already exists in 503*6777b538SAndroid Build Coastguard Worker # webp_cache_path. 504*6777b538SAndroid Build Coastguard Worker pass 505*6777b538SAndroid Build Coastguard Worker 506*6777b538SAndroid Build Coastguard Worker os.remove(png_path) 507*6777b538SAndroid Build Coastguard Worker original_dir = os.path.dirname(os.path.dirname(png_path)) 508*6777b538SAndroid Build Coastguard Worker rename_tuple = (os.path.relpath(png_path, original_dir), 509*6777b538SAndroid Build Coastguard Worker os.path.relpath(webp_path, original_dir)) 510*6777b538SAndroid Build Coastguard Worker return rename_tuple, cache_hit 511*6777b538SAndroid Build Coastguard Worker 512*6777b538SAndroid Build Coastguard Worker 513*6777b538SAndroid Build Coastguard Workerdef _ConvertToWebP(cwebp_binary, png_paths, path_info, webp_cache_dir): 514*6777b538SAndroid Build Coastguard Worker cwebp_version = subprocess.check_output([cwebp_binary, '-version']).rstrip() 515*6777b538SAndroid Build Coastguard Worker shard_args = [(f, ) for f in png_paths 516*6777b538SAndroid Build Coastguard Worker if not _PNG_WEBP_EXCLUSION_PATTERN.match(f)] 517*6777b538SAndroid Build Coastguard Worker 518*6777b538SAndroid Build Coastguard Worker build_utils.MakeDirectory(webp_cache_dir) 519*6777b538SAndroid Build Coastguard Worker results = parallel.BulkForkAndCall(_ConvertToWebPSingle, 520*6777b538SAndroid Build Coastguard Worker shard_args, 521*6777b538SAndroid Build Coastguard Worker cwebp_binary=cwebp_binary, 522*6777b538SAndroid Build Coastguard Worker cwebp_version=cwebp_version, 523*6777b538SAndroid Build Coastguard Worker webp_cache_dir=webp_cache_dir) 524*6777b538SAndroid Build Coastguard Worker total_cache_hits = 0 525*6777b538SAndroid Build Coastguard Worker for rename_tuple, cache_hit in results: 526*6777b538SAndroid Build Coastguard Worker path_info.RegisterRename(*rename_tuple) 527*6777b538SAndroid Build Coastguard Worker total_cache_hits += int(cache_hit) 528*6777b538SAndroid Build Coastguard Worker 529*6777b538SAndroid Build Coastguard Worker logging.debug('png->webp cache: %d/%d', total_cache_hits, len(shard_args)) 530*6777b538SAndroid Build Coastguard Worker 531*6777b538SAndroid Build Coastguard Worker 532*6777b538SAndroid Build Coastguard Workerdef _RemoveImageExtensions(directory, path_info): 533*6777b538SAndroid Build Coastguard Worker """Remove extensions from image files in the passed directory. 534*6777b538SAndroid Build Coastguard Worker 535*6777b538SAndroid Build Coastguard Worker This reduces binary size but does not affect android's ability to load the 536*6777b538SAndroid Build Coastguard Worker images. 537*6777b538SAndroid Build Coastguard Worker """ 538*6777b538SAndroid Build Coastguard Worker for f in _IterFiles(directory): 539*6777b538SAndroid Build Coastguard Worker if (f.endswith('.png') or f.endswith('.webp')) and not f.endswith('.9.png'): 540*6777b538SAndroid Build Coastguard Worker path_with_extension = f 541*6777b538SAndroid Build Coastguard Worker path_no_extension = os.path.splitext(path_with_extension)[0] 542*6777b538SAndroid Build Coastguard Worker if path_no_extension != path_with_extension: 543*6777b538SAndroid Build Coastguard Worker shutil.move(path_with_extension, path_no_extension) 544*6777b538SAndroid Build Coastguard Worker path_info.RegisterRename( 545*6777b538SAndroid Build Coastguard Worker os.path.relpath(path_with_extension, directory), 546*6777b538SAndroid Build Coastguard Worker os.path.relpath(path_no_extension, directory)) 547*6777b538SAndroid Build Coastguard Worker 548*6777b538SAndroid Build Coastguard Worker 549*6777b538SAndroid Build Coastguard Workerdef _CompileSingleDep(index, dep_subdir, keep_predicate, aapt2_path, 550*6777b538SAndroid Build Coastguard Worker partials_dir): 551*6777b538SAndroid Build Coastguard Worker unique_name = '{}_{}'.format(index, os.path.basename(dep_subdir)) 552*6777b538SAndroid Build Coastguard Worker partial_path = os.path.join(partials_dir, '{}.zip'.format(unique_name)) 553*6777b538SAndroid Build Coastguard Worker 554*6777b538SAndroid Build Coastguard Worker compile_command = [ 555*6777b538SAndroid Build Coastguard Worker aapt2_path, 556*6777b538SAndroid Build Coastguard Worker 'compile', 557*6777b538SAndroid Build Coastguard Worker # TODO(wnwen): Turn this on once aapt2 forces 9-patch to be crunched. 558*6777b538SAndroid Build Coastguard Worker # '--no-crunch', 559*6777b538SAndroid Build Coastguard Worker '--dir', 560*6777b538SAndroid Build Coastguard Worker dep_subdir, 561*6777b538SAndroid Build Coastguard Worker '-o', 562*6777b538SAndroid Build Coastguard Worker partial_path 563*6777b538SAndroid Build Coastguard Worker ] 564*6777b538SAndroid Build Coastguard Worker 565*6777b538SAndroid Build Coastguard Worker # There are resources targeting API-versions lower than our minapi. For 566*6777b538SAndroid Build Coastguard Worker # various reasons it's easier to let aapt2 ignore these than for us to 567*6777b538SAndroid Build Coastguard Worker # remove them from our build (e.g. it's from a 3rd party library). 568*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput( 569*6777b538SAndroid Build Coastguard Worker compile_command, 570*6777b538SAndroid Build Coastguard Worker stderr_filter=lambda output: build_utils.FilterLines( 571*6777b538SAndroid Build Coastguard Worker output, r'ignoring configuration .* for (styleable|attribute)')) 572*6777b538SAndroid Build Coastguard Worker 573*6777b538SAndroid Build Coastguard Worker # Filtering these files is expensive, so only apply filters to the partials 574*6777b538SAndroid Build Coastguard Worker # that have been explicitly targeted. 575*6777b538SAndroid Build Coastguard Worker if keep_predicate: 576*6777b538SAndroid Build Coastguard Worker logging.debug('Applying .arsc filtering to %s', dep_subdir) 577*6777b538SAndroid Build Coastguard Worker protoresources.StripUnwantedResources(partial_path, keep_predicate) 578*6777b538SAndroid Build Coastguard Worker return partial_path 579*6777b538SAndroid Build Coastguard Worker 580*6777b538SAndroid Build Coastguard Worker 581*6777b538SAndroid Build Coastguard Workerdef _CreateValuesKeepPredicate(exclusion_rules, dep_subdir): 582*6777b538SAndroid Build Coastguard Worker patterns = [ 583*6777b538SAndroid Build Coastguard Worker x[1] for x in exclusion_rules 584*6777b538SAndroid Build Coastguard Worker if build_utils.MatchesGlob(dep_subdir, [x[0]]) 585*6777b538SAndroid Build Coastguard Worker ] 586*6777b538SAndroid Build Coastguard Worker if not patterns: 587*6777b538SAndroid Build Coastguard Worker return None 588*6777b538SAndroid Build Coastguard Worker 589*6777b538SAndroid Build Coastguard Worker regexes = [re.compile(p) for p in patterns] 590*6777b538SAndroid Build Coastguard Worker return lambda x: not any(r.search(x) for r in regexes) 591*6777b538SAndroid Build Coastguard Worker 592*6777b538SAndroid Build Coastguard Worker 593*6777b538SAndroid Build Coastguard Workerdef _CompileDeps(aapt2_path, dep_subdirs, dep_subdir_overlay_set, temp_dir, 594*6777b538SAndroid Build Coastguard Worker exclusion_rules): 595*6777b538SAndroid Build Coastguard Worker partials_dir = os.path.join(temp_dir, 'partials') 596*6777b538SAndroid Build Coastguard Worker build_utils.MakeDirectory(partials_dir) 597*6777b538SAndroid Build Coastguard Worker 598*6777b538SAndroid Build Coastguard Worker job_params = [(i, dep_subdir, 599*6777b538SAndroid Build Coastguard Worker _CreateValuesKeepPredicate(exclusion_rules, dep_subdir)) 600*6777b538SAndroid Build Coastguard Worker for i, dep_subdir in enumerate(dep_subdirs)] 601*6777b538SAndroid Build Coastguard Worker 602*6777b538SAndroid Build Coastguard Worker # Filtering is slow, so ensure jobs with keep_predicate are started first. 603*6777b538SAndroid Build Coastguard Worker job_params.sort(key=lambda x: not x[2]) 604*6777b538SAndroid Build Coastguard Worker partials = list( 605*6777b538SAndroid Build Coastguard Worker parallel.BulkForkAndCall(_CompileSingleDep, 606*6777b538SAndroid Build Coastguard Worker job_params, 607*6777b538SAndroid Build Coastguard Worker aapt2_path=aapt2_path, 608*6777b538SAndroid Build Coastguard Worker partials_dir=partials_dir)) 609*6777b538SAndroid Build Coastguard Worker 610*6777b538SAndroid Build Coastguard Worker partials_cmd = list() 611*6777b538SAndroid Build Coastguard Worker for i, partial in enumerate(partials): 612*6777b538SAndroid Build Coastguard Worker dep_subdir = job_params[i][1] 613*6777b538SAndroid Build Coastguard Worker if dep_subdir in dep_subdir_overlay_set: 614*6777b538SAndroid Build Coastguard Worker partials_cmd += ['-R'] 615*6777b538SAndroid Build Coastguard Worker partials_cmd += [partial] 616*6777b538SAndroid Build Coastguard Worker return partials_cmd 617*6777b538SAndroid Build Coastguard Worker 618*6777b538SAndroid Build Coastguard Worker 619*6777b538SAndroid Build Coastguard Workerdef _CreateResourceInfoFile(path_info, info_path, dependencies_res_zips): 620*6777b538SAndroid Build Coastguard Worker for zip_file in dependencies_res_zips: 621*6777b538SAndroid Build Coastguard Worker zip_info_file_path = zip_file + '.info' 622*6777b538SAndroid Build Coastguard Worker if os.path.exists(zip_info_file_path): 623*6777b538SAndroid Build Coastguard Worker path_info.MergeInfoFile(zip_info_file_path) 624*6777b538SAndroid Build Coastguard Worker path_info.Write(info_path) 625*6777b538SAndroid Build Coastguard Worker 626*6777b538SAndroid Build Coastguard Worker 627*6777b538SAndroid Build Coastguard Workerdef _RemoveUnwantedLocalizedStrings(dep_subdirs, options): 628*6777b538SAndroid Build Coastguard Worker """Remove localized strings that should not go into the final output. 629*6777b538SAndroid Build Coastguard Worker 630*6777b538SAndroid Build Coastguard Worker Args: 631*6777b538SAndroid Build Coastguard Worker dep_subdirs: List of resource dependency directories. 632*6777b538SAndroid Build Coastguard Worker options: Command-line options namespace. 633*6777b538SAndroid Build Coastguard Worker """ 634*6777b538SAndroid Build Coastguard Worker # Collect locale and file paths from the existing subdirs. 635*6777b538SAndroid Build Coastguard Worker # The following variable maps Android locale names to 636*6777b538SAndroid Build Coastguard Worker # sets of corresponding xml file paths. 637*6777b538SAndroid Build Coastguard Worker locale_to_files_map = collections.defaultdict(set) 638*6777b538SAndroid Build Coastguard Worker for directory in dep_subdirs: 639*6777b538SAndroid Build Coastguard Worker for f in _IterFiles(directory): 640*6777b538SAndroid Build Coastguard Worker locale = resource_utils.FindLocaleInStringResourceFilePath(f) 641*6777b538SAndroid Build Coastguard Worker if locale: 642*6777b538SAndroid Build Coastguard Worker locale_to_files_map[locale].add(f) 643*6777b538SAndroid Build Coastguard Worker 644*6777b538SAndroid Build Coastguard Worker all_locales = set(locale_to_files_map) 645*6777b538SAndroid Build Coastguard Worker 646*6777b538SAndroid Build Coastguard Worker # Set A: wanted locales, either all of them or the 647*6777b538SAndroid Build Coastguard Worker # list provided by --locale-allowlist. 648*6777b538SAndroid Build Coastguard Worker wanted_locales = all_locales 649*6777b538SAndroid Build Coastguard Worker if options.locale_allowlist: 650*6777b538SAndroid Build Coastguard Worker wanted_locales = _ToAndroidLocales(options.locale_allowlist) 651*6777b538SAndroid Build Coastguard Worker 652*6777b538SAndroid Build Coastguard Worker # Set B: shared resources locales, which is either set A 653*6777b538SAndroid Build Coastguard Worker # or the list provided by --shared-resources-allowlist-locales 654*6777b538SAndroid Build Coastguard Worker shared_resources_locales = wanted_locales 655*6777b538SAndroid Build Coastguard Worker shared_names_allowlist = set() 656*6777b538SAndroid Build Coastguard Worker if options.shared_resources_allowlist_locales: 657*6777b538SAndroid Build Coastguard Worker shared_names_allowlist = set( 658*6777b538SAndroid Build Coastguard Worker resource_utils.GetRTxtStringResourceNames( 659*6777b538SAndroid Build Coastguard Worker options.shared_resources_allowlist)) 660*6777b538SAndroid Build Coastguard Worker 661*6777b538SAndroid Build Coastguard Worker shared_resources_locales = _ToAndroidLocales( 662*6777b538SAndroid Build Coastguard Worker options.shared_resources_allowlist_locales) 663*6777b538SAndroid Build Coastguard Worker 664*6777b538SAndroid Build Coastguard Worker # Remove any file that belongs to a locale not covered by 665*6777b538SAndroid Build Coastguard Worker # either A or B. 666*6777b538SAndroid Build Coastguard Worker removable_locales = (all_locales - wanted_locales - shared_resources_locales) 667*6777b538SAndroid Build Coastguard Worker for locale in removable_locales: 668*6777b538SAndroid Build Coastguard Worker for path in locale_to_files_map[locale]: 669*6777b538SAndroid Build Coastguard Worker os.remove(path) 670*6777b538SAndroid Build Coastguard Worker 671*6777b538SAndroid Build Coastguard Worker # For any locale in B but not in A, only keep the shared 672*6777b538SAndroid Build Coastguard Worker # resource strings in each file. 673*6777b538SAndroid Build Coastguard Worker for locale in shared_resources_locales - wanted_locales: 674*6777b538SAndroid Build Coastguard Worker for path in locale_to_files_map[locale]: 675*6777b538SAndroid Build Coastguard Worker resource_utils.FilterAndroidResourceStringsXml( 676*6777b538SAndroid Build Coastguard Worker path, lambda x: x in shared_names_allowlist) 677*6777b538SAndroid Build Coastguard Worker 678*6777b538SAndroid Build Coastguard Worker # For any locale in A but not in B, only keep the strings 679*6777b538SAndroid Build Coastguard Worker # that are _not_ from shared resources in the file. 680*6777b538SAndroid Build Coastguard Worker for locale in wanted_locales - shared_resources_locales: 681*6777b538SAndroid Build Coastguard Worker for path in locale_to_files_map[locale]: 682*6777b538SAndroid Build Coastguard Worker resource_utils.FilterAndroidResourceStringsXml( 683*6777b538SAndroid Build Coastguard Worker path, lambda x: x not in shared_names_allowlist) 684*6777b538SAndroid Build Coastguard Worker 685*6777b538SAndroid Build Coastguard Worker 686*6777b538SAndroid Build Coastguard Workerdef _FilterResourceFiles(dep_subdirs, keep_predicate): 687*6777b538SAndroid Build Coastguard Worker # Create a function that selects which resource files should be packaged 688*6777b538SAndroid Build Coastguard Worker # into the final output. Any file that does not pass the predicate will 689*6777b538SAndroid Build Coastguard Worker # be removed below. 690*6777b538SAndroid Build Coastguard Worker png_paths = [] 691*6777b538SAndroid Build Coastguard Worker for directory in dep_subdirs: 692*6777b538SAndroid Build Coastguard Worker for f in _IterFiles(directory): 693*6777b538SAndroid Build Coastguard Worker if not keep_predicate(f): 694*6777b538SAndroid Build Coastguard Worker os.remove(f) 695*6777b538SAndroid Build Coastguard Worker elif f.endswith('.png'): 696*6777b538SAndroid Build Coastguard Worker png_paths.append(f) 697*6777b538SAndroid Build Coastguard Worker 698*6777b538SAndroid Build Coastguard Worker return png_paths 699*6777b538SAndroid Build Coastguard Worker 700*6777b538SAndroid Build Coastguard Worker 701*6777b538SAndroid Build Coastguard Workerdef _PackageApk(options, build): 702*6777b538SAndroid Build Coastguard Worker """Compile and link resources with aapt2. 703*6777b538SAndroid Build Coastguard Worker 704*6777b538SAndroid Build Coastguard Worker Args: 705*6777b538SAndroid Build Coastguard Worker options: The command-line options. 706*6777b538SAndroid Build Coastguard Worker build: BuildContext object. 707*6777b538SAndroid Build Coastguard Worker Returns: 708*6777b538SAndroid Build Coastguard Worker The manifest package name for the APK. 709*6777b538SAndroid Build Coastguard Worker """ 710*6777b538SAndroid Build Coastguard Worker logging.debug('Extracting resource .zips') 711*6777b538SAndroid Build Coastguard Worker dep_subdirs = [] 712*6777b538SAndroid Build Coastguard Worker dep_subdir_overlay_set = set() 713*6777b538SAndroid Build Coastguard Worker for dependency_res_zip in options.dependencies_res_zips: 714*6777b538SAndroid Build Coastguard Worker extracted_dep_subdirs = resource_utils.ExtractDeps([dependency_res_zip], 715*6777b538SAndroid Build Coastguard Worker build.deps_dir) 716*6777b538SAndroid Build Coastguard Worker dep_subdirs += extracted_dep_subdirs 717*6777b538SAndroid Build Coastguard Worker if dependency_res_zip in options.dependencies_res_zip_overlays: 718*6777b538SAndroid Build Coastguard Worker dep_subdir_overlay_set.update(extracted_dep_subdirs) 719*6777b538SAndroid Build Coastguard Worker 720*6777b538SAndroid Build Coastguard Worker logging.debug('Applying locale transformations') 721*6777b538SAndroid Build Coastguard Worker path_info = resource_utils.ResourceInfoFile() 722*6777b538SAndroid Build Coastguard Worker _RenameLocaleResourceDirs(dep_subdirs, path_info) 723*6777b538SAndroid Build Coastguard Worker 724*6777b538SAndroid Build Coastguard Worker logging.debug('Applying file-based exclusions') 725*6777b538SAndroid Build Coastguard Worker keep_predicate = _CreateKeepPredicate(options.resource_exclusion_regex, 726*6777b538SAndroid Build Coastguard Worker options.resource_exclusion_exceptions) 727*6777b538SAndroid Build Coastguard Worker png_paths = _FilterResourceFiles(dep_subdirs, keep_predicate) 728*6777b538SAndroid Build Coastguard Worker 729*6777b538SAndroid Build Coastguard Worker if options.locale_allowlist or options.shared_resources_allowlist_locales: 730*6777b538SAndroid Build Coastguard Worker logging.debug('Applying locale-based string exclusions') 731*6777b538SAndroid Build Coastguard Worker _RemoveUnwantedLocalizedStrings(dep_subdirs, options) 732*6777b538SAndroid Build Coastguard Worker 733*6777b538SAndroid Build Coastguard Worker if png_paths and options.png_to_webp: 734*6777b538SAndroid Build Coastguard Worker logging.debug('Converting png->webp') 735*6777b538SAndroid Build Coastguard Worker _ConvertToWebP(options.webp_binary, png_paths, path_info, 736*6777b538SAndroid Build Coastguard Worker options.webp_cache_dir) 737*6777b538SAndroid Build Coastguard Worker logging.debug('Applying drawable transformations') 738*6777b538SAndroid Build Coastguard Worker for directory in dep_subdirs: 739*6777b538SAndroid Build Coastguard Worker _MoveImagesToNonMdpiFolders(directory, path_info) 740*6777b538SAndroid Build Coastguard Worker _RemoveImageExtensions(directory, path_info) 741*6777b538SAndroid Build Coastguard Worker 742*6777b538SAndroid Build Coastguard Worker logging.debug('Running aapt2 compile') 743*6777b538SAndroid Build Coastguard Worker exclusion_rules = [x.split(':', 1) for x in options.values_filter_rules] 744*6777b538SAndroid Build Coastguard Worker partials = _CompileDeps(options.aapt2_path, dep_subdirs, 745*6777b538SAndroid Build Coastguard Worker dep_subdir_overlay_set, build.temp_dir, 746*6777b538SAndroid Build Coastguard Worker exclusion_rules) 747*6777b538SAndroid Build Coastguard Worker 748*6777b538SAndroid Build Coastguard Worker link_command = [ 749*6777b538SAndroid Build Coastguard Worker options.aapt2_path, 750*6777b538SAndroid Build Coastguard Worker 'link', 751*6777b538SAndroid Build Coastguard Worker '--auto-add-overlay', 752*6777b538SAndroid Build Coastguard Worker '--no-version-vectors', 753*6777b538SAndroid Build Coastguard Worker '--output-text-symbols', 754*6777b538SAndroid Build Coastguard Worker build.r_txt_path, 755*6777b538SAndroid Build Coastguard Worker ] 756*6777b538SAndroid Build Coastguard Worker 757*6777b538SAndroid Build Coastguard Worker for j in options.include_resources: 758*6777b538SAndroid Build Coastguard Worker link_command += ['-I', j] 759*6777b538SAndroid Build Coastguard Worker if options.proguard_file: 760*6777b538SAndroid Build Coastguard Worker link_command += ['--proguard', build.proguard_path] 761*6777b538SAndroid Build Coastguard Worker link_command += ['--proguard-minimal-keep-rules'] 762*6777b538SAndroid Build Coastguard Worker if options.emit_ids_out: 763*6777b538SAndroid Build Coastguard Worker link_command += ['--emit-ids', build.emit_ids_path] 764*6777b538SAndroid Build Coastguard Worker 765*6777b538SAndroid Build Coastguard Worker # Note: only one of --proto-format, --shared-lib or --app-as-shared-lib 766*6777b538SAndroid Build Coastguard Worker # can be used with recent versions of aapt2. 767*6777b538SAndroid Build Coastguard Worker if options.shared_resources: 768*6777b538SAndroid Build Coastguard Worker link_command.append('--shared-lib') 769*6777b538SAndroid Build Coastguard Worker 770*6777b538SAndroid Build Coastguard Worker if int(options.min_sdk_version) > 21: 771*6777b538SAndroid Build Coastguard Worker link_command.append('--no-xml-namespaces') 772*6777b538SAndroid Build Coastguard Worker 773*6777b538SAndroid Build Coastguard Worker if options.package_id: 774*6777b538SAndroid Build Coastguard Worker link_command += [ 775*6777b538SAndroid Build Coastguard Worker '--package-id', 776*6777b538SAndroid Build Coastguard Worker '0x%02x' % options.package_id, 777*6777b538SAndroid Build Coastguard Worker '--allow-reserved-package-id', 778*6777b538SAndroid Build Coastguard Worker ] 779*6777b538SAndroid Build Coastguard Worker 780*6777b538SAndroid Build Coastguard Worker fixed_manifest, desired_manifest_package_name, fixed_manifest_package = ( 781*6777b538SAndroid Build Coastguard Worker _FixManifest(options, build.temp_dir)) 782*6777b538SAndroid Build Coastguard Worker if options.rename_manifest_package: 783*6777b538SAndroid Build Coastguard Worker desired_manifest_package_name = options.rename_manifest_package 784*6777b538SAndroid Build Coastguard Worker 785*6777b538SAndroid Build Coastguard Worker link_command += [ 786*6777b538SAndroid Build Coastguard Worker '--manifest', fixed_manifest, '--rename-manifest-package', 787*6777b538SAndroid Build Coastguard Worker desired_manifest_package_name 788*6777b538SAndroid Build Coastguard Worker ] 789*6777b538SAndroid Build Coastguard Worker 790*6777b538SAndroid Build Coastguard Worker if options.package_id is not None: 791*6777b538SAndroid Build Coastguard Worker package_id = options.package_id 792*6777b538SAndroid Build Coastguard Worker elif options.shared_resources: 793*6777b538SAndroid Build Coastguard Worker package_id = 0 794*6777b538SAndroid Build Coastguard Worker else: 795*6777b538SAndroid Build Coastguard Worker package_id = 0x7f 796*6777b538SAndroid Build Coastguard Worker _CreateStableIdsFile(options.use_resource_ids_path, build.stable_ids_path, 797*6777b538SAndroid Build Coastguard Worker fixed_manifest_package, package_id) 798*6777b538SAndroid Build Coastguard Worker link_command += ['--stable-ids', build.stable_ids_path] 799*6777b538SAndroid Build Coastguard Worker 800*6777b538SAndroid Build Coastguard Worker link_command += partials 801*6777b538SAndroid Build Coastguard Worker 802*6777b538SAndroid Build Coastguard Worker # We always create a binary arsc file first, then convert to proto, so flags 803*6777b538SAndroid Build Coastguard Worker # such as --shared-lib can be supported. 804*6777b538SAndroid Build Coastguard Worker link_command += ['-o', build.arsc_path] 805*6777b538SAndroid Build Coastguard Worker 806*6777b538SAndroid Build Coastguard Worker logging.debug('Starting: aapt2 link') 807*6777b538SAndroid Build Coastguard Worker link_proc = subprocess.Popen(link_command) 808*6777b538SAndroid Build Coastguard Worker 809*6777b538SAndroid Build Coastguard Worker # Create .res.info file in parallel. 810*6777b538SAndroid Build Coastguard Worker if options.info_path: 811*6777b538SAndroid Build Coastguard Worker logging.debug('Creating .res.info file') 812*6777b538SAndroid Build Coastguard Worker _CreateResourceInfoFile(path_info, build.info_path, 813*6777b538SAndroid Build Coastguard Worker options.dependencies_res_zips) 814*6777b538SAndroid Build Coastguard Worker 815*6777b538SAndroid Build Coastguard Worker exit_code = link_proc.wait() 816*6777b538SAndroid Build Coastguard Worker assert exit_code == 0, f'aapt2 link cmd failed with {exit_code=}' 817*6777b538SAndroid Build Coastguard Worker logging.debug('Finished: aapt2 link') 818*6777b538SAndroid Build Coastguard Worker 819*6777b538SAndroid Build Coastguard Worker if options.shared_resources: 820*6777b538SAndroid Build Coastguard Worker logging.debug('Resolving styleables in R.txt') 821*6777b538SAndroid Build Coastguard Worker # Need to resolve references because unused resource removal tool does not 822*6777b538SAndroid Build Coastguard Worker # support references in R.txt files. 823*6777b538SAndroid Build Coastguard Worker resource_utils.ResolveStyleableReferences(build.r_txt_path) 824*6777b538SAndroid Build Coastguard Worker 825*6777b538SAndroid Build Coastguard Worker if exit_code: 826*6777b538SAndroid Build Coastguard Worker raise subprocess.CalledProcessError(exit_code, link_command) 827*6777b538SAndroid Build Coastguard Worker 828*6777b538SAndroid Build Coastguard Worker if options.proguard_file and (options.shared_resources 829*6777b538SAndroid Build Coastguard Worker or options.app_as_shared_lib): 830*6777b538SAndroid Build Coastguard Worker # Make sure the R class associated with the manifest package does not have 831*6777b538SAndroid Build Coastguard Worker # its onResourcesLoaded method obfuscated or removed, so that the framework 832*6777b538SAndroid Build Coastguard Worker # can call it in the case where the APK is being loaded as a library. 833*6777b538SAndroid Build Coastguard Worker with open(build.proguard_path, 'a') as proguard_file: 834*6777b538SAndroid Build Coastguard Worker keep_rule = ''' 835*6777b538SAndroid Build Coastguard Worker -keep,allowoptimization class {package}.R {{ 836*6777b538SAndroid Build Coastguard Worker public static void onResourcesLoaded(int); 837*6777b538SAndroid Build Coastguard Worker }} 838*6777b538SAndroid Build Coastguard Worker '''.format(package=desired_manifest_package_name) 839*6777b538SAndroid Build Coastguard Worker proguard_file.write(textwrap.dedent(keep_rule)) 840*6777b538SAndroid Build Coastguard Worker 841*6777b538SAndroid Build Coastguard Worker logging.debug('Running aapt2 convert') 842*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput([ 843*6777b538SAndroid Build Coastguard Worker options.aapt2_path, 'convert', '--output-format', 'proto', '-o', 844*6777b538SAndroid Build Coastguard Worker build.proto_path, build.arsc_path 845*6777b538SAndroid Build Coastguard Worker ]) 846*6777b538SAndroid Build Coastguard Worker 847*6777b538SAndroid Build Coastguard Worker # Workaround for b/147674078. This is only needed for WebLayer and does not 848*6777b538SAndroid Build Coastguard Worker # affect WebView usage, since WebView does not used dynamic attributes. 849*6777b538SAndroid Build Coastguard Worker if options.shared_resources: 850*6777b538SAndroid Build Coastguard Worker logging.debug('Hardcoding dynamic attributes') 851*6777b538SAndroid Build Coastguard Worker protoresources.HardcodeSharedLibraryDynamicAttributes( 852*6777b538SAndroid Build Coastguard Worker build.proto_path, options.is_bundle_module, 853*6777b538SAndroid Build Coastguard Worker options.shared_resources_allowlist) 854*6777b538SAndroid Build Coastguard Worker 855*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput([ 856*6777b538SAndroid Build Coastguard Worker options.aapt2_path, 'convert', '--output-format', 'binary', '-o', 857*6777b538SAndroid Build Coastguard Worker build.arsc_path, build.proto_path 858*6777b538SAndroid Build Coastguard Worker ]) 859*6777b538SAndroid Build Coastguard Worker 860*6777b538SAndroid Build Coastguard Worker # Sanity check that the created resources have the expected package ID. 861*6777b538SAndroid Build Coastguard Worker logging.debug('Performing sanity check') 862*6777b538SAndroid Build Coastguard Worker _, actual_package_id = resource_utils.ExtractArscPackage( 863*6777b538SAndroid Build Coastguard Worker options.aapt2_path, 864*6777b538SAndroid Build Coastguard Worker build.arsc_path if options.arsc_path else build.proto_path) 865*6777b538SAndroid Build Coastguard Worker # When there are no resources, ExtractArscPackage returns (None, None), in 866*6777b538SAndroid Build Coastguard Worker # this case there is no need to check for matching package ID. 867*6777b538SAndroid Build Coastguard Worker if actual_package_id is not None and actual_package_id != package_id: 868*6777b538SAndroid Build Coastguard Worker raise Exception('Invalid package ID 0x%x (expected 0x%x)' % 869*6777b538SAndroid Build Coastguard Worker (actual_package_id, package_id)) 870*6777b538SAndroid Build Coastguard Worker 871*6777b538SAndroid Build Coastguard Worker return desired_manifest_package_name 872*6777b538SAndroid Build Coastguard Worker 873*6777b538SAndroid Build Coastguard Worker 874*6777b538SAndroid Build Coastguard Workerdef _CreateStableIdsFile(in_path, out_path, package_name, package_id): 875*6777b538SAndroid Build Coastguard Worker """Transforms a file generated by --emit-ids from another package. 876*6777b538SAndroid Build Coastguard Worker 877*6777b538SAndroid Build Coastguard Worker --stable-ids is generally meant to be used by different versions of the same 878*6777b538SAndroid Build Coastguard Worker package. To make it work for other packages, we need to transform the package 879*6777b538SAndroid Build Coastguard Worker name references to match the package that resources are being generated for. 880*6777b538SAndroid Build Coastguard Worker """ 881*6777b538SAndroid Build Coastguard Worker if in_path: 882*6777b538SAndroid Build Coastguard Worker data = pathlib.Path(in_path).read_text() 883*6777b538SAndroid Build Coastguard Worker else: 884*6777b538SAndroid Build Coastguard Worker # Force IDs to use 0x01 for the type byte in order to ensure they are 885*6777b538SAndroid Build Coastguard Worker # different from IDs generated by other apps. https://crbug.com/1293336 886*6777b538SAndroid Build Coastguard Worker data = 'pkg:id/fake_resource_id = 0x7f010000\n' 887*6777b538SAndroid Build Coastguard Worker # Replace "pkg:" with correct package name. 888*6777b538SAndroid Build Coastguard Worker data = re.sub(r'^.*?:', package_name + ':', data, flags=re.MULTILINE) 889*6777b538SAndroid Build Coastguard Worker # Replace "0x7f" with correct package id. 890*6777b538SAndroid Build Coastguard Worker data = re.sub(r'0x..', '0x%02x' % package_id, data) 891*6777b538SAndroid Build Coastguard Worker pathlib.Path(out_path).write_text(data) 892*6777b538SAndroid Build Coastguard Worker 893*6777b538SAndroid Build Coastguard Worker 894*6777b538SAndroid Build Coastguard Workerdef _WriteOutputs(options, build): 895*6777b538SAndroid Build Coastguard Worker possible_outputs = [ 896*6777b538SAndroid Build Coastguard Worker (options.srcjar_out, build.srcjar_path), 897*6777b538SAndroid Build Coastguard Worker (options.r_text_out, build.r_txt_path), 898*6777b538SAndroid Build Coastguard Worker (options.arsc_path, build.arsc_path), 899*6777b538SAndroid Build Coastguard Worker (options.proto_path, build.proto_path), 900*6777b538SAndroid Build Coastguard Worker (options.proguard_file, build.proguard_path), 901*6777b538SAndroid Build Coastguard Worker (options.emit_ids_out, build.emit_ids_path), 902*6777b538SAndroid Build Coastguard Worker (options.info_path, build.info_path), 903*6777b538SAndroid Build Coastguard Worker ] 904*6777b538SAndroid Build Coastguard Worker 905*6777b538SAndroid Build Coastguard Worker for final, temp in possible_outputs: 906*6777b538SAndroid Build Coastguard Worker # Write file only if it's changed. 907*6777b538SAndroid Build Coastguard Worker if final and not (os.path.exists(final) and filecmp.cmp(final, temp)): 908*6777b538SAndroid Build Coastguard Worker shutil.move(temp, final) 909*6777b538SAndroid Build Coastguard Worker 910*6777b538SAndroid Build Coastguard Worker 911*6777b538SAndroid Build Coastguard Workerdef _CreateNormalizedManifestForVerification(options): 912*6777b538SAndroid Build Coastguard Worker with build_utils.TempDir() as tempdir: 913*6777b538SAndroid Build Coastguard Worker fixed_manifest, _, _ = _FixManifest(options, tempdir) 914*6777b538SAndroid Build Coastguard Worker with open(fixed_manifest) as f: 915*6777b538SAndroid Build Coastguard Worker return manifest_utils.NormalizeManifest( 916*6777b538SAndroid Build Coastguard Worker f.read(), options.verification_version_code_offset, 917*6777b538SAndroid Build Coastguard Worker options.verification_library_version_offset) 918*6777b538SAndroid Build Coastguard Worker 919*6777b538SAndroid Build Coastguard Worker 920*6777b538SAndroid Build Coastguard Workerdef main(args): 921*6777b538SAndroid Build Coastguard Worker build_utils.InitLogging('RESOURCE_DEBUG') 922*6777b538SAndroid Build Coastguard Worker args = build_utils.ExpandFileArgs(args) 923*6777b538SAndroid Build Coastguard Worker options = _ParseArgs(args) 924*6777b538SAndroid Build Coastguard Worker 925*6777b538SAndroid Build Coastguard Worker if options.expected_file: 926*6777b538SAndroid Build Coastguard Worker actual_data = _CreateNormalizedManifestForVerification(options) 927*6777b538SAndroid Build Coastguard Worker diff_utils.CheckExpectations(actual_data, options) 928*6777b538SAndroid Build Coastguard Worker if options.only_verify_expectations: 929*6777b538SAndroid Build Coastguard Worker return 930*6777b538SAndroid Build Coastguard Worker 931*6777b538SAndroid Build Coastguard Worker path = options.arsc_path or options.proto_path 932*6777b538SAndroid Build Coastguard Worker debug_temp_resources_dir = os.environ.get('TEMP_RESOURCES_DIR') 933*6777b538SAndroid Build Coastguard Worker if debug_temp_resources_dir: 934*6777b538SAndroid Build Coastguard Worker path = os.path.join(debug_temp_resources_dir, os.path.basename(path)) 935*6777b538SAndroid Build Coastguard Worker else: 936*6777b538SAndroid Build Coastguard Worker # Use a deterministic temp directory since .pb files embed the absolute 937*6777b538SAndroid Build Coastguard Worker # path of resources: crbug.com/939984 938*6777b538SAndroid Build Coastguard Worker path = path + '.tmpdir' 939*6777b538SAndroid Build Coastguard Worker build_utils.DeleteDirectory(path) 940*6777b538SAndroid Build Coastguard Worker 941*6777b538SAndroid Build Coastguard Worker with resource_utils.BuildContext( 942*6777b538SAndroid Build Coastguard Worker temp_dir=path, keep_files=bool(debug_temp_resources_dir)) as build: 943*6777b538SAndroid Build Coastguard Worker 944*6777b538SAndroid Build Coastguard Worker manifest_package_name = _PackageApk(options, build) 945*6777b538SAndroid Build Coastguard Worker 946*6777b538SAndroid Build Coastguard Worker # If --shared-resources-allowlist is used, all the resources listed in the 947*6777b538SAndroid Build Coastguard Worker # corresponding R.txt file will be non-final, and an onResourcesLoaded() 948*6777b538SAndroid Build Coastguard Worker # will be generated to adjust them at runtime. 949*6777b538SAndroid Build Coastguard Worker # 950*6777b538SAndroid Build Coastguard Worker # Otherwise, if --shared-resources is used, the all resources will be 951*6777b538SAndroid Build Coastguard Worker # non-final, and an onResourcesLoaded() method will be generated too. 952*6777b538SAndroid Build Coastguard Worker # 953*6777b538SAndroid Build Coastguard Worker # Otherwise, all resources will be final, and no method will be generated. 954*6777b538SAndroid Build Coastguard Worker # 955*6777b538SAndroid Build Coastguard Worker rjava_build_options = resource_utils.RJavaBuildOptions() 956*6777b538SAndroid Build Coastguard Worker if options.shared_resources_allowlist: 957*6777b538SAndroid Build Coastguard Worker rjava_build_options.ExportSomeResources( 958*6777b538SAndroid Build Coastguard Worker options.shared_resources_allowlist) 959*6777b538SAndroid Build Coastguard Worker rjava_build_options.GenerateOnResourcesLoaded() 960*6777b538SAndroid Build Coastguard Worker if options.shared_resources: 961*6777b538SAndroid Build Coastguard Worker # The final resources will only be used in WebLayer, so hardcode the 962*6777b538SAndroid Build Coastguard Worker # package ID to be what WebLayer expects. 963*6777b538SAndroid Build Coastguard Worker rjava_build_options.SetFinalPackageId( 964*6777b538SAndroid Build Coastguard Worker protoresources.SHARED_LIBRARY_HARDCODED_ID) 965*6777b538SAndroid Build Coastguard Worker elif options.shared_resources or options.app_as_shared_lib: 966*6777b538SAndroid Build Coastguard Worker rjava_build_options.ExportAllResources() 967*6777b538SAndroid Build Coastguard Worker rjava_build_options.GenerateOnResourcesLoaded() 968*6777b538SAndroid Build Coastguard Worker 969*6777b538SAndroid Build Coastguard Worker custom_root_package_name = options.r_java_root_package_name 970*6777b538SAndroid Build Coastguard Worker grandparent_custom_package_name = None 971*6777b538SAndroid Build Coastguard Worker 972*6777b538SAndroid Build Coastguard Worker # Always generate an R.java file for the package listed in 973*6777b538SAndroid Build Coastguard Worker # AndroidManifest.xml because this is where Android framework looks to find 974*6777b538SAndroid Build Coastguard Worker # onResourcesLoaded() for shared library apks. While not actually necessary 975*6777b538SAndroid Build Coastguard Worker # for application apks, it also doesn't hurt. 976*6777b538SAndroid Build Coastguard Worker apk_package_name = manifest_package_name 977*6777b538SAndroid Build Coastguard Worker 978*6777b538SAndroid Build Coastguard Worker if options.package_name and not options.arsc_package_name: 979*6777b538SAndroid Build Coastguard Worker # Feature modules have their own custom root package name and should 980*6777b538SAndroid Build Coastguard Worker # inherit from the appropriate base module package. This behaviour should 981*6777b538SAndroid Build Coastguard Worker # not be present for test apks with an apk under test. Thus, 982*6777b538SAndroid Build Coastguard Worker # arsc_package_name is used as it is only defined for test apks with an 983*6777b538SAndroid Build Coastguard Worker # apk under test. 984*6777b538SAndroid Build Coastguard Worker custom_root_package_name = options.package_name 985*6777b538SAndroid Build Coastguard Worker grandparent_custom_package_name = options.r_java_root_package_name 986*6777b538SAndroid Build Coastguard Worker # Feature modules have the same manifest package as the base module but 987*6777b538SAndroid Build Coastguard Worker # they should not create an R.java for said manifest package because it 988*6777b538SAndroid Build Coastguard Worker # will be created in the base module. 989*6777b538SAndroid Build Coastguard Worker apk_package_name = None 990*6777b538SAndroid Build Coastguard Worker 991*6777b538SAndroid Build Coastguard Worker if options.srcjar_out: 992*6777b538SAndroid Build Coastguard Worker logging.debug('Creating R.srcjar') 993*6777b538SAndroid Build Coastguard Worker resource_utils.CreateRJavaFiles(build.srcjar_dir, apk_package_name, 994*6777b538SAndroid Build Coastguard Worker build.r_txt_path, 995*6777b538SAndroid Build Coastguard Worker options.extra_res_packages, 996*6777b538SAndroid Build Coastguard Worker rjava_build_options, options.srcjar_out, 997*6777b538SAndroid Build Coastguard Worker custom_root_package_name, 998*6777b538SAndroid Build Coastguard Worker grandparent_custom_package_name) 999*6777b538SAndroid Build Coastguard Worker with action_helpers.atomic_output(build.srcjar_path) as f: 1000*6777b538SAndroid Build Coastguard Worker zip_helpers.zip_directory(f, build.srcjar_dir) 1001*6777b538SAndroid Build Coastguard Worker 1002*6777b538SAndroid Build Coastguard Worker logging.debug('Copying outputs') 1003*6777b538SAndroid Build Coastguard Worker _WriteOutputs(options, build) 1004*6777b538SAndroid Build Coastguard Worker 1005*6777b538SAndroid Build Coastguard Worker if options.depfile: 1006*6777b538SAndroid Build Coastguard Worker assert options.srcjar_out, 'Update first output below and remove assert.' 1007*6777b538SAndroid Build Coastguard Worker depfile_deps = (options.dependencies_res_zips + 1008*6777b538SAndroid Build Coastguard Worker options.dependencies_res_zip_overlays + 1009*6777b538SAndroid Build Coastguard Worker options.include_resources) 1010*6777b538SAndroid Build Coastguard Worker action_helpers.write_depfile(options.depfile, options.srcjar_out, 1011*6777b538SAndroid Build Coastguard Worker depfile_deps) 1012*6777b538SAndroid Build Coastguard Worker 1013*6777b538SAndroid Build Coastguard Worker 1014*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 1015*6777b538SAndroid Build Coastguard Worker main(sys.argv[1:]) 1016