Skip to content

Commit

Permalink
Add Android IDL jar outputs.
Browse files Browse the repository at this point in the history
These outputs are a jar and source jar for the results of aidl processing. 

This is used to add aidl output to IDEs separate from the source code,
similar to annotation output (gen jars).

--
MOS_MIGRATED_REVID=104024453
  • Loading branch information
Googler authored and hanwen committed Sep 28, 2015
1 parent a72be0f commit 22616ae
Show file tree
Hide file tree
Showing 21 changed files with 999 additions and 250 deletions.
1 change: 1 addition & 0 deletions src/java_tools/buildjar/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ java_library(
],
visibility = [
"//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/genclass:__pkg__",
"//src/tools/android/java/com/google/devtools/build/android/idlclass:__pkg__",
],
deps = [
"//third_party:guava",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public class AndroidRepositoryRules {
"aar_generator",
"shuffle_jars",
"merge_dexzips",
"debug_keystore");
"debug_keystore",
"IdlClass");

private static final Function<? super Rule, Map<String, Label>> BINDINGS_FUNCTION =
new Function< Rule, Map<String, Label>>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,21 @@ private static AndroidRuleIdeInfo makeAndroidRuleIdeInfo(
builder.addTransitiveResources(makeArtifactLocation(transitiveResource));
}

boolean hasIdlSources = !provider.getIdlSrcs().isEmpty();
builder.setHasIdlSources(hasIdlSources);
if (hasIdlSources) {
LibraryArtifact.Builder jarBuilder = LibraryArtifact.newBuilder();
Artifact idlClassJar = provider.getIdlClassJar();
if (idlClassJar != null) {
jarBuilder.setJar(makeArtifactLocation(idlClassJar));
}
Artifact idlSourceJar = provider.getIdlSourceJar();
if (idlSourceJar != null) {
jarBuilder.setSourceJar(makeArtifactLocation(idlSourceJar));
}
builder.setIdlJar(jarBuilder.build());
}

return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ private static RuleConfiguredTargetBuilder init(
javaSemantics,
androidSemantics,
resourceApk,
AndroidIdlProvider.EMPTY,
ruleContext.getConfiguration().isCodeCoverageEnabled(),
true /* collectJavaCompilationArgs */);
if (resourceClasses == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.MiddlemanFactory;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
Expand All @@ -35,7 +34,6 @@
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
Expand Down Expand Up @@ -65,16 +63,13 @@
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
import com.google.devtools.build.lib.rules.java.JavaUtil;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

Expand Down Expand Up @@ -102,12 +97,11 @@ public class AndroidCommon {
private Artifact genClassJar;
private Artifact genSourceJar;

private Collection<Artifact> idls;
private AndroidIdlProvider transitiveIdlImportData;
private NestedSet<ResourceContainer> transitiveResources;
private Map<Artifact, Artifact> translatedIdlSources = ImmutableMap.of();
private boolean asNeverLink;
private boolean exportDeps;
private Artifact manifestProtoOutput;
private AndroidIdlHelper idlHelper;

public AndroidCommon(RuleContext ruleContext, JavaCommon javaCommon) {
this.ruleContext = ruleContext;
Expand Down Expand Up @@ -212,13 +206,16 @@ public static void createDexAction(
public static AndroidIdeInfoProvider createAndroidIdeInfoProvider(
RuleContext ruleContext,
AndroidSemantics semantics,
AndroidIdlHelper idlHelper,
ResourceApk resourceApk,
Artifact zipAlignedApk,
Iterable<Artifact> apksUnderTest) {
AndroidIdeInfoProvider.Builder ideInfoProviderBuilder =
new AndroidIdeInfoProvider.Builder()
.addIdlParcelables(getIdlParcelables(ruleContext))
.addIdlSrcs(getIdlSrcs(ruleContext))
.setIdlClassJar(idlHelper.getIdlClassJar())
.setIdlSourceJar(idlHelper.getIdlSourceJar())
.addIdlParcelables(idlHelper.getIdlParcelables())
.addIdlSrcs(idlHelper.getIdlSources())
.addAllApksUnderTest(apksUnderTest);

if (zipAlignedApk != null) {
Expand Down Expand Up @@ -385,17 +382,22 @@ private static Artifact createResourceJarArtifact(RuleContext ruleContext,

public JavaTargetAttributes init(
JavaSemantics javaSemantics, AndroidSemantics androidSemantics,
ResourceApk resourceApk, AndroidIdlProvider transitiveIdlImportData,
ResourceApk resourceApk,
boolean addCoverageSupport, boolean collectJavaCompilationArgs) throws InterruptedException {
ImmutableList<Artifact> extraSources =
resourceApk.isLegacy() || resourceApk.getResourceJavaSrcJar() == null

classJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR);
idlHelper = new AndroidIdlHelper(ruleContext, classJar);

ImmutableList.Builder<Artifact> extraSourcesBuilder = ImmutableList.<Artifact>builder()
.addAll(resourceApk.isLegacy() || resourceApk.getResourceJavaSrcJar() == null
? ImmutableList.<Artifact>of()
: ImmutableList.of(resourceApk.getResourceJavaSrcJar());
: ImmutableList.of(resourceApk.getResourceJavaSrcJar()))
.addAll(idlHelper.getIdlGeneratedJavaSources());

JavaTargetAttributes.Builder attributes = init(
androidSemantics,
transitiveIdlImportData,
resourceApk.getTransitiveResources(),
extraSources);
extraSourcesBuilder.build());
JavaCompilationArtifacts.Builder artifactsBuilder = new JavaCompilationArtifacts.Builder();
if (resourceApk.isLegacy()) {
compileResources(javaSemantics, artifactsBuilder, attributes,
Expand Down Expand Up @@ -430,23 +432,11 @@ public JavaTargetAttributes init(

private JavaTargetAttributes.Builder init(
AndroidSemantics androidSemantics,
AndroidIdlProvider transitiveIdlImportData,
NestedSet<AndroidResourcesProvider.ResourceContainer> transitiveResources,
Collection<Artifact> extraArtifacts) {
this.transitiveIdlImportData = transitiveIdlImportData;
this.transitiveResources = transitiveResources;

ImmutableList.Builder<Artifact> extraSrcsBuilder =
new ImmutableList.Builder<Artifact>().addAll(extraArtifacts);

idls = getIdlSrcs(ruleContext);
if (!idls.isEmpty() && !ruleContext.hasErrors()) {
translatedIdlSources = generateTranslatedIdlArtifacts(ruleContext, idls);
}

javaCommon.initializeJavacOpts(androidSemantics.getJavacArguments());
JavaTargetAttributes.Builder attributes = javaCommon.initCommon(
extraSrcsBuilder.addAll(translatedIdlSources.values()).build());
JavaTargetAttributes.Builder attributes = javaCommon.initCommon(extraArtifacts);

attributes.setBootClassPath(ImmutableList.of(
AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar()));
Expand Down Expand Up @@ -533,7 +523,6 @@ private void initJava(
}

Artifact jar = null;
classJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR);
if (attributes.hasSourceFiles() || attributes.hasSourceJars() || attributes.hasResources()) {
// We only want to add a jar to the classpath of a dependent rule if it has content.
javaArtifactsBuilder.addRuntimeJar(classJar);
Expand All @@ -542,7 +531,7 @@ private void initJava(

filesBuilder.add(classJar);

Artifact manifestProtoOutput = helper.createManifestProtoOutput(classJar);
manifestProtoOutput = helper.createManifestProtoOutput(classJar);

// The gensrc jar is created only if the target uses annotation processing. Otherwise,
// it is null, and the source jar action will not depend on the compile action.
Expand Down Expand Up @@ -597,17 +586,13 @@ public RuleConfiguredTargetBuilder addTransitiveInfoProviders(
ResourceApk resourceApk,
Artifact zipAlignedApk,
Iterable<Artifact> apksUnderTest) {
if (!idls.isEmpty()) {
generateAndroidIdlActions(
ruleContext, idls, transitiveIdlImportData, translatedIdlSources);
}

Runfiles runfiles = new Runfiles.Builder(ruleContext.getWorkspaceName())
.addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES)
.build();

javaCommon.addTransitiveInfoProviders(builder, filesToBuild, classJar);
javaCommon.addGenJarsProvider(builder, genClassJar, genSourceJar);
idlHelper.addTransitiveInfoProviders(builder, classJar, manifestProtoOutput);

return builder
.setFilesToBuild(filesToBuild)
Expand All @@ -621,9 +606,8 @@ public RuleConfiguredTargetBuilder addTransitiveInfoProviders(
new AndroidResourcesProvider(ruleContext.getLabel(), transitiveResources))
.add(
AndroidIdeInfoProvider.class,
createAndroidIdeInfoProvider(
ruleContext, androidSemantics, resourceApk, zipAlignedApk, apksUnderTest))
.add(AndroidIdlProvider.class, transitiveIdlImportData)
createAndroidIdeInfoProvider(ruleContext, androidSemantics, idlHelper,
resourceApk, zipAlignedApk, apksUnderTest))
.add(
JavaCompilationArgsProvider.class,
new JavaCompilationArgsProvider(
Expand All @@ -647,38 +631,6 @@ public static PathFragment getAssetDir(RuleContext ruleContext) {
Type.STRING));
}

public static ImmutableList<Artifact> getIdlParcelables(RuleContext ruleContext) {
return ruleContext.getRule().isAttrDefined("idl_parcelables", BuildType.LABEL_LIST)
? ImmutableList.copyOf(ruleContext.getPrerequisiteArtifacts(
"idl_parcelables", Mode.TARGET).filter(AndroidRuleClasses.ANDROID_IDL).list())
: ImmutableList.<Artifact>of();
}

public static Collection<Artifact> getIdlSrcs(RuleContext ruleContext) {
if (!ruleContext.getRule().isAttrDefined("idl_srcs", BuildType.LABEL_LIST)) {
return ImmutableList.of();
}
checkIdlSrcsSamePackage(ruleContext);
return ruleContext.getPrerequisiteArtifacts(
"idl_srcs", Mode.TARGET).filter(AndroidRuleClasses.ANDROID_IDL).list();
}

public static void checkIdlSrcsSamePackage(RuleContext ruleContext) {
PathFragment packageName = ruleContext.getLabel().getPackageFragment();
Collection<Artifact> idls = ruleContext
.getPrerequisiteArtifacts("idl_srcs", Mode.TARGET)
.filter(AndroidRuleClasses.ANDROID_IDL)
.list();
for (Artifact idl : idls) {
Label idlLabel = idl.getOwner();
if (!packageName.equals(idlLabel.getPackageFragment())) {
ruleContext.attributeError("idl_srcs", "do not import '" + idlLabel + "' directly. "
+ "You should either move the file to this package or depend on "
+ "an appropriate rule there");
}
}
}

public static NestedSet<LinkerInput> collectTransitiveNativeLibraries(
Iterable<? extends TransitiveInfoCollection> deps) {
NestedSetBuilder<LinkerInput> builder = NestedSetBuilder.stableOrder();
Expand Down Expand Up @@ -733,24 +685,6 @@ public static NestedSet<Artifact> getApplicationApks(RuleContext ruleContext) {
return applicationApksBuilder.build();
}

private ImmutableMap<Artifact, Artifact> generateTranslatedIdlArtifacts(
RuleContext ruleContext, Collection<Artifact> idls) {
ImmutableMap.Builder<Artifact, Artifact> outputJavaSources = ImmutableMap.builder();
String ruleName = ruleContext.getRule().getName();
// for each aidl file use aggregated preprocessed files to generate Java code
for (Artifact idl : idls) {
// Reconstruct the package tree under <rule>_aidl to avoid a name conflict
// if the same AIDL files are used in multiple targets.
PathFragment javaOutputPath = FileSystemUtils.replaceExtension(
new PathFragment(ruleName + "_aidl").getRelative(idl.getRootRelativePath()),
".java");
Artifact output = ruleContext.getPackageRelativeArtifact(
javaOutputPath, ruleContext.getConfiguration().getGenfilesDirectory());
outputJavaSources.put(idl, output);
}
return outputJavaSources.build();
}

private JavaCompilationArgs collectJavaCompilationArgs(RuleContext ruleContext,
boolean recursive, boolean neverLink, boolean hasSrcs) {
JavaCompilationArgs.Builder builder = JavaCompilationArgs.builder()
Expand All @@ -762,85 +696,6 @@ private JavaCompilationArgs collectJavaCompilationArgs(RuleContext ruleContext,
return builder.build();
}

private void generateAndroidIdlActions(RuleContext ruleContext,
Collection<Artifact> idls, AndroidIdlProvider transitiveIdlImportData,
Map<Artifact, Artifact> translatedIdlSources) {
AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
Set<Artifact> preprocessedIdls = new LinkedHashSet<>();
List<String> preprocessedArgs = new ArrayList<>();

// add imports
for (String idlImport : transitiveIdlImportData.getTransitiveIdlImportRoots()) {
preprocessedArgs.add("-I" + idlImport);
}

// preprocess each aidl file
preprocessedArgs.add("-p" + sdk.getFrameworkAidl().getExecPathString());
String ruleName = ruleContext.getRule().getName();
for (Artifact idl : idls) {
// Reconstruct the package tree under <rule>_aidl to avoid a name conflict
// if the source AIDL files are also generated.
PathFragment preprocessedPath = new PathFragment(ruleName + "_aidl")
.getRelative(idl.getRootRelativePath());
Artifact preprocessed = ruleContext.getPackageRelativeArtifact(
preprocessedPath, ruleContext.getConfiguration().getGenfilesDirectory());
preprocessedIdls.add(preprocessed);
preprocessedArgs.add("-p" + preprocessed.getExecPathString());

createAndroidIdlPreprocessAction(ruleContext, idl, preprocessed);
}

// aggregate all preprocessed aidl files
MiddlemanFactory middlemanFactory = ruleContext.getAnalysisEnvironment().getMiddlemanFactory();
Artifact preprocessedIdlsMiddleman = middlemanFactory.createAggregatingMiddleman(
ruleContext.getActionOwner(), "AndroidIDLMiddleman", preprocessedIdls,
ruleContext.getConfiguration().getMiddlemanDirectory());

for (Artifact idl : translatedIdlSources.keySet()) {
createAndroidIdlAction(ruleContext, idl,
transitiveIdlImportData.getTransitiveIdlImports(),
preprocessedIdlsMiddleman, translatedIdlSources.get(idl), preprocessedArgs);
}
}

private void createAndroidIdlPreprocessAction(RuleContext ruleContext,
Artifact idl, Artifact preprocessed) {
AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
ruleContext.registerAction(new SpawnAction.Builder()
.setExecutable(sdk.getAidl())
// Note the below may be an overapproximation of the actual runfiles, due to "conditional
// artifacts" (see Runfiles.PruningManifest).
// TODO(bazel-team): When using getFilesToRun(), the middleman is
// not expanded. Fix by providing code to expand and use getFilesToRun here.
.addInput(idl)
.addOutput(preprocessed)
.addArgument("--preprocess")
.addArgument(preprocessed.getExecPathString())
.addArgument(idl.getExecPathString())
.setProgressMessage("Android IDL preprocessing")
.setMnemonic("AndroidIDLPreprocess")
.build(ruleContext));
}

private void createAndroidIdlAction(RuleContext ruleContext,
Artifact idl, Iterable<Artifact> idlImports, Artifact preprocessedIdls,
Artifact output, List<String> preprocessedArgs) {
AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
ruleContext.registerAction(new SpawnAction.Builder()
.setExecutable(sdk.getAidl())
.addInput(idl)
.addInputs(idlImports)
.addInput(preprocessedIdls)
.addInput(sdk.getFrameworkAidl())
.addOutput(output)
.addArgument("-b") // Fail if trying to compile a parcelable.
.addArguments(preprocessedArgs)
.addArgument(idl.getExecPathString())
.addArgument(output.getExecPathString())
.setProgressMessage("Android IDL generation")
.setMnemonic("AndroidIDLGnerate")
.build(ruleContext));
}

public ImmutableList<String> getJavacOpts() {
return javaCommon.getJavacOpts();
Expand Down
Loading

0 comments on commit 22616ae

Please sign in to comment.