mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
160 lines
5.7 KiB
Python
Executable File
160 lines
5.7 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Copyright (c) 2018 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Extracts a bundle module's classes from jar created in the synchronized
|
|
proguarding step and packages them into a new jar.
|
|
|
|
Synchronized proguarding means that, when several app modules are combined into
|
|
an app bundle, all un-optimized jars for all modules are grouped and sent to a
|
|
single proguard command, which generates a single, common, intermediate
|
|
optimized jar, and its mapping file.
|
|
|
|
This script is used to extract, from this synchronized proguard jar, all the
|
|
optimized classes corresponding to a single module, into a new .jar file. The
|
|
latter will be compiled later into the module's dex file.
|
|
|
|
For this, the script reads the module's un-obfuscated class names from the
|
|
module's unoptimized jars. Then, it maps those to obfuscated class names using
|
|
the proguard mapping file. Finally, it extracts the module's class files from
|
|
the proguarded jar and zips them into a new module jar. """
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
import zipfile
|
|
|
|
from util import build_utils
|
|
|
|
MANIFEST = """Manifest-Version: 1.0
|
|
Created-By: generate_proguarded_module_jar.py
|
|
"""
|
|
|
|
|
|
# TODO(tiborg): Share with merge_jar_info_files.py.
|
|
def _FullJavaNameFromClassFilePath(path):
|
|
if not path.endswith('.class'):
|
|
return ''
|
|
path = os.path.splitext(path)[0]
|
|
parts = []
|
|
while path:
|
|
# Use split to be platform independent.
|
|
head, tail = os.path.split(path)
|
|
path = head
|
|
parts.append(tail)
|
|
parts.reverse() # Package comes first
|
|
return '.'.join(parts)
|
|
|
|
|
|
def main(args):
|
|
args = build_utils.ExpandFileArgs(args)
|
|
parser = argparse.ArgumentParser()
|
|
build_utils.AddDepfileOption(parser)
|
|
parser.add_argument(
|
|
'--proguarded-jar',
|
|
required=True,
|
|
help='Path to input jar produced by synchronized proguarding')
|
|
parser.add_argument(
|
|
'--proguard-mapping',
|
|
required=True,
|
|
help='Path to input proguard mapping produced by synchronized '
|
|
'proguarding')
|
|
parser.add_argument(
|
|
'--module-input-jars',
|
|
required=True,
|
|
help='GN-list of input paths to un-optimized jar files for the current '
|
|
'module. The optimized versions of their .class files will go into '
|
|
'the output jar.')
|
|
parser.add_argument(
|
|
'--output-jar',
|
|
required=True,
|
|
help='Path to output jar file containing the module\'s optimized class '
|
|
'files')
|
|
parser.add_argument(
|
|
'--is-base-module',
|
|
action='store_true',
|
|
help='Inidcates to extract class files for a base module')
|
|
options = parser.parse_args(args)
|
|
options.module_input_jars = build_utils.ParseGnList(options.module_input_jars)
|
|
|
|
# Read class names of the currently processed module.
|
|
classes = set()
|
|
for module_jar in options.module_input_jars:
|
|
with zipfile.ZipFile(module_jar) as zip_info:
|
|
for path in zip_info.namelist():
|
|
fully_qualified_name = _FullJavaNameFromClassFilePath(path)
|
|
if fully_qualified_name:
|
|
classes.add(fully_qualified_name)
|
|
|
|
# Parse the proguarding mapping to be able to map un-obfuscated to obfuscated
|
|
# names.
|
|
# Proguard mapping files have the following format:
|
|
#
|
|
# {un-obfuscated class name 1} -> {obfuscated class name 1}:
|
|
# {un-obfuscated member name 1} -> {obfuscated member name 1}
|
|
# ...
|
|
# {un-obfuscated class name 2} -> {obfuscated class name 2}:
|
|
# ...
|
|
# ...
|
|
obfuscation_map = {}
|
|
with open(options.proguard_mapping, 'r') as proguard_mapping_file:
|
|
for line in proguard_mapping_file:
|
|
# Skip indented lines since they map member names and not class names.
|
|
if line.startswith(' '):
|
|
continue
|
|
line = line.strip()
|
|
# Skip empty lines.
|
|
if not line:
|
|
continue
|
|
assert line.endswith(':')
|
|
full, obfuscated = line.strip(':').split(' -> ')
|
|
assert full
|
|
assert obfuscated
|
|
obfuscation_map[full] = obfuscated
|
|
|
|
# Collect the obfuscated names of classes, which should go into the currently
|
|
# processed module.
|
|
obfuscated_module_classes = set(
|
|
obfuscation_map[c] for c in classes if c in obfuscation_map)
|
|
|
|
# Collect horizontally merged classes to later make sure that those only go
|
|
# into the base module. Merging classes horizontally means that proguard took
|
|
# two classes that don't inherit from each other and merged them into one.
|
|
horiz_merged_classes = set()
|
|
obfuscated_classes = sorted(obfuscation_map.values())
|
|
prev_obfuscated_class = None
|
|
for obfuscated_class in obfuscated_classes:
|
|
if prev_obfuscated_class and obfuscated_class == prev_obfuscated_class:
|
|
horiz_merged_classes.add(obfuscated_class)
|
|
prev_obfuscated_class = obfuscated_class
|
|
|
|
# Move horizontally merged classes into the base module.
|
|
if options.is_base_module:
|
|
obfuscated_module_classes |= horiz_merged_classes
|
|
else:
|
|
obfuscated_module_classes -= horiz_merged_classes
|
|
|
|
# Extract module class files from proguarded jar and store them in a module
|
|
# split jar.
|
|
with zipfile.ZipFile(
|
|
os.path.abspath(options.output_jar), 'w',
|
|
zipfile.ZIP_DEFLATED) as output_jar:
|
|
with zipfile.ZipFile(os.path.abspath(options.proguarded_jar),
|
|
'r') as proguarded_jar:
|
|
for obfuscated_class in obfuscated_module_classes:
|
|
class_path = obfuscated_class.replace('.', '/') + '.class'
|
|
class_file_content = proguarded_jar.read(class_path)
|
|
output_jar.writestr(class_path, class_file_content)
|
|
output_jar.writestr('META-INF/MANIFEST.MF', MANIFEST)
|
|
|
|
if options.depfile:
|
|
build_utils.WriteDepfile(
|
|
options.depfile, options.output_jar, options.module_input_jars +
|
|
[options.proguard_mapping, options.proguarded_jar], add_pydeps=False)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(sys.argv[1:])
|