def main(raw_args): options = _ParseArgs(raw_args) arsc_package, _ = resource_utils.ExtractArscPackage( options.aapt2_path, options.in_apk) # Extract version from the compiled manifest since it might have been set # via aapt, and not exist in the manifest's text form. version_code, version_name, manifest_package = ( resource_utils.ExtractBinaryManifestValues(options.aapt2_path, options.in_apk)) new_manifest_data = _ProcessManifest(options.src_manifest, arsc_package, options.disable_isolated_processes) with tempfile.NamedTemporaryFile() as tmp_manifest, \ tempfile.NamedTemporaryFile() as tmp_apk: tmp_manifest.write(new_manifest_data) tmp_manifest.flush() cmd = [ options.aapt2_path, 'link', '-o', tmp_apk.name, '--manifest', tmp_manifest.name, '-I', options.in_apk, '--replace-version', '--version-code', version_code, '--version-name', version_name, '--rename-manifest-package', manifest_package, '--debug-mode' ] for j in options.android_sdk_jars: cmd += ['-I', j] subprocess.check_call(cmd) with zipfile.ZipFile(options.out_apk, 'w') as z: path_transform = lambda p: None if p != 'AndroidManifest.xml' else p build_utils.MergeZips(z, [tmp_apk.name], path_transform=path_transform) path_transform = lambda p: None if p == 'AndroidManifest.xml' else p build_utils.MergeZips(z, [options.in_apk], path_transform=path_transform)
def build(self): assert self._injars is not None assert self._outjar is not None assert self._configs is not None _combined_injars_path = os.path.join(self._tmp_dir, 'injars.jar') _combined_libjars_path = os.path.join(self._tmp_dir, 'libjars.jar') _combined_proguard_configs_path = os.path.join(self._tmp_dir, 'includes.txt') build_utils.MergeZips(_combined_injars_path, self._injars) build_utils.MergeZips(_combined_libjars_path, self._libraries) _CombineConfigs(_combined_proguard_configs_path, self.GetConfigs()) if self._proguard_jar_path.endswith('.jar'): cmd = [ 'java', '-jar', self._proguard_jar_path, '-include', _combined_proguard_configs_path ] else: cmd = [ self._proguard_jar_path, '@' + _combined_proguard_configs_path ] if self._mapping: cmd += ['-applymapping', self._mapping] if self._libraries: cmd += ['-libraryjars', _combined_libjars_path] if self._min_api: cmd += [ '-assumenosideeffects class android.os.Build$VERSION {' + ' public static final int SDK_INT return ' + self._min_api + '..9999; }' ] for optimization in self._disabled_optimizations: cmd += ['-optimizations', '!' + optimization] # The output jar must be specified after inputs. cmd += [ '-forceprocessing', '-injars', _combined_injars_path, '-outjars', self._outjar, '-printseeds', self._outjar + '.seeds', '-printusage', self._outjar + '.usage', '-printmapping', self._mapping_output, ] if self._verbose: cmd.append('-verbose') return cmd
def _OptimizeWithProguard(options, config_paths, libraries, dynamic_config_data, print_stdout=False): with build_utils.TempDir() as tmp_dir: combined_injars_path = os.path.join(tmp_dir, 'injars.jar') combined_libjars_path = os.path.join(tmp_dir, 'libjars.jar') combined_proguard_configs_path = os.path.join(tmp_dir, 'includes.txt') tmp_mapping_path = os.path.join(tmp_dir, 'mapping.txt') tmp_output_jar = os.path.join(tmp_dir, 'output.jar') build_utils.MergeZips(combined_injars_path, options.input_paths) build_utils.MergeZips(combined_libjars_path, libraries) with open(combined_proguard_configs_path, 'w') as f: f.write(_CombineConfigs(config_paths, dynamic_config_data)) if options.proguard_path.endswith('.jar'): cmd = [ build_utils.JAVA_PATH, '-jar', options.proguard_path, '-include', combined_proguard_configs_path ] else: cmd = [options.proguard_path, '@' + combined_proguard_configs_path] cmd += [ '-forceprocessing', '-libraryjars', combined_libjars_path, '-injars', combined_injars_path, '-outjars', tmp_output_jar, '-printmapping', tmp_mapping_path, ] # Warning: and Error: are sent to stderr, but messages and Note: are sent # to stdout. stdout_filter = None stderr_filter = None if print_stdout: stdout_filter = _ProguardOutputFilter() stderr_filter = _ProguardOutputFilter() build_utils.CheckOutput( cmd, print_stdout=True, print_stderr=True, stdout_filter=stdout_filter, stderr_filter=stderr_filter) # ProGuard will skip writing if the file would be empty. build_utils.Touch(tmp_mapping_path) # Copy output files to correct locations. shutil.move(tmp_output_jar, options.output_path) shutil.move(tmp_mapping_path, options.mapping_output)
def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64): # Expected files to copy from 32- to 64-bit APK together with whether to # compress within the .apk. expected_files = {'snapshot_blob_32.bin': False} if args.shared_library: expected_files[ args.shared_library] = not args.uncompress_shared_libraries # need to unpack APKs to compare their contents UnpackApk(args.apk_64bit, tmp_dir_64) UnpackApk(args.apk_32bit, tmp_dir_32) # TODO(ssid): unwind file should be included in monochrome apk once all the # official builds start including the file. https://crbug.com/819888. ignores = ['META-INF', 'AndroidManifest.xml', 'unwind_cfi'] if args.ignore_classes_dex: ignores += ['classes.dex', 'classes2.dex'] if args.debug: # see http://crbug.com/648720 ignores += ['webview_licenses.notice'] dcmp = filecmp.dircmp(tmp_dir_64, tmp_dir_32, ignore=ignores) diff_files = GetDiffFiles(dcmp, tmp_dir_32) # Check that diff_files match exactly those files we want to insert into # the 64-bit APK. CheckFilesExpected(diff_files, expected_files, args.component_build) with zipfile.ZipFile(tmp_apk, 'w') as out_zip: build_utils.MergeZips(out_zip, [args.apk_64bit], exclude_patterns=['META-INF/*']) AddDiffFiles(diff_files, tmp_dir_32, out_zip, expected_files, args.component_build, args.uncompress_shared_libraries)
def main(raw_args): options = _ParseArgs(raw_args) with open(options.src_manifest) as f: main_manifest_data = f.read() new_manifest_data = _ProcessManifest(main_manifest_data, options.disable_isolated_processes) with open(options.out_manifest, 'w') as f: f.write(new_manifest_data) if options.out_apk: version_code, version_name = _ExtractVersionFromApk( options.aapt_path, options.in_apk) with tempfile.NamedTemporaryFile() as f: cmd = [ options.aapt_path, 'package', '-f', '-F', f.name, '-M', options.out_manifest, '-I', options.in_apk, '--replace-version', '--version-code', version_code, '--version-name', version_name, '--debug-mode' ] for j in options.android_sdk_jars: cmd += ['-I', j] subprocess.check_call(cmd) with zipfile.ZipFile(f.name, 'a') as z: path_transform = lambda p: None if p == 'AndroidManifest.xml' else p build_utils.MergeZips(z, [options.in_apk], path_transform=path_transform) shutil.copyfile(f.name, options.out_apk) return 0
def main(): parser = argparse.ArgumentParser() parser.add_argument('--input', required=True, help='Input zip file.') parser.add_argument('--output', required=True, help='Output zip file') parser.add_argument('--exclude-globs', help='GN list of exclude globs') parser.add_argument('--include-globs', help='GN list of include globs') parser.add_argument( '--strip-resource-classes-for', help='GN list of java package names exclude R.class files in.') argv = build_utils.ExpandFileArgs(sys.argv[1:]) args = parser.parse_args(argv) args.exclude_globs = build_utils.ParseGnList(args.exclude_globs) args.include_globs = build_utils.ParseGnList(args.include_globs) args.strip_resource_classes_for = build_utils.ParseGnList( args.strip_resource_classes_for) path_transform = CreatePathTransform(args.exclude_globs, args.include_globs, args.strip_resource_classes_for) with build_utils.AtomicOutput(args.output) as f: if path_transform: build_utils.MergeZips(f.name, [args.input], path_transform=path_transform) else: shutil.copy(args.input, f.name)
def main(args): args = build_utils.ExpandFileArgs(args) parser = optparse.OptionParser() build_utils.AddDepfileOption(parser) parser.add_option('--output', help='Path to output jar.') parser.add_option('--use-ijars', action='store_true', help='Use .interface.jar rather than the given jars.') parser.add_option('--inputs', action='append', help='List of jar inputs.') options, _ = parser.parse_args(args) build_utils.CheckOptions(options, parser, ['output', 'inputs']) input_jars = [] for inputs_arg in options.inputs: input_jars.extend(build_utils.ParseGypList(inputs_arg)) if options.use_ijars: ijar_re = re.compile(r'\.jar$') input_jars = [ijar_re.sub('.interface.jar', p) for p in input_jars] build_utils.MergeZips(options.output, input_jars) if options.depfile: build_utils.WriteDepfile( options.depfile, input_jars + build_utils.GetPythonDependencies())
def main(argv): options, _ = ParseArgs(argv) input_jars = build_utils.ParseGypList(options.input_jars_paths) if options.testapp: dependency_class_filters = [ '*R.class', '*R$*.class', '*Manifest.class', '*BuildConfig.class' ] build_utils.MergeZips(options.test_jar_path, input_jars, dependency_class_filters) if ((options.configuration_name == 'Release' and options.proguard_enabled) or (options.configuration_name == 'Debug' and options.debug_build_proguard_enabled)): DoProguard(options) else: output_files = [ options.obfuscated_jar_path, options.obfuscated_jar_path + '.info', options.obfuscated_jar_path + '.dump', options.obfuscated_jar_path + '.seeds', options.obfuscated_jar_path + '.usage', options.obfuscated_jar_path + '.mapping' ] for f in output_files: if os.path.exists(f): os.remove(f) build_utils.Touch(f) if options.stamp: build_utils.Touch(options.stamp)
def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64): # Expected files to copy from 32- to 64-bit APK together with whether to # compress within the .apk. expected_files = {'snapshot_blob_32.bin': False} if args.shared_library: expected_files[ args.shared_library] = not args.uncompress_shared_libraries if args.has_unwind_cfi: expected_files['unwind_cfi_32'] = False # TODO(crbug.com/839191): we should pass this in via script arguments. if not args.loadable_module_32: args.loadable_module_32.append('libarcore_sdk_c_minimal.so') for f in args.loadable_module_32: expected_files[f] = not args.uncompress_shared_libraries for f in args.loadable_module_64: expected_files[f] = not args.uncompress_shared_libraries # need to unpack APKs to compare their contents UnpackApk(args.apk_64bit, tmp_dir_64) UnpackApk(args.apk_32bit, tmp_dir_32) ignores = ['META-INF', 'AndroidManifest.xml'] if args.ignore_classes_dex: ignores += ['classes.dex', 'classes2.dex'] if args.debug: # see http://crbug.com/648720 ignores += ['webview_licenses.notice'] dcmp = filecmp.dircmp(tmp_dir_64, tmp_dir_32, ignore=ignores) diff_files = GetDiffFiles(dcmp, tmp_dir_32) # Check that diff_files match exactly those files we want to insert into # the 64-bit APK. CheckFilesExpected(diff_files, expected_files, args.component_build) with zipfile.ZipFile(tmp_apk, 'w') as out_zip: exclude_patterns = ['META-INF/*'] # If there are libraries for which we don't want the 32 bit versions, we # should remove them here. if args.loadable_module_32: exclude_patterns.extend([ '*' + f for f in args.loadable_module_32 if f not in args.loadable_module_64 ]) path_transform = ( lambda p: None if build_utils.MatchesGlob(p, exclude_patterns) else p) build_utils.MergeZips(out_zip, [args.apk_64bit], path_transform=path_transform) AddDiffFiles(diff_files, tmp_dir_32, out_zip, expected_files, args.component_build, args.uncompress_shared_libraries)
def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64): # expected_files is the set of 32-bit related files that we expect to differ # between a 32- and 64-bit build. Hence, they will be skipped when seeding the # generated APK with the original 64-bit version, and explicitly copied in # from the 32-bit version. expected_files = [] assets_path = 'base/assets' if args.bundle else 'assets' expected_files.append('%s/snapshot_blob_32.bin' % assets_path) if args.has_unwind_cfi: expected_files.append('%s/unwind_cfi_32' % assets_path) # All native libraries are assumed to differ, and will be merged. with zipfile.ZipFile(args.apk_32bit) as z: expected_files.extend([p for p in z.namelist() if p.endswith('.so')]) UnpackApk(args.apk_32bit, tmp_dir_32) UnpackApk(args.apk_64bit, tmp_dir_64, expected_files) # These are files that we know will be different, and we will hence ignore in # the file comparison. ignores = ['META-INF', 'AndroidManifest.xml'] if args.ignore_classes_dex: ignores += ['classes.dex', 'classes2.dex', 'classes3.dex'] if args.debug: # see http://crbug.com/648720 ignores += ['webview_licenses.notice'] if args.bundle: # if merging a bundle we must ignore the bundle specific # proto files as they will always be different. ignores += ['BundleConfig.pb', 'native.pb'] dcmp = filecmp.dircmp( tmp_dir_64, tmp_dir_32, ignore=ignores) diff_files = GetDiffFiles(dcmp, tmp_dir_32) # Check that diff_files match exactly those files we want to insert into # the 64-bit APK. CheckFilesExpected(diff_files, expected_files) with zipfile.ZipFile(tmp_apk, 'w') as out_zip: exclude_patterns = ['META-INF/*'] + expected_files # Build the initial merged APK from the 64-bit APK, excluding all files we # will pull from the 32-bit APK. path_transform = ( lambda p: None if build_utils.MatchesGlob(p, exclude_patterns) else p) build_utils.MergeZips( out_zip, [args.apk_64bit], path_transform=path_transform) # Add the files from the 32-bit APK. AddDiffFiles(diff_files, tmp_dir_32, out_zip, args.uncompress_shared_libraries)
def CombineZips(zip_files, output_path): # When packaging resources, if the top-level directories in the zip file are # of the form 0, 1, ..., then each subdirectory will be passed to aapt as a # resources directory. While some resources just clobber others (image files, # etc), other resources (particularly .xml files) need to be more # intelligently merged. That merging is left up to aapt. def path_transform(name, src_zip): return '%d/%s' % (zip_files.index(src_zip), name) build_utils.MergeZips(output_path, zip_files, path_transform=path_transform)
def main(args): args = build_utils.ExpandFileArgs(args) parser = argparse.ArgumentParser(args) parser.add_argument('--input-files', help='GN-list of files to zip.') parser.add_argument( '--input-files-base-dir', help='Paths in the archive will be relative to this directory') parser.add_argument('--input-zips', help='GN-list of zips to merge.') parser.add_argument('--input-zips-excluded-globs', help='GN-list of globs for paths to exclude.') parser.add_argument('--output', required=True, help='Path to output archive.') compress_group = parser.add_mutually_exclusive_group() compress_group.add_argument('--compress', action='store_true', help='Compress entries') compress_group.add_argument('--no-compress', action='store_false', dest='compress', help='Do not compress entries') build_utils.AddDepfileOption(parser) options = parser.parse_args(args) with build_utils.AtomicOutput(options.output) as f: with zipfile.ZipFile(f.name, 'w') as out_zip: depfile_deps = None if options.input_files: files = build_utils.ParseGnList(options.input_files) build_utils.DoZip(files, out_zip, base_dir=options.input_files_base_dir, compress_fn=lambda _: options.compress) if options.input_zips: files = build_utils.ParseGnList(options.input_zips) depfile_deps = files path_transform = None if options.input_zips_excluded_globs: globs = build_utils.ParseGnList( options.input_zips_excluded_globs) path_transform = ( lambda p: None if build_utils.MatchesGlob(p, globs) else p) build_utils.MergeZips(out_zip, files, path_transform=path_transform, compress=options.compress) # Depfile used only by dist_jar(). if options.depfile: build_utils.WriteDepfile(options.depfile, options.output, inputs=depfile_deps, add_pydeps=False)
def main(args): args = build_utils.ExpandFileArgs(args) parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) parser.add_argument('--output', required=True, help='Path to output aar.') parser.add_argument('--jars', required=True, help='GN list of jar inputs.') parser.add_argument('--dependencies-res-zips', required=True, help='GN list of resource zips') parser.add_argument('--r-text-files', required=True, help='GN list of R.txt files to merge') parser.add_argument('--proguard-configs', required=True, help='GN list of ProGuard flag files to merge.') parser.add_argument( '--android-manifest', help='Path to AndroidManifest.xml to include.', default=os.path.join(_ANDROID_BUILD_DIR, 'AndroidManifest.xml')) options = parser.parse_args(args) options.jars = build_utils.ParseGnList(options.jars) options.dependencies_res_zips = build_utils.ParseGnList( options.dependencies_res_zips) options.r_text_files = build_utils.ParseGnList(options.r_text_files) options.proguard_configs = build_utils.ParseGnList(options.proguard_configs) with tempfile.NamedTemporaryFile(delete=False) as staging_file: try: with zipfile.ZipFile(staging_file.name, 'w') as z: build_utils.AddToZipHermetic( z, 'AndroidManifest.xml', src_path=options.android_manifest) with tempfile.NamedTemporaryFile() as jar_file: build_utils.MergeZips(jar_file.name, options.jars) build_utils.AddToZipHermetic(z, 'classes.jar', src_path=jar_file.name) build_utils.AddToZipHermetic( z, 'R.txt', data=_MergeRTxt(options.r_text_files)) build_utils.AddToZipHermetic(z, 'public.txt', data='') if options.proguard_configs: build_utils.AddToZipHermetic( z, 'proguard.txt', data=_MergeProguardConfigs(options.proguard_configs)) _AddResources(z, options.dependencies_res_zips) except: os.unlink(staging_file.name) raise shutil.move(staging_file.name, options.output) if options.depfile: all_inputs = (options.jars + options.dependencies_res_zips + options.r_text_files + options.proguard_configs) build_utils.WriteDepfile(options.depfile, options.output, all_inputs)
def main(args): args = build_utils.ExpandFileArgs(args) parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) parser.add_argument('--output', required=True, help='Path to output jar.') parser.add_argument('--jars', required=True, help='GN list of jar inputs.') options = parser.parse_args(args) input_jars = build_utils.ParseGnList(options.jars) build_utils.MergeZips(options.output, input_jars) if options.depfile: build_utils.WriteDepfile(options.depfile, options.output, input_jars)
def Jar(class_files, classes_dir, jar_path, manifest_file=None, provider_configurations=None, additional_files=None): jar_path = os.path.abspath(jar_path) # The paths of the files in the jar will be the same as they are passed in to # the command. Because of this, the command should be run in # options.classes_dir so the .class file paths in the jar are correct. jar_cwd = classes_dir class_files_rel = [os.path.relpath(f, jar_cwd) for f in class_files] with tempfile.NamedTemporaryFile(suffix='.jar') as tmp_jar: jar_cmd = ['jar', 'cf0', tmp_jar.name] if manifest_file: jar_cmd[1] += 'm' jar_cmd.append(os.path.abspath(manifest_file)) jar_cmd.extend(class_files_rel) for filepath, jar_filepath in additional_files or []: full_jar_filepath = os.path.join(jar_cwd, jar_filepath) jar_dir = os.path.dirname(full_jar_filepath) if not os.path.exists(jar_dir): os.makedirs(jar_dir) # Some of our JARs are mode 0440 because they exist in the source tree as # symlinks to JARs managed by CIPD. shutil.copyfile copies the contents, # not the permissions, so the resulting copy is writeable despite the # the source JAR not being so. (shutil.copy does copy the permissions and # as such doesn't work without changing the mode after.) shutil.copyfile(filepath, full_jar_filepath) jar_cmd.append(jar_filepath) if provider_configurations: service_dir = os.path.join(jar_cwd, 'META-INF', 'services') if not os.path.exists(service_dir): os.makedirs(service_dir) for config in provider_configurations: config_jar_path = os.path.join(service_dir, os.path.basename(config)) shutil.copy(config, config_jar_path) jar_cmd.append(os.path.relpath(config_jar_path, jar_cwd)) if not class_files_rel: empty_file = os.path.join(classes_dir, '.empty') build_utils.Touch(empty_file) jar_cmd.append(os.path.relpath(empty_file, jar_cwd)) build_utils.CheckOutput(jar_cmd, cwd=jar_cwd) # Zeros out timestamps so that builds are hermetic. build_utils.MergeZips(jar_path, [tmp_jar.name])
def CombineZips(zip_files, output_path, support_zh_hk): # When packaging resources, if the top-level directories in the zip file are # of the form 0, 1, ..., then each subdirectory will be passed to aapt as a # resources directory. While some resources just clobber others (image files, # etc), other resources (particularly .xml files) need to be more # intelligently merged. That merging is left up to aapt. def path_transform(name, src_zip): return '%d/%s' % (zip_files.index(src_zip), name) # We don't currently support zh-HK on Chrome for Android, but on the # native side we resolve zh-HK resources to zh-TW. This logic is # duplicated here by just copying the zh-TW res folders to zh-HK. # See https://crbug.com/780847. with build_utils.TempDir() as temp_dir: if support_zh_hk: zip_files = _DuplicateZhResources(zip_files, temp_dir) build_utils.MergeZips(output_path, zip_files, path_transform=path_transform)
def main(args): args = build_utils.ExpandFileArgs(args) parser = optparse.OptionParser() build_utils.AddDepfileOption(parser) parser.add_option('--output', help='Path to output jar.') parser.add_option('--inputs', action='append', help='List of jar inputs.') options, _ = parser.parse_args(args) build_utils.CheckOptions(options, parser, ['output', 'inputs']) input_jars = [] for inputs_arg in options.inputs: input_jars.extend(build_utils.ParseGnList(inputs_arg)) build_utils.MergeZips(options.output, input_jars) if options.depfile: build_utils.WriteDepfile(options.depfile, options.output, input_jars)
def Jar(class_files, classes_dir, jar_path, manifest_file=None, provider_configurations=None, additional_files=None): jar_path = os.path.abspath(jar_path) # The paths of the files in the jar will be the same as they are passed in to # the command. Because of this, the command should be run in # options.classes_dir so the .class file paths in the jar are correct. jar_cwd = classes_dir class_files_rel = [os.path.relpath(f, jar_cwd) for f in class_files] with tempfile.NamedTemporaryFile(suffix='.jar') as tmp_jar: jar_cmd = ['jar', 'cf0', tmp_jar.name] if manifest_file: jar_cmd[1] += 'm' jar_cmd.append(os.path.abspath(manifest_file)) jar_cmd.extend(class_files_rel) for filepath, jar_filepath in additional_files or []: full_jar_filepath = os.path.join(jar_cwd, jar_filepath) jar_dir = os.path.dirname(full_jar_filepath) if not os.path.exists(jar_dir): os.makedirs(jar_dir) shutil.copy(filepath, full_jar_filepath) jar_cmd.append(jar_filepath) if provider_configurations: service_dir = os.path.join(jar_cwd, 'META-INF', 'services') if not os.path.exists(service_dir): os.makedirs(service_dir) for config in provider_configurations: config_jar_path = os.path.join(service_dir, os.path.basename(config)) shutil.copy(config, config_jar_path) jar_cmd.append(os.path.relpath(config_jar_path, jar_cwd)) if not class_files_rel: empty_file = os.path.join(classes_dir, '.empty') build_utils.Touch(empty_file) jar_cmd.append(os.path.relpath(empty_file, jar_cwd)) build_utils.CheckOutput(jar_cmd, cwd=jar_cwd) # Zeros out timestamps so that builds are hermetic. build_utils.MergeZips(jar_path, [tmp_jar.name])
def main(): options = _ParseArgs() with open(options.src_manifest) as f: main_manifest_data = f.read() new_manifest_data = _ProcessManifest(main_manifest_data, options.disable_isolated_processes) with open(options.out_manifest, 'w') as f: f.write(new_manifest_data) if options.out_apk: version_code, version_name = _ExtractVersionFromApk( options.aapt_path, options.in_apk) with tempfile.NamedTemporaryFile() as f: cmd = [options.aapt_path, 'package', '-f', '-F', f.name, '-M', options.out_manifest, '-I', options.android_sdk_jar, '-I', options.in_apk, '--replace-version', '--version-code', version_code, '--version-name', version_name, '--debug-mode'] subprocess.check_call(cmd) with zipfile.ZipFile(f.name, 'a') as z: build_utils.MergeZips( z, [options.in_apk], exclude_patterns=['AndroidManifest.xml']) shutil.copyfile(f.name, options.out_apk)
def main(): parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) parser.add_argument( '--excluded-classes', help='A list of .class file patterns to exclude from the jar.') parser.add_argument('--src-search-dirs', action='append', help='A list of directories that should be searched' ' for the source files.') parser.add_argument('--src-files', action='append', help='A list of source files to jar.') parser.add_argument( '--src-jars', action='append', help='A list of source jars to include in addition to source files.') parser.add_argument('--src-list-files', action='append', help='A list of files that contain a list of sources,' ' e.g. a list of \'.sources\' files generated by GN.') parser.add_argument('--jar-path', help='Jar output path.', required=True) options = parser.parse_args() src_jars = [] for gn_list in options.src_jars: src_jars.extend(build_utils.ParseGnList(gn_list)) src_search_dirs = [] for gn_src_search_dirs in options.src_search_dirs: src_search_dirs.extend(build_utils.ParseGnList(gn_src_search_dirs)) src_list_files = [] if options.src_list_files: for gn_src_list_file in options.src_list_files: src_list_files.extend(build_utils.ParseGnList(gn_src_list_file)) src_files = [] for gn_src_files in options.src_files: src_files.extend(build_utils.ParseGnList(gn_src_files)) # Add files from --source_list_files for src_list_file in src_list_files: with open(src_list_file, 'r') as f: src_files.extend(f.read().splitlines()) # Preprocess source files by removing any prefix that comes before # the Java package name. for i, s in enumerate(src_files): prefix_position = s.find(JAVA_PACKAGE_PREFIX) if prefix_position != -1: src_files[i] = s[prefix_position:] excluded_classes = [] if options.excluded_classes: classes = build_utils.ParseGnList(options.excluded_classes) excluded_classes.extend(f.replace('.class', '.java') for f in classes) predicate = None if excluded_classes: predicate = lambda f: not build_utils.MatchesGlob(f, excluded_classes) # Create a dictionary that maps every source directory # to source files that it contains. dir_to_files_map = {} # Initialize the map. for src_search_dir in src_search_dirs: dir_to_files_map[src_search_dir] = [] # Fill the map. for src_file in src_files: number_of_file_instances = 0 for src_search_dir in src_search_dirs: target_path = os.path.join(src_search_dir, src_file) if os.path.isfile(target_path): number_of_file_instances += 1 if not predicate or predicate(src_file): dir_to_files_map[src_search_dir].append(target_path) if (number_of_file_instances > 1): raise Exception( 'There is more than one instance of file %s in %s' % (src_file, src_search_dirs)) if (number_of_file_instances < 1): raise Exception('Unable to find file %s in %s' % (src_file, src_search_dirs)) # Jar the sources from every source search directory. with build_utils.AtomicOutput(options.jar_path) as o, \ zipfile.ZipFile(o, 'w', zipfile.ZIP_DEFLATED) as z: for src_search_dir in src_search_dirs: subpaths = dir_to_files_map[src_search_dir] if subpaths: build_utils.DoZip(subpaths, z, base_dir=src_search_dir) else: raise Exception( 'Directory %s does not contain any files and can be' ' removed from the list of directories to search' % src_search_dir) # Jar additional src jars if src_jars: build_utils.MergeZips(z, src_jars, compress=True) if options.depfile: deps = [] for sources in dir_to_files_map.itervalues(): deps.extend(sources) # Srcjar deps already captured in GN rules (no need to list them here). build_utils.WriteDepfile(options.depfile, options.jar_path, deps)
def main(args): args = build_utils.ExpandFileArgs(args) parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) parser.add_argument('--output', required=True, help='Path to output aar.') parser.add_argument('--jars', required=True, help='GN list of jar inputs.') parser.add_argument('--dependencies-res-zips', required=True, help='GN list of resource zips') parser.add_argument('--r-text-files', required=True, help='GN list of R.txt files to merge') parser.add_argument('--proguard-configs', required=True, help='GN list of ProGuard flag files to merge.') parser.add_argument('--android-manifest', help='Path to AndroidManifest.xml to include.', default=os.path.join(_ANDROID_BUILD_DIR, 'AndroidManifest.xml')) parser.add_argument('--native-libraries', default='', help='GN list of native libraries. If non-empty then ' 'ABI must be specified.') parser.add_argument('--abi', help='ABI (e.g. armeabi-v7a) for native libraries.') parser.add_argument('--jar-excluded-globs', help='GN-list of globs for paths to exclude in jar.') parser.add_argument('--jar-included-globs', help='GN-list of globs for paths to include in jar.') options = parser.parse_args(args) if options.native_libraries and not options.abi: parser.error('You must provide --abi if you have native libs') options.jars = build_utils.ParseGnList(options.jars) options.dependencies_res_zips = build_utils.ParseGnList( options.dependencies_res_zips) options.r_text_files = build_utils.ParseGnList(options.r_text_files) options.proguard_configs = build_utils.ParseGnList( options.proguard_configs) options.native_libraries = build_utils.ParseGnList( options.native_libraries) options.jar_excluded_globs = build_utils.ParseGnList( options.jar_excluded_globs) options.jar_included_globs = build_utils.ParseGnList( options.jar_included_globs) with tempfile.NamedTemporaryFile(delete=False) as staging_file: try: with zipfile.ZipFile(staging_file.name, 'w') as z: build_utils.AddToZipHermetic(z, 'AndroidManifest.xml', src_path=options.android_manifest) path_transform = CreatePathTransform( options.jar_excluded_globs, options.jar_included_globs, []) with tempfile.NamedTemporaryFile() as jar_file: build_utils.MergeZips(jar_file.name, options.jars, path_transform=path_transform) build_utils.AddToZipHermetic(z, 'classes.jar', src_path=jar_file.name) build_utils.AddToZipHermetic(z, 'R.txt', data=_MergeRTxt( options.r_text_files)) build_utils.AddToZipHermetic(z, 'public.txt', data='') if options.proguard_configs: build_utils.AddToZipHermetic(z, 'proguard.txt', data=_MergeProguardConfigs( options.proguard_configs)) _AddResources(z, options.dependencies_res_zips) for native_library in options.native_libraries: libname = os.path.basename(native_library) build_utils.AddToZipHermetic(z, os.path.join( 'jni', options.abi, libname), src_path=native_library) except: os.unlink(staging_file.name) raise shutil.move(staging_file.name, options.output) if options.depfile: all_inputs = (options.jars + options.dependencies_res_zips + options.r_text_files + options.proguard_configs) build_utils.WriteDepfile(options.depfile, options.output, all_inputs, add_pydeps=False)
def main(argv): options, _ = ParseArgs(argv) library_classpath = [options.android_sdk_jar] input_jars = build_utils.ParseGypList(options.input_jars_paths) dependency_class_filters = [ '*R.class', '*R$*.class', '*Manifest.class', '*BuildConfig.class' ] if options.testapp: build_utils.MergeZips(options.test_jar_path, input_jars, dependency_class_filters) if options.configuration_name == 'Release' and options.proguard_enabled: proguard_cmd = [ 'java', '-jar', options.proguard_jar_path, '-forceprocessing', '-libraryjars', ':'.join(library_classpath), '-dump', options.obfuscated_jar_path + '.dump', '-printseeds', options.obfuscated_jar_path + '.seeds', '-printusage', options.obfuscated_jar_path + '.usage', '-printmapping', options.obfuscated_jar_path + '.mapping', ] exclude_paths = [] configs = build_utils.ParseGypList(options.proguard_configs) if (options.tested_apk_obfuscated_jar_path and options.tested_apk_obfuscated_jar_path != '/'): # configs should only contain the process_resources.py generated config. assert len(configs) == 1, ( 'test apks should not have custom proguard configs: ' + str(configs)) tested_jar_info = build_utils.ReadJson( options.tested_apk_obfuscated_jar_path + '.info') exclude_paths = tested_jar_info['inputs'] configs = tested_jar_info['configs'] proguard_cmd += [ '-dontobfuscate', '-dontoptimize', '-dontshrink', '-dontskipnonpubliclibraryclassmembers', '-libraryjars', options.tested_apk_obfuscated_jar_path, '-applymapping', options.tested_apk_obfuscated_jar_path + '.mapping', ] proguard_injars = [p for p in input_jars if p not in exclude_paths] proguard_cmd += ['-injars', ':'.join(proguard_injars)] for config_file in configs: proguard_cmd += ['-include', config_file] # The output jar must be specified after inputs. proguard_cmd += ['-outjars', options.obfuscated_jar_path] build_utils.CheckOutput(proguard_cmd) this_info = {'inputs': proguard_injars, 'configs': configs} build_utils.WriteJson(this_info, options.obfuscated_jar_path + '.info') else: output_files = [ options.obfuscated_jar_path, options.obfuscated_jar_path + '.info', options.obfuscated_jar_path + '.dump', options.obfuscated_jar_path + '.seeds', options.obfuscated_jar_path + '.usage', options.obfuscated_jar_path + '.mapping' ] for f in output_files: if os.path.exists(f): os.remove(f) build_utils.Touch(f) if options.stamp: build_utils.Touch(options.stamp)
def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64): # Expected files to copy from 32- to 64-bit APK together with whether to # compress within the .apk. expected_files = {'snapshot_blob_32.bin': False} if args.shared_library: expected_files[ args.shared_library] = not args.uncompress_shared_libraries if args.has_unwind_cfi: expected_files['unwind_cfi_32'] = False # TODO(crbug.com/839191): we should pass this in via script arguments. if not args.loadable_module_32: args.loadable_module_32.append('libarcore_sdk_c.so') for f in args.loadable_module_32: expected_files[f] = not args.uncompress_shared_libraries for f in args.loadable_module_64: expected_files[f] = not args.uncompress_shared_libraries # need to unpack APKs to compare their contents assets_path = 'base/assets' if args.bundle else 'assets' exclude_files_64 = [ '%s/snapshot_blob_32.bin' % assets_path, GetTargetAbiPath(args.apk_32bit, args.shared_library) ] if 'libcrashpad_handler.so' in expected_files: exclude_files_64.append( GetTargetAbiPath(args.apk_32bit, 'libcrashpad_handler.so')) if 'libcrashpad_handler_trampoline.so' in expected_files: exclude_files_64.append( GetTargetAbiPath(args.apk_32bit, 'libcrashpad_handler_trampoline.so')) if args.has_unwind_cfi: exclude_files_64.append('%s/unwind_cfi_32' % assets_path) UnpackApk(args.apk_64bit, tmp_dir_64, exclude_files_64) UnpackApk(args.apk_32bit, tmp_dir_32) ignores = ['META-INF', 'AndroidManifest.xml'] if args.ignore_classes_dex: ignores += ['classes.dex', 'classes2.dex'] if args.debug: # see http://crbug.com/648720 ignores += ['webview_licenses.notice'] if args.bundle: # if merging a bundle we must ignore the bundle specific # proto files as they will always be different. ignores += ['BundleConfig.pb', 'native.pb', 'resources.pb'] dcmp = filecmp.dircmp(tmp_dir_64, tmp_dir_32, ignore=ignores) diff_files = GetDiffFiles(dcmp, tmp_dir_32) # Check that diff_files match exactly those files we want to insert into # the 64-bit APK. CheckFilesExpected(diff_files, expected_files, args.component_build) with zipfile.ZipFile(tmp_apk, 'w') as out_zip: exclude_patterns = ['META-INF/*'] + exclude_files_64 # If there are libraries for which we don't want the 32 bit versions, we # should remove them here. if args.loadable_module_32: exclude_patterns.extend([ '*' + f for f in args.loadable_module_32 if f not in args.loadable_module_64 ]) path_transform = ( lambda p: None if build_utils.MatchesGlob(p, exclude_patterns) else p) build_utils.MergeZips(out_zip, [args.apk_64bit], path_transform=path_transform) AddDiffFiles(diff_files, tmp_dir_32, out_zip, expected_files, args.component_build, args.uncompress_shared_libraries)