1 #!/usr/bin/env python 2 # 3 # Copyright 2014 The Chromium Authors. All rights reserved. 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 7 """Generates the obfuscated jar and test jar for an apk. 8 9 If proguard is not enabled or 'Release' is not in the configuration name, 10 obfuscation will be a no-op. 11 """ 12 13 import optparse 14 import os 15 import sys 16 17 from util import build_utils 18 19 def ParseArgs(argv): 20 parser = optparse.OptionParser() 21 parser.add_option('--android-sdk', help='path to the Android SDK folder') 22 parser.add_option('--android-sdk-tools', 23 help='path to the Android SDK build tools folder') 24 parser.add_option('--android-sdk-jar', 25 help='path to Android SDK\'s android.jar') 26 parser.add_option('--proguard-jar-path', 27 help='Path to proguard.jar in the sdk') 28 parser.add_option('--input-jars-paths', 29 help='Path to jars to include in obfuscated jar') 30 31 parser.add_option('--proguard-configs', 32 help='Paths to proguard config files') 33 34 parser.add_option('--configuration-name', 35 help='Gyp configuration name (i.e. Debug, Release)') 36 parser.add_option('--proguard-enabled', action='store_true', 37 help='Set if proguard is enabled for this target.') 38 39 parser.add_option('--obfuscated-jar-path', 40 help='Output path for obfuscated jar.') 41 42 parser.add_option('--testapp', action='store_true', 43 help='Set this if building an instrumentation test apk') 44 parser.add_option('--tested-apk-obfuscated-jar-path', 45 help='Path to obfusctated jar of the tested apk') 46 parser.add_option('--test-jar-path', 47 help='Output path for jar containing all the test apk\'s ' 48 'code.') 49 50 parser.add_option('--stamp', help='File to touch on success') 51 52 (options, args) = parser.parse_args(argv) 53 54 if args: 55 parser.error('No positional arguments should be given. ' + str(args)) 56 57 # Check that required options have been provided. 58 required_options = ( 59 'android_sdk', 60 'android_sdk_tools', 61 'android_sdk_jar', 62 'proguard_jar_path', 63 'input_jars_paths', 64 'configuration_name', 65 'obfuscated_jar_path', 66 ) 67 68 if options.testapp: 69 required_options += ( 70 'test_jar_path', 71 ) 72 73 build_utils.CheckOptions(options, parser, required=required_options) 74 75 return options, args 76 77 78 def main(argv): 79 options, _ = ParseArgs(argv) 80 81 library_classpath = [options.android_sdk_jar] 82 input_jars = build_utils.ParseGypList(options.input_jars_paths) 83 84 dependency_class_filters = [ 85 '*R.class', '*R$*.class', '*Manifest.class', '*BuildConfig.class'] 86 87 if options.testapp: 88 build_utils.MergeZips( 89 options.test_jar_path, input_jars, dependency_class_filters) 90 91 if options.configuration_name == 'Release' and options.proguard_enabled: 92 proguard_cmd = [ 93 'java', '-jar', options.proguard_jar_path, 94 '-forceprocessing', 95 '-libraryjars', ':'.join(library_classpath), 96 '-dump', options.obfuscated_jar_path + '.dump', 97 '-printseeds', options.obfuscated_jar_path + '.seeds', 98 '-printusage', options.obfuscated_jar_path + '.usage', 99 '-printmapping', options.obfuscated_jar_path + '.mapping', 100 ] 101 102 exclude_paths = [] 103 configs = build_utils.ParseGypList(options.proguard_configs) 104 if (options.tested_apk_obfuscated_jar_path and 105 options.tested_apk_obfuscated_jar_path != '/'): 106 # configs should only contain the process_resources.py generated config. 107 assert len(configs) == 1, ( 108 'test apks should not have custom proguard configs: ' + str(configs)) 109 tested_jar_info = build_utils.ReadJson( 110 options.tested_apk_obfuscated_jar_path + '.info') 111 exclude_paths = tested_jar_info['inputs'] 112 configs = tested_jar_info['configs'] 113 proguard_cmd += [ 114 '-dontobfuscate', 115 '-dontoptimize', 116 '-dontshrink', 117 '-dontskipnonpubliclibraryclassmembers', 118 '-libraryjars', options.tested_apk_obfuscated_jar_path, 119 '-applymapping', options.tested_apk_obfuscated_jar_path + '.mapping', 120 ] 121 122 proguard_injars = [p for p in input_jars if p not in exclude_paths] 123 proguard_cmd += ['-injars', ':'.join(proguard_injars)] 124 125 for config_file in configs: 126 proguard_cmd += ['-include', config_file] 127 128 # The output jar must be specified after inputs. 129 proguard_cmd += ['-outjars', options.obfuscated_jar_path] 130 131 build_utils.CheckOutput(proguard_cmd) 132 133 this_info = { 134 'inputs': proguard_injars, 135 'configs': configs 136 } 137 138 build_utils.WriteJson( 139 this_info, options.obfuscated_jar_path + '.info') 140 else: 141 output_files = [ 142 options.obfuscated_jar_path, 143 options.obfuscated_jar_path + '.info', 144 options.obfuscated_jar_path + '.dump', 145 options.obfuscated_jar_path + '.seeds', 146 options.obfuscated_jar_path + '.usage', 147 options.obfuscated_jar_path + '.mapping'] 148 for f in output_files: 149 if os.path.exists(f): 150 os.remove(f) 151 build_utils.Touch(f) 152 153 if options.stamp: 154 build_utils.Touch(options.stamp) 155 156 if __name__ == '__main__': 157 sys.exit(main(sys.argv[1:])) 158