Parse option -flattenpackagehierarchy [package_name].
Bug: 37764746
Change-Id: I03934d0341b1ff8981945c2a2a16124f0fbb903d
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 241746b..86844a3 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.OutputMode;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
@@ -379,6 +380,7 @@
// TODO(zerny): Consider which other proguard options should be given flags.
assert internal.packagePrefix.length() == 0;
+ internal.packageObfuscationMode = proguardConfiguration.getPackageObfuscationMode();
internal.packagePrefix = proguardConfiguration.getPackagePrefix();
assert internal.allowAccessModification;
internal.allowAccessModification = proguardConfiguration.getAllowAccessModification();
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 0338533..72ad9f3 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.naming.DictionaryReader;
+import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
@@ -19,6 +20,7 @@
private final List<Path> injars = new ArrayList<>();
private final List<Path> libraryjars = new ArrayList<>();
+ private PackageObfuscationMode packageObfuscationMode = PackageObfuscationMode.NONE;
private String packagePrefix = null;
private boolean allowAccessModification = false;
private boolean ignoreWarnings = false;
@@ -53,7 +55,17 @@
this.libraryjars.addAll(libraryJars);
}
+ public PackageObfuscationMode getPackageObfuscationMode() {
+ return packageObfuscationMode;
+ }
+
public void setPackagePrefix(String packagePrefix) {
+ packageObfuscationMode = PackageObfuscationMode.REPACKAGE;
+ this.packagePrefix = packagePrefix;
+ }
+
+ public void setFlattenPackagePrefix(String packagePrefix) {
+ packageObfuscationMode = PackageObfuscationMode.FLATTEN;
this.packagePrefix = packagePrefix;
}
@@ -139,6 +151,7 @@
dexItemFactory,
injars,
libraryjars,
+ packageObfuscationMode,
packagePrefix,
allowAccessModification,
ignoreWarnings,
@@ -164,6 +177,7 @@
private final DexItemFactory dexItemFactory;
private final List<Path> injars;
private final List<Path> libraryjars;
+ private final PackageObfuscationMode packageObfuscationMode;
private final String packagePrefix;
private final boolean allowAccessModification;
private final boolean ignoreWarnings;
@@ -188,6 +202,7 @@
DexItemFactory factory,
List<Path> injars,
List<Path> libraryjars,
+ PackageObfuscationMode packageObfuscationMode,
String packagePrefix,
boolean allowAccessModification,
boolean ignoreWarnings,
@@ -210,6 +225,7 @@
this.dexItemFactory = factory;
this.injars = ImmutableList.copyOf(injars);
this.libraryjars = ImmutableList.copyOf(libraryjars);
+ this.packageObfuscationMode = packageObfuscationMode;
this.packagePrefix = packagePrefix;
this.allowAccessModification = allowAccessModification;
this.ignoreWarnings = ignoreWarnings;
@@ -254,6 +270,10 @@
return libraryjars;
}
+ public PackageObfuscationMode getPackageObfuscationMode() {
+ return packageObfuscationMode;
+ }
+
public String getPackagePrefix() {
return packagePrefix;
}
@@ -333,6 +353,7 @@
super(factory,
ImmutableList.of() /* injars */,
ImmutableList.of() /* libraryjars */,
+ PackageObfuscationMode.REPACKAGE, /* TODO(b/36799686): should be NONE once implemented */
"" /* package prefix */,
false /* allowAccessModification */,
false /* ignoreWarnings */,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 31fb77d..1ab82f6 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.shaking.ProguardTypeMatcher.ClassOrType;
import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.LongInterval;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -131,7 +132,7 @@
(option = Iterables.find(warnedSingleArgOptions,
this::skipOptionWithSingleArg, null)) != null
|| (option = Iterables.find(warnedFlagOptions, this::skipFlag, null)) != null) {
- System.out.println("WARNING: Ignoring option: -" + option);
+ warnIgnoringOptions(option);
} else if ((option = Iterables.find(unsupportedFlagOptions, this::skipFlag, null)) != null) {
throw parseError("Unsupported option: -" + option);
} else if (acceptString("keepattributes")) {
@@ -150,7 +151,7 @@
configurationBuilder.addRule(rule);
} else if (acceptString("dontoptimize")) {
configurationBuilder.setOptimize(false);
- System.out.println("WARNING: Ignoring option: -dontoptimize");
+ warnIgnoringOptions("dontoptimize");
} else if (acceptString("optimizationpasses")) {
skipWhitespace();
Integer expectedOptimizationPasses = acceptInteger();
@@ -158,7 +159,7 @@
throw parseError("Missing n of \"-optimizationpasses n\"");
}
configurationBuilder.setOptimizationPasses(expectedOptimizationPasses);
- System.out.println("WARNING: Ignoring option: -optimizationpasses");
+ warnIgnoringOptions("optimizationpasses");
} else if (acceptString("dontobfuscate")) {
configurationBuilder.setObfuscating(false);
} else if (acceptString("dontshrink")) {
@@ -180,6 +181,9 @@
configurationBuilder.addDontWarnPattern(pattern);
} while (acceptChar(','));
} else if (acceptString("repackageclasses")) {
+ if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.FLATTEN) {
+ warnOverridingOptions("repackageclasses", "flattenpackagehierarchy");
+ }
skipWhitespace();
if (acceptChar('\'')) {
configurationBuilder.setPackagePrefix(parsePackageNameOrEmptyString());
@@ -187,6 +191,24 @@
} else {
configurationBuilder.setPackagePrefix("");
}
+ } else if (acceptString("flattenpackagehierarchy")) {
+ if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.REPACKAGE) {
+ warnOverridingOptions("repackageclasses", "flattenpackagehierarchy");
+ skipWhitespace();
+ if (isOptionalArgumentGiven()) {
+ skipSingleArgument();
+ }
+ } else {
+ skipWhitespace();
+ if (acceptChar('\'')) {
+ configurationBuilder.setFlattenPackagePrefix(parsePackageNameOrEmptyString());
+ expectChar('\'');
+ } else {
+ configurationBuilder.setFlattenPackagePrefix("");
+ }
+ }
+ // TODO(b/37764746): warn until package flattening is implemented and in effect.
+ warnIgnoringOptions("flattenpackagehierarchy");
} else if (acceptString("allowaccessmodification")) {
configurationBuilder.setAllowAccessModification(true);
} else if (acceptString("printmapping")) {
@@ -229,6 +251,14 @@
return true;
}
+ private void warnIgnoringOptions(String optionName) {
+ System.out.println("WARNING: Ignoring option: -" + optionName);
+ }
+
+ private void warnOverridingOptions(String optionName, String victim) {
+ System.out.println("WARNING: option -" + optionName + " overrides -" + victim);
+ }
+
private void parseInclude() throws ProguardRuleParserException {
Path included = parseFileName();
try {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 9fea848..7d7ea46 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -76,6 +76,7 @@
public Path printMainDexListFile;
public boolean ignoreMissingClasses = false;
public boolean skipMinification = false;
+ public PackageObfuscationMode packageObfuscationMode = PackageObfuscationMode.NONE;
public String packagePrefix = "";
public boolean allowAccessModification = true;
public boolean inlineAccessors = true;
@@ -134,6 +135,15 @@
return logArgumentsFilter.indexOf(qualifiedName) >= 0;
}
+ public enum PackageObfuscationMode {
+ // General package obfuscation.
+ NONE,
+ // Repackaging all classes into the single user-given (or top-level) package.
+ REPACKAGE,
+ // Repackaging all packages into the single user-given (or top-level) package.
+ FLATTEN
+ }
+
public static class OutlineOptions {
public boolean enabled = true;
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index b0fe113..7a81186 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -80,6 +80,7 @@
private void copyProguardConfigurationToInternalOptions(
ProguardConfiguration config, InternalOptions options) {
+ options.packageObfuscationMode = config.getPackageObfuscationMode();
options.packagePrefix = config.getPackagePrefix();
options.allowAccessModification = config.getAllowAccessModification();
options.classObfuscationDictionary = config.getClassObfuscationDictionary();
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index ad1a392..6f2a347 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexAccessFlags;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -56,6 +57,18 @@
VALID_PROGUARD_DIR + "keepdirectories.flags";
private static final String DONT_OBFUSCATE =
VALID_PROGUARD_DIR + "dontobfuscate.flags";
+ private static final String PACKAGE_OBFUSCATION_1 =
+ VALID_PROGUARD_DIR + "package-obfuscation-1.flags";
+ private static final String PACKAGE_OBFUSCATION_2 =
+ VALID_PROGUARD_DIR + "package-obfuscation-2.flags";
+ private static final String PACKAGE_OBFUSCATION_3 =
+ VALID_PROGUARD_DIR + "package-obfuscation-3.flags";
+ private static final String PACKAGE_OBFUSCATION_4 =
+ VALID_PROGUARD_DIR + "package-obfuscation-4.flags";
+ private static final String PACKAGE_OBFUSCATION_5 =
+ VALID_PROGUARD_DIR + "package-obfuscation-5.flags";
+ private static final String PACKAGE_OBFUSCATION_6 =
+ VALID_PROGUARD_DIR + "package-obfuscation-6.flags";
private static final String DONT_SHRINK =
VALID_PROGUARD_DIR + "dontshrink.flags";
private static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES =
@@ -257,7 +270,72 @@
@Test
public void parseDontobfuscate() throws IOException, ProguardRuleParserException {
- new ProguardConfigurationParser(new DexItemFactory()).parse(Paths.get(DONT_OBFUSCATE));
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(DONT_OBFUSCATE));
+ ProguardConfiguration config = parser.getConfig();
+ assertFalse(config.isObfuscating());
+ }
+
+ @Test
+ public void parseRepackageClassesEmpty() throws IOException, ProguardRuleParserException {
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(PACKAGE_OBFUSCATION_1));
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
+ assertNotNull(config.getPackagePrefix());
+ assertEquals("", config.getPackagePrefix());
+ }
+
+ @Test
+ public void parseRepackageClassesNonEmpty() throws IOException, ProguardRuleParserException {
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(PACKAGE_OBFUSCATION_2));
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
+ assertNotNull(config.getPackagePrefix());
+ assertEquals("p.q.r", config.getPackagePrefix());
+ }
+
+ @Test
+ public void parseFlattenPackageHierarchyEmpty() throws IOException, ProguardRuleParserException {
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(PACKAGE_OBFUSCATION_3));
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(PackageObfuscationMode.FLATTEN, config.getPackageObfuscationMode());
+ assertNotNull(config.getPackagePrefix());
+ assertEquals("", config.getPackagePrefix());
+ }
+
+ @Test
+ public void parseFlattenPackageHierarchyNonEmpty() throws IOException, ProguardRuleParserException {
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(PACKAGE_OBFUSCATION_4));
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(PackageObfuscationMode.FLATTEN, config.getPackageObfuscationMode());
+ assertNotNull(config.getPackagePrefix());
+ assertEquals("p.q.r", config.getPackagePrefix());
+ }
+
+ @Test
+ public void flattenPackageHierarchyCannotOverrideRepackageClasses()
+ throws IOException, ProguardRuleParserException {
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(PACKAGE_OBFUSCATION_5));
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
+ assertNotNull(config.getPackagePrefix());
+ assertEquals("top", config.getPackagePrefix());
+ }
+
+ @Test
+ public void repackageClassesOverridesFlattenPackageHierarchy()
+ throws IOException, ProguardRuleParserException {
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ parser.parse(Paths.get(PACKAGE_OBFUSCATION_6));
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
+ assertNotNull(config.getPackagePrefix());
+ assertEquals("top", config.getPackagePrefix());
}
@Test
diff --git a/src/test/proguard/valid/package-obfuscation-1.flags b/src/test/proguard/valid/package-obfuscation-1.flags
new file mode 100644
index 0000000..a852b2e
--- /dev/null
+++ b/src/test/proguard/valid/package-obfuscation-1.flags
@@ -0,0 +1,5 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-repackageclasses
diff --git a/src/test/proguard/valid/package-obfuscation-2.flags b/src/test/proguard/valid/package-obfuscation-2.flags
new file mode 100644
index 0000000..5d847d3
--- /dev/null
+++ b/src/test/proguard/valid/package-obfuscation-2.flags
@@ -0,0 +1,5 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-repackageclasses 'p.q.r'
diff --git a/src/test/proguard/valid/package-obfuscation-3.flags b/src/test/proguard/valid/package-obfuscation-3.flags
new file mode 100644
index 0000000..84d6aa3
--- /dev/null
+++ b/src/test/proguard/valid/package-obfuscation-3.flags
@@ -0,0 +1,5 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-flattenpackagehierarchy
diff --git a/src/test/proguard/valid/package-obfuscation-4.flags b/src/test/proguard/valid/package-obfuscation-4.flags
new file mode 100644
index 0000000..e872bfc
--- /dev/null
+++ b/src/test/proguard/valid/package-obfuscation-4.flags
@@ -0,0 +1,5 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-flattenpackagehierarchy 'p.q.r'
diff --git a/src/test/proguard/valid/package-obfuscation-5.flags b/src/test/proguard/valid/package-obfuscation-5.flags
new file mode 100644
index 0000000..0455d30
--- /dev/null
+++ b/src/test/proguard/valid/package-obfuscation-5.flags
@@ -0,0 +1,6 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-repackageclasses 'top'
+-flattenpackagehierarchy 'cannot.override.the.above'
diff --git a/src/test/proguard/valid/package-obfuscation-6.flags b/src/test/proguard/valid/package-obfuscation-6.flags
new file mode 100644
index 0000000..f3c1f59
--- /dev/null
+++ b/src/test/proguard/valid/package-obfuscation-6.flags
@@ -0,0 +1,6 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-flattenpackagehierarchy 'will.be.ignored'
+-repackageclasses 'top'