diff --git a/android/config.go b/android/config.go index bbb08dde7..b95d4e7aa 100644 --- a/android/config.go +++ b/android/config.go @@ -1962,6 +1962,10 @@ func (c *config) UseResourceProcessorByDefault() bool { return c.productVariables.GetBuildFlagBool("RELEASE_USE_RESOURCE_PROCESSOR_BY_DEFAULT") } +func (c *config) UseTransitiveJarsInClasspath() bool { + return c.productVariables.GetBuildFlagBool("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH") +} + var ( mainlineApexContributionBuildFlagsToApexNames = map[string]string{ "RELEASE_APEX_CONTRIBUTIONS_ADBD": "com.android.adbd", diff --git a/java/aar.go b/java/aar.go index 8ceeace20..bffe88bd6 100644 --- a/java/aar.go +++ b/java/aar.go @@ -1297,6 +1297,10 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { var staticJars android.Paths var staticHeaderJars android.Paths var staticResourceJars android.Paths + var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path] + var transitiveStaticLibsImplementationJars []*android.DepSet[android.Path] + var transitiveStaticLibsResourceJars []*android.DepSet[android.Path] + ctx.VisitDirectDeps(func(module android.Module) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { tag := ctx.OtherModuleDependencyTag(module) @@ -1305,66 +1309,111 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { staticJars = append(staticJars, dep.ImplementationJars...) staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...) staticResourceJars = append(staticResourceJars, dep.ResourceJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } + if dep.TransitiveStaticLibsImplementationJars != nil { + transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars) + } + if dep.TransitiveStaticLibsResourceJars != nil { + transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars) + } } } addCLCFromDep(ctx, module, a.classLoaderContexts) addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary) }) + completeStaticLibsHeaderJars := android.NewDepSet(android.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsHeaderJars) + completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsImplementationJars) + completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsResourceJars) + var implementationJarFile android.Path - if len(staticJars) > 0 { - combineJars := append(android.Paths{classpathFile}, staticJars...) - combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName).OutputPath - TransformJarsToJar(ctx, combinedImplementationJar, "combine", combineJars, android.OptionalPath{}, false, nil, nil) - implementationJarFile = combinedImplementationJar + var combineJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + combineJars = completeStaticLibsImplementationJars.ToList() + } else { + combineJars = append(android.Paths{classpathFile}, staticJars...) + } + + if len(combineJars) > 1 { + implementationJarOutputPath := android.PathForModuleOut(ctx, "combined", jarName) + TransformJarsToJar(ctx, implementationJarOutputPath, "combine", combineJars, android.OptionalPath{}, false, nil, nil) + implementationJarFile = implementationJarOutputPath } else { implementationJarFile = classpathFile } var resourceJarFile android.Path - if len(staticResourceJars) > 1 { + var resourceJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + resourceJars = completeStaticLibsResourceJars.ToList() + } else { + resourceJars = staticResourceJars + } + if len(resourceJars) > 1 { combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName) - TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{}, + TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{}, false, nil, nil) resourceJarFile = combinedJar - } else if len(staticResourceJars) == 1 { - resourceJarFile = staticResourceJars[0] + } else if len(resourceJars) == 1 { + resourceJarFile = resourceJars[0] } // merge implementation jar with resources if necessary - implementationAndResourcesJar := implementationJarFile - if resourceJarFile != nil { - jars := android.Paths{resourceJarFile, implementationAndResourcesJar} + var implementationAndResourcesJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + implementationAndResourcesJars = append(slices.Clone(resourceJars), combineJars...) + } else { + implementationAndResourcesJars = android.PathsIfNonNil(resourceJarFile, implementationJarFile) + } + var implementationAndResourcesJar android.Path + if len(implementationAndResourcesJars) > 1 { combinedJar := android.PathForModuleOut(ctx, "withres", jarName) - TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{}, + TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJars, android.OptionalPath{}, false, nil, nil) implementationAndResourcesJar = combinedJar + } else { + implementationAndResourcesJar = implementationAndResourcesJars[0] } a.implementationJarFile = implementationJarFile // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel() - if len(staticHeaderJars) > 0 { - combineJars := append(android.Paths{classpathFile}, staticHeaderJars...) + var headerJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + headerJars = completeStaticLibsHeaderJars.ToList() + } else { + headerJars = append(android.Paths{classpathFile}, staticHeaderJars...) + } + if len(headerJars) > 1 { headerJarFile := android.PathForModuleOut(ctx, "turbine-combined", jarName) - TransformJarsToJar(ctx, headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil) + TransformJarsToJar(ctx, headerJarFile, "combine header jars", headerJars, android.OptionalPath{}, false, nil, nil) a.headerJarFile = headerJarFile } else { - a.headerJarFile = classpathFile + a.headerJarFile = headerJars[0] } - ctx.CheckbuildFile(a.headerJarFile) - ctx.CheckbuildFile(a.implementationJarFile) + if ctx.Config().UseTransitiveJarsInClasspath() { + ctx.CheckbuildFile(classpathFile) + } else { + ctx.CheckbuildFile(a.headerJarFile) + ctx.CheckbuildFile(a.implementationJarFile) + } android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ - HeaderJars: android.PathsIfNonNil(a.headerJarFile), - ResourceJars: android.PathsIfNonNil(resourceJarFile), - TransitiveLibsHeaderJarsForR8: a.transitiveLibsHeaderJarsForR8, - TransitiveStaticLibsHeaderJarsForR8: a.transitiveStaticLibsHeaderJarsForR8, - ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile), - ImplementationJars: android.PathsIfNonNil(a.implementationJarFile), - StubsLinkType: Implementation, + HeaderJars: android.PathsIfNonNil(a.headerJarFile), + LocalHeaderJars: android.PathsIfNonNil(classpathFile), + TransitiveStaticLibsHeaderJars: completeStaticLibsHeaderJars, + TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars, + TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars, + ResourceJars: android.PathsIfNonNil(resourceJarFile), + TransitiveLibsHeaderJarsForR8: a.transitiveLibsHeaderJarsForR8, + TransitiveStaticLibsHeaderJarsForR8: a.transitiveStaticLibsHeaderJarsForR8, + ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile), + ImplementationJars: android.PathsIfNonNil(a.implementationJarFile), + StubsLinkType: Implementation, // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts }) diff --git a/java/base.go b/java/base.go index a31c8489b..a63533127 100644 --- a/java/base.go +++ b/java/base.go @@ -464,15 +464,10 @@ type Module struct { // inserting into the bootclasspath/classpath of another compile headerJarFile android.Path - repackagedHeaderJarFile android.Path - // jar file containing implementation classes including static library dependencies but no // resources implementationJarFile android.Path - // jar file containing only resources including from static library dependencies - resourceJar android.Path - // args and dependencies to package source files into a srcjar srcJarArgs []string srcJarDeps android.Paths @@ -1256,7 +1251,6 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // Collect .java and .kt files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...) - var kotlinJars android.Paths var kotlinHeaderJars android.Paths // Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before @@ -1266,6 +1260,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...) + var localImplementationJars android.Paths + // If compiling headers then compile them and skip the rest if proptools.Bool(j.properties.Headers_only) { if srcFiles.HasExt(".kt") { @@ -1275,20 +1271,41 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.") } - _, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, + transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars + + localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraCombinedJars) - combinedHeaderJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine") - combinedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine") + combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine") + if jarjared { + localHeaderJars = android.Paths{combinedHeaderJarFile} + transitiveStaticLibsHeaderJars = nil + } + combinedHeaderJarFile, repackaged := j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine") + if repackaged { + localHeaderJars = android.Paths{combinedHeaderJarFile} + transitiveStaticLibsHeaderJars = nil + } if ctx.Failed() { return } j.headerJarFile = combinedHeaderJarFile - ctx.CheckbuildFile(j.headerJarFile) + if ctx.Config().UseTransitiveJarsInClasspath() { + if len(localHeaderJars) > 0 { + ctx.CheckbuildFile(localHeaderJars...) + } else { + // There are no local sources or resources in this module, so there is nothing to checkbuild. + ctx.UncheckedModule() + } + } else { + ctx.CheckbuildFile(j.headerJarFile) + } android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ HeaderJars: android.PathsIfNonNil(j.headerJarFile), + LocalHeaderJars: localHeaderJars, + TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8, AidlIncludeDirs: j.exportAidlIncludeDirs, @@ -1347,7 +1364,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar") kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) srcJars = append(srcJars, kaptSrcJar) - kotlinJars = append(kotlinJars, kaptResJar) + localImplementationJars = append(localImplementationJars, kaptResJar) // Disable annotation processing in javac, it's already been handled by kapt flags.processorPath = nil flags.processors = nil @@ -1360,21 +1377,24 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath return } - kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc") + kotlinJarPath, _ := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc") // Make javac rule depend on the kotlinc rule flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...) - kotlinJars = append(kotlinJars, kotlinJarPath) + localImplementationJars = append(localImplementationJars, kotlinJarPath) + kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar) } - jars := slices.Clone(kotlinJars) - j.compiledSrcJars = srcJars + transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars + enableSharding := false - var headerJarFileWithoutDepsOrJarjar android.Path + var localHeaderJars android.Paths + var shardingHeaderJars android.Paths + var repackagedHeaderJarFile android.Path if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine { if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 { enableSharding = true @@ -1387,11 +1407,26 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath extraJars := slices.Clone(kotlinHeaderJars) extraJars = append(extraJars, extraCombinedJars...) var combinedHeaderJarFile android.Path - headerJarFileWithoutDepsOrJarjar, combinedHeaderJarFile = - j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) + localHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) + shardingHeaderJars = localHeaderJars - j.headerJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine") - j.repackagedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine") + var jarjared bool + j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine") + if jarjared { + // jarjar modifies transitive static dependencies, use the combined header jar and drop the transitive + // static libs header jars. + localHeaderJars = android.Paths{j.headerJarFile} + transitiveStaticLibsHeaderJars = nil + } + var repackaged bool + repackagedHeaderJarFile, repackaged = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine") + if repackaged { + // repackage modifies transitive static dependencies, use the combined header jar and drop the transitive + // static libs header jars. + // TODO(b/356688296): this shouldn't export both the unmodified and repackaged header jars + localHeaderJars = android.Paths{j.headerJarFile, repackagedHeaderJarFile} + transitiveStaticLibsHeaderJars = nil + } } if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 { hasErrorproneableFiles := false @@ -1426,8 +1461,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } if enableSharding { - if headerJarFileWithoutDepsOrJarjar != nil { - flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...) + if len(shardingHeaderJars) > 0 { + flags.classpath = append(classpath(slices.Clone(shardingHeaderJars)), flags.classpath...) } shardSize := int(*(j.properties.Javac_shard_size)) var shardSrcs []android.Paths @@ -1436,8 +1471,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath for idx, shardSrc := range shardSrcs { classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc, nil, flags, extraJarDeps) - classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx)) - jars = append(jars, classes) + classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx)) + localImplementationJars = append(localImplementationJars, classes) } } // Assume approximately 5 sources per srcjar. @@ -1449,21 +1484,21 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath for idx, shardSrcJars := range shardSrcJarsList { classes := j.compileJavaClasses(ctx, jarName, startIdx+idx, nil, shardSrcJars, flags, extraJarDeps) - classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx)) - jars = append(jars, classes) + classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx)) + localImplementationJars = append(localImplementationJars, classes) } } } else { classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps) - classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac") - jars = append(jars, classes) + classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac") + localImplementationJars = append(localImplementationJars, classes) } if ctx.Failed() { return } } - jars = append(jars, extraCombinedJars...) + localImplementationJars = append(localImplementationJars, extraCombinedJars...) j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles @@ -1490,42 +1525,18 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath resArgs = append(resArgs, extraArgs...) resDeps = append(resDeps, extraDeps...) + var localResourceJars android.Paths if len(resArgs) > 0 { resourceJar := android.PathForModuleOut(ctx, "res", jarName) TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps) - j.resourceJar = resourceJar if ctx.Failed() { return } + localResourceJars = append(localResourceJars, resourceJar) } - var resourceJars android.Paths - if j.resourceJar != nil { - resourceJars = append(resourceJars, j.resourceJar) - } if Bool(j.properties.Include_srcs) { - resourceJars = append(resourceJars, includeSrcJar) - } - resourceJars = append(resourceJars, deps.staticResourceJars...) - - if len(resourceJars) > 1 { - combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName) - TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{}, - false, nil, nil) - j.resourceJar = combinedJar - } else if len(resourceJars) == 1 { - j.resourceJar = resourceJars[0] - } - - if len(deps.staticJars) > 0 { - jars = append(jars, deps.staticJars...) - } - - jars = append(jars, extraDepCombinedJars...) - - manifest := j.overrideManifest - if !manifest.Valid() && j.properties.Manifest != nil { - manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest)) + localResourceJars = append(localResourceJars, includeSrcJar) } services := android.PathsForModuleSrc(ctx, j.properties.Services) @@ -1550,35 +1561,68 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath Implicits: services, Args: args, }) - jars = append(jars, servicesJar) + localResourceJars = append(localResourceJars, servicesJar) + } + + completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, localResourceJars, deps.transitiveStaticLibsResourceJars) + + var combinedResourceJar android.Path + var resourceJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + resourceJars = completeStaticLibsResourceJars.ToList() + } else { + resourceJars = append(slices.Clone(localResourceJars), deps.staticResourceJars...) + } + if len(resourceJars) == 1 { + combinedResourceJar = resourceJars[0] + } else if len(resourceJars) > 0 { + combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName) + TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{}, + false, nil, nil) + combinedResourceJar = combinedJar + } + + manifest := j.overrideManifest + if !manifest.Valid() && j.properties.Manifest != nil { + manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest)) } // Combine the classes built from sources, any manifests, and any static libraries into // classes.jar. If there is only one input jar this step will be skipped. var outputFile android.Path + completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, localImplementationJars, deps.transitiveStaticLibsImplementationJars) + + var jars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + jars = completeStaticLibsImplementationJars.ToList() + } else { + jars = append(slices.Clone(localImplementationJars), deps.staticJars...) + } + + jars = append(jars, extraDepCombinedJars...) + if len(jars) == 1 && !manifest.Valid() { // Optimization: skip the combine step as there is nothing to do // TODO(ccross): this leaves any module-info.class files, but those should only come from // prebuilt dependencies until we support modules in the platform build, so there shouldn't be - // any if len(jars) == 1. + // any if len(extraJars) == 0. // moduleStubLinkType determines if the module is the TopLevelStubLibrary generated // from sdk_library. The TopLevelStubLibrary contains only one static lib, // either with .from-source or .from-text suffix. // outputFile should be agnostic to the build configuration, - // thus "combine" the single static lib in order to prevent the static lib from being exposed + // thus copy the single input static lib in order to prevent the static lib from being exposed // to the copy rules. - stub, _ := moduleStubLinkType(j) - - if stub { - combinedJar := android.PathForModuleOut(ctx, "combined", jarName) + if stub, _ := moduleStubLinkType(j); stub { + copiedJar := android.PathForModuleOut(ctx, "combined", jarName) ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, Input: jars[0], - Output: combinedJar, + Output: copiedJar, }) - outputFile = combinedJar + completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, android.Paths{copiedJar}, nil) + outputFile = copiedJar } else { outputFile = jars[0] } @@ -1590,13 +1634,21 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } // jarjar implementation jar if necessary - jarjarFile := j.jarjarIfNecessary(ctx, outputFile, jarName, "") + jarjarFile, jarjarred := j.jarjarIfNecessary(ctx, outputFile, jarName, "") + if jarjarred { + localImplementationJars = android.Paths{jarjarFile} + completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil) + } outputFile = jarjarFile // jarjar resource jar if necessary - if j.resourceJar != nil { - resourceJarJarFile := j.jarjarIfNecessary(ctx, j.resourceJar, jarName, "resource") - j.resourceJar = resourceJarJarFile + if combinedResourceJar != nil { + resourceJarJarFile, jarjarred := j.jarjarIfNecessary(ctx, combinedResourceJar, jarName, "resource") + combinedResourceJar = resourceJarJarFile + if jarjarred { + localResourceJars = android.Paths{resourceJarJarFile} + completeStaticLibsResourceJars = android.NewDepSet(android.PREORDER, localResourceJars, nil) + } } if ctx.Failed() { @@ -1664,6 +1716,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName) convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile) j.headerJarFile = headerJarFile + if len(localImplementationJars) == 1 && ctx.Config().UseTransitiveJarsInClasspath() { + localHeaderJarFile := android.PathForModuleOut(ctx, "local-javac-header", jarName) + convertImplementationJarToHeaderJar(ctx, localImplementationJars[0], localHeaderJarFile) + localHeaderJars = append(localHeaderJars, localHeaderJarFile) + } else { + localHeaderJars = append(localHeaderJars, headerJarFile) + } } // enforce syntax check to jacoco filters for any build (http://b/183622051) @@ -1677,16 +1736,27 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } // merge implementation jar with resources if necessary - implementationAndResourcesJar := outputFile - if j.resourceJar != nil { - jars := android.Paths{j.resourceJar, implementationAndResourcesJar} - combinedJar := android.PathForModuleOut(ctx, "withres", jarName) - TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest, - false, nil, nil) - implementationAndResourcesJar = combinedJar + var implementationAndResourcesJarsToCombine android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + resourceJars := completeStaticLibsResourceJars.ToList() + if len(resourceJars) > 0 { + implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJars.ToList()...) + implementationAndResourcesJarsToCombine = append(implementationAndResourcesJarsToCombine, extraDepCombinedJars...) + } + } else { + if combinedResourceJar != nil { + implementationAndResourcesJarsToCombine = android.Paths{combinedResourceJar, outputFile} + } } - j.implementationAndResourcesJar = implementationAndResourcesJar + if len(implementationAndResourcesJarsToCombine) > 0 { + combinedJar := android.PathForModuleOut(ctx, "withres", jarName) + TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJarsToCombine, manifest, + false, nil, nil) + outputFile = combinedJar + } + + j.implementationAndResourcesJar = outputFile // Enable dex compilation for the APEX variants, unless it is disabled explicitly compileDex := j.dexProperties.Compile_dex @@ -1712,7 +1782,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath flags: flags, sdkVersion: j.SdkVersion(ctx), minSdkVersion: j.MinSdkVersion(ctx), - classesJar: implementationAndResourcesJar, + classesJar: outputFile, jarName: jarName, } if j.GetProfileGuided() && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting() { @@ -1738,10 +1808,20 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } // merge dex jar with resources if necessary - if j.resourceJar != nil { - jars := android.Paths{dexOutputFile, j.resourceJar} + var dexAndResourceJarsToCombine android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + resourceJars := completeStaticLibsResourceJars.ToList() + if len(resourceJars) > 0 { + dexAndResourceJarsToCombine = append(android.Paths{dexOutputFile}, resourceJars...) + } + } else { + if combinedResourceJar != nil { + dexAndResourceJarsToCombine = android.Paths{dexOutputFile, combinedResourceJar} + } + } + if len(dexAndResourceJarsToCombine) > 0 { combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName) - TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{}, + TransformJarsToJar(ctx, combinedJar, "for dex resources", dexAndResourceJarsToCombine, android.OptionalPath{}, false, nil, nil) if *j.dexProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName) @@ -1774,15 +1854,12 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } else { // There is no code to compile into a dex jar, make sure the resources are propagated // to the APK if this is an app. - outputFile = implementationAndResourcesJar - j.dexJarFile = makeDexJarPathFromPath(j.resourceJar) + j.dexJarFile = makeDexJarPathFromPath(combinedResourceJar) } if ctx.Failed() { return } - } else { - outputFile = implementationAndResourcesJar } if ctx.Device() { @@ -1814,17 +1891,34 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.collectTransitiveSrcFiles(ctx, srcFiles) - ctx.CheckbuildFile(j.implementationJarFile) - ctx.CheckbuildFile(j.headerJarFile) + if ctx.Config().UseTransitiveJarsInClasspath() { + if len(localImplementationJars) > 0 || len(localResourceJars) > 0 || len(localHeaderJars) > 0 { + ctx.CheckbuildFile(localImplementationJars...) + ctx.CheckbuildFile(localResourceJars...) + ctx.CheckbuildFile(localHeaderJars...) + } else { + // There are no local sources or resources in this module, so there is nothing to checkbuild. + ctx.UncheckedModule() + } + } else { + ctx.CheckbuildFile(j.implementationJarFile) + ctx.CheckbuildFile(j.headerJarFile) + } android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ - HeaderJars: android.PathsIfNonNil(j.headerJarFile), - RepackagedHeaderJars: android.PathsIfNonNil(j.repackagedHeaderJarFile), + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile), + + LocalHeaderJars: localHeaderJars, + TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), + TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars, + TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars, + TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8, ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar), ImplementationJars: android.PathsIfNonNil(j.implementationJarFile), - ResourceJars: android.PathsIfNonNil(j.resourceJar), + ResourceJars: android.PathsIfNonNil(combinedResourceJar), AidlIncludeDirs: j.exportAidlIncludeDirs, SrcJarArgs: j.srcJarArgs, SrcJarDeps: j.srcJarDeps, @@ -1960,22 +2054,26 @@ func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths, deps deps, flags javaBuilderFlags, jarName string, - extraJars android.Paths) (headerJar android.Path, combinedHeaderJar android.Path) { + extraJars android.Paths) (localHeaderJars android.Paths, combinedHeaderJar android.Path) { - var jars android.Paths if len(srcFiles) > 0 || len(srcJars) > 0 { // Compile java sources into turbine.jar. turbineJar := android.PathForModuleOut(ctx, "turbine", jarName) TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags) - jars = append(jars, turbineJar) - headerJar = turbineJar + localHeaderJars = append(localHeaderJars, turbineJar) } - jars = append(jars, extraJars...) + localHeaderJars = append(localHeaderJars, extraJars...) // Combine any static header libraries into classes-header.jar. If there is only // one input jar this step will be skipped. - jars = append(jars, deps.staticHeaderJars...) + var jars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + depSet := android.NewDepSet(android.PREORDER, localHeaderJars, deps.transitiveStaticLibsHeaderJars) + jars = depSet.ToList() + } else { + jars = append(slices.Clone(localHeaderJars), deps.staticHeaderJars...) + } // we cannot skip the combine step for now if there is only one jar // since we have to strip META-INF/TRANSITIVE dir from turbine.jar @@ -1983,9 +2081,7 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"}) - ctx.CheckbuildFile(combinedHeaderJarOutputPath) - - return headerJar, combinedHeaderJarOutputPath + return localHeaderJars, combinedHeaderJarOutputPath } func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, @@ -2041,6 +2137,7 @@ func (j *providesTransitiveHeaderJarsForR8) collectTransitiveHeaderJarsForR8(ctx if dep.TransitiveStaticLibsHeaderJarsForR8 != nil { transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJarsForR8) } + } }) j.transitiveLibsHeaderJarsForR8 = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs) @@ -2288,29 +2385,17 @@ func (j *Module) checkSdkLinkType( func (j *Module) collectDeps(ctx android.ModuleContext) deps { var deps deps - if ctx.Device() { - sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) - if sdkDep.invalidVersion { - ctx.AddMissingDependencies(sdkDep.bootclasspath) - ctx.AddMissingDependencies(sdkDep.java9Classpath) - } else if sdkDep.useFiles { - // sdkDep.jar is actually equivalent to turbine header.jar. - deps.classpath = append(deps.classpath, sdkDep.jars...) - deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...) - deps.aidlPreprocess = sdkDep.aidl - // Add the sdk module dependency to `compileDepNames`. - // This ensures that the dependency is reported in `module_bp_java_deps.json` - // TODO (b/358608607): Move this to decodeSdkDep - sdkSpec := android.SdkContext(j).SdkVersion(ctx) - j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String())) - } else { - deps.aidlPreprocess = sdkDep.aidl - } - } - sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName()) j.collectTransitiveHeaderJarsForR8(ctx) + + var transitiveBootClasspathHeaderJars []*android.DepSet[android.Path] + var transitiveClasspathHeaderJars []*android.DepSet[android.Path] + var transitiveJava9ClasspathHeaderJars []*android.DepSet[android.Path] + var transitiveStaticJarsHeaderLibs []*android.DepSet[android.Path] + var transitiveStaticJarsImplementationLibs []*android.DepSet[android.Path] + var transitiveStaticJarsResourceLibs []*android.DepSet[android.Path] + ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -2330,6 +2415,10 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx)) deps.classpath = append(deps.classpath, depHeaderJars...) deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...) + + // TODO: SDK libraries should export a provider with TransitiveClasspathHeaderJars + depHeaderJarsSet := android.NewDepSet(android.PREORDER, depHeaderJars, nil) + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJarsSet) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -2345,6 +2434,9 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { switch tag { case bootClasspathTag: deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } case sdkLibTag, libTag, instrumentationForTag: if _, ok := module.(*Plugin); ok { ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName) @@ -2358,8 +2450,15 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine + + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } case java9LibTag: deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } case staticLibTag: if _, ok := module.(*Plugin); ok { ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName) @@ -2375,6 +2474,17 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { // optimization. deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) + + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, dep.TransitiveStaticLibsHeaderJars) + } + if dep.TransitiveStaticLibsImplementationJars != nil { + transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, dep.TransitiveStaticLibsImplementationJars) + } + if dep.TransitiveStaticLibsResourceJars != nil { + transitiveStaticJarsResourceLibs = append(transitiveStaticJarsResourceLibs, dep.TransitiveStaticLibsResourceJars) + } case pluginTag: if plugin, ok := module.(*Plugin); ok { if plugin.pluginProperties.Processor_class != nil { @@ -2423,11 +2533,18 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) deps.dexClasspath = append(deps.classpath, dep.Srcs()...) + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, + android.NewDepSet(android.PREORDER, dep.Srcs(), nil)) case staticLibTag: checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) deps.staticJars = append(deps.staticJars, dep.Srcs()...) deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...) + + depHeaderJars := android.NewDepSet(android.PREORDER, dep.Srcs(), nil) + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJars) + transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, depHeaderJars) + transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, depHeaderJars) } } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok { switch tag { @@ -2440,8 +2557,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { // If a system modules dependency has been added to the bootclasspath // then add its libs to the bootclasspath. if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok { - depHeaderJars := sm.HeaderJars - deps.bootClasspath = append(deps.bootClasspath, depHeaderJars...) + deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars...) + if sm.TransitiveStaticLibsHeaderJars != nil { + transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, + sm.TransitiveStaticLibsHeaderJars) + } } else { ctx.PropertyErrorf("boot classpath dependency %q does not provide SystemModulesProvider", ctx.OtherModuleName(module)) @@ -2472,6 +2592,39 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary) }) + deps.transitiveStaticLibsHeaderJars = transitiveStaticJarsHeaderLibs + deps.transitiveStaticLibsImplementationJars = transitiveStaticJarsImplementationLibs + deps.transitiveStaticLibsResourceJars = transitiveStaticJarsResourceLibs + + if ctx.Config().UseTransitiveJarsInClasspath() { + depSet := android.NewDepSet(android.PREORDER, nil, transitiveClasspathHeaderJars) + deps.classpath = depSet.ToList() + depSet = android.NewDepSet(android.PREORDER, nil, transitiveBootClasspathHeaderJars) + deps.bootClasspath = depSet.ToList() + depSet = android.NewDepSet(android.PREORDER, nil, transitiveJava9ClasspathHeaderJars) + deps.java9Classpath = depSet.ToList() + } + + if ctx.Device() { + sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) + if sdkDep.invalidVersion { + ctx.AddMissingDependencies(sdkDep.bootclasspath) + ctx.AddMissingDependencies(sdkDep.java9Classpath) + } else if sdkDep.useFiles { + // sdkDep.jar is actually equivalent to turbine header.jar. + deps.classpath = append(slices.Clone(classpath(sdkDep.jars)), deps.classpath...) + deps.dexClasspath = append(slices.Clone(classpath(sdkDep.jars)), deps.dexClasspath...) + deps.aidlPreprocess = sdkDep.aidl + // Add the sdk module dependency to `compileDepNames`. + // This ensures that the dependency is reported in `module_bp_java_deps.json` + // TODO (b/358608607): Move this to decodeSdkDep + sdkSpec := android.SdkContext(j).SdkVersion(ctx) + j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String())) + } else { + deps.aidlPreprocess = sdkDep.aidl + } + } + return deps } @@ -2783,22 +2936,22 @@ func getJarJarRuleText(provider *JarJarProviderData) string { } // Repackage the flags if the jarjar rule txt for the flags is generated -func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path { +func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) { if j.repackageJarjarRules == nil { - return infile + return infile, false } repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info, jarName) TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules) - return repackagedJarjarFile + return repackagedJarjarFile, true } -func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path { +func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) { if j.expandJarjarRules == nil { - return infile + return infile, false } jarjarFile := android.PathForModuleOut(ctx, "jarjar", info, jarName) TransformJarJar(ctx, jarjarFile, infile, j.expandJarjarRules) - return jarjarFile + return jarjarFile, true } diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 7cc06fc41..3f4e3cda0 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -96,6 +96,10 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont ctx.PropertyErrorf("libs", "at least one dependency is required") } + var transitiveHeaderJars []*android.DepSet[android.Path] + var transitiveImplementationJars []*android.DepSet[android.Path] + var transitiveResourceJars []*android.DepSet[android.Path] + ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { d.headerJars = append(d.headerJars, dep.HeaderJars...) @@ -105,6 +109,16 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...) d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...) + + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } + if dep.TransitiveStaticLibsImplementationJars != nil { + transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars) + } + if dep.TransitiveStaticLibsResourceJars != nil { + transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars) + } } else { ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) } @@ -131,13 +145,17 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont } android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ - HeaderJars: d.headerJars, - ImplementationAndResourcesJars: d.implementationAndResourceJars, - ImplementationJars: d.implementationJars, - ResourceJars: d.resourceJars, - SrcJarArgs: d.srcJarArgs, - SrcJarDeps: d.srcJarDeps, - StubsLinkType: Implementation, + HeaderJars: d.headerJars, + LocalHeaderJars: d.headerJars, + TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, nil, transitiveHeaderJars), + TransitiveStaticLibsImplementationJars: android.NewDepSet(android.PREORDER, nil, transitiveImplementationJars), + TransitiveStaticLibsResourceJars: android.NewDepSet(android.PREORDER, nil, transitiveResourceJars), + ImplementationAndResourcesJars: d.implementationAndResourceJars, + ImplementationJars: d.implementationJars, + ResourceJars: d.resourceJars, + SrcJarArgs: d.srcJarArgs, + SrcJarDeps: d.srcJarDeps, + StubsLinkType: Implementation, // TODO: Not sure if aconfig flags that have been moved between device and host variants // make sense. }) diff --git a/java/java.go b/java/java.go index f30d892b7..797a90dfc 100644 --- a/java/java.go +++ b/java/java.go @@ -254,6 +254,7 @@ var ProguardSpecInfoProvider = blueprint.NewProvider[ProguardSpecInfo]() type JavaInfo struct { // HeaderJars is a list of jars that can be passed as the javac classpath in order to link // against this module. If empty, ImplementationJars should be used instead. + // Unlike LocalHeaderJars, HeaderJars includes classes from static dependencies. HeaderJars android.Paths RepackagedHeaderJars android.Paths @@ -264,6 +265,15 @@ type JavaInfo struct { // set of header jars for all transitive static libs deps TransitiveStaticLibsHeaderJarsForR8 *android.DepSet[android.Path] + // depset of header jars for this module and all transitive static dependencies + TransitiveStaticLibsHeaderJars *android.DepSet[android.Path] + + // depset of implementation jars for this module and all transitive static dependencies + TransitiveStaticLibsImplementationJars *android.DepSet[android.Path] + + // depset of resource jars for this module and all transitive static dependencies + TransitiveStaticLibsResourceJars *android.DepSet[android.Path] + // ImplementationAndResourceJars is a list of jars that contain the implementations of classes // in the module as well as any resources included in the module. ImplementationAndResourcesJars android.Paths @@ -275,6 +285,9 @@ type JavaInfo struct { // ResourceJars is a list of jars that contain the resources included in the module. ResourceJars android.Paths + // LocalHeaderJars is a list of jars that contain classes from this module, but not from any static dependencies. + LocalHeaderJars android.Paths + // AidlIncludeDirs is a list of directories that should be passed to the aidl tool when // depending on this module. AidlIncludeDirs android.Paths @@ -568,6 +581,10 @@ type deps struct { aconfigProtoFiles android.Paths disableTurbine bool + + transitiveStaticLibsHeaderJars []*android.DepSet[android.Path] + transitiveStaticLibsImplementationJars []*android.DepSet[android.Path] + transitiveStaticLibsResourceJars []*android.DepSet[android.Path] } func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) { @@ -1008,7 +1025,7 @@ func (j *Library) setInstallRules(ctx android.ModuleContext, installModuleName s } hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host() if hostDexNeeded { - j.hostdexInstallFile = ctx.InstallFile( + j.hostdexInstallFile = ctx.InstallFileWithoutCheckbuild( android.PathForHostDexInstall(ctx, "framework"), j.Stem()+"-hostdex.jar", j.outputFile) } @@ -1022,7 +1039,7 @@ func (j *Library) setInstallRules(ctx android.ModuleContext, installModuleName s } else { installDir = android.PathForModuleInstall(ctx, "framework") } - j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) + j.installFile = ctx.InstallFileWithoutCheckbuild(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) } } @@ -2359,11 +2376,14 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.Phony(ctx.ModuleName(), al.stubsJar) android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ - HeaderJars: android.PathsIfNonNil(al.stubsJar), - ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar), - ImplementationJars: android.PathsIfNonNil(al.stubsJar), - AidlIncludeDirs: android.Paths{}, - StubsLinkType: Stubs, + HeaderJars: android.PathsIfNonNil(al.stubsJar), + LocalHeaderJars: android.PathsIfNonNil(al.stubsJar), + TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, android.PathsIfNonNil(al.stubsJar), nil), + TransitiveStaticLibsImplementationJars: android.NewDepSet(android.PREORDER, android.PathsIfNonNil(al.stubsJar), nil), + ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar), + ImplementationJars: android.PathsIfNonNil(al.stubsJar), + AidlIncludeDirs: android.Paths{}, + StubsLinkType: Stubs, // No aconfig libraries on api libraries }) } @@ -2634,6 +2654,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { var flags javaBuilderFlags + var transitiveClasspathHeaderJars []*android.DepSet[android.Path] + var transitiveBootClasspathHeaderJars []*android.DepSet[android.Path] + var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path] + var transitiveStaticLibsImplementationJars []*android.DepSet[android.Path] + var transitiveStaticLibsResourceJars []*android.DepSet[android.Path] + j.collectTransitiveHeaderJarsForR8(ctx) var staticJars android.Paths var staticResourceJars android.Paths @@ -2645,32 +2671,67 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { case libTag, sdkLibTag: flags.classpath = append(flags.classpath, dep.HeaderJars...) flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } case staticLibTag: flags.classpath = append(flags.classpath, dep.HeaderJars...) staticJars = append(staticJars, dep.ImplementationJars...) staticResourceJars = append(staticResourceJars, dep.ResourceJars...) staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } + if dep.TransitiveStaticLibsImplementationJars != nil { + transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars) + } + if dep.TransitiveStaticLibsResourceJars != nil { + transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars) + } case bootClasspathTag: flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } } } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag, sdkLibTag: - flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) + depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx)) + flags.classpath = append(flags.classpath, depHeaderJars...) + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, + android.NewDepSet(android.PREORDER, depHeaderJars, nil)) } } addCLCFromDep(ctx, module, j.classLoaderContexts) }) - jars := android.PathsForModuleSrc(ctx, j.properties.Jars) + localJars := android.PathsForModuleSrc(ctx, j.properties.Jars) jarName := j.Stem() + ".jar" + // Combine only the local jars together for use in transitive classpaths. + // Always pass input jar through TransformJarsToJar to strip module-info.class from prebuilts. + localCombinedHeaderJar := android.PathForModuleOut(ctx, "local-combined", jarName) + TransformJarsToJar(ctx, localCombinedHeaderJar, "combine local prebuilt implementation jars", localJars, android.OptionalPath{}, + false, j.properties.Exclude_files, j.properties.Exclude_dirs) + localStrippedJars := android.Paths{localCombinedHeaderJar} + + completeStaticLibsHeaderJars := android.NewDepSet(android.PREORDER, localStrippedJars, transitiveStaticLibsHeaderJars) + completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, localStrippedJars, transitiveStaticLibsImplementationJars) + completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsResourceJars) + // Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output // file of the module to be named jarName. var outputFile android.Path combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName) - implementationJars := append(slices.Clone(jars), staticJars...) + var implementationJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + implementationJars = completeStaticLibsImplementationJars.ToList() + } else { + implementationJars = append(slices.Clone(localJars), staticJars...) + } TransformJarsToJar(ctx, combinedImplementationJar, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{}, false, j.properties.Exclude_files, j.properties.Exclude_dirs) outputFile = combinedImplementationJar @@ -2693,7 +2754,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { if reuseImplementationJarAsHeaderJar { headerJar = outputFile } else { - headerJars := append(slices.Clone(jars), staticHeaderJars...) + var headerJars android.Paths + if ctx.Config().UseTransitiveJarsInClasspath() { + headerJars = completeStaticLibsHeaderJars.ToList() + } else { + headerJars = append(slices.Clone(localJars), staticHeaderJars...) + } headerOutputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName) TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{}, false, j.properties.Exclude_files, j.properties.Exclude_dirs) @@ -2712,6 +2778,11 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } else { headerJar = outputFile } + + // Enabling jetifier requires modifying classes from transitive dependencies, disable transitive + // classpath and use the combined header jar instead. + completeStaticLibsHeaderJars = android.NewDepSet(android.PREORDER, android.Paths{headerJar}, nil) + completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, android.Paths{outputFile}, nil) } implementationJarFile := outputFile @@ -2735,7 +2806,11 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) - ctx.CheckbuildFile(outputFile) + if ctx.Config().UseTransitiveJarsInClasspath() { + ctx.CheckbuildFile(localJars...) + } else { + ctx.CheckbuildFile(outputFile) + } if ctx.Device() { // If this is a variant created for a prebuilt_apex then use the dex implementation jar @@ -2817,14 +2892,18 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ - HeaderJars: android.PathsIfNonNil(j.combinedHeaderFile), - TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, - TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8, - ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile), - ImplementationJars: android.PathsIfNonNil(implementationJarFile.WithoutRel()), - ResourceJars: android.PathsIfNonNil(resourceJarFile), - AidlIncludeDirs: j.exportAidlIncludeDirs, - StubsLinkType: j.stubsLinkType, + HeaderJars: android.PathsIfNonNil(j.combinedHeaderFile), + LocalHeaderJars: android.PathsIfNonNil(j.combinedHeaderFile), + TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, + TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8, + TransitiveStaticLibsHeaderJars: completeStaticLibsHeaderJars, + TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars, + TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars, + ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile), + ImplementationJars: android.PathsIfNonNil(implementationJarFile.WithoutRel()), + ResourceJars: android.PathsIfNonNil(resourceJarFile), + AidlIncludeDirs: j.exportAidlIncludeDirs, + StubsLinkType: j.stubsLinkType, // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts }) diff --git a/java/java_test.go b/java/java_test.go index 9e39b51aa..e4e6bca9c 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -20,6 +20,7 @@ import ( "path/filepath" "reflect" "runtime" + "slices" "strconv" "strings" "testing" @@ -211,7 +212,7 @@ func TestJavaLinkType(t *testing.T) { } func TestSimple(t *testing.T) { - ctx, _ := testJava(t, ` + bp := ` java_library { name: "foo", srcs: ["a.java"], @@ -222,31 +223,157 @@ func TestSimple(t *testing.T) { java_library { name: "bar", srcs: ["b.java"], + static_libs: ["quz"], } java_library { name: "baz", srcs: ["c.java"], + static_libs: ["quz"], } - `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") - combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") + java_library { + name: "quz", + srcs: ["d.java"], + }` - if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { - t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs) + frameworkTurbineCombinedJars := []string{ + "out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar", + "out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar", } - baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String() - barTurbine := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar") - bazTurbine := filepath.Join("out", "soong", ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar") + frameworkTurbineJars := []string{ + "out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar", + "out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar", + } - android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barTurbine) + testCases := []struct { + name string - android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazTurbine) + preparer android.FixturePreparer - if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz { - t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz) + fooJavacInputs []string + fooJavacClasspath []string + fooCombinedInputs []string + fooHeaderCombinedInputs []string + + barJavacInputs []string + barJavacClasspath []string + barCombinedInputs []string + barHeaderCombinedInputs []string + }{ + { + name: "normal", + preparer: android.NullFixturePreparer, + fooJavacInputs: []string{"a.java"}, + fooJavacClasspath: slices.Concat( + frameworkTurbineCombinedJars, + []string{ + "out/soong/.intermediates/bar/android_common/turbine-combined/bar.jar", + "out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar", + }, + ), + fooCombinedInputs: []string{ + "out/soong/.intermediates/foo/android_common/javac/foo.jar", + "out/soong/.intermediates/baz/android_common/combined/baz.jar", + }, + + fooHeaderCombinedInputs: []string{ + "out/soong/.intermediates/foo/android_common/turbine/foo.jar", + "out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar", + }, + + barJavacInputs: []string{"b.java"}, + barJavacClasspath: slices.Concat( + frameworkTurbineCombinedJars, + []string{ + "out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar", + }, + ), + barCombinedInputs: []string{ + "out/soong/.intermediates/bar/android_common/javac/bar.jar", + "out/soong/.intermediates/quz/android_common/javac/quz.jar", + }, + barHeaderCombinedInputs: []string{ + "out/soong/.intermediates/bar/android_common/turbine/bar.jar", + "out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar", + }, + }, + { + name: "transitive classpath", + preparer: PrepareForTestWithTransitiveClasspathEnabled, + fooJavacInputs: []string{"a.java"}, + fooJavacClasspath: slices.Concat( + frameworkTurbineJars, + []string{ + "out/soong/.intermediates/bar/android_common/turbine/bar.jar", + "out/soong/.intermediates/quz/android_common/turbine/quz.jar", + "out/soong/.intermediates/baz/android_common/turbine/baz.jar", + }, + ), + fooCombinedInputs: []string{ + "out/soong/.intermediates/foo/android_common/javac/foo.jar", + "out/soong/.intermediates/baz/android_common/javac/baz.jar", + "out/soong/.intermediates/quz/android_common/javac/quz.jar", + }, + + fooHeaderCombinedInputs: []string{ + "out/soong/.intermediates/foo/android_common/turbine/foo.jar", + "out/soong/.intermediates/baz/android_common/turbine/baz.jar", + "out/soong/.intermediates/quz/android_common/turbine/quz.jar", + }, + + barJavacInputs: []string{"b.java"}, + barJavacClasspath: slices.Concat( + frameworkTurbineJars, + []string{"out/soong/.intermediates/quz/android_common/turbine/quz.jar"}, + ), + barCombinedInputs: []string{ + "out/soong/.intermediates/bar/android_common/javac/bar.jar", + "out/soong/.intermediates/quz/android_common/javac/quz.jar", + }, + barHeaderCombinedInputs: []string{ + "out/soong/.intermediates/bar/android_common/turbine/bar.jar", + "out/soong/.intermediates/quz/android_common/turbine/quz.jar", + }, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + tt.preparer, + ).RunTestWithBp(t, bp) + foo := result.ModuleForTests("foo", "android_common") + + fooJavac := foo.Rule("javac") + android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs) + + fooJavacClasspath := fooJavac.Args["classpath"] + android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath, + strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":")) + + fooCombinedJar := foo.Output("combined/foo.jar") + android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs) + + fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar") + android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs) + + bar := result.ModuleForTests("bar", "android_common") + barJavac := bar.Rule("javac") + android.AssertPathsRelativeToTopEquals(t, "bar javac inputs", tt.barJavacInputs, barJavac.Inputs) + + barJavacClasspath := barJavac.Args["classpath"] + android.AssertStringPathsRelativeToTopEquals(t, "bar javac classpath", result.Config, tt.barJavacClasspath, + strings.Split(strings.TrimPrefix(barJavacClasspath, "-classpath "), ":")) + + barCombinedJar := bar.Output("combined/bar.jar") + android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs) + + barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar") + android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs) + }) } } @@ -590,7 +717,7 @@ func TestPrebuilts(t *testing.T) { barModule := ctx.ModuleForTests("bar", "android_common") barJar := barModule.Output("combined/bar.jar").Output bazModule := ctx.ModuleForTests("baz", "android_common") - bazJar := bazModule.Rule("combineJar").Output + bazJar := bazModule.Output("combined/baz.jar").Output sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common"). Output("combined/sdklib.stubs.jar").Output diff --git a/java/kotlin_test.go b/java/kotlin_test.go index 844e974a4..f6e7fcaaa 100644 --- a/java/kotlin_test.go +++ b/java/kotlin_test.go @@ -56,6 +56,13 @@ func TestKotlin(t *testing.T) { "out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine-combined/kotlin-annotations.jar", } + kotlinStdlibTurbineJars := []string{ + "out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine/kotlin-stdlib.jar", + "out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine/kotlin-stdlib-jdk7.jar", + "out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine/kotlin-stdlib-jdk8.jar", + "out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine/kotlin-annotations.jar", + } + kotlinStdlibJavacJars := []string{ "out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar", "out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar", @@ -68,11 +75,21 @@ func TestKotlin(t *testing.T) { "out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine-combined/core-lambda-stubs.jar", } + bootclasspathTurbineJars := []string{ + "out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine/stable.core.platform.api.stubs.jar", + "out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine/core-lambda-stubs.jar", + } + frameworkTurbineCombinedJars := []string{ "out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar", "out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar", } + frameworkTurbineJars := []string{ + "out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar", + "out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar", + } + testCases := []struct { name string @@ -150,6 +167,69 @@ func TestKotlin(t *testing.T) { kotlinStdlibTurbineCombinedJars, ), }, + { + name: "transitive classpath", + preparer: PrepareForTestWithTransitiveClasspathEnabled, + fooKotlincInputs: []string{"a.java", "b.kt"}, + fooJavacInputs: []string{"a.java"}, + fooKotlincClasspath: slices.Concat( + bootclasspathTurbineJars, + frameworkTurbineJars, + []string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"}, + kotlinStdlibTurbineJars, + ), + fooJavacClasspath: slices.Concat( + []string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"}, + frameworkTurbineJars, + []string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"}, + kotlinStdlibTurbineJars, + ), + fooCombinedInputs: slices.Concat( + []string{ + "out/soong/.intermediates/foo/android_common/kotlin/foo.jar", + "out/soong/.intermediates/foo/android_common/javac/foo.jar", + "out/soong/.intermediates/quz/android_common/kotlin/quz.jar", + }, + kotlinStdlibJavacJars, + ), + fooHeaderCombinedInputs: slices.Concat( + []string{ + "out/soong/.intermediates/foo/android_common/turbine/foo.jar", + "out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar", + "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar", + }, + kotlinStdlibTurbineJars, + ), + + barKotlincInputs: []string{"b.kt"}, + barKotlincClasspath: slices.Concat( + bootclasspathTurbineJars, + frameworkTurbineJars, + []string{ + "out/soong/.intermediates/foo/android_common/turbine/foo.jar", + "out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar", + "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar", + }, + kotlinStdlibTurbineJars, + []string{"out/soong/.intermediates/baz/android_common/turbine/baz.jar"}, + ), + barCombinedInputs: slices.Concat( + []string{ + "out/soong/.intermediates/bar/android_common/kotlin/bar.jar", + "out/soong/.intermediates/baz/android_common/javac/baz.jar", + "out/soong/.intermediates/quz/android_common/kotlin/quz.jar", + }, + kotlinStdlibJavacJars, + ), + barHeaderCombinedInputs: slices.Concat( + []string{ + "out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar", + "out/soong/.intermediates/baz/android_common/turbine/baz.jar", + "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar", + }, + kotlinStdlibTurbineJars, + ), + }, } for _, tt := range testCases { diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 485776b99..12d5877c8 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -907,7 +907,7 @@ func TestJavaSdkLibraryImport(t *testing.T) { fooModule := result.ModuleForTests("foo"+scope, "android_common") javac := fooModule.Rule("javac") - sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output + sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String()) } diff --git a/java/sdk_test.go b/java/sdk_test.go index 2dac27af1..9bfe6a2b5 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -391,15 +391,19 @@ func TestClasspath(t *testing.T) { t.Parallel() t.Run("basic", func(t *testing.T) { t.Parallel() - testClasspathTestCases(t, classpathTestcases, false) + testClasspathTestCases(t, classpathTestcases, false, false) }) t.Run("Always_use_prebuilt_sdks=true", func(t *testing.T) { - testClasspathTestCases(t, classpathTestcases, true) + testClasspathTestCases(t, classpathTestcases, true, false) + }) + + t.Run("UseTransitiveJarsInClasspath", func(t *testing.T) { + testClasspathTestCases(t, classpathTestcases, false, true) }) } -func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks bool) { +func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks, useTransitiveJarsInClasspath bool) { for _, testcase := range classpathTestcases { if testcase.forAlwaysUsePrebuiltSdks != nil && *testcase.forAlwaysUsePrebuiltSdks != alwaysUsePrebuiltSdks { continue @@ -437,7 +441,14 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase convertModulesToPaths := func(cp []string) []string { ret := make([]string, len(cp)) for i, e := range cp { - ret[i] = defaultModuleToPath(e) + switch { + case e == `""`, strings.HasSuffix(e, ".jar"): + ret[i] = e + case useTransitiveJarsInClasspath: + ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine", e+".jar") + default: + ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine-combined", e+".jar") + } } return ret } @@ -531,6 +542,9 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) }) } + if useTransitiveJarsInClasspath { + preparer = PrepareForTestWithTransitiveClasspathEnabled + } fixtureFactory := android.GroupFixturePreparers( prepareForJavaTest, diff --git a/java/system_modules.go b/java/system_modules.go index f89bf9ea6..d9430b25e 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -127,6 +127,9 @@ type SystemModulesProviderInfo struct { OutputDir android.Path OutputDirDeps android.Paths + + // depset of header jars for this module and all transitive static dependencies + TransitiveStaticLibsHeaderJars *android.DepSet[android.Path] } var SystemModulesProvider = blueprint.NewProvider[*SystemModulesProviderInfo]() @@ -149,18 +152,23 @@ type SystemModulesProperties struct { func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) { var jars android.Paths + var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path] ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { jars = append(jars, dep.HeaderJars...) + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } } }) system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars) android.SetProvider(ctx, SystemModulesProvider, &SystemModulesProviderInfo{ - HeaderJars: jars, - OutputDir: system.outputDir, - OutputDirDeps: system.outputDeps, + HeaderJars: jars, + OutputDir: system.outputDir, + OutputDirDeps: system.outputDeps, + TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsHeaderJars), }) } diff --git a/java/testing.go b/java/testing.go index 03dcee667..e31e0d2bb 100644 --- a/java/testing.go +++ b/java/testing.go @@ -581,6 +581,7 @@ func gatherRequiredDepsForTest() string { name: "%[1]s-lib", sdk_version: "none", system_modules: "none", + srcs: ["a.java"], } `, extra) } @@ -780,3 +781,5 @@ func FixtureSetBootImageInstallDirOnDevice(name string, installDir string) andro config.installDir = installDir }) } + +var PrepareForTestWithTransitiveClasspathEnabled = android.PrepareForTestWithBuildFlag("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH", "true")