1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*8975f5c5SAndroid Build Coastguard Worker# encoding: utf-8 3*8975f5c5SAndroid Build Coastguard Worker# Copyright 2021 The Chromium Authors 4*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 6*8975f5c5SAndroid Build Coastguard Worker 7*8975f5c5SAndroid Build Coastguard Workerimport argparse 8*8975f5c5SAndroid Build Coastguard Workerimport os 9*8975f5c5SAndroid Build Coastguard Workerimport pathlib 10*8975f5c5SAndroid Build Coastguard Workerimport sys 11*8975f5c5SAndroid Build Coastguard Worker 12*8975f5c5SAndroid Build Coastguard Workerfrom util import build_utils 13*8975f5c5SAndroid Build Coastguard Workerfrom util import resource_utils 14*8975f5c5SAndroid Build Coastguard Workerimport action_helpers # build_utils adds //build to sys.path. 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard Worker 17*8975f5c5SAndroid Build Coastguard Workerdef _FilterUnusedResources(r_text_in, r_text_out, unused_resources_config): 18*8975f5c5SAndroid Build Coastguard Worker removed_resources = set() 19*8975f5c5SAndroid Build Coastguard Worker with open(unused_resources_config, encoding='utf-8') as output_config: 20*8975f5c5SAndroid Build Coastguard Worker for line in output_config: 21*8975f5c5SAndroid Build Coastguard Worker # example line: attr/line_height#remove 22*8975f5c5SAndroid Build Coastguard Worker resource = line.split('#')[0] 23*8975f5c5SAndroid Build Coastguard Worker resource_type, resource_name = resource.split('/') 24*8975f5c5SAndroid Build Coastguard Worker removed_resources.add((resource_type, resource_name)) 25*8975f5c5SAndroid Build Coastguard Worker kept_lines = [] 26*8975f5c5SAndroid Build Coastguard Worker with open(r_text_in, encoding='utf-8') as infile: 27*8975f5c5SAndroid Build Coastguard Worker for line in infile: 28*8975f5c5SAndroid Build Coastguard Worker # example line: int attr line_height 0x7f0014ee 29*8975f5c5SAndroid Build Coastguard Worker resource_type, resource_name = line.split(' ')[1:3] 30*8975f5c5SAndroid Build Coastguard Worker if (resource_type, resource_name) not in removed_resources: 31*8975f5c5SAndroid Build Coastguard Worker kept_lines.append(line) 32*8975f5c5SAndroid Build Coastguard Worker 33*8975f5c5SAndroid Build Coastguard Worker with open(r_text_out, 'w', encoding='utf-8') as out_file: 34*8975f5c5SAndroid Build Coastguard Worker out_file.writelines(kept_lines) 35*8975f5c5SAndroid Build Coastguard Worker 36*8975f5c5SAndroid Build Coastguard Worker 37*8975f5c5SAndroid Build Coastguard Workerdef _WritePaths(dest_path, lines): 38*8975f5c5SAndroid Build Coastguard Worker pathlib.Path(dest_path).write_text('\n'.join(lines) + '\n') 39*8975f5c5SAndroid Build Coastguard Worker 40*8975f5c5SAndroid Build Coastguard Worker 41*8975f5c5SAndroid Build Coastguard Workerdef main(args): 42*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 43*8975f5c5SAndroid Build Coastguard Worker 44*8975f5c5SAndroid Build Coastguard Worker action_helpers.add_depfile_arg(parser) 45*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--script', 46*8975f5c5SAndroid Build Coastguard Worker required=True, 47*8975f5c5SAndroid Build Coastguard Worker help='Path to the unused resources detector script.') 48*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 49*8975f5c5SAndroid Build Coastguard Worker '--dependencies-res-zips', 50*8975f5c5SAndroid Build Coastguard Worker required=True, 51*8975f5c5SAndroid Build Coastguard Worker action='append', 52*8975f5c5SAndroid Build Coastguard Worker help='Resources zip archives to investigate for unused resources.') 53*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--dexes', 54*8975f5c5SAndroid Build Coastguard Worker action='append', 55*8975f5c5SAndroid Build Coastguard Worker required=True, 56*8975f5c5SAndroid Build Coastguard Worker help='Path to dex file, or zip with dex files.') 57*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 58*8975f5c5SAndroid Build Coastguard Worker '--proguard-mapping', 59*8975f5c5SAndroid Build Coastguard Worker help='Path to proguard mapping file for the optimized dex.') 60*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--r-text-in', required=True, help='Path to input R.txt') 61*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 62*8975f5c5SAndroid Build Coastguard Worker '--r-text-out', 63*8975f5c5SAndroid Build Coastguard Worker help='Path to output R.txt with unused resources removed.') 64*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--android-manifests', 65*8975f5c5SAndroid Build Coastguard Worker action='append', 66*8975f5c5SAndroid Build Coastguard Worker required=True, 67*8975f5c5SAndroid Build Coastguard Worker help='Path to AndroidManifest') 68*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--output-config', 69*8975f5c5SAndroid Build Coastguard Worker required=True, 70*8975f5c5SAndroid Build Coastguard Worker help='Path to output the aapt2 config to.') 71*8975f5c5SAndroid Build Coastguard Worker args = build_utils.ExpandFileArgs(args) 72*8975f5c5SAndroid Build Coastguard Worker options = parser.parse_args(args) 73*8975f5c5SAndroid Build Coastguard Worker options.dependencies_res_zips = (action_helpers.parse_gn_list( 74*8975f5c5SAndroid Build Coastguard Worker options.dependencies_res_zips)) 75*8975f5c5SAndroid Build Coastguard Worker 76*8975f5c5SAndroid Build Coastguard Worker # in case of no resources, short circuit early. 77*8975f5c5SAndroid Build Coastguard Worker if not options.dependencies_res_zips: 78*8975f5c5SAndroid Build Coastguard Worker build_utils.Touch(options.output_config) 79*8975f5c5SAndroid Build Coastguard Worker return 80*8975f5c5SAndroid Build Coastguard Worker 81*8975f5c5SAndroid Build Coastguard Worker with build_utils.TempDir() as temp_dir: 82*8975f5c5SAndroid Build Coastguard Worker dep_subdirs = [] 83*8975f5c5SAndroid Build Coastguard Worker for dependency_res_zip in options.dependencies_res_zips: 84*8975f5c5SAndroid Build Coastguard Worker dep_subdirs += resource_utils.ExtractDeps([dependency_res_zip], temp_dir) 85*8975f5c5SAndroid Build Coastguard Worker 86*8975f5c5SAndroid Build Coastguard Worker # Use files for paths to avoid command line getting too long. 87*8975f5c5SAndroid Build Coastguard Worker # https://crbug.com/362019371 88*8975f5c5SAndroid Build Coastguard Worker manifests_file = os.path.join(temp_dir, 'manifests-inputs.txt') 89*8975f5c5SAndroid Build Coastguard Worker resources_file = os.path.join(temp_dir, 'resources-inputs.txt') 90*8975f5c5SAndroid Build Coastguard Worker dexes_file = os.path.join(temp_dir, 'dexes-inputs.txt') 91*8975f5c5SAndroid Build Coastguard Worker 92*8975f5c5SAndroid Build Coastguard Worker _WritePaths(manifests_file, options.android_manifests) 93*8975f5c5SAndroid Build Coastguard Worker _WritePaths(resources_file, dep_subdirs) 94*8975f5c5SAndroid Build Coastguard Worker _WritePaths(dexes_file, options.dexes) 95*8975f5c5SAndroid Build Coastguard Worker 96*8975f5c5SAndroid Build Coastguard Worker cmd = [ 97*8975f5c5SAndroid Build Coastguard Worker options.script, 98*8975f5c5SAndroid Build Coastguard Worker '--rtxts', 99*8975f5c5SAndroid Build Coastguard Worker options.r_text_in, 100*8975f5c5SAndroid Build Coastguard Worker '--manifests', 101*8975f5c5SAndroid Build Coastguard Worker manifests_file, 102*8975f5c5SAndroid Build Coastguard Worker '--resourceDirs', 103*8975f5c5SAndroid Build Coastguard Worker resources_file, 104*8975f5c5SAndroid Build Coastguard Worker '--dexes', 105*8975f5c5SAndroid Build Coastguard Worker dexes_file, 106*8975f5c5SAndroid Build Coastguard Worker '--outputConfig', 107*8975f5c5SAndroid Build Coastguard Worker options.output_config, 108*8975f5c5SAndroid Build Coastguard Worker ] 109*8975f5c5SAndroid Build Coastguard Worker if options.proguard_mapping: 110*8975f5c5SAndroid Build Coastguard Worker cmd += [ 111*8975f5c5SAndroid Build Coastguard Worker '--mapping', 112*8975f5c5SAndroid Build Coastguard Worker options.proguard_mapping, 113*8975f5c5SAndroid Build Coastguard Worker ] 114*8975f5c5SAndroid Build Coastguard Worker build_utils.CheckOutput(cmd) 115*8975f5c5SAndroid Build Coastguard Worker 116*8975f5c5SAndroid Build Coastguard Worker if options.r_text_out: 117*8975f5c5SAndroid Build Coastguard Worker _FilterUnusedResources(options.r_text_in, options.r_text_out, 118*8975f5c5SAndroid Build Coastguard Worker options.output_config) 119*8975f5c5SAndroid Build Coastguard Worker 120*8975f5c5SAndroid Build Coastguard Worker if options.depfile: 121*8975f5c5SAndroid Build Coastguard Worker depfile_deps = (options.dependencies_res_zips + options.android_manifests + 122*8975f5c5SAndroid Build Coastguard Worker options.dexes) + [options.r_text_in] 123*8975f5c5SAndroid Build Coastguard Worker if options.proguard_mapping: 124*8975f5c5SAndroid Build Coastguard Worker depfile_deps.append(options.proguard_mapping) 125*8975f5c5SAndroid Build Coastguard Worker action_helpers.write_depfile(options.depfile, options.output_config, 126*8975f5c5SAndroid Build Coastguard Worker depfile_deps) 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard Worker 129*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 130*8975f5c5SAndroid Build Coastguard Worker main(sys.argv[1:]) 131