#!/usr/bin/env python3 # Copyright 2019 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import argparse import os import re import sys import zipfile sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir)) from pylib.dex import dex_parser from util import build_utils import action_helpers # build_utils adds //build to sys.path. _FLAGS_PATH = ( '//chrome/android/java/static_library_dex_reference_workarounds.flags') def _FindIllegalStaticLibraryReferences(static_lib_dex_files, main_apk_dex_files): main_apk_defined_types = set() for dex_file in main_apk_dex_files: for class_def_item in dex_file.class_def_item_list: main_apk_defined_types.add( dex_file.GetTypeString(class_def_item.class_idx)) static_lib_referenced_types = set() for dex_file in static_lib_dex_files: for type_item in dex_file.type_item_list: static_lib_referenced_types.add( dex_file.GetString(type_item.descriptor_idx)) return main_apk_defined_types.intersection(static_lib_referenced_types) def _DexFilesFromPath(path): if zipfile.is_zipfile(path): with zipfile.ZipFile(path) as z: return [ dex_parser.DexFile(bytearray(z.read(name))) for name in z.namelist() if re.match(r'.*classes[0-9]*\.dex$', name) ] else: with open(path) as f: return dex_parser.DexFile(bytearray(f.read())) def main(args): args = build_utils.ExpandFileArgs(args) parser = argparse.ArgumentParser() action_helpers.add_depfile_arg(parser) parser.add_argument( '--stamp', required=True, help='Path to file to touch upon success.') parser.add_argument( '--static-library-dex', required=True, help='classes.dex or classes.zip for the static library APK that was ' 'proguarded with other dependent APKs') parser.add_argument( '--static-library-dependent-dex', required=True, action='append', dest='static_library_dependent_dexes', help='classes.dex or classes.zip for the APKs that use the static ' 'library APK') args = parser.parse_args(args) static_library_dexfiles = _DexFilesFromPath(args.static_library_dex) for path in args.static_library_dependent_dexes: dependent_dexfiles = _DexFilesFromPath(path) illegal_references = _FindIllegalStaticLibraryReferences( static_library_dexfiles, dependent_dexfiles) if illegal_references: msg = 'Found illegal references from {} to {}\n'.format( args.static_library_dex, path) msg += 'Add a -keep rule to avoid this. ' msg += 'See {} for an example and why this is necessary.\n'.format( _FLAGS_PATH) msg += 'The illegal references are:\n' msg += '\n'.join(illegal_references) sys.stderr.write(msg) sys.exit(1) input_paths = [args.static_library_dex] + args.static_library_dependent_dexes build_utils.Touch(args.stamp) action_helpers.write_depfile(args.depfile, args.stamp, inputs=input_paths) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))