Convert apk obfuscation to python

For the apk specific java files, we now run proguard on the jar instead of the classes.

BUG=375324,359249

Review URL: https://codereview.chromium.org/322443005

git-svn-id: http://src.chromium.org/svn/trunk/src/build@276377 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
cjhopman@chromium.org 2014-06-11 13:19:47 +00:00
Родитель 13a0d7453b
Коммит 9a78557855
4 изменённых файлов: 188 добавлений и 210 удалений

Просмотреть файл

@ -1,175 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2005-2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project default="-obfuscate">
<property name="verbose" value="false" />
<property name="out.dir" location="${OUT_DIR}" />
<!-- Output directories -->
<property name="out.dir" value="bin" />
<property name="out.absolute.dir" location="${out.dir}" />
<property name="out.classes.absolute.dir" location="${out.dir}/classes" />
<!-- tools location -->
<property name="sdk.dir" location="${ANDROID_SDK_ROOT}"/>
<property name="android.tools.dir" location="${sdk.dir}/tools" />
<property name="project.target.android.jar" location="${ANDROID_SDK_JAR}" />
<path id="project.target.class.path">
<pathelement location="${project.target.android.jar}" />
</path>
<!-- jar file from where the tasks are loaded -->
<path id="android.antlibs">
<pathelement path="${sdk.dir}/tools/lib/ant-tasks.jar" />
</path>
<!-- Custom tasks -->
<taskdef resource="anttasks.properties" classpathref="android.antlibs" />
<!-- Classpath for javac -->
<path id="javac.custom.classpath">
<filelist files="${INPUT_JARS_PATHS}"/>
</path>
<condition property="project.is.testapp" value="true" else="false">
<equals arg1="${IS_TEST_APK}" arg2="1" />
</condition>
<property name="proguard.enabled" value="${PROGUARD_ENABLED}" />
<property name="proguard.config" value="${PROGUARD_FLAGS}" />
<property name="manifest.file" value="${ANDROID_MANIFEST}" />
<property name="manifest.abs.file" location="${manifest.file}" />
<!-- Obfuscate target
This is only active in release builds when proguard.config is defined
in default.properties.
-->
<!--
Override obfuscate target to pass javac.custom.classpath to Proguard. SDK tools do not provide
any way to pass custom class paths to Proguard.
-->
<target name="-obfuscate">
<if condition="${project.is.testapp}">
<then>
<!-- get the project manifest package -->
<xpath input="${manifest.abs.file}"
expression="/manifest/@package" output="project.app.package" />
<loadresource property="project.app.packagepath">
<propertyresource name="project.app.package"/>
<filterchain>
<replacestring from="." to="/"/>
</filterchain>
</loadresource>
<property name="create.test.jar.exclusions" value="${project.app.packagepath}/R.class ${project.app.packagepath}/R$*.class ${project.app.packagepath}/Manifest.class ${project.app.packagepath}/Manifest$*.class ${project.app.packagepath}/BuildConfig.class"/>
<jar destfile="${TEST_JAR_PATH}"
excludes="${create.test.jar.exclusions}"
duplicate="preserve"
>
<restrict>
<name name="**/*.class"/>
<archives>
<zips>
<path refid="javac.custom.classpath"/>
</zips>
</archives>
</restrict>
<fileset dir="${out.dir}/classes"/>
</jar>
</then>
</if>
<if>
<condition>
<and>
<istrue value="${proguard.enabled}"/>
<equals arg1="${CONFIGURATION_NAME}" arg2="Release"/>
</and>
</condition>
<then>
<property name="obfuscate.absolute.dir" location="${out.absolute.dir}/proguard"/>
<property name="preobfuscate.jar.file" value="${obfuscate.absolute.dir}/original.jar"/>
<property name="obfuscated.jar.file" value="${OBFUSCATED_JAR_PATH}"/>
<property name="obfuscated.jar.abs.file" location="${obfuscated.jar.file}"/>
<!-- Add Proguard Tasks -->
<property name="proguard.jar" location="${android.tools.dir}/proguard/lib/proguard.jar"/>
<taskdef name="proguard" classname="proguard.ant.ProGuardTask" classpath="${proguard.jar}"/>
<!-- Set the android classpath Path object into a single property. It'll be
all the jar files separated by a platform path-separator.
Each path must be quoted if it contains spaces.
-->
<pathconvert property="project.target.classpath.value" refid="project.target.class.path">
<firstmatchmapper>
<regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
<identitymapper/>
</firstmatchmapper>
</pathconvert>
<!-- Build a path object with all the jar files that must be obfuscated.
This include the project compiled source code and any 3rd party jar
files. -->
<path id="project.all.classes.path">
<pathelement location="${preobfuscate.jar.file}"/>
<!-- Pass javac.custom.classpath for apks. -->
<path refid="javac.custom.classpath"/>
</path>
<!-- Set the project jar files Path object into a single property. It'll be
all the jar files separated by a platform path-separator.
Each path must be quoted if it contains spaces.
-->
<pathconvert property="project.all.classes.value" refid="project.all.classes.path">
<firstmatchmapper>
<regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
<identitymapper/>
</firstmatchmapper>
</pathconvert>
<!-- Turn the path property ${proguard.config} from an A:B:C property
into a series of includes: -include A -include B -include C
suitable for processing by the ProGuard task. Note - this does
not include the leading '-include "' or the closing '"'; those
are added under the <proguard> call below.
-->
<path id="proguard.configpath">
<filelist files="${proguard.config}"/>
</path>
<pathconvert pathsep='" -include "' property="proguard.configcmd"
refid="proguard.configpath"/>
<mkdir dir="${obfuscate.absolute.dir}"/>
<delete file="${preobfuscate.jar.file}"/>
<delete file="${obfuscated.jar.abs.file}"/>
<jar basedir="${out.classes.absolute.dir}"
destfile="${preobfuscate.jar.file}"/>
<proguard>
-include "${proguard.configcmd}"
-injars ${project.all.classes.value}
-outjars "${obfuscated.jar.abs.file}"
-libraryjars ${project.target.classpath.value}
-dump "${obfuscate.absolute.dir}/dump.txt"
-printseeds "${obfuscate.absolute.dir}/seeds.txt"
-printusage "${obfuscate.absolute.dir}/usage.txt"
-printmapping "${obfuscate.absolute.dir}/mapping.txt"
</proguard>
</then>
</if>
<touch file="${STAMP}" />
</target>
</project>

132
android/gyp/apk_obfuscate.py Executable file
Просмотреть файл

@ -0,0 +1,132 @@
#!/usr/bin/env python
#
# Copyright 2014 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.
"""Generates the obfuscated jar and test jar for an apk.
If proguard is not enabled or 'Release' is not in the configuration name,
obfuscation will be a no-op.
"""
import fnmatch
import optparse
import os
import sys
import zipfile
from util import build_utils
def ParseArgs(argv):
parser = optparse.OptionParser()
parser.add_option('--android-sdk', help='path to the Android SDK folder')
parser.add_option('--android-sdk-tools',
help='path to the Android SDK build tools folder')
parser.add_option('--android-sdk-jar',
help='path to Android SDK\'s android.jar')
parser.add_option('--proguard-jar-path',
help='Path to proguard.jar in the sdk')
parser.add_option('--input-jars-paths',
help='Path to jars to include in obfuscated jar')
parser.add_option('--proguard-config-files',
help='Paths to proguard config files')
parser.add_option('--configuration-name',
help='Gyp configuration name (i.e. Debug, Release)')
parser.add_option('--proguard-enabled', action='store_true',
help='Set if proguard is enabled for this target.')
parser.add_option('--obfuscated-jar-path',
help='Output path for obfuscated jar.')
parser.add_option('--testapp', action='store_true',
help='Set this if building an instrumentation test apk')
parser.add_option('--test-jar-path',
help='Output path for jar containing all the test apk\'s '
'code.')
parser.add_option('--stamp', help='File to touch on success')
(options, args) = parser.parse_args(argv)
if args:
parser.error('No positional arguments should be given. ' + str(args))
# Check that required options have been provided.
required_options = (
'android_sdk',
'android_sdk_tools',
'android_sdk_jar',
'proguard_jar_path',
'input_jars_paths',
'configuration_name',
'obfuscated_jar_path',
)
build_utils.CheckOptions(options, parser, required=required_options)
return options, args
def main(argv):
options, _ = ParseArgs(argv)
library_classpath = [options.android_sdk_jar]
javac_custom_classpath = build_utils.ParseGypList(options.input_jars_paths)
dependency_class_filters = [
'*R.class', '*R$*.class', '*Manifest.class', '*BuildConfig.class']
def DependencyClassFilter(name):
for name_filter in dependency_class_filters:
if fnmatch.fnmatch(name, name_filter):
return False
return True
if options.testapp:
with zipfile.ZipFile(options.test_jar_path, 'w') as test_jar:
for jar in build_utils.ParseGypList(options.input_jars_paths):
with zipfile.ZipFile(jar, 'r') as jar_zip:
for name in filter(DependencyClassFilter, jar_zip.namelist()):
with jar_zip.open(name) as zip_entry:
test_jar.writestr(name, zip_entry.read())
if options.configuration_name == 'Release' and options.proguard_enabled:
proguard_project_classpath = javac_custom_classpath
proguard_cmd = [
'java', '-jar', options.proguard_jar_path,
'-forceprocessing',
'-injars', ':'.join(proguard_project_classpath),
'-libraryjars', ':'.join(library_classpath),
'-outjars', options.obfuscated_jar_path,
'-dump', options.obfuscated_jar_path + '.dump',
'-printseeds', options.obfuscated_jar_path + '.seeds',
'-printusage', options.obfuscated_jar_path + '.usage',
'-printmapping', options.obfuscated_jar_path + '.mapping',
]
for proguard_file in build_utils.ParseGypList(
options.proguard_config_files):
proguard_cmd += ['-include', proguard_file]
build_utils.CheckOutput(proguard_cmd)
else:
output_files = [
options.obfuscated_jar_path,
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)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

Просмотреть файл

@ -12,14 +12,4 @@
'library_dexed_jars_paths': ['>(apk_output_jar_path)'],
},
},
# Add an action with the appropriate output. This allows the generated
# buildfiles to determine which target the output corresponds to.
'actions': [
{
'action_name': 'fake_generate_jar',
'inputs': [],
'outputs': ['>(apk_output_jar_path)'],
'action': [],
},
],
}

Просмотреть файл

@ -98,6 +98,7 @@
'jar_excluded_classes': [],
'jar_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
'obfuscated_jar_path': '<(intermediate_dir)/obfuscated.jar',
'test_jar_path': '<(PRODUCT_DIR)/test.lib.java/<(apk_name).jar',
'dex_path': '<(intermediate_dir)/classes.dex',
'emma_device_jar': '<(android_sdk_root)/tools/lib/emma_device.jar',
'android_manifest_path%': '<(java_in_dir)/AndroidManifest.xml',
@ -585,6 +586,7 @@
],
'outputs': [
'<(jar_stamp)',
'<(jar_path)',
],
'action': [
'python', '<(DEPTH)/build/android/gyp/jar.py',
@ -595,43 +597,72 @@
]
},
{
'action_name': 'ant_obfuscate_<(_target_name)',
'action_name': 'obfuscate_<(_target_name)',
'message': 'Obfuscating <(_target_name)',
'variables': {
'additional_obfuscate_options': [],
'proguard_out_dir': '<(intermediate_dir)/proguard',
'proguard_input_jar_paths': [
'>@(input_jars_paths)',
'<(jar_path)',
],
'conditions': [
['is_test_apk == 1', {
'additional_obfuscate_options': [
'--testapp',
],
}],
['proguard_enabled == "true"', {
'additional_obfuscate_options': [
'--proguard-enabled',
],
}],
],
},
'conditions': [
['is_test_apk == 1', {
'outputs': [
'<(test_jar_path)',
],
}],
],
'inputs': [
'<(DEPTH)/build/android/ant/apk-obfuscate.xml',
'<(DEPTH)/build/android/gyp/apk_obfuscate.py',
'<(DEPTH)/build/android/gyp/util/build_utils.py',
'<(DEPTH)/build/android/gyp/ant.py',
'<(android_manifest_path)',
'>@(proguard_flags_paths)',
'<(instr_stamp)',
'>@(proguard_input_jar_paths)',
],
'outputs': [
# This lists obfuscate_stamp instead of obfuscated_jar_path because
# ant only writes the latter if the md5 of the inputs changes.
'<(obfuscate_stamp)',
# In non-Release builds, these paths will all be empty files.
'<(obfuscated_jar_path)',
'<(obfuscated_jar_path).dump',
'<(obfuscated_jar_path).seeds',
'<(obfuscated_jar_path).mapping',
'<(obfuscated_jar_path).usage',
],
'action': [
'python', '<(DEPTH)/build/android/gyp/ant.py',
'-quiet',
'-DANDROID_MANIFEST=<(android_manifest_path)',
'-DANDROID_SDK_JAR=<(android_sdk_jar)',
'-DANDROID_SDK_ROOT=<(android_sdk_root)',
'-DANDROID_SDK_VERSION=<(android_sdk_version)',
'-DANDROID_SDK_TOOLS=<(android_sdk_tools)',
'-DAPK_NAME=<(apk_name)',
'-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)',
'-DINPUT_JARS_PATHS=>(input_jars_paths)',
'-DIS_TEST_APK=<(is_test_apk)',
'-DOBFUSCATED_JAR_PATH=<(obfuscated_jar_path)',
'-DOUT_DIR=<(intermediate_dir)',
'-DPROGUARD_ENABLED=<(proguard_enabled)',
'-DPROGUARD_FLAGS=<(proguard_flags_paths)',
'-DTEST_JAR_PATH=<(PRODUCT_DIR)/test.lib.java/<(apk_name).jar',
'python', '<(DEPTH)/build/android/gyp/apk_obfuscate.py',
'-DSTAMP=<(obfuscate_stamp)',
'-Dbasedir=.',
'-buildfile',
'<(DEPTH)/build/android/ant/apk-obfuscate.xml',
'--configuration-name', '<(CONFIGURATION_NAME)',
'--android-sdk', '<(android_sdk)',
'--android-sdk-tools', '<(android_sdk_tools)',
'--android-sdk-jar', '<(android_sdk_jar)',
'--input-jars-paths=>(proguard_input_jar_paths)',
'--test-jar-path', '<(test_jar_path)',
'--obfuscated-jar-path', '<(obfuscated_jar_path)',
'--proguard-jar-path', '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
'--proguard-config-files=<(proguard_flags_paths)',
'--stamp', '<(obfuscate_stamp)',
'<@(additional_obfuscate_options)',
],
},
{