def main(): build_utils.InitLogging('PROGUARD_DEBUG') options = _ParseOptions() logging.debug('Preparing configs') proguard_configs = options.proguard_configs # ProGuard configs that are derived from flags. dynamic_config_data = _CreateDynamicConfig(options) # ProGuard configs that are derived from flags. merged_configs = _CombineConfigs(proguard_configs, dynamic_config_data, exclude_generated=True) print_stdout = _ContainsDebuggingConfig(merged_configs) or options.verbose if options.expected_file: diff_utils.CheckExpectations(merged_configs, options) if options.only_verify_expectations: build_utils.WriteDepfile(options.depfile, options.actual_file, inputs=options.proguard_configs) return logging.debug('Looking for embedded configs') libraries = [] for p in options.classpath: # TODO(bjoyce): Remove filter once old android support libraries are gone. # Fix for having Library class extend program class dependency problem. if 'com_android_support' in p or 'android_support_test' in p: continue # If a jar is part of input no need to include it as library jar. if p not in libraries and p not in options.input_paths: libraries.append(p) _VerifyNoEmbeddedConfigs(options.input_paths + libraries) _OptimizeWithR8(options, proguard_configs, libraries, dynamic_config_data, print_stdout) if not options.disable_checks: logging.debug('Running tracereferences') all_dex_files = [] if options.output_path: all_dex_files.append(options.output_path) if options.dex_dests: all_dex_files.extend(options.dex_dests) _CheckForMissingSymbols(options.r8_path, all_dex_files, options.classpath, options.warnings_as_errors) for output in options.extra_mapping_output_paths: shutil.copy(options.mapping_output, output) inputs = options.proguard_configs + options.input_paths + libraries if options.apply_mapping: inputs.append(options.apply_mapping) _MaybeWriteStampAndDepFile(options, inputs)
def main(): options = _ParseOptions() libraries = [] for p in options.classpath: # TODO(bjoyce): Remove filter once old android support libraries are gone. # Fix for having Library class extend program class dependency problem. if 'com_android_support' in p or 'android_support_test' in p: continue # If a jar is part of input no need to include it as library jar. if p not in libraries and p not in options.input_paths: libraries.append(p) _VerifyNoEmbeddedConfigs(options.input_paths + libraries) proguard_configs = options.proguard_configs if options.disable_checkdiscard: proguard_configs = _ValidateAndFilterCheckDiscards(proguard_configs) # ProGuard configs that are derived from flags. dynamic_config_data = _CreateDynamicConfig(options) # ProGuard configs that are derived from flags. merged_configs = _CombineConfigs(proguard_configs, dynamic_config_data, exclude_generated=True) print_stdout = _ContainsDebuggingConfig(merged_configs) or options.verbose if options.expected_file: diff_utils.CheckExpectations(merged_configs, options) if options.only_verify_expectations: build_utils.WriteDepfile(options.depfile, options.actual_file, inputs=options.proguard_configs) return _OptimizeWithR8(options, proguard_configs, libraries, dynamic_config_data, print_stdout) # After ProGuard / R8 has run: for output in options.extra_mapping_output_paths: shutil.copy(options.mapping_output, output) inputs = options.proguard_configs + options.input_paths + libraries if options.apply_mapping: inputs.append(options.apply_mapping) _MaybeWriteStampAndDepFile(options, inputs)
def main(): """Compare the flags with the checked in list.""" parser = argparse.ArgumentParser() diff_utils.AddCommandLineFlags(parser) parser.add_argument('--current-flags', help='Path to flags to check against expectations.') options = parser.parse_args() flags = ParseFlags(options.current_flags) flags = MergeFlags(flags) msg = """ This expectation file is meant to inform the build team about changes to flags used when building native libraries in chrome (most importantly any that relate to security). This is to ensure the flags are replicated when building native libraries outside of the repo. Please update the .expected files and a WATCHLIST entry will alert the build team to your change.""" diff_utils.CheckExpectations('\n'.join(sorted(flags)), options, custom_msg=msg)
def main(args): build_utils.InitLogging('RESOURCE_DEBUG') args = build_utils.ExpandFileArgs(args) options = _ParseArgs(args) if options.expected_file: actual_data = _CreateNormalizedManifestForVerification(options) diff_utils.CheckExpectations(actual_data, options) if options.only_verify_expectations: return path = options.arsc_path or options.proto_path debug_temp_resources_dir = os.environ.get('TEMP_RESOURCES_DIR') if debug_temp_resources_dir: path = os.path.join(debug_temp_resources_dir, os.path.basename(path)) else: # Use a deterministic temp directory since .pb files embed the absolute # path of resources: crbug.com/939984 path = path + '.tmpdir' build_utils.DeleteDirectory(path) with resource_utils.BuildContext( temp_dir=path, keep_files=bool(debug_temp_resources_dir)) as build: manifest_package_name = _PackageApk(options, build) # If --shared-resources-allowlist is used, all the resources listed in the # corresponding R.txt file will be non-final, and an onResourcesLoaded() # will be generated to adjust them at runtime. # # Otherwise, if --shared-resources is used, the all resources will be # non-final, and an onResourcesLoaded() method will be generated too. # # Otherwise, all resources will be final, and no method will be generated. # rjava_build_options = resource_utils.RJavaBuildOptions() if options.shared_resources_allowlist: rjava_build_options.ExportSomeResources( options.shared_resources_allowlist) rjava_build_options.GenerateOnResourcesLoaded() if options.shared_resources: # The final resources will only be used in WebLayer, so hardcode the # package ID to be what WebLayer expects. rjava_build_options.SetFinalPackageId( protoresources.SHARED_LIBRARY_HARDCODED_ID) elif options.shared_resources or options.app_as_shared_lib: rjava_build_options.ExportAllResources() rjava_build_options.GenerateOnResourcesLoaded() custom_root_package_name = options.r_java_root_package_name grandparent_custom_package_name = None # Always generate an R.java file for the package listed in # AndroidManifest.xml because this is where Android framework looks to find # onResourcesLoaded() for shared library apks. While not actually necessary # for application apks, it also doesn't hurt. apk_package_name = manifest_package_name if options.package_name and not options.arsc_package_name: # Feature modules have their own custom root package name and should # inherit from the appropriate base module package. This behaviour should # not be present for test apks with an apk under test. Thus, # arsc_package_name is used as it is only defined for test apks with an # apk under test. custom_root_package_name = options.package_name grandparent_custom_package_name = options.r_java_root_package_name # Feature modules have the same manifest package as the base module but # they should not create an R.java for said manifest package because it # will be created in the base module. apk_package_name = None logging.debug('Creating R.srcjar') resource_utils.CreateRJavaFiles( build.srcjar_dir, apk_package_name, build.r_txt_path, options.extra_res_packages, rjava_build_options, options.srcjar_out, custom_root_package_name, grandparent_custom_package_name, options.extra_main_r_text_files) build_utils.ZipDir(build.srcjar_path, build.srcjar_dir) # Sanity check that the created resources have the expected package ID. logging.debug('Performing sanity check') if options.package_id: expected_id = options.package_id elif options.shared_resources: expected_id = 0 else: expected_id = 127 # == '0x7f'. _, package_id = resource_utils.ExtractArscPackage( options.aapt2_path, build.arsc_path if options.arsc_path else build.proto_path) if package_id != expected_id: raise Exception('Invalid package ID 0x%x (expected 0x%x)' % (package_id, expected_id)) logging.debug('Copying outputs') _WriteOutputs(options, build) if options.depfile: depfile_deps = (options.dependencies_res_zips + options.dependencies_res_zip_overlays + options.extra_main_r_text_files + options.include_resources) build_utils.WriteDepfile(options.depfile, options.srcjar_out, depfile_deps)
def main(args): build_utils.InitLogging('RESOURCE_DEBUG') args = build_utils.ExpandFileArgs(args) options = _ParseArgs(args) if options.expected_file: actual_data = _CreateNormalizedManifest(options) diff_utils.CheckExpectations(actual_data, options) if options.only_verify_expectations: return depfile_deps = (options.dependencies_res_zips + options.dependencies_res_zip_overlays + options.extra_main_r_text_files + options.include_resources) possible_input_paths = depfile_deps + options.resources_config_paths + [ options.aapt2_path, options.android_manifest, options.expected_file, options.expected_file_base, options.shared_resources_allowlist, options.use_resource_ids_path, options.webp_binary, ] input_paths = [p for p in possible_input_paths if p] input_strings = [ options.app_as_shared_lib, options.arsc_package_name, options.debuggable, options.extra_res_packages, options.failure_file, options.include_resources, options.locale_allowlist, options.manifest_package, options.max_sdk_version, options.min_sdk_version, options.no_xml_namespaces, options.package_id, options.package_name, options.png_to_webp, options.rename_manifest_package, options.resource_exclusion_exceptions, options.resource_exclusion_regex, options.r_java_root_package_name, options.shared_resources, options.shared_resources_allowlist_locales, options.short_resource_paths, options.strip_resource_names, options.support_zh_hk, options.target_sdk_version, options.values_filter_rules, options.version_code, options.version_name, options.webp_cache_dir, ] output_paths = [options.srcjar_out] possible_output_paths = [ options.actual_file, options.arsc_path, options.emit_ids_out, options.info_path, options.optimized_arsc_path, options.optimized_proto_path, options.proguard_file, options.proguard_file_main_dex, options.proto_path, options.resources_path_map_out_path, options.r_text_out, ] output_paths += [p for p in possible_output_paths if p] # Since we overspecify deps, this target depends on java deps that are not # going to change its output. This target is also slow (6-12 seconds) and # blocking the critical path. We want changes to java_library targets to not # trigger re-compilation of resources, thus we need to use md5_check. md5_check.CallAndWriteDepfileIfStale(lambda: _OnStaleMd5(options), options, input_paths=input_paths, input_strings=input_strings, output_paths=output_paths, depfile_deps=depfile_deps)
def main(): build_utils.InitLogging('PROGUARD_DEBUG') options = _ParseOptions() logging.debug('Preparing configs') proguard_configs = options.proguard_configs # ProGuard configs that are derived from flags. dynamic_config_data = _CreateDynamicConfig(options) # ProGuard configs that are derived from flags. merged_configs = _CombineConfigs( proguard_configs, dynamic_config_data, exclude_generated=True) print_stdout = _ContainsDebuggingConfig(merged_configs) or options.verbose if options.expected_file: diff_utils.CheckExpectations(merged_configs, options) if options.only_verify_expectations: build_utils.WriteDepfile(options.depfile, options.actual_file, inputs=options.proguard_configs) return logging.debug('Looking for embedded configs') libraries = [] for p in options.classpath: # TODO(bjoyce): Remove filter once old android support libraries are gone. # Fix for having Library class extend program class dependency problem. if 'com_android_support' in p or 'android_support_test' in p: continue # If a jar is part of input no need to include it as library jar. if p not in libraries and p not in options.input_paths: libraries.append(p) _VerifyNoEmbeddedConfigs(options.input_paths + libraries) if options.keep_rules_output_path: _OutputKeepRules(options.r8_path, options.input_paths, options.classpath, options.keep_rules_targets_regex, options.keep_rules_output_path) return base_context = _OptimizeWithR8(options, proguard_configs, libraries, dynamic_config_data, print_stdout) if not options.disable_checks: logging.debug('Running tracereferences') all_dex_files = [] if options.output_path: all_dex_files.append(options.output_path) if options.dex_dests: all_dex_files.extend(options.dex_dests) error_title = 'DEX contains references to non-existent symbols after R8.' _CheckForMissingSymbols(options.r8_path, all_dex_files, options.classpath, options.warnings_as_errors, error_title) # Also ensure that base module doesn't have any references to child dex # symbols. # TODO(agrieve): Remove this check once r8 desugaring is fixed to not put # synthesized classes in the base module. error_title = 'Base module DEX contains references symbols within DFMs.' _CheckForMissingSymbols(options.r8_path, [base_context.final_output_path], options.classpath, options.warnings_as_errors, error_title) for output in options.extra_mapping_output_paths: shutil.copy(options.mapping_output, output) inputs = options.proguard_configs + options.input_paths + libraries if options.apply_mapping: inputs.append(options.apply_mapping) _MaybeWriteStampAndDepFile(options, inputs)
def main(args): build_utils.InitLogging('APKBUILDER_DEBUG') args = build_utils.ExpandFileArgs(args) options = _ParseArgs(args) # Until Python 3.7, there's no better way to set compression level. # The default is 6. if options.best_compression: # Compresses about twice as slow as the default. zlib.Z_DEFAULT_COMPRESSION = 9 else: # Compresses about twice as fast as the default. zlib.Z_DEFAULT_COMPRESSION = 1 # Manually align only when alignment is necessary. # Python's zip implementation duplicates file comments in the central # directory, whereas zipalign does not, so use zipalign for official builds. fast_align = options.format == 'apk' and not options.best_compression native_libs = sorted(options.native_libs) # Include native libs in the depfile_deps since GN doesn't know about the # dependencies when is_component_build=true. depfile_deps = list(native_libs) # For targets that depend on static library APKs, dex paths are created by # the static library's dexsplitter target and GN doesn't know about these # paths. if options.dex_file: depfile_deps.append(options.dex_file) secondary_native_libs = [] if options.secondary_native_libs: secondary_native_libs = sorted(options.secondary_native_libs) depfile_deps += secondary_native_libs if options.java_resources: # Included via .build_config.json, so need to write it to depfile. depfile_deps.extend(options.java_resources) assets = _ExpandPaths(options.assets) uncompressed_assets = _ExpandPaths(options.uncompressed_assets) # Included via .build_config.json, so need to write it to depfile. depfile_deps.extend(x[0] for x in assets) depfile_deps.extend(x[0] for x in uncompressed_assets) depfile_deps.append(options.resource_apk) # Bundle modules have a structure similar to APKs, except that resources # are compiled in protobuf format (instead of binary xml), and that some # files are located into different top-level directories, e.g.: # AndroidManifest.xml -> manifest/AndroidManifest.xml # classes.dex -> dex/classes.dex # res/ -> res/ (unchanged) # assets/ -> assets/ (unchanged) # <other-file> -> root/<other-file> # # Hence, the following variables are used to control the location of files in # the final archive. if options.format == 'bundle-module': apk_manifest_dir = 'manifest/' apk_root_dir = 'root/' apk_dex_dir = 'dex/' else: apk_manifest_dir = '' apk_root_dir = '' apk_dex_dir = '' def _GetAssetDetails(assets, uncompressed_assets, fast_align, allow_reads): ret = _GetAssetsToAdd(assets, fast_align, disable_compression=False, allow_reads=allow_reads) ret.extend( _GetAssetsToAdd(uncompressed_assets, fast_align, disable_compression=True, allow_reads=allow_reads)) return ret libs_to_add = _GetNativeLibrariesToAdd( native_libs, options.android_abi, options.uncompress_shared_libraries, fast_align, options.library_always_compress, options.library_renames) if options.secondary_android_abi: libs_to_add.extend( _GetNativeLibrariesToAdd( secondary_native_libs, options.secondary_android_abi, options.uncompress_shared_libraries, fast_align, options.library_always_compress, options.library_renames)) if options.expected_file: # We compute expectations without reading the files. This allows us to check # expectations for different targets by just generating their build_configs # and not have to first generate all the actual files and all their # dependencies (for example by just passing --only-verify-expectations). asset_details = _GetAssetDetails(assets, uncompressed_assets, fast_align, allow_reads=False) actual_data = _CreateExpectationsData(libs_to_add, asset_details) diff_utils.CheckExpectations(actual_data, options) if options.only_verify_expectations: if options.depfile: build_utils.WriteDepfile(options.depfile, options.actual_file, inputs=depfile_deps) return # If we are past this point, we are going to actually create the final apk so # we should recompute asset details again but maybe perform some optimizations # based on the size of the files on disk. assets_to_add = _GetAssetDetails( assets, uncompressed_assets, fast_align, allow_reads=True) # Targets generally do not depend on apks, so no need for only_if_changed. with build_utils.AtomicOutput(options.output_apk, only_if_changed=False) as f: with zipfile.ZipFile(options.resource_apk) as resource_apk, \ zipfile.ZipFile(f, 'w') as out_apk: def add_to_zip(zip_path, data, compress=True, alignment=4): zipalign.AddToZipHermetic( out_apk, zip_path, data=data, compress=compress, alignment=0 if compress and not fast_align else alignment) def copy_resource(zipinfo, out_dir=''): add_to_zip( out_dir + zipinfo.filename, resource_apk.read(zipinfo.filename), compress=zipinfo.compress_type != zipfile.ZIP_STORED) # Make assets come before resources in order to maintain the same file # ordering as GYP / aapt. http://crbug.com/561862 resource_infos = resource_apk.infolist() # 1. AndroidManifest.xml logging.debug('Adding AndroidManifest.xml') copy_resource( resource_apk.getinfo('AndroidManifest.xml'), out_dir=apk_manifest_dir) # 2. Assets logging.debug('Adding assets/') _AddFiles(out_apk, assets_to_add) # 3. Dex files logging.debug('Adding classes.dex') if options.dex_file: with open(options.dex_file, 'rb') as dex_file_obj: if options.dex_file.endswith('.dex'): max_dex_number = 1 # This is the case for incremental_install=true. add_to_zip( apk_dex_dir + 'classes.dex', dex_file_obj.read(), compress=not options.uncompress_dex) else: max_dex_number = 0 with zipfile.ZipFile(dex_file_obj) as dex_zip: for dex in (d for d in dex_zip.namelist() if d.endswith('.dex')): max_dex_number += 1 add_to_zip( apk_dex_dir + dex, dex_zip.read(dex), compress=not options.uncompress_dex) if options.jdk_libs_dex_file: with open(options.jdk_libs_dex_file, 'rb') as dex_file_obj: add_to_zip( apk_dex_dir + 'classes{}.dex'.format(max_dex_number + 1), dex_file_obj.read(), compress=not options.uncompress_dex) # 4. Native libraries. logging.debug('Adding lib/') _AddFiles(out_apk, libs_to_add) # Add a placeholder lib if the APK should be multi ABI but is missing libs # for one of the ABIs. native_lib_placeholders = options.native_lib_placeholders secondary_native_lib_placeholders = ( options.secondary_native_lib_placeholders) if options.is_multi_abi: if ((secondary_native_libs or secondary_native_lib_placeholders) and not native_libs and not native_lib_placeholders): native_lib_placeholders += ['libplaceholder.so'] if ((native_libs or native_lib_placeholders) and not secondary_native_libs and not secondary_native_lib_placeholders): secondary_native_lib_placeholders += ['libplaceholder.so'] # Add placeholder libs. for name in sorted(native_lib_placeholders): # Note: Empty libs files are ignored by md5check (can cause issues # with stale builds when the only change is adding/removing # placeholders). apk_path = 'lib/%s/%s' % (options.android_abi, name) add_to_zip(apk_path, '', alignment=0x1000) for name in sorted(secondary_native_lib_placeholders): # Note: Empty libs files are ignored by md5check (can cause issues # with stale builds when the only change is adding/removing # placeholders). apk_path = 'lib/%s/%s' % (options.secondary_android_abi, name) add_to_zip(apk_path, '', alignment=0x1000) # 5. Resources logging.debug('Adding res/') for info in sorted(resource_infos, key=lambda i: i.filename): if info.filename != 'AndroidManifest.xml': copy_resource(info) # 6. Java resources that should be accessible via # Class.getResourceAsStream(), in particular parts of Emma jar. # Prebuilt jars may contain class files which we shouldn't include. logging.debug('Adding Java resources') for java_resource in options.java_resources: with zipfile.ZipFile(java_resource, 'r') as java_resource_jar: for apk_path in sorted(java_resource_jar.namelist()): apk_path_lower = apk_path.lower() if apk_path_lower.startswith('meta-inf/'): continue if apk_path_lower.endswith('/'): continue if apk_path_lower.endswith('.class'): continue add_to_zip(apk_root_dir + apk_path, java_resource_jar.read(apk_path)) if options.format == 'apk': zipalign_path = None if fast_align else options.zipalign_path finalize_apk.FinalizeApk(options.apksigner_jar, zipalign_path, f.name, f.name, options.key_path, options.key_passwd, options.key_name, int(options.min_sdk_version), warnings_as_errors=options.warnings_as_errors) logging.debug('Moving file into place') if options.depfile: build_utils.WriteDepfile(options.depfile, options.output_apk, inputs=depfile_deps)