blob: ed659718697358b3c17390a6c8afa6ea62f5cf38 [file] [log] [blame]
/*
* Copyright (C) 2015 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.
*/
package com.android.build.gradle.internal;
import static com.android.builder.model.AndroidProject.FD_OUTPUTS;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.build.gradle.AndroidConfig;
import com.android.build.gradle.TestAndroidConfig;
import com.android.build.gradle.internal.scope.AndroidTask;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask;
import com.android.build.gradle.internal.test.TestApplicationTestData;
import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.internal.variant.BaseVariantOutputData;
import com.android.build.gradle.internal.variant.LibraryVariantData;
import com.android.build.gradle.tasks.TestModuleProGuardTask;
import com.android.builder.core.AndroidBuilder;
import com.android.builder.model.AndroidProject;
import com.android.builder.testing.ConnectedDeviceProvider;
import com.android.builder.testing.TestData;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import proguard.ParseException;
/**
* TaskManager for standalone test application that lives in a separate module from the tested
* application.
*/
public class TestApplicationTaskManager extends ApplicationTaskManager {
public TestApplicationTaskManager(Project project,
AndroidBuilder androidBuilder,
AndroidConfig extension,
SdkHandler sdkHandler,
DependencyManager dependencyManager,
ToolingModelBuilderRegistry toolingRegistry) {
super(project, androidBuilder, extension, sdkHandler, dependencyManager, toolingRegistry);
}
@Override
public void createTasksForVariantData(@NonNull TaskFactory tasks,
@NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
super.createTasksForVariantData(tasks, variantData);
// create a new configuration with the target application coordinates.
final Configuration testTarget = project.getConfigurations().create("testTarget");
DependencyHandler dependencyHandler = project.getDependencies();
TestAndroidConfig testExtension = (TestAndroidConfig) extension;
dependencyHandler.add("testTarget",
dependencyHandler.project(
ImmutableMap.of(
"path", testExtension.getTargetProjectPath(),
"configuration", testExtension.getTargetVariant())));
// and create the configuration for the project's metadata.
final Configuration testTargetMetadata = project.getConfigurations().create("testTargetMetadata");
dependencyHandler.add("testTargetMetadata", dependencyHandler.project(
ImmutableMap.of(
"path", testExtension.getTargetProjectPath(),
"configuration", testExtension.getTargetVariant() + "-metadata"
)));
TestData testData = new TestApplicationTestData(
variantData, testTarget, testTargetMetadata, androidBuilder);
// create the test connected check task.
AndroidTask<DeviceProviderInstrumentTestTask> testConnectedCheck =
getAndroidTasks().create(
tasks,
new DeviceProviderInstrumentTestTask.ConfigAction(
variantData.getScope(),
new ConnectedDeviceProvider(
sdkHandler.getSdkInfo().getAdb(),
new LoggerWrapper(getLogger())),
testData));
// make the test application connectedCheck depends on the configuration added above so
// we can retrieve its artifacts
testConnectedCheck.dependsOn(tasks,
testTarget,
testTargetMetadata,
variantData.assembleVariantTask);
// make the main ConnectedCheck task depends on this test connectedCheck
Task connectedCheck = tasks.named(CONNECTED_CHECK);
if (connectedCheck != null) {
connectedCheck.dependsOn(testConnectedCheck.getName());
}
}
@Override
@Nullable
public File maybeCreateProguardTasks(
@NonNull final TaskFactory tasks,
@NonNull final VariantScope scope,
@NonNull final PostCompilationData pcData) {
DependencyHandler dependencyHandler = project.getDependencies();
TestAndroidConfig testExtension = (TestAndroidConfig) extension;
Configuration testTargetMapping = project.getConfigurations().create("testTargetMapping");
dependencyHandler.add("testTargetMapping", dependencyHandler.project(
ImmutableMap.of(
"path", testExtension.getTargetProjectPath(),
"configuration", testExtension.getTargetVariant() + "-mapping"
)));
if (testTargetMapping.getFiles().isEmpty()
|| scope.getVariantConfiguration().getProvidedOnlyJars().isEmpty()) {
return null;
}
BaseVariantData<? extends BaseVariantOutputData> variantData = scope.getVariantData();
final TestModuleProGuardTask proguardTask = project.getTasks().create(
scope.getTaskName("proguard"),
TestModuleProGuardTask.class);
variantData.obfuscationTask = proguardTask;
proguardTask.setLogger(getLogger());
// and create the configuration for the project's mapping file.
// Input the mapping from the tested app so that we can deal with obfuscated code.
proguardTask.setMappingConfiguration(testTargetMapping);
proguardTask.setVariantConfiguration(scope.getVariantConfiguration());
// --- Proguard Config ---
// Don't remove any code in tested app.
proguardTask.dontshrink();
proguardTask.dontoptimize();
// We can't call dontobfuscate, since that would make ProGuard ignore the mapping file.
try {
proguardTask.keep("class * {*;}");
proguardTask.keep("interface * {*;}");
proguardTask.keep("enum * {*;}");
} catch (ParseException e) {
throw new RuntimeException(e);
}
// libraryJars: the runtime jars. Do this in doFirst since the boot classpath isn't
// available until the SDK is loaded in the prebuild task
proguardTask.doFirst(new Action<Task>() {
@Override
public void execute(Task task) {
for (String runtimeJar : androidBuilder.getBootClasspathAsStrings()) {
try {
proguardTask.libraryjars(runtimeJar);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
});
try {
// injar: the compilation output
proguardTask.injars(pcData.getInputDirCallable());
if (pcData.getJavaResourcesInputDirCallable() != null) {
proguardTask.injars(pcData.getJavaResourcesInputDirCallable());
}
// injar: the packaged dependencies
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(1);
map.put("filter", "!META-INF/MANIFEST.MF");
proguardTask.injars(map, new Callable<Set<File>>() {
@Override
public Set<File> call() throws Exception {
return scope.getVariantConfiguration().getPackagedJars();
}
});
proguardTask.libraryjars(new Callable<List<File>>() {
@Override
public List<File> call() throws Exception {
return scope.getVariantConfiguration().getProvidedOnlyJars();
}
});
// All -dontwarn rules for test dependencies should go in here:
proguardTask.configuration(
variantData.getVariantConfiguration().getTestProguardFiles());
// --- Out files ---
proguardTask.outjars(scope.getProguardOutputFile());
final File proguardOut = project.file(
new File(project.getBuildDir(),
FD_OUTPUTS
+ File.separatorChar
+ "mapping"
+ File.separatorChar
+ variantData.getVariantConfiguration().getDirName()));
proguardTask.dump(new File(proguardOut, "dump.txt"));
proguardTask.printseeds(new File(proguardOut, "seeds.txt"));
proguardTask.printusage(new File(proguardOut, "usage.txt"));
proguardTask.printmapping(new File(proguardOut, "mapping.txt"));
// proguard doesn't verify that the seed/mapping/usage folders exist and will fail
// if they don't so create them.
proguardTask.doFirst(new Action<Task>() {
@Override
public void execute(Task task) {
if (!proguardOut.mkdirs()) {
throw new RuntimeException(
"Cannot create proguard output folder " + proguardOut);
}
}
});
// update dependency.
optionalDependsOn(proguardTask, pcData.getClassGeneratingTasks());
optionalDependsOn(proguardTask, pcData.getLibraryGeneratingTasks());
pcData.setLibraryGeneratingTasks(ImmutableList.of(proguardTask));
pcData.setClassGeneratingTasks(ImmutableList.of(proguardTask));
// Update the inputs
return scope.getProguardOutputFile();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}