aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/jdk
diff options
context:
space:
mode:
Diffstat (limited to 'tools/jdk')
-rw-r--r--tools/jdk/BUILD26
-rw-r--r--tools/jdk/proguard_whitelister.py87
-rw-r--r--tools/jdk/proguard_whitelister_test.py73
-rw-r--r--tools/jdk/proguard_whitelister_test_input.cfg48
4 files changed, 233 insertions, 1 deletions
diff --git a/tools/jdk/BUILD b/tools/jdk/BUILD
index 3326081607..b8f04197eb 100644
--- a/tools/jdk/BUILD
+++ b/tools/jdk/BUILD
@@ -103,10 +103,34 @@ exports_files([
filegroup(
name = "srcs",
- srcs = ["BUILD"], # Tools are build from the workspace for tests.
+ srcs = [
+ "BUILD", # Tools are build from the workspace for tests.
+ "proguard_whitelister.py",
+ "proguard_whitelister_test.py",
+ "proguard_whitelister_test_input.cfg",
+ ],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
)
+
+py_binary(
+ name = "proguard_whitelister",
+ srcs = [
+ "proguard_whitelister.py",
+ ],
+ deps = [
+ "//third_party/py/gflags",
+ ],
+)
+
+py_test(
+ name = "proguard_whitelister_test",
+ srcs = ["proguard_whitelister_test.py"],
+ data = ["proguard_whitelister_test_input.cfg"],
+ deps = [
+ ":proguard_whitelister",
+ ],
+)
diff --git a/tools/jdk/proguard_whitelister.py b/tools/jdk/proguard_whitelister.py
new file mode 100644
index 0000000000..6c95360df7
--- /dev/null
+++ b/tools/jdk/proguard_whitelister.py
@@ -0,0 +1,87 @@
+# Copyright 2015 The Bazel Authors. All rights reserved.
+#
+# 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.
+
+"""Checks for proguard configuration rules that cannot be combined across libs.
+
+The only valid proguard arguments for a library are -keep, -assumenosideeffects,
+and -dontnote and -dontwarn when they are provided with arguments.
+Limiting libraries to using these flags prevents drastic, sweeping effects
+(such as obfuscation being disabled) from being inadvertently applied to a
+binary through a library dependency.
+"""
+
+import re
+import sys
+
+from third_party.py import gflags
+
+gflags.DEFINE_string('path', None, 'Path to the proguard config to validate')
+gflags.DEFINE_string('output', None, 'Where to put the validated config')
+
+FLAGS = gflags.FLAGS
+PROGUARD_COMMENTS_PATTERN = '#.*(\n|$)'
+
+
+class ProguardConfigValidator(object):
+ """Validates a proguard config."""
+
+ # Must be a tuple for str.startswith()
+ _VALID_ARGS = ('keep', 'assumenosideeffects')
+
+ def __init__(self, config_path, outconfig_path):
+ self._config_path = config_path
+ self._outconfig_path = outconfig_path
+
+ def ValidateAndWriteOutput(self):
+ with open(self._config_path) as config:
+ config_string = config.read()
+ invalid_configs = self._Validate(config_string)
+ if invalid_configs:
+ raise RuntimeError(
+ 'Invalid proguard config parameters: ' + str(invalid_configs))
+ with open(self._outconfig_path, 'w+') as outconfig:
+ config_string = '# Merged from %s \n%s' % (
+ self._config_path, config_string)
+ outconfig.write(config_string)
+
+ def _Validate(self, config):
+ """Checks the config for illegal arguments."""
+ config = re.sub(PROGUARD_COMMENTS_PATTERN, '', config)
+ args = config.split('-')
+ invalid_configs = []
+ for arg in args:
+ arg = arg.strip()
+ if not arg or self._ValidateArg(arg):
+ continue
+ invalid_configs.append('-' + arg.split()[0])
+
+ return invalid_configs
+
+ def _ValidateArg(self, arg):
+ if arg.startswith(ProguardConfigValidator._VALID_ARGS):
+ return True
+ elif arg.split()[0] in ['dontnote', 'dontwarn']:
+ if len(arg.split()) > 1:
+ return True
+ return False
+
+
+def main():
+ validator = ProguardConfigValidator(FLAGS.path, FLAGS.output)
+ validator.ValidateAndWriteOutput()
+
+
+if __name__ == '__main__':
+ FLAGS(sys.argv)
+ main()
diff --git a/tools/jdk/proguard_whitelister_test.py b/tools/jdk/proguard_whitelister_test.py
new file mode 100644
index 0000000000..6a24501fbe
--- /dev/null
+++ b/tools/jdk/proguard_whitelister_test.py
@@ -0,0 +1,73 @@
+# Copyright 2015 The Bazel Authors. All rights reserved.
+#
+# 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.
+
+import os
+import unittest
+
+from tools.jdk import proguard_whitelister
+
+
+class ProguardConfigValidatorTest(unittest.TestCase):
+
+ def _CreateValidator(self, input_path, output_path):
+ return proguard_whitelister.ProguardConfigValidator(input_path, output_path)
+
+ def testValidConfig(self):
+ input_path = os.path.join(
+ os.path.dirname(__file__), "proguard_whitelister_test_input.cfg")
+ tmpdir = os.environ["TEST_TMPDIR"]
+ output_path = os.path.join(tmpdir, "proguard_whitelister_test_output.cfg")
+ # This will raise an exception if the config is invalid.
+ self._CreateValidator(input_path, output_path).ValidateAndWriteOutput()
+ with file(output_path) as output:
+ self.assertTrue(("# Merged from %s" % input_path) in output.read())
+
+ def _TestInvalidConfig(self, invalid_args, config):
+ tmpdir = os.environ["TEST_TMPDIR"]
+ input_path = os.path.join(tmpdir, "proguard_whitelister_test_input.cfg")
+ with open(input_path, "w") as f:
+ f.write(config)
+ output_path = os.path.join(tmpdir, "proguard_whitelister_test_output.cfg")
+ validator = self._CreateValidator(input_path, output_path)
+ try:
+ validator.ValidateAndWriteOutput()
+ self.fail()
+ except RuntimeError as e:
+ for invalid_arg in invalid_args:
+ self.assertTrue(invalid_arg in str(e))
+
+ def testInvalidNoteConfig(self):
+ self._TestInvalidConfig(["-dontnote"], """\
+# We don"t want libraries disabling notes globally.
+-dontnote""")
+
+ def testInvalidWarnConfig(self):
+ self._TestInvalidConfig(["-dontwarn"], """\
+# We don"t want libraries disabling warnings globally.
+-dontwarn""")
+
+ def testInvalidOptimizationConfig(self):
+ self._TestInvalidConfig(["-optimizations"], """\
+# We don"t want libraries disabling global optimizations.
+-optimizations !class/merging/*,!code/allocation/variable""")
+
+ def testMultipleInvalidArgs(self):
+ self._TestInvalidConfig(["-optimizations", "-dontnote"], """\
+# We don"t want libraries disabling global optimizations.
+-optimizations !class/merging/*,!code/allocation/variable
+-dontnote""")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tools/jdk/proguard_whitelister_test_input.cfg b/tools/jdk/proguard_whitelister_test_input.cfg
new file mode 100644
index 0000000000..ceb3709dd8
--- /dev/null
+++ b/tools/jdk/proguard_whitelister_test_input.cfg
@@ -0,0 +1,48 @@
+# Copyright 2015 The Bazel Authors. All rights reserved.
+#
+# 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.
+
+# Note: put any environment specific flags in their respective proguard files:
+# proguard_test.flags, proguard_dev.flags, proguard_release.flags, etc
+
+# These classes reference resources that don't exist in pre-v11 builds
+-dontwarn com.google.android.apps.testapp.TestActivity
+
+# References to a hidden class
+-dontnote android.os.SystemProperties
+-keep class android.os.SystemProperties { *** get(...);}
+
+# Keep all classes extended from com.google.android.apps.testapp.MyBaseClass
+# because, e.g., we use reflection.
+-keep class * extends com.google.android.apps.testapp.MyBaseClass {
+ @com.google.android.apps.testapp.MyBaseClass$Inner <fields>;
+}
+
+# Needed because this field is accessed reflectively, and it exists in generated code.
+-keepclassmembers class * extends com.google.protobuf.nano.MessageNano {
+ *** apiHeader;
+}
+
+# Extensions are deserialized with a reflective call to newInstance().
+-keepclassmembers class * extends com.google.protobuf.nano.Extension {
+ <init>();
+}
+
+-dontnote android.support.v?.app.Fragment
+
+-keepnames class com.google.android.testapp.** extends com.google.android.testapp.resources.Resource { *; }
+
+-keepclasseswithmembers class derp.foo { bar;} -keepattributes *
+
+# This is a comment, so this should not cause problems -dontobfuscate
+# This is a comment, so # this should not cause problems -dontnote