aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2017-09-12 23:19:42 +0200
committerGravatar Philipp Wollermann <philwo@google.com>2017-09-13 19:06:26 +0200
commit93d65a4473c9c963a190b433f359ef7e52273bd4 (patch)
treef783a2bc2e145e5eb686eb40c451a2b94aeb5e9e /src/tools/android/java/com/google/devtools
parentf2c1e8331faf39406a889429de1cbdd9e03e1e3b (diff)
Support for local_resource_files in android_test
RELNOTES: none PiperOrigin-RevId: 168444499
Diffstat (limited to 'src/tools/android/java/com/google/devtools')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java93
1 files changed, 89 insertions, 4 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java
index 851829005c..4380a0b69b 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java
@@ -19,8 +19,13 @@ import com.android.ide.common.internal.LoggedErrorException;
import com.android.ide.common.internal.PngCruncher;
import com.android.ide.common.process.DefaultProcessExecutor;
import com.android.ide.common.process.LoggedProcessOutputHandler;
+import com.android.ide.common.xml.AndroidManifestParser;
+import com.android.ide.common.xml.ManifestData.Instrumentation;
+import com.android.io.StreamException;
import com.android.utils.StdLogger;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.android.AndroidDataMerger.MergeConflictException;
import com.google.devtools.build.android.AndroidResourceMerger.MergingException;
@@ -40,12 +45,18 @@ import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.TriState;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.file.FileSystems;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nullable;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.SAXException;
/**
* Provides an entry point for the resource processing using the AOSP build tools.
@@ -321,6 +332,19 @@ public class AndroidResourceProcessingAction {
help = "If passed, resource merge conflicts will be treated as errors instead of warnings"
)
public boolean throwOnResourceConflict;
+
+ @Option(
+ name = "packageUnderTest",
+ defaultValue = "null",
+ category = "config",
+ documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+ effectTags = {OptionEffectTag.UNKNOWN},
+ help =
+ "When building a test APK, the package of the binary being tested. Android resources can"
+ + " only be provided if there is no package under test or if the test instrumentation"
+ + " is in a different package."
+ )
+ public String packageUnderTest;
}
private static AaptConfigOptions aaptConfigOptions;
@@ -414,10 +438,22 @@ public class AndroidResourceProcessingAction {
if (options.packageType == VariantType.LIBRARY) {
resourceProcessor.writeDummyManifestForAapt(dummyManifest, options.packageForR);
- processedData = new MergedAndroidData(
- processedData.getResourceDir(),
- processedData.getAssetDir(),
- dummyManifest);
+ processedData =
+ new MergedAndroidData(
+ processedData.getResourceDir(), processedData.getAssetDir(), dummyManifest);
+ }
+
+ if (hasConflictWithPackageUnderTest(
+ options.packageUnderTest,
+ options.primaryData.resourceDirs,
+ processedData.getManifest(),
+ timer)) {
+ logger.log(
+ Level.SEVERE,
+ "Android resources cannot be provided if the instrumentation package is the same as "
+ + "the package under test, but the instrumentation package (in the manifest) and "
+ + "the package under test both had the same package: " + options.packageUnderTest);
+ System.exit(1);
}
resourceProcessor.processResources(
@@ -483,6 +519,55 @@ public class AndroidResourceProcessingAction {
logger.fine(String.format("Resources processed in %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
}
+ /**
+ * Checks if there is a conflict between the package under test and the package being built.
+ *
+ * When testing Android code, the test can be run in the same or a different process as the code
+ * being tested. If it's in the same process, we do not allow Android resources to be used by the
+ * test, as they could overwrite the resources used by the code being tested. If this APK won't
+ * be testing another APK, the test and code under test are in different processes, or no
+ * resources are being used, this isn't a concern.
+ *
+ * To determine whether the test and code under test are run in the same process, we check the
+ * package of the code under test, passed into this function, against the target packages of any
+ * <code>instrumentation</code> tags in this APK's manifest.
+ *
+ * @param packageUnderTest the package of the code under test, or null if no code is under test
+ * @param resourceDirs the resource directories for this APK
+ * @param processedManifest the processed manifest for this APK
+ *
+ * @return true if there is a conflict, false otherwise
+ */
+ @VisibleForTesting
+ static boolean hasConflictWithPackageUnderTest(
+ @Nullable String packageUnderTest,
+ ImmutableList<Path> resourceDirs,
+ Path processedManifest,
+ Stopwatch timer)
+ throws SAXException, StreamException, ParserConfigurationException, IOException {
+ if (packageUnderTest == null || resourceDirs.isEmpty()) {
+ return false;
+ }
+
+ // We are building a test APK with resources. Validate instrumentation package is different
+ // from the package under test. If it isn't, fail to prevent the test resources from
+ // overriding the resources of the APK under test.
+ try (InputStream stream = Files.newInputStream(processedManifest)) {
+ for (Instrumentation instrumentation :
+ AndroidManifestParser.parse(stream).getInstrumentations()) {
+ if (packageUnderTest.equals(instrumentation.getTargetPackage())) {
+ return true;
+ }
+ }
+ }
+
+ logger.fine(
+ String.format(
+ "Custom package and instrumentation verification finished at %sms",
+ timer.elapsed(TimeUnit.MILLISECONDS)));
+ return false;
+ }
+
private static boolean usePngCruncher() {
// If the value was set, use that.
if (aaptConfigOptions.useAaptCruncher != TriState.AUTO) {