diff options
Diffstat (limited to 'java/base.go')
| -rw-r--r-- | java/base.go | 919 |
1 files changed, 740 insertions, 179 deletions
diff --git a/java/base.go b/java/base.go index 991132321..caac98abc 100644 --- a/java/base.go +++ b/java/base.go @@ -17,9 +17,12 @@ package java import ( "fmt" "path/filepath" + "reflect" + "slices" "strconv" "strings" + "github.com/google/blueprint" "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" @@ -79,12 +82,18 @@ type CommonProperties struct { // list of java libraries that will be compiled into the resulting jar Static_libs []string `android:"arch_variant"` + // list of java libraries that should not be used to build this module + Exclude_static_libs []string `android:"arch_variant"` + // manifest file to be included in resulting jar Manifest *string `android:"path"` // if not blank, run jarjar using the specified rules file Jarjar_rules *string `android:"path,arch_variant"` + // if not blank, used as prefix to generate repackage rule + Jarjar_prefix *string + // If not blank, set the java version passed to javac as -source and -target Java_version *string @@ -129,7 +138,7 @@ type CommonProperties struct { // supported at compile time. It should only be needed to compile tests in // packages that exist in libcore and which are inconvenient to move // elsewhere. - Patch_module *string `android:"arch_variant"` + Patch_module *string Jacoco struct { // List of classes to include for instrumentation with jacoco to collect coverage @@ -184,6 +193,28 @@ type CommonProperties struct { // A list of java_library instances that provide additional hiddenapi annotations for the library. Hiddenapi_additional_annotations []string + + // Additional srcJars tacked in by GeneratedJavaLibraryModule + Generated_srcjars []android.Path `android:"mutated"` + + // intermediate aconfig cache file tacked in by GeneratedJavaLibraryModule + Aconfig_Cache_files []android.Path `android:"mutated"` + + // If true, then only the headers are built and not the implementation jar. + Headers_only *bool + + // A list of files or dependencies to make available to the build sandbox. This is + // useful if source files are symlinks, the targets of the symlinks must be listed here. + // Note that currently not all actions implemented by android_apps are sandboxed, so you + // may only see this being necessary in lint builds. + Compile_data []string `android:"path"` + + // Property signifying whether the module compiles stubs or not. + // Should be set to true when srcs of this module are stub files. + // This property does not need to be set to true when the module depends on + // the stubs via libs, but should be set to true when the module depends on + // the stubs via static libs. + Is_stubs_module *bool } // Properties that are specific to device modules. Host module factories should not add these when @@ -198,10 +229,6 @@ type DeviceProperties struct { // If the SDK kind is empty, it will be set to public. Sdk_version *string - // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. - // Defaults to sdk_version if not set. See sdk_version for possible values. - Min_sdk_version *string - // if not blank, set the maximum version of the sdk that the compiled artifacts will run against. // Defaults to empty string "". See sdk_version for possible values. Max_sdk_version *string @@ -274,13 +301,17 @@ type DeviceProperties struct { HiddenAPIFlagFileProperties } -// Device properties that can be overridden by overriding module (e.g. override_android_app) -type OverridableDeviceProperties struct { +// Properties that can be overridden by overriding module (e.g. override_android_app) +type OverridableProperties struct { // set the name of the output. If not set, `name` is used. // To override a module with this property set, overriding module might need to set this as well. // Otherwise, both the overridden and the overriding modules will have the same output name, which // can cause the duplicate output error. Stem *string + + // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. + // Defaults to sdk_version if not set. See sdk_version for possible values. + Min_sdk_version *string } // Functionality common to Module and Import @@ -395,7 +426,6 @@ type Module struct { android.ModuleBase android.DefaultableModuleBase android.ApexModuleBase - android.BazelModuleBase // Functionality common to Module and Import. embeddableInModuleAndImport @@ -404,12 +434,15 @@ type Module struct { protoProperties android.ProtoProperties deviceProperties DeviceProperties - overridableDeviceProperties OverridableDeviceProperties + overridableProperties OverridableProperties + sourceProperties android.SourceProperties // jar file containing header classes including static library dependencies, suitable for // 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 @@ -421,6 +454,9 @@ type Module struct { srcJarArgs []string srcJarDeps android.Paths + // the source files of this module and all its static dependencies + transitiveSrcFiles *android.DepSet[android.Path] + // jar file containing implementation classes and resources including static library // dependencies implementationAndResourcesJar android.Path @@ -471,6 +507,9 @@ type Module struct { // expanded Jarjar_rules expandJarjarRules android.Path + // jarjar rule for inherited jarjar rules + repackageJarjarRules android.Path + // Extra files generated by the module type to be added as java resources. extraResources android.Paths @@ -483,9 +522,6 @@ type Module struct { // list of the xref extraction files kytheFiles android.Paths - // Collect the module directory for IDE info in java/jdeps.go. - modulePaths []string - hideApexVariantFromMake bool sdkVersion android.SdkSpec @@ -493,6 +529,36 @@ type Module struct { maxSdkVersion android.ApiLevel sourceExtensions []string + + annoSrcJars android.Paths + + // output file name based on Stem property. + // This should be set in every ModuleWithStem's GenerateAndroidBuildActions + // or the module should override Stem(). + stem string + + // Values that will be set in the JarJarProvider data for jarjar repackaging, + // and merged with our dependencies' rules. + jarjarRenameRules map[string]string + + stubsLinkType StubsLinkType + + // Paths to the aconfig intermediate cache files that are provided by the + // java_aconfig_library or java_library modules that are statically linked + // to this module. Does not contain cache files from all transitive dependencies. + aconfigCacheFiles android.Paths +} + +var _ android.InstallableModule = (*Module)(nil) + +// To satisfy the InstallableModule interface +func (j *Module) EnforceApiContainerChecks() bool { + return true +} + +// Overrides android.ModuleBase.InstallInProduct() +func (j *Module) InstallInProduct() bool { + return j.ProductSpecific() } func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { @@ -551,9 +617,21 @@ func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { } } +func (j *Module) checkHeadersOnly(ctx android.ModuleContext) { + if _, ok := ctx.Module().(android.SdkContext); ok { + headersOnly := proptools.Bool(j.properties.Headers_only) + installable := proptools.Bool(j.properties.Installable) + + if headersOnly && installable { + ctx.PropertyErrorf("headers_only", "This module has conflicting settings. headers_only is true which, which means this module doesn't generate an implementation jar. However installable is set to true.") + } + } +} + func (j *Module) addHostProperties() { j.AddProperties( &j.properties, + &j.overridableProperties, &j.protoProperties, &j.usesLibraryProperties, ) @@ -563,7 +641,6 @@ func (j *Module) addHostAndDeviceProperties() { j.addHostProperties() j.AddProperties( &j.deviceProperties, - &j.overridableDeviceProperties, &j.dexer.dexProperties, &j.dexpreoptProperties, &j.linter.properties, @@ -581,31 +658,24 @@ func (j *Module) provideHiddenAPIPropertyInfo(ctx android.ModuleContext) { // Populate with package rules from the properties. hiddenAPIInfo.extractPackageRulesFromProperties(&j.deviceProperties.HiddenAPIPackageProperties) - ctx.SetProvider(hiddenAPIPropertyInfoProvider, hiddenAPIInfo) + android.SetProvider(ctx, hiddenAPIPropertyInfoProvider, hiddenAPIInfo) } -func (j *Module) OutputFiles(tag string) (android.Paths, error) { - switch tag { - case "": - return append(android.Paths{j.outputFile}, j.extraOutputFiles...), nil - case android.DefaultDistTag: - return android.Paths{j.outputFile}, nil - case ".jar": - return android.Paths{j.implementationAndResourcesJar}, nil - case ".hjar": - return android.Paths{j.headerJarFile}, nil - case ".proguard_map": - if j.dexer.proguardDictionary.Valid() { - return android.Paths{j.dexer.proguardDictionary.Path()}, nil - } - return nil, fmt.Errorf("%q was requested, but no output file was found.", tag) - default: - return nil, fmt.Errorf("unsupported module reference tag %q", tag) +// helper method for java modules to set OutputFilesProvider +func setOutputFiles(ctx android.ModuleContext, m Module) { + ctx.SetOutputFiles(append(android.Paths{m.outputFile}, m.extraOutputFiles...), "") + ctx.SetOutputFiles(android.Paths{m.outputFile}, android.DefaultDistTag) + ctx.SetOutputFiles(android.Paths{m.implementationAndResourcesJar}, ".jar") + ctx.SetOutputFiles(android.Paths{m.headerJarFile}, ".hjar") + if m.dexer.proguardDictionary.Valid() { + ctx.SetOutputFiles(android.Paths{m.dexer.proguardDictionary.Path()}, ".proguard_map") + } + ctx.SetOutputFiles(m.properties.Generated_srcjars, ".generated_srcjars") + if m.linter.outputs.xml != nil { + ctx.SetOutputFiles(android.Paths{m.linter.outputs.xml}, ".lint") } } -var _ android.OutputFileProducer = (*Module)(nil) - func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { initJavaModule(module, hod, false) } @@ -641,8 +711,9 @@ func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { // Force enable the instrumentation for java code that is built for APEXes ... // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent // doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true. - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) isJacocoAgent := ctx.ModuleName() == "jacocoagent" + if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() { if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) { return true @@ -666,12 +737,16 @@ func (j *Module) SystemModules() string { } func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { - if j.deviceProperties.Min_sdk_version != nil { - return android.ApiLevelFrom(ctx, *j.deviceProperties.Min_sdk_version) + if j.overridableProperties.Min_sdk_version != nil { + return android.ApiLevelFrom(ctx, *j.overridableProperties.Min_sdk_version) } return j.SdkVersion(ctx).ApiLevel } +func (j *Module) GetDeviceProperties() *DeviceProperties { + return &j.deviceProperties +} + func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { if j.deviceProperties.Max_sdk_version != nil { return android.ApiLevelFrom(ctx, *j.deviceProperties.Max_sdk_version) @@ -724,12 +799,14 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { } libDeps := ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) + + j.properties.Static_libs = android.RemoveListFromList(j.properties.Static_libs, j.properties.Exclude_static_libs) ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...) // Add dependency on libraries that provide additional hidden api annotations. ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...) - if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() { + if ctx.Config().EnforceInterPartitionJavaSdkLibrary() { // Require java_sdk_library at inter-partition java dependency to ensure stable // interface between partitions. If inter-partition java_library dependency is detected, // raise build error because java_library doesn't have a stable interface. @@ -762,9 +839,11 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { if dep != nil { if component, ok := dep.(SdkLibraryComponentDependency); ok { if lib := component.OptionalSdkLibraryImplementation(); lib != nil { - // Add library as optional if it's one of the optional compatibility libs. + // Add library as optional if it's one of the optional compatibility libs or it's + // explicitly listed in the optional_uses_libs property. tag := usesLibReqTag - if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) { + if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) || + android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs) { tag = usesLibOptTag } ctx.AddVariationDependencies(nil, tag, *lib) @@ -961,8 +1040,16 @@ func (j *Module) collectJavacFlags( ctx android.ModuleContext, flags javaBuilderFlags, srcFiles android.Paths) javaBuilderFlags { // javac flags. javacFlags := j.properties.Javacflags + var needsDebugInfo bool + + needsDebugInfo = false + for _, flag := range javacFlags { + if strings.HasPrefix(flag, "-g") { + needsDebugInfo = true + } + } - if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() { + if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() && !needsDebugInfo { // For non-host binaries, override the -g flag passed globally to remove // local variable debug info to reduce disk and memory usage. javacFlags = append(javacFlags, "-g:source,lines") @@ -971,44 +1058,18 @@ func (j *Module) collectJavacFlags( if flags.javaVersion.usesJavaModules() { javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...) + } else if len(j.properties.Openjdk9.Javacflags) > 0 { + // java version defaults higher than openjdk 9, these conditionals should no longer be necessary + ctx.PropertyErrorf("openjdk9.javacflags", "JDK version defaults to higher than 9") + } + if flags.javaVersion.usesJavaModules() { if j.properties.Patch_module != nil { // Manually specify build directory in case it is not under the repo root. // (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so // just adding a symlink under the root doesn't help.) patchPaths := []string{".", ctx.Config().SoongOutDir()} - // b/150878007 - // - // Workaround to support *Bazel-executed* JDK9 javac in Bazel's - // execution root for --patch-module. If this javac command line is - // invoked within Bazel's execution root working directory, the top - // level directories (e.g. libcore/, tools/, frameworks/) are all - // symlinks. JDK9 javac does not traverse into symlinks, which causes - // --patch-module to fail source file lookups when invoked in the - // execution root. - // - // Short of patching javac or enumerating *all* directories as possible - // input dirs, manually add the top level dir of the source files to be - // compiled. - topLevelDirs := map[string]bool{} - for _, srcFilePath := range srcFiles { - srcFileParts := strings.Split(srcFilePath.String(), "/") - // Ignore source files that are already in the top level directory - // as well as generated files in the out directory. The out - // directory may be an absolute path, which means srcFileParts[0] is the - // empty string, so check that as well. Note that "out" in Bazel's execution - // root is *not* a symlink, which doesn't cause problems for --patch-modules - // anyway, so it's fine to not apply this workaround for generated - // source files. - if len(srcFileParts) > 1 && - srcFileParts[0] != "" && - srcFileParts[0] != "out" { - topLevelDirs[srcFileParts[0]] = true - } - } - patchPaths = append(patchPaths, android.SortedKeys(topLevelDirs)...) - classPath := flags.classpath.FormJavaClassPath("") if classPath != "" { patchPaths = append(patchPaths, classPath) @@ -1036,7 +1097,24 @@ func (j *Module) AddJSONData(d *map[string]interface{}) { } -func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { +func (j *Module) addGeneratedSrcJars(path android.Path) { + j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path) +} + +func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) { + + // Auto-propagating jarjar rules + jarjarProviderData := j.collectJarJarRules(ctx) + if jarjarProviderData != nil { + android.SetProvider(ctx, JarJarProvider, *jarjarProviderData) + text := getJarJarRuleText(jarjarProviderData) + if text != "" { + ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt") + android.WriteFileRule(ctx, ruleTextFile, text) + j.repackageJarjarRules = ruleTextFile + } + } + j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs) deps := j.collectDeps(ctx) @@ -1044,6 +1122,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { if flags.javaVersion.usesJavaModules() { j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...) + } else if len(j.properties.Openjdk9.Javacflags) > 0 { + // java version defaults higher than openjdk 9, these conditionals should no longer be necessary + ctx.PropertyErrorf("openjdk9.srcs", "JDK version defaults to higher than 9") } srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs) @@ -1074,16 +1155,15 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { srcJars := srcFiles.FilterByExt(".srcjar") srcJars = append(srcJars, deps.srcJars...) - if aaptSrcJar != nil { - srcJars = append(srcJars, aaptSrcJar) - } + srcJars = append(srcJars, extraSrcJars...) + srcJars = append(srcJars, j.properties.Generated_srcjars...) srcFiles = srcFiles.FilterOutByExt(".srcjar") if j.properties.Jarjar_rules != nil { j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules) } - jarName := ctx.ModuleName() + ".jar" + jarName := j.Stem() + ".jar" var uniqueJavaFiles android.Paths set := make(map[string]bool) @@ -1105,6 +1185,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...) uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...) j.uniqueSrcFiles = uniqueSrcFiles + android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()}) // We don't currently run annotation processors in turbine, which means we can't use turbine // generated header jars when an annotation processor that generates API is enabled. One @@ -1118,6 +1199,45 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { var kotlinJars android.Paths var kotlinHeaderJars android.Paths + // Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before + // any dependencies so that it can override any non-final R classes from dependencies with the + // final R classes from the app. + flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...) + + j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...) + + // If compiling headers then compile them and skip the rest + if proptools.Bool(j.properties.Headers_only) { + if srcFiles.HasExt(".kt") { + ctx.ModuleErrorf("Compiling headers_only with .kt not supported") + } + if ctx.Config().IsEnvFalse("TURBINE_ENABLED") || disableTurbine { + ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.") + } + + _, j.headerJarFile, _ = + j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, + extraCombinedJars) + if ctx.Failed() { + return + } + + android.SetProvider(ctx, JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars, + TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars, + AidlIncludeDirs: j.exportAidlIncludeDirs, + ExportedPlugins: j.exportedPluginJars, + ExportedPluginClasses: j.exportedPluginClasses, + ExportedPluginDisableTurbine: j.exportedDisableTurbine, + StubsLinkType: j.stubsLinkType, + AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles, + }) + + j.outputFile = j.headerJarFile + return + } + if srcFiles.HasExt(".kt") { // When using kotlin sources turbine is used to generate annotation processor sources, // including for annotation processors that generate API, so we can use turbine for @@ -1178,10 +1298,12 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { return } + kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar.OutputPath, jarName, "kotlinc") + // Make javac rule depend on the kotlinc rule flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...) - kotlinJars = append(kotlinJars, kotlinJar) + kotlinJars = append(kotlinJars, kotlinJarPath) kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar) // Jar kotlin classes into the final jar after javac @@ -1196,7 +1318,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } } - jars := append(android.Paths(nil), kotlinJars...) + jars := slices.Clone(kotlinJars) j.compiledSrcJars = srcJars @@ -1211,8 +1333,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // allow for the use of annotation processors that do function correctly // with sharding enabled. See: b/77284273. } - headerJarFileWithoutDepsOrJarjar, j.headerJarFile = - j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars) + extraJars := append(slices.Clone(kotlinHeaderJars), extraCombinedJars...) + headerJarFileWithoutDepsOrJarjar, j.headerJarFile, j.repackagedHeaderJarFile = + j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) if ctx.Failed() { return } @@ -1241,8 +1364,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // this module, or else we could have duplicated errorprone messages. errorproneFlags := enableErrorproneFlags(flags) errorprone := android.PathForModuleOut(ctx, "errorprone", jarName) + errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar") - transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneFlags, nil, + transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil, "errorprone", "errorprone") extraJarDeps = append(extraJarDeps, errorprone) @@ -1259,16 +1383,26 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { 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) } } + // Assume approximately 5 sources per srcjar. + // For framework-minus-apex in AOSP at the time this was written, there are 266 srcjars, with a mean + // of 5.8 sources per srcjar, but a median of 1, a standard deviation of 10, and a max of 48 source files. if len(srcJars) > 0 { - classes := j.compileJavaClasses(ctx, jarName, len(shardSrcs), - nil, srcJars, flags, extraJarDeps) - jars = append(jars, classes) + startIdx := len(shardSrcs) + shardSrcJarsList := android.ShardPaths(srcJars, shardSize/5) + 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) + } } } else { classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps) + classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac") jars = append(jars, classes) } if ctx.Failed() { @@ -1276,6 +1410,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } } + jars = append(jars, extraCombinedJars...) + j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles var includeSrcJar android.WritablePath @@ -1372,12 +1508,20 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // prebuilt dependencies until we support modules in the platform build, so there shouldn't be // any if len(jars) == 1. + // 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 + // to the copy rules. + stub, _ := moduleStubLinkType(ctx.ModuleName()) + // Transform the single path to the jar into an OutputPath as that is required by the following // code. - if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok { + if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok && !stub { // The path contains an embedded OutputPath so reuse that. outputFile = moduleOutPath.OutputPath - } else if outputPath, ok := jars[0].(android.OutputPath); ok { + } else if outputPath, ok := jars[0].(android.OutputPath); ok && !stub { // The path is an OutputPath so reuse it directly. outputFile = outputPath } else { @@ -1446,7 +1590,13 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.implementationJarFile = outputFile if j.headerJarFile == nil { - j.headerJarFile = j.implementationJarFile + // If this module couldn't generate a header jar (for example due to api generating annotation processors) + // then use the implementation jar. Run it through zip2zip first to remove any files in META-INF/services + // so that javac on modules that depend on this module don't pick up annotation processors (which may be + // missing their implementations) from META-INF/services/javax.annotation.processing.Processor. + headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName) + convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile) + j.headerJarFile = headerJarFile } // enforce syntax check to jacoco filters for any build (http://b/183622051) @@ -1473,7 +1623,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Enable dex compilation for the APEX variants, unless it is disabled explicitly compileDex := j.dexProperties.Compile_dex - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() { if compileDex == nil { compileDex = proptools.BoolPtr(true) @@ -1486,7 +1636,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) { if j.hasCode(ctx) { if j.shouldInstrumentStatic(ctx) { - j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles, + j.dexer.extraProguardFlagsFiles = append(j.dexer.extraProguardFlagsFiles, android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) } // Dex compilation @@ -1498,11 +1648,28 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { classesJar: implementationAndResourcesJar, jarName: jarName, } - dexOutputFile = j.dexer.compileDex(ctx, params) + if j.GetProfileGuided() && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting() { + ctx.PropertyErrorf("enable_profile_rewriting", + "Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on. The attached profile should be sourced from an unoptimized/unobfuscated APK.", + ) + } + if j.EnableProfileRewriting() { + profile := j.GetProfile() + if profile == "" || !j.GetProfileGuided() { + ctx.PropertyErrorf("enable_profile_rewriting", "Profile and Profile_guided must be set when enable_profile_rewriting is true") + } + params.artProfileInput = &profile + } + dexOutputFile, dexArtProfileOutput := j.dexer.compileDex(ctx, params) if ctx.Failed() { return } + // If r8/d8 provides a profile that matches the optimized dex, use that for dexpreopt. + if dexArtProfileOutput != nil { + j.dexpreopter.SetRewrittenProfile(*dexArtProfileOutput) + } + // merge dex jar with resources if necessary if j.resourceJar != nil { jars := android.Paths{dexOutputFile, j.resourceJar} @@ -1511,7 +1678,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { false, nil, nil) if *j.dexProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName).OutputPath - TransformZipAlign(ctx, combinedAlignedJar, combinedJar) + TransformZipAlign(ctx, combinedAlignedJar, combinedJar, nil) dexOutputFile = combinedAlignedJar } else { dexOutputFile = combinedJar @@ -1528,7 +1695,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) // Dexpreopting - j.dexpreopt(ctx, dexOutputFile) + libName := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()) + if j.SdkLibraryName() != nil && strings.HasSuffix(ctx.ModuleName(), ".impl") { + libName = strings.TrimSuffix(libName, ".impl") + } + j.dexpreopt(ctx, libName, dexOutputFile) outputFile = dexOutputFile } else { @@ -1546,30 +1717,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } if ctx.Device() { - lintSDKVersion := func(apiLevel android.ApiLevel) int { + lintSDKVersion := func(apiLevel android.ApiLevel) android.ApiLevel { if !apiLevel.IsPreview() { - return apiLevel.FinalInt() + return apiLevel } else { - // When running metalava, we pass --version-codename. When that value - // is not REL, metalava will add 1 to the --current-version argument. - // On old branches, PLATFORM_SDK_VERSION is the latest version (for that - // branch) and the codename is REL, except potentially on the most - // recent non-master branch. On that branch, it goes through two other - // phases before it gets to the phase previously described: - // - PLATFORM_SDK_VERSION has not been updated yet, and the codename - // is not rel. This happens for most of the internal branch's life - // while the branch has been cut but is still under active development. - // - PLATFORM_SDK_VERSION has been set, but the codename is still not - // REL. This happens briefly during the release process. During this - // state the code to add --current-version is commented out, and then - // that commenting out is reverted after the codename is set to REL. - // On the master branch, the PLATFORM_SDK_VERSION always represents a - // prior version and the codename is always non-REL. - // - // We need to add one here to match metalava adding 1. Technically - // this means that in the state described in the second bullet point - // above, this number is 1 higher than it should be. - return ctx.Config().PlatformSdkVersion().FinalInt() + 1 + return ctx.Config().DefaultAppTargetSdk(ctx) } } @@ -1584,28 +1736,35 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.compileSdkKind = j.SdkVersion(ctx).Kind j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" + j.linter.compile_data = android.PathsForModuleSrc(ctx, j.properties.Compile_data) if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() { j.linter.buildModuleReportZip = true } j.linter.lint(ctx) } + j.collectTransitiveSrcFiles(ctx, srcFiles) + ctx.CheckbuildFile(outputFile) - ctx.SetProvider(JavaInfoProvider, JavaInfo{ - HeaderJars: android.PathsIfNonNil(j.headerJarFile), - TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars, - TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars, - ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar), - ImplementationJars: android.PathsIfNonNil(j.implementationJarFile), - ResourceJars: android.PathsIfNonNil(j.resourceJar), - AidlIncludeDirs: j.exportAidlIncludeDirs, - SrcJarArgs: j.srcJarArgs, - SrcJarDeps: j.srcJarDeps, - ExportedPlugins: j.exportedPluginJars, - ExportedPluginClasses: j.exportedPluginClasses, - ExportedPluginDisableTurbine: j.exportedDisableTurbine, - JacocoReportClassesFile: j.jacocoReportClassesFile, + android.SetProvider(ctx, JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + RepackagedHeaderJars: android.PathsIfNonNil(j.repackagedHeaderJarFile), + TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars, + TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars, + ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar), + ImplementationJars: android.PathsIfNonNil(j.implementationJarFile), + ResourceJars: android.PathsIfNonNil(j.resourceJar), + AidlIncludeDirs: j.exportAidlIncludeDirs, + SrcJarArgs: j.srcJarArgs, + SrcJarDeps: j.srcJarDeps, + TransitiveSrcFiles: j.transitiveSrcFiles, + ExportedPlugins: j.exportedPluginJars, + ExportedPluginClasses: j.exportedPluginClasses, + ExportedPluginDisableTurbine: j.exportedDisableTurbine, + JacocoReportClassesFile: j.jacocoReportClassesFile, + StubsLinkType: j.stubsLinkType, + AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles, }) // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource @@ -1616,6 +1775,52 @@ func (j *Module) useCompose() bool { return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs) } +func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []*android.DepSet[android.Path]) { + ctx.VisitDirectDeps(func(m android.Module) { + depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider) + depTag := ctx.OtherModuleDependencyTag(m) + + if depProguardInfo.UnconditionallyExportedProguardFlags != nil { + transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags) + transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags) + } + + if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil { + transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles) + } + }) + + return transitiveProguardFlags, transitiveUnconditionalExportedFlags +} + +func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo { + transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx) + + directUnconditionalExportedFlags := android.Paths{} + proguardFlagsForThisModule := android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files) + exportUnconditionally := proptools.Bool(j.dexProperties.Optimize.Export_proguard_flags_files) + if exportUnconditionally { + // if we explicitly export, then our unconditional exports are the same as our transitive flags + transitiveUnconditionalExportedFlags = transitiveProguardFlags + directUnconditionalExportedFlags = proguardFlagsForThisModule + } + + return ProguardSpecInfo{ + Export_proguard_flags_files: exportUnconditionally, + ProguardFlagsFiles: android.NewDepSet[android.Path]( + android.POSTORDER, + proguardFlagsForThisModule, + transitiveProguardFlags, + ), + UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path]( + android.POSTORDER, + directUnconditionalExportedFlags, + transitiveUnconditionalExportedFlags, + ), + } + +} + // Returns a copy of the supplied flags, but with all the errorprone-related // fields copied to the regular build's fields. func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags { @@ -1635,20 +1840,26 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath { kzipName := pathtools.ReplaceExtension(jarName, "kzip") + annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar") if idx >= 0 { kzipName = strings.TrimSuffix(jarName, filepath.Ext(jarName)) + strconv.Itoa(idx) + ".kzip" + annoSrcJar = android.PathForModuleOut(ctx, "javac", "anno-"+strconv.Itoa(idx)+".srcjar") jarName += strconv.Itoa(idx) } classes := android.PathForModuleOut(ctx, "javac", jarName).OutputPath - TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, flags, extraJarDeps) + TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) - if ctx.Config().EmitXrefRules() { + if ctx.Config().EmitXrefRules() && ctx.Module() == ctx.PrimaryModule() { extractionFile := android.PathForModuleOut(ctx, kzipName) emitXrefRule(ctx, extractionFile, idx, srcFiles, srcJars, flags, extraJarDeps) j.kytheFiles = append(j.kytheFiles, extractionFile) } + if len(flags.processorPath) > 0 { + j.annoSrcJars = append(j.annoSrcJars, annoSrcJar) + } + return classes } @@ -1679,7 +1890,7 @@ 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, jarjarAndDepsHeaderJar android.Path) { + extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar android.Path) { var jars android.Paths if len(srcFiles) > 0 || len(srcJars) > 0 { @@ -1687,7 +1898,7 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars turbineJar := android.PathForModuleOut(ctx, "turbine", jarName) TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags) if ctx.Failed() { - return nil, nil + return nil, nil, nil } jars = append(jars, turbineJar) headerJar = turbineJar @@ -1712,11 +1923,22 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules) jarjarAndDepsHeaderJar = jarjarFile if ctx.Failed() { - return nil, nil + return nil, nil, nil } } - return headerJar, jarjarAndDepsHeaderJar + if j.repackageJarjarRules != nil { + repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-turbine-jarjar", jarName) + TransformJarJar(ctx, repackagedJarjarFile, jarjarAndDepsHeaderJar, j.repackageJarjarRules) + jarjarAndDepsRepackagedHeaderJar = repackagedJarjarFile + if ctx.Failed() { + return nil, nil, nil + } + } else { + jarjarAndDepsRepackagedHeaderJar = jarjarAndDepsHeaderJar + } + + return headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar } func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, @@ -1734,44 +1956,47 @@ func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, type providesTransitiveHeaderJars struct { // set of header jars for all transitive libs deps - transitiveLibsHeaderJars *android.DepSet + transitiveLibsHeaderJars *android.DepSet[android.Path] // set of header jars for all transitive static libs deps - transitiveStaticLibsHeaderJars *android.DepSet + transitiveStaticLibsHeaderJars *android.DepSet[android.Path] } -func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet { +func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet[android.Path] { return j.transitiveLibsHeaderJars } -func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet { +func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet[android.Path] { return j.transitiveStaticLibsHeaderJars } func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) { directLibs := android.Paths{} directStaticLibs := android.Paths{} - transitiveLibs := []*android.DepSet{} - transitiveStaticLibs := []*android.DepSet{} + transitiveLibs := []*android.DepSet[android.Path]{} + transitiveStaticLibs := []*android.DepSet[android.Path]{} ctx.VisitDirectDeps(func(module android.Module) { // don't add deps of the prebuilt version of the same library if ctx.ModuleName() == android.RemoveOptionalPrebuiltPrefix(module.Name()) { return } - dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) - if dep.TransitiveLibsHeaderJars != nil { - transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars) - } - if dep.TransitiveStaticLibsHeaderJars != nil { - transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars) - } - + dep, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider) tag := ctx.OtherModuleDependencyTag(module) _, isUsesLibDep := tag.(usesLibraryDependencyTag) if tag == libTag || tag == r8LibraryJarTag || isUsesLibDep { directLibs = append(directLibs, dep.HeaderJars...) } else if tag == staticLibTag { directStaticLibs = append(directStaticLibs, dep.HeaderJars...) + } else { + // Don't propagate transitive libs for other kinds of dependencies. + return + } + + if dep.TransitiveLibsHeaderJars != nil { + transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars) + } + if dep.TransitiveStaticLibsHeaderJars != nil { + transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars) } }) j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs) @@ -1792,7 +2017,7 @@ func (j *Module) ImplementationJars() android.Paths { return android.Paths{j.implementationJarFile} } -func (j *Module) DexJarBuildPath() OptionalDexJarPath { +func (j *Module) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { return j.dexJarFile } @@ -1825,9 +2050,9 @@ func (j *Module) IDEInfo(dpInfo *android.IdeInfo) { if j.expandJarjarRules != nil { dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String()) } - dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...) dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...) dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...) + dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...) } func (j *Module) CompilerDeps() []string { @@ -1865,13 +2090,31 @@ func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersi } func (j *Module) Stem() string { - return proptools.StringDefault(j.overridableDeviceProperties.Stem, j.Name()) + if j.stem == "" { + panic("Stem() called before stem property was set") + } + return j.stem } func (j *Module) JacocoReportClassesFile() android.Path { return j.jacocoReportClassesFile } +func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) { + var fromDeps []*android.DepSet[android.Path] + ctx.VisitDirectDeps(func(module android.Module) { + tag := ctx.OtherModuleDependencyTag(module) + if tag == staticLibTag { + depInfo, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider) + if depInfo.TransitiveSrcFiles != nil { + fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles) + } + } + }) + + j.transitiveSrcFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps) +} + func (j *Module) IsInstallable() bool { return Bool(j.properties.Installable) } @@ -1923,19 +2166,22 @@ type moduleWithSdkDep interface { func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) { switch name { - case android.SdkCore.JavaLibraryName(ctx.Config()), "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs", + case android.SdkCore.DefaultJavaLibraryName(), + "legacy.core.platform.api.stubs", + "stable.core.platform.api.stubs", "stub-annotations", "private-stub-annotations-jar", - "core-lambda-stubs", "core-generated-annotation-stubs": + "core-lambda-stubs", + "core-generated-annotation-stubs": return javaCore, true - case android.SdkPublic.JavaLibraryName(ctx.Config()): + case android.SdkPublic.DefaultJavaLibraryName(): return javaSdk, true - case android.SdkSystem.JavaLibraryName(ctx.Config()): + case android.SdkSystem.DefaultJavaLibraryName(): return javaSystem, true - case android.SdkModule.JavaLibraryName(ctx.Config()): + case android.SdkModule.DefaultJavaLibraryName(): return javaModule, true - case android.SdkSystemServer.JavaLibraryName(ctx.Config()): + case android.SdkSystemServer.DefaultJavaLibraryName(): return javaSystemServer, true - case android.SdkTest.JavaLibraryName(ctx.Config()): + case android.SdkTest.DefaultJavaLibraryName(): return javaSystem, true } @@ -2031,15 +2277,14 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } - } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { - dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) - if sdkLinkType != javaPlatform && - ctx.OtherModuleHasProvider(module, SyspropPublicStubInfoProvider) { - // dep is a sysprop implementation library, but this module is not linking against - // the platform, so it gets the sysprop public stubs library instead. Replace - // dep with the JavaInfo from the SyspropPublicStubInfoProvider. - syspropDep := ctx.OtherModuleProvider(module, SyspropPublicStubInfoProvider).(SyspropPublicStubInfo) - dep = syspropDep.JavaInfo + } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { + if sdkLinkType != javaPlatform { + if syspropDep, ok := android.OtherModuleProvider(ctx, module, SyspropPublicStubInfoProvider); ok { + // dep is a sysprop implementation library, but this module is not linking against + // the platform, so it gets the sysprop public stubs library instead. Replace + // dep with the JavaInfo from the SyspropPublicStubInfoProvider. + dep = syspropDep.JavaInfo + } } switch tag { case bootClasspathTag: @@ -2050,6 +2295,10 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } deps.classpath = append(deps.classpath, dep.HeaderJars...) deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...) + if len(dep.RepackagedHeaderJars) == 1 && !slices.Contains(dep.HeaderJars, dep.RepackagedHeaderJars[0]) { + deps.classpath = append(deps.classpath, dep.RepackagedHeaderJars...) + deps.dexClasspath = append(deps.dexClasspath, dep.RepackagedHeaderJars...) + } deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine @@ -2069,6 +2318,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { // annotation processor that generates API is incompatible with the turbine // optimization. deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) case pluginTag: if plugin, ok := module.(*Plugin); ok { if plugin.pluginProperties.Processor_class != nil { @@ -2111,7 +2361,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case syspropPublicStubDepTag: // This is a sysprop implementation library, forward the JavaInfoProvider from // the corresponding sysprop public stub library as SyspropPublicStubInfoProvider. - ctx.SetProvider(SyspropPublicStubInfoProvider, SyspropPublicStubInfo{ + android.SetProvider(ctx, SyspropPublicStubInfoProvider, SyspropPublicStubInfo{ JavaInfo: dep, }) } @@ -2127,6 +2377,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticJars = append(deps.staticJars, dep.Srcs()...) deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...) } + } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok { + switch tag { + case staticLibTag: + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) + } } else { switch tag { case bootClasspathTag: @@ -2149,11 +2404,320 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } addCLCFromDep(ctx, module, j.classLoaderContexts) + addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary) }) return deps } +// Provider for jarjar renaming rules. +// +// Modules can set their jarjar renaming rules with addJarJarRenameRule, and those renamings will be +// passed to all rdeps. The typical way that these renamings will NOT be inherited is when a module +// links against stubs -- these are not passed through stubs. The classes will remain unrenamed on +// classes until a module with jarjar_prefix is reached, and all as yet unrenamed classes will then +// be renamed from that module. +// TODO: Add another property to suppress the forwarding of +type DependencyUse int + +const ( + RenameUseInvalid DependencyUse = iota + RenameUseInclude + RenameUseExclude +) + +type RenameUseElement struct { + DepName string + RenameUse DependencyUse + Why string // token for determining where in the logic the decision was made. +} + +type JarJarProviderData struct { + // Mapping of class names: original --> renamed. If the value is "", the class will be + // renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has + // attribute). Rdeps of that module will inherit the renaming. + Rename map[string]string + RenameUse []RenameUseElement +} + +func (this JarJarProviderData) GetDebugString() string { + result := "" + for _, k := range android.SortedKeys(this.Rename) { + v := this.Rename[k] + if strings.Contains(k, "android.companion.virtual.flags.FakeFeatureFlagsImpl") { + result += k + "-->" + v + ";" + } + } + return result +} + +var JarJarProvider = blueprint.NewProvider[JarJarProviderData]() + +var overridableJarJarPrefix = "com.android.internal.hidden_from_bootclasspath" + +func init() { + android.SetJarJarPrefixHandler(mergeJarJarPrefixes) +} + +// BaseJarJarProviderData contains information that will propagate across dependencies regardless of +// whether they are java modules or not. +type BaseJarJarProviderData struct { + JarJarProviderData JarJarProviderData +} + +func (this BaseJarJarProviderData) GetDebugString() string { + return this.JarJarProviderData.GetDebugString() +} + +var BaseJarJarProvider = blueprint.NewProvider[BaseJarJarProviderData]() + +// mergeJarJarPrefixes is called immediately before module.GenerateAndroidBuildActions is called. +// Since there won't be a JarJarProvider, we create the BaseJarJarProvider if any of our deps have +// either JarJarProvider or BaseJarJarProvider. +func mergeJarJarPrefixes(ctx android.ModuleContext) { + mod := ctx.Module() + // Explicitly avoid propagating into some module types. + switch reflect.TypeOf(mod).String() { + case "*java.Droidstubs": + return + } + jarJarData := collectDirectDepsProviders(ctx) + if jarJarData != nil { + providerData := BaseJarJarProviderData{ + JarJarProviderData: *jarJarData, + } + android.SetProvider(ctx, BaseJarJarProvider, providerData) + } + +} + +// Add a jarjar renaming rule to this module, to be inherited to all dependent modules. +func (module *Module) addJarJarRenameRule(original string, renamed string) { + if module.jarjarRenameRules == nil { + module.jarjarRenameRules = make(map[string]string) + } + module.jarjarRenameRules[original] = renamed +} + +func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProviderData) { + // Gather repackage information from deps + // If the dep jas a JarJarProvider, it is used. Otherwise, any BaseJarJarProvider is used. + + module := ctx.Module() + moduleName := module.Name() + + ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) { + tag := ctx.OtherModuleDependencyTag(m) + // This logic mirrors that in (*Module).collectDeps above. There are several places + // where we explicitly return RenameUseExclude, even though it is the default, to + // indicate that it has been verified to be the case. + // + // Note well: there are probably cases that are getting to the unconditional return + // and are therefore wrong. + shouldIncludeRenames := func() (DependencyUse, string) { + if moduleName == m.Name() { + return RenameUseInclude, "name" // If we have the same module name, include the renames. + } + if sc, ok := module.(android.SdkContext); ok { + if ctx.Device() { + sdkDep := decodeSdkDep(ctx, sc) + if !sdkDep.invalidVersion && sdkDep.useFiles { + return RenameUseExclude, "useFiles" + } + } + } + if IsJniDepTag(tag) || tag == certificateTag || tag == proguardRaiseTag { + return RenameUseExclude, "tags" + } + if _, ok := m.(SdkLibraryDependency); ok { + switch tag { + case sdkLibTag, libTag: + return RenameUseExclude, "sdklibdep" // matches collectDeps() + } + return RenameUseInvalid, "sdklibdep" // dep is not used in collectDeps() + } else if ji, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { + switch ji.StubsLinkType { + case Stubs: + return RenameUseExclude, "info" + case Implementation: + return RenameUseInclude, "info" + default: + //fmt.Printf("collectDirectDepsProviders: %v -> %v StubsLinkType unknown\n", module, m) + // Fall through to the heuristic logic. + } + switch reflect.TypeOf(m).String() { + case "*java.GeneratedJavaLibraryModule": + // Probably a java_aconfig_library module. + // TODO: make this check better. + return RenameUseInclude, "reflect" + } + switch tag { + case bootClasspathTag: + return RenameUseExclude, "tagswitch" + case sdkLibTag, libTag, instrumentationForTag: + return RenameUseInclude, "tagswitch" + case java9LibTag: + return RenameUseExclude, "tagswitch" + case staticLibTag: + return RenameUseInclude, "tagswitch" + case pluginTag: + return RenameUseInclude, "tagswitch" + case errorpronePluginTag: + return RenameUseInclude, "tagswitch" + case exportedPluginTag: + return RenameUseInclude, "tagswitch" + case kotlinStdlibTag, kotlinAnnotationsTag: + return RenameUseExclude, "tagswitch" + case kotlinPluginTag: + return RenameUseInclude, "tagswitch" + default: + return RenameUseExclude, "tagswitch" + } + } else if _, ok := m.(android.SourceFileProducer); ok { + switch tag { + case sdkLibTag, libTag, staticLibTag: + return RenameUseInclude, "srcfile" + default: + return RenameUseExclude, "srcfile" + } + } else if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { + return RenameUseInclude, "aconfig_declarations_group" + } else { + switch tag { + case bootClasspathTag: + return RenameUseExclude, "else" + case systemModulesTag: + return RenameUseInclude, "else" + } + } + // If we got here, choose the safer option, which may lead to a build failure, rather + // than runtime failures on the device. + return RenameUseExclude, "end" + } + + if result == nil { + result = &JarJarProviderData{ + Rename: make(map[string]string), + RenameUse: make([]RenameUseElement, 0), + } + } + how, why := shouldIncludeRenames() + result.RenameUse = append(result.RenameUse, RenameUseElement{DepName: m.Name(), RenameUse: how, Why: why}) + if how != RenameUseInclude { + // Nothing to merge. + return + } + + merge := func(theirs *JarJarProviderData) { + for orig, renamed := range theirs.Rename { + if preexisting, exists := (*result).Rename[orig]; !exists || preexisting == "" { + result.Rename[orig] = renamed + } else if preexisting != "" && renamed != "" && preexisting != renamed { + if strings.HasPrefix(preexisting, overridableJarJarPrefix) { + result.Rename[orig] = renamed + } else if !strings.HasPrefix(renamed, overridableJarJarPrefix) { + ctx.ModuleErrorf("1. Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting, ctx.ModuleName(), m.Name()) + continue + } + } + } + } + if theirs, ok := android.OtherModuleProvider(ctx, m, JarJarProvider); ok { + merge(&theirs) + } else if theirs, ok := android.OtherModuleProvider(ctx, m, BaseJarJarProvider); ok { + // TODO: if every java.Module should have a JarJarProvider, and we find only the + // BaseJarJarProvider, then there is a bug. Consider seeing if m can be cast + // to java.Module. + merge(&theirs.JarJarProviderData) + } + }) + return +} + +func (this Module) GetDebugString() string { + return "sdk_version=" + proptools.String(this.deviceProperties.Sdk_version) +} + +// Merge the jarjar rules we inherit from our dependencies, any that have been added directly to +// us, and if it's been set, apply the jarjar_prefix property to rename them. +func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProviderData { + // Gather repackage information from deps + result := collectDirectDepsProviders(ctx) + + // Update that with entries we've stored for ourself + for orig, renamed := range module.jarjarRenameRules { + if result == nil { + result = &JarJarProviderData{ + Rename: make(map[string]string), + } + } + if renamed != "" { + if preexisting, exists := (*result).Rename[orig]; exists && preexisting != renamed { + ctx.ModuleErrorf("Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting) + continue + } + } + (*result).Rename[orig] = renamed + } + + // If there are no renamings, then jarjar_prefix does nothing, so skip the extra work. + if result == nil { + return nil + } + + // If they've given us a jarjar_prefix property, then we will use that to rename any classes + // that have not yet been renamed. + prefix := proptools.String(module.properties.Jarjar_prefix) + if prefix != "" { + if prefix[0] == '.' { + ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not start with '.'") + return nil + } + if prefix[len(prefix)-1] == '.' { + ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not end with '.'") + return nil + } + + var updated map[string]string + for orig, renamed := range (*result).Rename { + if renamed == "" { + if updated == nil { + updated = make(map[string]string) + } + updated[orig] = prefix + "." + orig + } + } + for orig, renamed := range updated { + (*result).Rename[orig] = renamed + } + } + + return result +} + +// Get the jarjar rule text for a given provider for the fully resolved rules. Classes that map +// to "" won't be in this list because they shouldn't be renamed yet. +func getJarJarRuleText(provider *JarJarProviderData) string { + result := "" + for _, orig := range android.SortedKeys(provider.Rename) { + renamed := provider.Rename[orig] + if renamed != "" { + result += "rule " + orig + " " + renamed + "\n" + } + } + return result +} + +// Repackage the flags if the jarjar rule txt for the flags is generated +func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.WritablePath, jarName, info string) android.WritablePath { + if j.repackageJarjarRules == nil { + return infile + } + repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info+jarName) + TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules) + return repackagedJarjarFile +} + func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) { deps.processorPath = append(deps.processorPath, pluginJars...) deps.processorClasses = append(deps.processorClasses, pluginClasses...) @@ -2175,15 +2739,12 @@ type ModuleWithStem interface { var _ ModuleWithStem = (*Module)(nil) -func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - switch ctx.ModuleType() { - case "java_library", "java_library_host", "java_library_static": - if lib, ok := ctx.Module().(*Library); ok { - javaLibraryBp2Build(ctx, lib) - } - case "java_binary_host": - if binary, ok := ctx.Module().(*Binary); ok { - javaBinaryHostBp2Build(ctx, binary) - } - } +type ModuleWithUsesLibrary interface { + UsesLibrary() *usesLibrary } + +func (j *Module) UsesLibrary() *usesLibrary { + return &j.usesLibrary +} + +var _ ModuleWithUsesLibrary = (*Module)(nil) |