diff options
Diffstat (limited to 'java/java.go')
| -rw-r--r-- | java/java.go | 909 |
1 files changed, 665 insertions, 244 deletions
diff --git a/java/java.go b/java/java.go index 46344c842..67b9ba966 100644 --- a/java/java.go +++ b/java/java.go @@ -26,9 +26,9 @@ import ( "strings" "android/soong/remoteexec" - "android/soong/testing" "github.com/google/blueprint" + "github.com/google/blueprint/depset" "github.com/google/blueprint/proptools" "android/soong/android" @@ -70,9 +70,9 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { // established, to not get the dependencies split into the wrong variants and // to support the checks in dexpreoptDisabled(). ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel() + ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator) // needs access to ApexInfoProvider which is available after variant creation - ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel() + ctx.BottomUp("jacoco_deps", jacocoDepsMutator) }) ctx.RegisterParallelSingletonType("kythe_java_extract", kytheExtractJavaFactory) @@ -226,9 +226,9 @@ var ( // Rule for generating device binary default wrapper deviceBinaryWrapper = pctx.StaticRule("deviceBinaryWrapper", blueprint.RuleParams{ - Command: `echo -e '#!/system/bin/sh\n` + + Command: `printf '#!/system/bin/sh\n` + `export CLASSPATH=/system/framework/$jar_name\n` + - `exec app_process /$partition/bin $main_class "$$@"'> ${out}`, + `exec app_process /$partition/bin $main_class "$$@"\n'> ${out}`, Description: "Generating device binary wrapper ${jar_name}", }, "jar_name", "partition", "main_class") ) @@ -242,27 +242,68 @@ type ProguardSpecInfo struct { // TransitiveDepsProguardSpecFiles is a depset of paths to proguard flags files that are exported from // all transitive deps. This list includes all proguard flags files from transitive static dependencies, // and all proguard flags files from transitive libs dependencies which set `export_proguard_spec: true`. - ProguardFlagsFiles *android.DepSet[android.Path] + ProguardFlagsFiles depset.DepSet[android.Path] // implementation detail to store transitive proguard flags files from exporting shared deps - UnconditionallyExportedProguardFlags *android.DepSet[android.Path] + UnconditionallyExportedProguardFlags depset.DepSet[android.Path] } var ProguardSpecInfoProvider = blueprint.NewProvider[ProguardSpecInfo]() +type AndroidLibraryDependencyInfo struct { + ExportPackage android.Path + ResourcesNodeDepSet depset.DepSet[*resourcesNode] + RRODirsDepSet depset.DepSet[rroDir] + ManifestsDepSet depset.DepSet[android.Path] +} + +type UsesLibraryDependencyInfo struct { + DexJarBuildPath OptionalDexJarPath + DexJarInstallPath android.Path + ClassLoaderContexts dexpreopt.ClassLoaderContextMap +} + +type SdkLibraryComponentDependencyInfo struct { + // The name of the implementation library for the optional SDK library or nil, if there isn't one. + OptionalSdkLibraryImplementation *string +} + +type ProvidesUsesLibInfo struct { + ProvidesUsesLib *string +} + +type ModuleWithUsesLibraryInfo struct { + UsesLibrary *usesLibrary +} + +type ModuleWithSdkDepInfo struct { + SdkLinkType sdkLinkType + Stubs bool +} + // JavaInfo contains information about a java module for use by modules that depend on it. 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 // set of header jars for all transitive libs deps - TransitiveLibsHeaderJars *android.DepSet[android.Path] + TransitiveLibsHeaderJarsForR8 depset.DepSet[android.Path] // set of header jars for all transitive static libs deps - TransitiveStaticLibsHeaderJars *android.DepSet[android.Path] + TransitiveStaticLibsHeaderJarsForR8 depset.DepSet[android.Path] + + // depset of header jars for this module and all transitive static dependencies + TransitiveStaticLibsHeaderJars depset.DepSet[android.Path] + + // depset of implementation jars for this module and all transitive static dependencies + TransitiveStaticLibsImplementationJars depset.DepSet[android.Path] + + // depset of resource jars for this module and all transitive static dependencies + TransitiveStaticLibsResourceJars depset.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. @@ -275,6 +316,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 @@ -287,7 +331,7 @@ type JavaInfo struct { SrcJarDeps android.Paths // The source files of this module and all its transitive static dependencies. - TransitiveSrcFiles *android.DepSet[android.Path] + TransitiveSrcFiles depset.DepSet[android.Path] // ExportedPlugins is a list of paths that should be used as annotation processors for any // module that depends on this module. @@ -313,10 +357,89 @@ type JavaInfo struct { // AconfigIntermediateCacheOutputPaths is a path to the cache files collected from the // java_aconfig_library modules that are statically linked to this module. AconfigIntermediateCacheOutputPaths android.Paths + + SdkVersion android.SdkSpec + + // output file of the module, which may be a classes jar or a dex jar + OutputFile android.Path + + ExtraOutputFiles android.Paths + + AndroidLibraryDependencyInfo *AndroidLibraryDependencyInfo + + UsesLibraryDependencyInfo *UsesLibraryDependencyInfo + + SdkLibraryComponentDependencyInfo *SdkLibraryComponentDependencyInfo + + ProvidesUsesLibInfo *ProvidesUsesLibInfo + + ModuleWithUsesLibraryInfo *ModuleWithUsesLibraryInfo + + ModuleWithSdkDepInfo *ModuleWithSdkDepInfo + + // output file containing classes.dex and resources + DexJarFile OptionalDexJarPath + + // installed file for binary dependency + InstallFile android.Path + + // The path to the dex jar that is in the boot class path. If this is unset then the associated + // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional + // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar + // themselves. + // + // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on + // this file so using the encoded dex jar here would result in a cycle in the ninja rules. + BootDexJarPath OptionalDexJarPath + + // The compressed state of the dex file being encoded. This is used to ensure that the encoded + // dex file has the same state. + UncompressDexState *bool + + // True if the module containing this structure contributes to the hiddenapi information or has + // that information encoded within it. + Active bool + + BuiltInstalled string + + BuiltInstalledForApex []dexpreopterInstall + + // The config is used for two purposes: + // - Passing dexpreopt information about libraries from Soong to Make. This is needed when + // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py). + // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself. + // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally + // dexpreopt another partition). + ConfigPath android.WritablePath + + // The path to the profile on host that dexpreopter generates. This is used as the input for + // dex2oat. + OutputProfilePathOnHost android.Path + + LogtagsSrcs android.Paths + + ProguardDictionary android.OptionalPath + + ProguardUsageZip android.OptionalPath + + LinterReports android.Paths + + // installed file for hostdex copy + HostdexInstallFile android.InstallPath + + // Additional srcJars tacked in by GeneratedJavaLibraryModule + GeneratedSrcjars []android.Path + + // True if profile-guided optimization is actually enabled. + ProfileGuided bool } var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]() +type JavaLibraryInfo struct{} + +var JavaLibraryInfoProvider = blueprint.NewProvider[JavaLibraryInfo]() + // SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to // the sysprop implementation library. type SyspropPublicStubInfo struct { @@ -343,12 +466,17 @@ type UsesLibraryDependency interface { // TODO(jungjw): Move this to kythe.go once it's created. type xref interface { XrefJavaFiles() android.Paths + XrefKotlinFiles() android.Paths } func (j *Module) XrefJavaFiles() android.Paths { return j.kytheFiles } +func (j *Module) XrefKotlinFiles() android.Paths { + return j.kytheKotlinFiles +} + func (d dependencyTag) PropagateAconfigValidation() bool { return d.static } @@ -432,7 +560,6 @@ var ( javaApiContributionTag = dependencyTag{name: "java-api-contribution"} aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"} jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true} - binaryInstallTag = dependencyTag{name: "binary install", runtimeLinked: true, installable: true} usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) @@ -553,7 +680,7 @@ type deps struct { // are provided by systemModules. java9Classpath classpath - processorPath classpath + processorPath classpath `` errorProneProcessorPath classpath processorClasses []string staticJars android.Paths @@ -568,13 +695,17 @@ type deps struct { aconfigProtoFiles android.Paths disableTurbine bool + + transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] + transitiveStaticLibsImplementationJars []depset.DepSet[android.Path] + transitiveStaticLibsResourceJars []depset.DepSet[android.Path] } -func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) { - for _, f := range dep.Srcs() { +func checkProducesJars(ctx android.ModuleContext, dep android.SourceFilesInfo, module android.ModuleProxy) { + for _, f := range dep.Srcs { if f.Ext() != ".jar" { ctx.ModuleErrorf("genrule %q must generate files ending with .jar to be used as a libs or static_libs dependency", - ctx.OtherModuleName(dep.(blueprint.Module))) + ctx.OtherModuleName(module)) } } } @@ -585,10 +716,8 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an } else if ctx.Device() { return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx)) } else if ctx.Config().TargetsJava21() { - // Temporary experimental flag to be able to try and build with - // java version 21 options. The flag, if used, just sets Java - // 21 as the default version, leaving any components that - // target an older version intact. + // Build flag that controls whether Java 21 is used as the default + // target version, or Java 17. return JAVA_VERSION_21 } else { return JAVA_VERSION_17 @@ -923,6 +1052,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules. // TODO (b/331665856): Implement a principled solution for this. j.HideFromMake() + j.SkipInstall() } j.provideHiddenAPIPropertyInfo(ctx) @@ -980,25 +1110,118 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexpreopter.disableDexpreopt() } } - j.compile(ctx, nil, nil, nil) + javaInfo := j.compile(ctx, nil, nil, nil, nil) - // If this module is an impl library created from java_sdk_library, - // install the files under the java_sdk_library module outdir instead of this module outdir. - if j.SdkLibraryName() != nil && strings.HasSuffix(j.Name(), ".impl") { - j.setInstallRules(ctx, proptools.String(j.SdkLibraryName())) - } else { - j.setInstallRules(ctx, ctx.ModuleName()) - } + j.setInstallRules(ctx) android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ TestOnly: Bool(j.sourceProperties.Test_only), TopLevelTarget: j.sourceProperties.Top_level_test_target, }) + android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{}) + + if javaInfo != nil { + setExtraJavaInfo(ctx, j, javaInfo) + javaInfo.ExtraOutputFiles = j.extraOutputFiles + javaInfo.DexJarFile = j.dexJarFile + javaInfo.InstallFile = j.installFile + javaInfo.BootDexJarPath = j.bootDexJarPath + javaInfo.UncompressDexState = j.uncompressDexState + javaInfo.Active = j.active + javaInfo.BuiltInstalledForApex = j.builtInstalledForApex + javaInfo.BuiltInstalled = j.builtInstalled + javaInfo.ConfigPath = j.configPath + javaInfo.OutputProfilePathOnHost = j.outputProfilePathOnHost + javaInfo.LogtagsSrcs = j.logtagsSrcs + javaInfo.ProguardDictionary = j.proguardDictionary + javaInfo.ProguardUsageZip = j.proguardUsageZip + javaInfo.LinterReports = j.reports + javaInfo.HostdexInstallFile = j.hostdexInstallFile + javaInfo.GeneratedSrcjars = j.properties.Generated_srcjars + javaInfo.ProfileGuided = j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided + + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + } + setOutputFiles(ctx, j.Module) + + j.javaLibraryModuleInfoJSON(ctx) + + buildComplianceMetadata(ctx) +} + +func (j *Library) javaLibraryModuleInfoJSON(ctx android.ModuleContext) *android.ModuleInfoJSON { + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.implementationAndResourcesJar != nil { + moduleInfoJSON.ClassesJar = []string{j.implementationAndResourcesJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} + + if j.hostDexNeeded() { + hostDexModuleInfoJSON := ctx.ExtraModuleInfoJSON() + hostDexModuleInfoJSON.SubName = "-hostdex" + hostDexModuleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.implementationAndResourcesJar != nil { + hostDexModuleInfoJSON.ClassesJar = []string{j.implementationAndResourcesJar.String()} + } + hostDexModuleInfoJSON.SystemSharedLibs = []string{"none"} + hostDexModuleInfoJSON.SupportedVariantsOverride = []string{"HOST"} + } + + if j.hideApexVariantFromMake { + moduleInfoJSON.Disabled = true + j.dexpreopter.ModuleInfoJSONForApex(ctx) + } + return moduleInfoJSON +} + +func buildComplianceMetadata(ctx android.ModuleContext) { + // Dump metadata that can not be done in android/compliance-metadata.go + complianceMetadataInfo := ctx.ComplianceMetadataInfo() + builtFiles := ctx.GetOutputFiles().DefaultOutputFiles.Strings() + for _, paths := range ctx.GetOutputFiles().TaggedOutputFiles { + builtFiles = append(builtFiles, paths.Strings()...) + } + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.BUILT_FILES, android.FirstUniqueStrings(builtFiles)) + + // Static deps + staticDepNames := make([]string, 0) + staticDepFiles := android.Paths{} + ctx.VisitDirectDepsWithTag(staticLibTag, func(module android.Module) { + if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { + staticDepNames = append(staticDepNames, module.Name()) + staticDepFiles = append(staticDepFiles, dep.ImplementationJars...) + staticDepFiles = append(staticDepFiles, dep.HeaderJars...) + staticDepFiles = append(staticDepFiles, dep.ResourceJars...) + } + }) + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEPS, android.FirstUniqueStrings(staticDepNames)) + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepFiles.Strings())) +} + +func (j *Library) getJarInstallDir(ctx android.ModuleContext) android.InstallPath { + var installDir android.InstallPath + if ctx.InstallInTestcases() { + var archDir string + if !ctx.Host() { + archDir = ctx.DeviceConfig().DeviceArch() + } + installModuleName := ctx.ModuleName() + // If this module is an impl library created from java_sdk_library, + // install the files under the java_sdk_library module outdir instead of this module outdir. + if j.SdkLibraryName() != nil && strings.HasSuffix(j.Name(), ".impl") { + installModuleName = proptools.String(j.SdkLibraryName()) + } + installDir = android.PathForModuleInstall(ctx, installModuleName, archDir) + } else { + installDir = android.PathForModuleInstall(ctx, "framework") + } + return installDir } -func (j *Library) setInstallRules(ctx android.ModuleContext, installModuleName string) { +func (j *Library) setInstallRules(ctx android.ModuleContext) { apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if (Bool(j.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() { @@ -1008,21 +1231,11 @@ 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) } - var installDir android.InstallPath - if ctx.InstallInTestcases() { - var archDir string - if !ctx.Host() { - archDir = ctx.DeviceConfig().DeviceArch() - } - installDir = android.PathForModuleInstall(ctx, installModuleName, archDir) - } else { - installDir = android.PathForModuleInstall(ctx, "framework") - } - j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) + j.installFile = ctx.InstallFileWithoutCheckbuild(j.getJarInstallDir(ctx), j.Stem()+".jar", j.outputFile, extraInstallDeps...) } } @@ -1266,6 +1479,22 @@ type testProperties struct { // the test Data []string `android:"path"` + // Same as data, but will add dependencies on modules using the device's os variation and + // the common arch variation. Useful for a host test that wants to embed a module built for + // device. + Device_common_data []string `android:"path_device_common"` + + // same as data, but adds dependencies using the device's os variation and the device's first + // architecture's variation. Can be used to add a module built for device to the data of a + // host test. + Device_first_data []string `android:"path_device_first"` + + // same as data, but adds dependencies using the device's os variation and the device's first + // 32-bit architecture's variation. If a 32-bit arch doesn't exist for this device, it will use + // a 64 bit arch instead. Can be used to add a module built for device to the data of a + // host test. + Device_first_prefer32_data []string `android:"path_device_first_prefer32"` + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true // explicitly. @@ -1279,7 +1508,7 @@ type testProperties struct { Test_options TestOptions // Names of modules containing JNI libraries that should be installed alongside the test. - Jni_libs []string + Jni_libs proptools.Configurable[[]string] // Install the test into a folder named for the module in all test suites. Per_testcase_directory *bool @@ -1463,10 +1692,11 @@ func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) { } } - if len(j.testProperties.Jni_libs) > 0 { + jniLibs := j.testProperties.Jni_libs.GetOrDefault(ctx, nil) + if len(jniLibs) > 0 { for _, target := range ctx.MultiTargets() { sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) - ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...) + ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, jniLibs...) } } @@ -1515,23 +1745,28 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.Test.generateAndroidBuildActionsWithConfig(ctx, configs) - android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{}) android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ - InstalledFiles: j.data, - OutputFile: j.outputFile, - TestConfig: j.testConfig, - RequiredModuleNames: j.RequiredModuleNames(ctx), - TestSuites: j.testProperties.Test_suites, - IsHost: true, - LocalSdkVersion: j.sdkVersion.String(), - IsUnitTest: Bool(j.testProperties.Test_options.Unit_test), + TestcaseRelDataFiles: testcaseRel(j.data), + OutputFile: j.outputFile, + TestConfig: j.testConfig, + RequiredModuleNames: j.RequiredModuleNames(ctx), + TestSuites: j.testProperties.Test_suites, + IsHost: true, + LocalSdkVersion: j.sdkVersion.String(), + IsUnitTest: Bool(j.testProperties.Test_options.Unit_test), + MkInclude: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", + MkAppClass: "JAVA_LIBRARIES", }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + if proptools.Bool(j.testProperties.Test_options.Unit_test) { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } } func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { checkMinSdkVersionMts(ctx, j.MinSdkVersion(ctx)) j.generateAndroidBuildActionsWithConfig(ctx, nil) - android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) { @@ -1555,18 +1790,23 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, }) j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data) + j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_common_data)...) + j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_data)...) + j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_prefer32_data)...) j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) - ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataNativeBinsTag, func(dep android.ModuleProxy) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) - ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) - ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) { + var directImplementationDeps android.Paths + var transitiveImplementationDeps []depset.DepSet[android.Path] + ctx.VisitDirectDepsProxyWithTag(jniLibTag, func(dep android.ModuleProxy) { sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider) if sharedLibInfo.SharedLibrary != nil { // Copy to an intermediate output directory to append "lib[64]" to the path, @@ -1584,16 +1824,85 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, Output: relocatedLib, }) j.data = append(j.data, relocatedLib) + + directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps) + } } else { ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) } }) + android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{ + ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps), + }) + j.Library.GenerateAndroidBuildActions(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + // LOCAL_MODULE_TAGS + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + var allTestConfigs android.Paths + if j.testConfig != nil { + allTestConfigs = append(allTestConfigs, j.testConfig) + } + allTestConfigs = append(allTestConfigs, j.extraTestConfigs...) + if len(allTestConfigs) > 0 { + moduleInfoJSON.TestConfig = allTestConfigs.Strings() + } else { + optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + if optionalConfig.Valid() { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String()) + } + } + if len(j.testProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, j.testProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + if _, ok := j.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + if proptools.Bool(j.testProperties.Test_options.Unit_test) { + moduleInfoJSON.IsUnitTest = "true" + if ctx.Host() { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } + } + moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, j.testProperties.Test_mainline_modules...) + + // Install test deps + if !ctx.Config().KatiEnabled() { + pathInTestCases := android.PathForModuleInstall(ctx, "testcases", ctx.ModuleName()) + if j.testConfig != nil { + ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".config", j.testConfig) + } + testDeps := append(j.data, j.extraTestConfigs...) + for _, data := range android.SortedUniquePaths(testDeps) { + dataPath := android.DataPath{SrcPath: data} + ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath}) + } + if j.installFile != nil { + ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".jar", j.installFile) + } + } } func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Library.GenerateAndroidBuildActions(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + if len(j.testHelperLibraryProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, j.testHelperLibraryProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + if optionalConfig.Valid() { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String()) + } } func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1683,7 +1992,7 @@ func TestFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) module.Module.sourceProperties.Top_level_test_target = true @@ -1700,7 +2009,7 @@ func TestHelperLibraryFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) InitJavaModule(module, android.HostAndDeviceSupported) @@ -1772,8 +2081,7 @@ type binaryProperties struct { // Name of the class containing main to be inserted into the manifest as Main-Class. Main_class *string - // Names of modules containing JNI libraries that should be installed alongside the host - // variant of the binary. + // Names of modules containing JNI libraries that should be installed alongside the binary. Jni_libs []string `android:"arch_variant"` } @@ -1782,10 +2090,10 @@ type Binary struct { binaryProperties binaryProperties - isWrapperVariant bool - wrapperFile android.Path binaryFile android.InstallPath + + androidMkNamesOfJniLibs []string } func (j *Binary) HostToolPath() android.OptionalPath { @@ -1795,84 +2103,94 @@ func (j *Binary) HostToolPath() android.OptionalPath { func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.stem = proptools.StringDefault(j.overridableProperties.Stem, ctx.ModuleName()) - if ctx.Arch().ArchType == android.Common { - // Compile the jar - if j.binaryProperties.Main_class != nil { - if j.properties.Manifest != nil { - ctx.PropertyErrorf("main_class", "main_class cannot be used when manifest is set") - } - manifestFile := android.PathForModuleOut(ctx, "manifest.txt") - GenerateMainClassManifest(ctx, manifestFile, String(j.binaryProperties.Main_class)) - j.overrideManifest = android.OptionalPathForPath(manifestFile) - } - - j.Library.GenerateAndroidBuildActions(ctx) + // Handle the binary wrapper. This comes before compiling the jar so that the wrapper + // is the first PackagingSpec + if j.binaryProperties.Wrapper != nil { + j.wrapperFile = android.PathForModuleSrc(ctx, *j.binaryProperties.Wrapper) } else { - // Handle the binary wrapper - j.isWrapperVariant = true - - if j.binaryProperties.Wrapper != nil { - j.wrapperFile = android.PathForModuleSrc(ctx, *j.binaryProperties.Wrapper) - } else { - if ctx.Windows() { - ctx.PropertyErrorf("wrapper", "wrapper is required for Windows") - } + if ctx.Windows() { + ctx.PropertyErrorf("wrapper", "wrapper is required for Windows") + } - if ctx.Device() { - // device binary should have a main_class property if it does not - // have a specific wrapper, so that a default wrapper can - // be generated for it. - if j.binaryProperties.Main_class == nil { - ctx.PropertyErrorf("main_class", "main_class property "+ - "is required for device binary if no default wrapper is assigned") - } else { - wrapper := android.PathForModuleOut(ctx, ctx.ModuleName()+".sh") - jarName := j.Stem() + ".jar" - partition := j.PartitionTag(ctx.DeviceConfig()) - ctx.Build(pctx, android.BuildParams{ - Rule: deviceBinaryWrapper, - Output: wrapper, - Args: map[string]string{ - "jar_name": jarName, - "partition": partition, - "main_class": String(j.binaryProperties.Main_class), - }, - }) - j.wrapperFile = wrapper - } + if ctx.Device() { + // device binary should have a main_class property if it does not + // have a specific wrapper, so that a default wrapper can + // be generated for it. + if j.binaryProperties.Main_class == nil { + ctx.PropertyErrorf("main_class", "main_class property "+ + "is required for device binary if no default wrapper is assigned") } else { - j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh") + wrapper := android.PathForModuleOut(ctx, ctx.ModuleName()+".sh") + jarName := j.Stem() + ".jar" + partition := j.PartitionTag(ctx.DeviceConfig()) + ctx.Build(pctx, android.BuildParams{ + Rule: deviceBinaryWrapper, + Output: wrapper, + Args: map[string]string{ + "jar_name": jarName, + "partition": partition, + "main_class": String(j.binaryProperties.Main_class), + }, + }) + j.wrapperFile = wrapper } + } else { + j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh") } + } - ext := "" - if ctx.Windows() { - ext = ".bat" + ext := "" + if ctx.Windows() { + ext = ".bat" + } + + // The host installation rules make the installed wrapper depend on all the dependencies + // of the wrapper variant, which will include the common variant's jar file and any JNI + // libraries. This is verified by TestBinary. Also make it depend on the jar file so that + // the binary file timestamp will update when the jar file timestamp does. The jar file is + // built later on, in j.Library.GenerateAndroidBuildActions, so we have to create an identical + // installpath representing it here. + j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"), + ctx.ModuleName()+ext, j.wrapperFile, j.getJarInstallDir(ctx).Join(ctx, j.Stem()+".jar")) + + // Set the jniLibs of this binary. + // These will be added to `LOCAL_REQUIRED_MODULES`, and the kati packaging system will + // install these alongside the java binary. + ctx.VisitDirectDepsProxyWithTag(jniInstallTag, func(jni android.ModuleProxy) { + // Use the BaseModuleName of the dependency (without any prebuilt_ prefix) + commonInfo, _ := android.OtherModuleProvider(ctx, jni, android.CommonModuleInfoKey) + j.androidMkNamesOfJniLibs = append(j.androidMkNamesOfJniLibs, commonInfo.BaseModuleName+":"+commonInfo.Target.Arch.ArchType.Bitness()) + }) + // Check that native libraries are not listed in `required`. Prompt users to use `jni_libs` instead. + ctx.VisitDirectDepsProxyWithTag(android.RequiredDepTag, func(dep android.ModuleProxy) { + if _, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider); hasSharedLibraryInfo { + ctx.ModuleErrorf("cc_library %s is no longer supported in `required` of java_binary modules. Please use jni_libs instead.", dep.Name()) } + }) - // The host installation rules make the installed wrapper depend on all the dependencies - // of the wrapper variant, which will include the common variant's jar file and any JNI - // libraries. This is verified by TestBinary. - j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"), - ctx.ModuleName()+ext, j.wrapperFile) - - setOutputFiles(ctx, j.Library.Module) + // Compile the jar + if j.binaryProperties.Main_class != nil { + if j.properties.Manifest != nil { + ctx.PropertyErrorf("main_class", "main_class cannot be used when manifest is set") + } + manifestFile := android.PathForModuleOut(ctx, "manifest.txt") + GenerateMainClassManifest(ctx, manifestFile, String(j.binaryProperties.Main_class)) + j.overrideManifest = android.OptionalPathForPath(manifestFile) } + + j.Library.GenerateAndroidBuildActions(ctx) } func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) { - if ctx.Arch().ArchType == android.Common { - j.deps(ctx) - } + j.deps(ctx) // These dependencies ensure the installation rules will install the jar file when the - // wrapper is installed, and the jni libraries on host when the wrapper is installed. - if ctx.Arch().ArchType != android.Common && ctx.Os().Class == android.Host { - ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...) - } - if ctx.Arch().ArchType != android.Common { - ctx.AddVariationDependencies( - []blueprint.Variation{{Mutator: "arch", Variation: android.CommonArch.String()}}, - binaryInstallTag, ctx.ModuleName()) + // wrapper is installed, and the jni libraries when the wrapper is installed. + if ctx.Os().Class == android.Host { + ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniInstallTag, j.binaryProperties.Jni_libs...) + } else if ctx.Os().Class == android.Device { + ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), jniInstallTag, j.binaryProperties.Jni_libs...) + } else { + ctx.ModuleErrorf("Unknown os class") } } @@ -1892,7 +2210,7 @@ func BinaryFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) - android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst) + android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) return module @@ -1910,7 +2228,7 @@ func BinaryHostFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) - android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst) + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon) android.InitDefaultableModule(module) return module } @@ -1994,11 +2312,11 @@ type JavaApiLibraryProperties struct { // List of shared java libs that this module has dependencies to and // should be passed as classpath in javac invocation - Libs []string + Libs proptools.Configurable[[]string] // List of java libs that this module has static dependencies to and will be // merge zipped after metalava invocation - Static_libs []string + Static_libs proptools.Configurable[[]string] // Version of previously released API file for compatibility check. Previous_api *string `android:"path"` @@ -2063,7 +2381,7 @@ func (al *ApiLibrary) StubsJar() android.Path { func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, homeDir android.WritablePath, - classpath android.Paths, configFiles android.Paths) *android.RuleBuilderCommand { + classpath android.Paths, configFiles android.Paths, apiSurface *string) *android.RuleBuilderCommand { rule.Command().Text("rm -rf").Flag(homeDir.String()) rule.Command().Text("mkdir -p").Flag(homeDir.String()) @@ -2104,6 +2422,8 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, addMetalavaConfigFilesToCmd(cmd, configFiles) + addOptionalApiSurfaceToCmd(cmd, apiSurface) + if len(classpath) == 0 { // The main purpose of the `--api-class-resolution api` option is to force metalava to ignore // classes on the classpath when an API file contains missing classes. However, as this command @@ -2174,8 +2494,8 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { } } - ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...) - ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...) + ctx.AddVariationDependencies(nil, libTag, al.properties.Libs.GetOrDefault(ctx, nil)...) + ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs.GetOrDefault(ctx, nil)...) for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName) @@ -2187,6 +2507,17 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { var scopeOrderMap = AllApiScopes.MapToIndex( func(s *apiScope) string { return s.name }) +// Add some extra entries into scopeOrderMap for some special api surface names needed by libcore, +// external/conscrypt and external/icu and java/core-libraries. +func init() { + count := len(scopeOrderMap) + scopeOrderMap["core"] = count + 1 + scopeOrderMap["core-platform"] = count + 2 + scopeOrderMap["intra-core"] = count + 3 + scopeOrderMap["core-platform-plus-public"] = count + 4 + scopeOrderMap["core-platform-legacy"] = count + 5 +} + func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo { for _, srcFileInfo := range srcFilesInfo { if srcFileInfo.ApiSurface == "" { @@ -2235,7 +2566,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { var bootclassPaths android.Paths var staticLibs android.Paths var systemModulesPaths android.Paths - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(dep) switch tag { case javaApiContributionTag: @@ -2247,22 +2578,25 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { case libTag: if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { classPaths = append(classPaths, provider.HeaderJars...) + al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...) } case bootClasspathTag: if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { bootclassPaths = append(bootclassPaths, provider.HeaderJars...) + al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...) } case staticLibTag: if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { staticLibs = append(staticLibs, provider.HeaderJars...) + al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...) } case systemModulesTag: if sm, ok := android.OtherModuleProvider(ctx, dep, SystemModulesProvider); ok { systemModulesPaths = append(systemModulesPaths, sm.HeaderJars...) } case metalavaCurrentApiTimestampTag: - if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok { - al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp()) + if currentApiTimestampProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider); ok { + al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp) } case aconfigDeclarationTag: if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok { @@ -2294,7 +2628,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { combinedPaths := append(([]android.Path)(nil), systemModulesPaths...) combinedPaths = append(combinedPaths, classPaths...) combinedPaths = append(combinedPaths, bootclassPaths...) - cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, combinedPaths, configFiles) + cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, combinedPaths, configFiles, al.properties.Api_surface) al.stubsFlags(ctx, cmd, stubsDir) @@ -2358,14 +2692,19 @@ 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, + javaInfo := &JavaInfo{ + HeaderJars: android.PathsIfNonNil(al.stubsJar), + LocalHeaderJars: android.PathsIfNonNil(al.stubsJar), + TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, android.PathsIfNonNil(al.stubsJar), nil), + TransitiveStaticLibsImplementationJars: depset.New(depset.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 - }) + } + setExtraJavaInfo(ctx, al, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) } func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { @@ -2404,19 +2743,19 @@ func (al *ApiLibrary) TargetSdkVersion(ctx android.EarlyModuleContext) android.A return al.SdkVersion(ctx).ApiLevel } -func (al *ApiLibrary) IDEInfo(i *android.IdeInfo) { - i.Deps = append(i.Deps, al.ideDeps()...) - i.Libs = append(i.Libs, al.properties.Libs...) - i.Static_libs = append(i.Static_libs, al.properties.Static_libs...) +func (al *ApiLibrary) IDEInfo(ctx android.BaseModuleContext, i *android.IdeInfo) { + i.Deps = append(i.Deps, al.ideDeps(ctx)...) + i.Libs = append(i.Libs, al.properties.Libs.GetOrDefault(ctx, nil)...) + i.Static_libs = append(i.Static_libs, al.properties.Static_libs.GetOrDefault(ctx, nil)...) i.SrcJars = append(i.SrcJars, al.stubsSrcJar.String()) } // deps of java_api_library for module_bp_java_deps.json -func (al *ApiLibrary) ideDeps() []string { +func (al *ApiLibrary) ideDeps(ctx android.BaseModuleContext) []string { ret := []string{} - ret = append(ret, al.properties.Libs...) - ret = append(ret, al.properties.Static_libs...) - if al.properties.System_modules != nil { + ret = append(ret, al.properties.Libs.GetOrDefault(ctx, nil)...) + ret = append(ret, al.properties.Static_libs.GetOrDefault(ctx, nil)...) + if proptools.StringDefault(al.properties.System_modules, "none") != "none" { ret = append(ret, proptools.String(al.properties.System_modules)) } // Other non java_library dependencies like java_api_contribution are ignored for now. @@ -2459,7 +2798,7 @@ type ImportProperties struct { Libs []string // List of static java libs that this module has dependencies to - Static_libs []string + Static_libs proptools.Configurable[[]string] // List of files to remove from the jar file(s) Exclude_files []string @@ -2587,20 +2926,9 @@ func (a *Import) JacocoReportClassesFile() android.Path { return nil } -func (j *Import) LintDepSets() LintDepSets { - return LintDepSets{} -} - -func (j *Import) getStrictUpdatabilityLinting() bool { - return false -} - -func (j *Import) setStrictUpdatabilityLinting(bool) { -} - func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) - ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...) + ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...) if ctx.Device() && Bool(j.dexProperties.Compile_dex) { sdkDeps(ctx, android.SdkContext(j), j.dexer) @@ -2634,43 +2962,74 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { var flags javaBuilderFlags - j.collectTransitiveHeaderJars(ctx) + var transitiveClasspathHeaderJars []depset.DepSet[android.Path] + var transitiveBootClasspathHeaderJars []depset.DepSet[android.Path] + var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] + var transitiveStaticLibsImplementationJars []depset.DepSet[android.Path] + var transitiveStaticLibsResourceJars []depset.DepSet[android.Path] + + j.collectTransitiveHeaderJarsForR8(ctx) var staticJars android.Paths var staticResourceJars android.Paths var staticHeaderJars android.Paths - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { switch tag { case libTag, sdkLibTag: flags.classpath = append(flags.classpath, dep.HeaderJars...) flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...) + 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...) + transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) + transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars) + transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars) case bootClasspathTag: flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...) + transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) } - } else if dep, ok := module.(SdkLibraryDependency); ok { + } else if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { switch tag { case libTag, sdkLibTag: - flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) + sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider) + generatingLibsString := android.PrettyConcat( + getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or") + ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString) } } 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 := depset.New(depset.PREORDER, localStrippedJars, transitiveStaticLibsHeaderJars) + completeStaticLibsImplementationJars := depset.New(depset.PREORDER, localStrippedJars, transitiveStaticLibsImplementationJars) + completeStaticLibsResourceJars := depset.New(depset.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 +3052,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 +3076,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 = depset.New(depset.PREORDER, android.Paths{headerJar}, nil) + completeStaticLibsImplementationJars = depset.New(depset.PREORDER, android.Paths{outputFile}, nil) } implementationJarFile := outputFile @@ -2725,6 +3094,23 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { outputFile = combinedJar } + proguardFlags := android.PathForModuleOut(ctx, "proguard_flags") + TransformJarToR8Rules(ctx, proguardFlags, outputFile) + + transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx) + android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{ + ProguardFlagsFiles: depset.New[android.Path]( + depset.POSTORDER, + android.Paths{proguardFlags}, + transitiveProguardFlags, + ), + UnconditionallyExportedProguardFlags: depset.New[android.Path]( + depset.POSTORDER, + nil, + transitiveUnconditionalExportedFlags, + ), + }) + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource. // Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check // in a module that depends on this module considers them equal. @@ -2735,42 +3121,21 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) + 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 - // obtained from the associated deapexer module. + // Shared libraries deapexed from prebuilt apexes are no longer supported. + // Set the dexJarBuildPath to a fake path. + // This allows soong analysis pass, but will be an error during ninja execution if there are + // any rdeps. ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if ai.ForPrebuiltApex { - // Get the path of the dex implementation jar from the `deapexer` module. - di, err := android.FindDeapexerProviderForModule(ctx) - if err != nil { - // An error was found, possibly due to multiple apexes in the tree that export this library - // Defer the error till a client tries to call DexJarBuildPath - j.dexJarFileErr = err - j.initHiddenAPIError(err) - return - } - dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(j.BaseModuleName()) - if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil { - dexJarFile := makeDexJarPathFromPath(dexOutputPath) - j.dexJarFile = dexJarFile - installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, ApexRootRelativePathToJavaLib(j.BaseModuleName())) - j.dexJarInstallFile = installPath - - j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath) - setUncompressDex(ctx, &j.dexpreopter, &j.dexer) - j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex - - if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil { - j.dexpreopter.inputProfilePathOnHost = profilePath - } - - // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex) - } else { - // This should never happen as a variant for a prebuilt_apex is only created if the - // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) - } + j.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported")) + j.initHiddenAPI(ctx, j.dexJarFile, outputFile, j.dexProperties.Uncompress_dex) } else if Bool(j.dexProperties.Compile_dex) { sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) if sdkDep.invalidVersion { @@ -2801,6 +3166,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { if ctx.Failed() { return } + ctx.CheckbuildFile(dexOutputFile) // Initialize the hiddenapi structure. j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex) @@ -2813,20 +3179,28 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ - HeaderJars: android.PathsIfNonNil(j.combinedHeaderFile), - TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars, - TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars, - ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile), - ImplementationJars: android.PathsIfNonNil(implementationJarFile.WithoutRel()), - ResourceJars: android.PathsIfNonNil(resourceJarFile), - AidlIncludeDirs: j.exportAidlIncludeDirs, - StubsLinkType: j.stubsLinkType, + javaInfo := &JavaInfo{ + 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 - }) + } + setExtraJavaInfo(ctx, j, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, "") ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, ".jar") + + buildComplianceMetadata(ctx) } func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) { @@ -2873,8 +3247,8 @@ func (j *Import) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { var _ android.ApexModule = (*Import)(nil) // Implements android.ApexModule -func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - return j.depIsInSameApex(ctx, dep) +func (j *Import) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + return j.depIsInSameApex(tag) } // Implements android.ApexModule @@ -2933,8 +3307,8 @@ var _ android.IDECustomizedModuleName = (*Import)(nil) // Collect information for opening IDE project files in java/jdeps.go. -func (j *Import) IDEInfo(dpInfo *android.IdeInfo) { - dpInfo.Jars = append(dpInfo.Jars, j.combinedHeaderFile.String()) +func (j *Import) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { + dpInfo.Jars = append(dpInfo.Jars, j.combinedImplementationFile.String()) } func (j *Import) IDECustomizedModuleName() string { @@ -3038,21 +3412,10 @@ func (a *DexImport) JacocoReportClassesFile() android.Path { return nil } -func (a *DexImport) LintDepSets() LintDepSets { - return LintDepSets{} -} - func (j *DexImport) IsInstallable() bool { return true } -func (j *DexImport) getStrictUpdatabilityLinting() bool { - return false -} - -func (j *DexImport) setStrictUpdatabilityLinting(bool) { -} - func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(j.properties.Jars) != 1 { ctx.PropertyErrorf("jars", "exactly one jar must be provided") @@ -3207,6 +3570,9 @@ func DefaultsFactory() android.Module { &JavaApiLibraryProperties{}, &bootclasspathFragmentProperties{}, &SourceOnlyBootclasspathProperties{}, + &ravenwoodTestProperties{}, + &AndroidAppImportProperties{}, + &UsesLibraryProperties{}, ) android.InitDefaultsModule(module) @@ -3222,15 +3588,20 @@ type kytheExtractJavaSingleton struct { func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonContext) { var xrefTargets android.Paths + var xrefKotlinTargets android.Paths ctx.VisitAllModules(func(module android.Module) { if javaModule, ok := module.(xref); ok { xrefTargets = append(xrefTargets, javaModule.XrefJavaFiles()...) + xrefKotlinTargets = append(xrefKotlinTargets, javaModule.XrefKotlinFiles()...) } }) // TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets if len(xrefTargets) > 0 { ctx.Phony("xref_java", xrefTargets...) } + if len(xrefKotlinTargets) > 0 { + ctx.Phony("xref_kotlin", xrefKotlinTargets...) + } } var Bool = proptools.Bool @@ -3239,24 +3610,28 @@ var String = proptools.String var inList = android.InList[string] // Add class loader context (CLC) of a given dependency to the current CLC. -func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, +func addCLCFromDep(ctx android.ModuleContext, depModule android.ModuleProxy, clcMap dexpreopt.ClassLoaderContextMap) { - dep, ok := depModule.(UsesLibraryDependency) - if !ok { + dep, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider) + if !ok || dep.UsesLibraryDependencyInfo == nil { return } depName := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(depModule)) var sdkLib *string - if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() { + if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryInfoProvider); ok && lib.SharedLibrary { // A shared SDK library. This should be added as a top-level CLC element. sdkLib = &depName - } else if ulib, ok := depModule.(ProvidesUsesLib); ok { + } else if lib := dep.SdkLibraryComponentDependencyInfo; lib != nil && lib.OptionalSdkLibraryImplementation != nil { + if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation)+".impl" { + sdkLib = lib.OptionalSdkLibraryImplementation + } + } else if ulib := dep.ProvidesUsesLibInfo; ulib != nil { // A non-SDK library disguised as an SDK library by the means of `provides_uses_lib` // property. This should be handled in the same way as a shared SDK library. - sdkLib = ulib.ProvidesUsesLib() + sdkLib = ulib.ProvidesUsesLib } depTag := ctx.OtherModuleDependencyTag(depModule) @@ -3283,26 +3658,27 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, if sdkLib != nil { optional := false if module, ok := ctx.Module().(ModuleWithUsesLibrary); ok { - if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs) { + if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) { optional = true } } clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, optional, - dep.DexJarBuildPath(ctx).PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) + dep.UsesLibraryDependencyInfo.DexJarBuildPath.PathOrNil(), + dep.UsesLibraryDependencyInfo.DexJarInstallPath, dep.UsesLibraryDependencyInfo.ClassLoaderContexts) } else { - clcMap.AddContextMap(dep.ClassLoaderContexts(), depName) + clcMap.AddContextMap(dep.UsesLibraryDependencyInfo.ClassLoaderContexts, depName) } } -func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.Module, +func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.ModuleProxy, usesLibrary *usesLibrary) { - dep, ok := depModule.(ModuleWithUsesLibrary) - if !ok { + dep, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider) + if !ok || dep.ModuleWithUsesLibraryInfo == nil { return } - for _, lib := range dep.UsesLibrary().usesLibraryProperties.Missing_optional_uses_libs { + for _, lib := range dep.ModuleWithUsesLibraryInfo.UsesLibrary.usesLibraryProperties.Missing_optional_uses_libs { if !android.InList(lib, usesLibrary.usesLibraryProperties.Missing_optional_uses_libs) { usesLibrary.usesLibraryProperties.Missing_optional_uses_libs = append(usesLibrary.usesLibraryProperties.Missing_optional_uses_libs, lib) @@ -3358,3 +3734,48 @@ func (j *JavaApiContributionImport) CreatedByJavaSdkLibraryName() *string { func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ap.JavaApiContribution.GenerateAndroidBuildActions(ctx) } + +func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo *JavaInfo) { + if alDep, ok := module.(AndroidLibraryDependency); ok { + javaInfo.AndroidLibraryDependencyInfo = &AndroidLibraryDependencyInfo{ + ExportPackage: alDep.ExportPackage(), + ResourcesNodeDepSet: alDep.ResourcesNodeDepSet(), + RRODirsDepSet: alDep.RRODirsDepSet(), + ManifestsDepSet: alDep.ManifestsDepSet(), + } + } + + if ulDep, ok := module.(UsesLibraryDependency); ok { + javaInfo.UsesLibraryDependencyInfo = &UsesLibraryDependencyInfo{ + DexJarBuildPath: ulDep.DexJarBuildPath(ctx), + DexJarInstallPath: ulDep.DexJarInstallPath(), + ClassLoaderContexts: ulDep.ClassLoaderContexts(), + } + } + + if slcDep, ok := module.(SdkLibraryComponentDependency); ok { + javaInfo.SdkLibraryComponentDependencyInfo = &SdkLibraryComponentDependencyInfo{ + OptionalSdkLibraryImplementation: slcDep.OptionalSdkLibraryImplementation(), + } + } + + if pul, ok := module.(ProvidesUsesLib); ok { + javaInfo.ProvidesUsesLibInfo = &ProvidesUsesLibInfo{ + ProvidesUsesLib: pul.ProvidesUsesLib(), + } + } + + if mwul, ok := module.(ModuleWithUsesLibrary); ok { + javaInfo.ModuleWithUsesLibraryInfo = &ModuleWithUsesLibraryInfo{ + UsesLibrary: mwul.UsesLibrary(), + } + } + + if mwsd, ok := module.(moduleWithSdkDep); ok { + linkType, stubs := mwsd.getSdkLinkType(ctx, ctx.ModuleName()) + javaInfo.ModuleWithSdkDepInfo = &ModuleWithSdkDepInfo{ + SdkLinkType: linkType, + Stubs: stubs, + } + } +} |