aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules
diff options
context:
space:
mode:
authorGravatar jingwen <jingwen@google.com>2017-12-13 17:38:06 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2017-12-13 17:39:28 -0800
commit70b6e5d7df8130f4e622e1ff9c1cd224d208d00e (patch)
tree3ac4745537b6577542189e6310f5b2c041b836d7 /src/main/java/com/google/devtools/build/lib/rules
parentc6557ea56476fd56ee94f2476ac01849841bcaf0 (diff)
Perform ZipFilterAction on the instrumentation JAR using the target JAR as filter. .class and R.class files are filtered out.
During an instrumentation test, jars from both APKS will be loaded onto the same classloader by ART. To prevent runtime crashes due to duplicate classes, we strip the dupe class out from the instrumentation jar. GITHUB: #903 RELNOTES: None. PiperOrigin-RevId: 178983712
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java29
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java26
2 files changed, 54 insertions, 1 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index 34df267956..f2121c5635 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -293,6 +293,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
Artifact deployJar = createDeployJar(ruleContext, javaSemantics, androidCommon, resourceClasses,
AndroidCommon.getAndroidConfig(ruleContext).checkDesugarDeps(), derivedJarFunction);
+ if (isInstrumentation(ruleContext)) {
+ deployJar = getFilteredDeployJar(ruleContext, deployJar);
+ }
+
OneVersionEnforcementLevel oneVersionEnforcementLevel =
ruleContext.getFragment(JavaConfiguration.class).oneVersionEnforcementLevel();
Artifact oneVersionOutputArtifact = null;
@@ -545,7 +549,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
new RuleConfiguredTargetBuilder(ruleContext);
// If this is an instrumentation APK, create the provider for android_instrumentation_test.
- if (ruleContext.attributes().isAttributeValueExplicitlySpecified("instruments")) {
+ if (isInstrumentation(ruleContext)) {
Artifact targetApk =
ruleContext
.getPrerequisite("instruments", Mode.TARGET)
@@ -1720,4 +1724,27 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
return ruleContext.getUniqueDirectoryArtifact("_dx", baseName,
ruleContext.getBinOrGenfilesDirectory());
}
+
+ /** Returns true if this android_binary target is an instrumentation binary */
+ private static boolean isInstrumentation(RuleContext ruleContext) {
+ return ruleContext.attributes().isAttributeValueExplicitlySpecified("instruments");
+ }
+
+ /**
+ * Perform class filtering using the target APK's predexed JAR. Filter duplicate .class and
+ * R.class files based on name. Prevents runtime crashes on ART. See b/19713845 for details.
+ */
+ private static Artifact getFilteredDeployJar(RuleContext ruleContext, Artifact deployJar)
+ throws InterruptedException {
+ Artifact filterJar =
+ ruleContext
+ .getPrerequisite("instruments", Mode.TARGET)
+ .getProvider(AndroidPreDexJarProvider.class)
+ .getPreDexJar();
+ Artifact filteredDeployJar =
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_TEST_FILTERED_JAR);
+ AndroidCommon.createZipFilterAction(
+ ruleContext, deployJar, filterJar, filteredDeployJar, /* checkHashMismatch */ false);
+ return filteredDeployJar;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
index d5175b4837..83a03c9e82 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
@@ -1052,4 +1052,30 @@ public class AndroidCommon {
"The resources attribute has been removed. Please use resource_files instead.");
}
}
+
+ /**
+ * Used for instrumentation tests. Filter out classes from the instrumentation JAR that are also
+ * present in the target JAR. During an instrumentation test, ART will load jars from both APKs
+ * into the same classloader. If the same class exists in both jars, there will be runtime
+ * crashes.
+ *
+ * <p>R.class files that share the same package are also filtered out to prevent
+ * surprising/incorrect references to resource IDs.
+ */
+ public static void createZipFilterAction(
+ RuleContext ruleContext,
+ Artifact in,
+ Artifact filter,
+ Artifact out,
+ boolean checkHashMismatch) {
+ new ZipFilterBuilder(ruleContext)
+ .setInputZip(in)
+ .addFilterZips(ImmutableList.of(filter))
+ .setOutputZip(out)
+ .addFileTypeToFilter(".class")
+ .setCheckHashMismatch(checkHashMismatch)
+ .addExplicitFilter("R\\.class")
+ .addExplicitFilter("R\\$.*\\.class")
+ .build();
+ }
}