diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 2 | ||||
| -rw-r--r-- | java/androidmk.go | 3 | ||||
| -rw-r--r-- | java/boot_image.go | 96 | ||||
| -rw-r--r-- | java/dexpreopt.go | 40 | ||||
| -rw-r--r-- | java/hiddenapi.go | 28 | ||||
| -rw-r--r-- | java/hiddenapi_modular.go | 185 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 117 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 34 | ||||
| -rw-r--r-- | java/java.go | 34 | ||||
| -rw-r--r-- | java/java_test.go | 192 | ||||
| -rw-r--r-- | java/lint.go | 55 | ||||
| -rw-r--r-- | java/lint_test.go | 204 | ||||
| -rw-r--r-- | java/platform_bootclasspath.go | 43 | ||||
| -rw-r--r-- | java/platform_bootclasspath_test.go | 92 | ||||
| -rw-r--r-- | java/sdk.go | 6 | ||||
| -rw-r--r-- | java/sdk_library.go | 59 | ||||
| -rw-r--r-- | java/testing.go | 6 |
17 files changed, 888 insertions, 308 deletions
diff --git a/java/Android.bp b/java/Android.bp index 2a4b596ab..8e3e10d9d 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -79,9 +79,11 @@ bootstrap_go_package { "droiddoc_test.go", "droidstubs_test.go", "hiddenapi_singleton_test.go", + "jacoco_test.go", "java_test.go", "jdeps_test.go", "kotlin_test.go", + "lint_test.go", "platform_bootclasspath_test.go", "platform_compat_config_test.go", "plugin_test.go", diff --git a/java/androidmk.go b/java/androidmk.go index 4e594a2fa..015454464 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -398,6 +398,9 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if len(app.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled) } + if app.dexpreopter.configPath != nil { + entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", app.dexpreopter.configPath) + } for _, extra := range app.extraOutputFiles { install := app.onDeviceDir + "/" + extra.Base() entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) diff --git a/java/boot_image.go b/java/boot_image.go index 0c4797609..d0862a961 100644 --- a/java/boot_image.go +++ b/java/boot_image.go @@ -16,6 +16,7 @@ package java import ( "fmt" + "path/filepath" "strings" "android/soong/android" @@ -53,7 +54,7 @@ func RegisterBootImageBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootImageFactory) } -type bootImageContentDependencyTag struct { +type bootclasspathFragmentContentDependencyTag struct { blueprint.BaseDependencyTag } @@ -62,16 +63,22 @@ type bootImageContentDependencyTag struct { // This is a temporary workaround to make it easier to migrate to boot image modules with proper // dependencies. // TODO(b/177892522): Remove this and add needed visibility. -func (b bootImageContentDependencyTag) ExcludeFromVisibilityEnforcement() { +func (b bootclasspathFragmentContentDependencyTag) ExcludeFromVisibilityEnforcement() { +} + +// The bootclasspath_fragment contents must never depend on prebuilts. +func (b bootclasspathFragmentContentDependencyTag) ReplaceSourceWithPrebuilt() bool { + return false } // The tag used for the dependency between the boot image module and its contents. -var bootImageContentDepTag = bootImageContentDependencyTag{} +var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{} -var _ android.ExcludeFromVisibilityEnforcementTag = bootImageContentDepTag +var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag +var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag -func IsbootImageContentDepTag(tag blueprint.DependencyTag) bool { - return tag == bootImageContentDepTag +func IsBootclasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool { + return tag == bootclasspathFragmentContentDepTag } type bootImageProperties struct { @@ -84,6 +91,8 @@ type bootImageProperties struct { // // The order of this list matters as it is the order that is used in the bootclasspath. Contents []string + + Hidden_api HiddenAPIFlagFileProperties } type BootImageModule struct { @@ -185,7 +194,7 @@ func (i BootImageInfo) AndroidBootImageFilesByArchType() map[android.ArchType]an func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { tag := ctx.OtherModuleDependencyTag(dep) - if tag == bootImageContentDepTag { + if IsBootclasspathFragmentContentDepTag(tag) { // Boot image contents are automatically added to apex. return true } @@ -200,8 +209,28 @@ func (b *BootImageModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, return nil } +// ComponentDepsMutator adds dependencies onto modules before any prebuilt modules without a +// corresponding source module are renamed. This means that adding a dependency using a name without +// a prebuilt_ prefix will always resolve to a source module and when using a name with that prefix +// it will always resolve to a prebuilt module. +func (b *BootImageModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { + module := ctx.Module() + _, isSourceModule := module.(*BootImageModule) + + for _, name := range b.properties.Contents { + // A bootclasspath_fragment must depend only on other source modules, while the + // prebuilt_bootclasspath_fragment must only depend on other prebuilt modules. + // + // TODO(b/177892522) - avoid special handling of jacocoagent. + if !isSourceModule && name != "jacocoagent" { + name = android.PrebuiltNameFromSource(name) + } + ctx.AddDependency(module, bootclasspathFragmentContentDepTag, name) + } + +} + func (b *BootImageModule) DepsMutator(ctx android.BottomUpMutatorContext) { - ctx.AddDependency(ctx.Module(), bootImageContentDepTag, b.properties.Contents...) if SkipDexpreoptBootJars(ctx) { return @@ -213,6 +242,9 @@ func (b *BootImageModule) DepsMutator(ctx android.BottomUpMutatorContext) { } func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Perform hidden API processing. + b.generateHiddenAPIBuildActions(ctx) + // Nothing to do if skipping the dexpreopt of boot image jars. if SkipDexpreoptBootJars(ctx) { return @@ -253,6 +285,15 @@ func (b *BootImageModule) getImageConfig(ctx android.EarlyModuleContext) *bootIm return imageConfig } +// generateHiddenAPIBuildActions generates all the hidden API related build rules. +func (b *BootImageModule) generateHiddenAPIBuildActions(ctx android.ModuleContext) { + // Resolve the properties to paths. + flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx) + + // Store the information for use by platform_bootclasspath. + ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo) +} + type bootImageMemberType struct { android.SdkMemberTypeBase } @@ -281,19 +322,58 @@ func (b *bootImageMemberType) CreateVariantPropertiesStruct() android.SdkMemberP type bootImageSdkMemberProperties struct { android.SdkMemberPropertiesBase + // The image name Image_name *string + + // Contents of the bootclasspath fragment + Contents []string + + // Flag files by *hiddenAPIFlagFileCategory + Flag_files_by_category map[*hiddenAPIFlagFileCategory]android.Paths } func (b *bootImageSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { module := variant.(*BootImageModule) b.Image_name = module.properties.Image_name + if b.Image_name == nil { + // Only one of image_name or contents can be specified. However, if image_name is set then the + // contents property is updated to match the configuration used to create the corresponding + // boot image. Therefore, contents property is only copied if the image name is not specified. + b.Contents = module.properties.Contents + } + + // Get the flag file information from the module. + mctx := ctx.SdkModuleContext() + flagFileInfo := mctx.OtherModuleProvider(module, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo) + b.Flag_files_by_category = flagFileInfo.categoryToPaths } func (b *bootImageSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { if b.Image_name != nil { propertySet.AddProperty("image_name", *b.Image_name) } + + if len(b.Contents) > 0 { + propertySet.AddPropertyWithTag("contents", b.Contents, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true)) + } + + builder := ctx.SnapshotBuilder() + if b.Flag_files_by_category != nil { + hiddenAPISet := propertySet.AddPropertySet("hidden_api") + for _, category := range hiddenAPIFlagFileCategories { + paths := b.Flag_files_by_category[category] + if len(paths) > 0 { + dests := []string{} + for _, p := range paths { + dest := filepath.Join("hiddenapi", p.Base()) + builder.CopyToSnapshot(p, dest) + dests = append(dests, dest) + } + hiddenAPISet.AddProperty(category.propertyName, dests) + } + } + } } var _ android.SdkMemberType = (*bootImageMemberType)(nil) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 3571590db..d00d74b8c 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -41,9 +41,12 @@ type dexpreopter struct { builtInstalled string - // A path to a dexpreopt.config file generated by Soong for libraries that may be used as a - // <uses-library> by Make modules. The path is passed to Make via LOCAL_SOONG_DEXPREOPT_CONFIG - // variable. If the path is nil, no config is generated (which is the case for apps and tests). + // 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 } @@ -138,27 +141,13 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr } } - if !d.isApp && !d.isTest { - // Slim dexpreopt config is serialized to dexpreopt.config files and used by - // dex_preopt_config_merger.py to get information about <uses-library> dependencies. - // Note that it might be needed even if dexpreopt is disabled for this module. - slimDexpreoptConfig := &dexpreopt.ModuleConfig{ - Name: ctx.ModuleName(), - DexLocation: dexLocation, - EnforceUsesLibraries: d.enforceUsesLibs, - ProvidesUsesLibrary: providesUsesLib, - ClassLoaderContexts: d.classLoaderContexts, - // The rest of the fields are not needed. - } - d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config") - dexpreopt.WriteSlimModuleConfigForMake(ctx, slimDexpreoptConfig, d.configPath) - } - - if d.dexpreoptDisabled(ctx) { + // If it is neither app nor test, make config files regardless of its dexpreopt setting. + // The config files are required for apps defined in make which depend on the lib. + // TODO(b/158843648): The config for apps should be generated as well regardless of setting. + if (d.isApp || d.isTest) && d.dexpreoptDisabled(ctx) { return } - globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) isSystemServerJar := inList(ctx.ModuleName(), global.SystemServerJars) @@ -251,6 +240,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr PresignedPrebuilt: d.isPresignedPrebuilt, } + d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config") + dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath) + + if d.dexpreoptDisabled(ctx) { + return + } + + globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) + dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig) if err != nil { ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 3ecb9772a..e57508546 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -156,16 +156,24 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationNa // A source module that has been replaced by a prebuilt can never be the primary module. if module.IsReplacedByPrebuilt() { - ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(prebuilt android.Module) { - if h, ok := prebuilt.(hiddenAPIIntf); ok && h.bootDexJar() != nil { - primary = false - } else { - ctx.ModuleErrorf( - "hiddenapi has determined that the source module %q should be ignored as it has been"+ - " replaced by the prebuilt module %q but unfortunately it does not provide a"+ - " suitable boot dex jar", ctx.ModuleName(), ctx.OtherModuleName(prebuilt)) - } - }) + if ctx.HasProvider(android.ApexInfoProvider) { + // The source module is in an APEX but the prebuilt module on which it depends is not in an + // APEX and so is not the one that will actually be used for hidden API processing. That + // means it is not possible to check to see if it is a suitable replacement so just assume + // that it is. + primary = false + } else { + ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(prebuilt android.Module) { + if h, ok := prebuilt.(hiddenAPIIntf); ok && h.bootDexJar() != nil { + primary = false + } else { + ctx.ModuleErrorf( + "hiddenapi has determined that the source module %q should be ignored as it has been"+ + " replaced by the prebuilt module %q but unfortunately it does not provide a"+ + " suitable boot dex jar", ctx.ModuleName(), ctx.OtherModuleName(prebuilt)) + } + }) + } } } h.primary = primary diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 7cf082b6a..8cc6f8f23 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -16,10 +16,163 @@ package java import ( "android/soong/android" + "github.com/google/blueprint" ) // Contains support for processing hiddenAPI in a modular fashion. +type hiddenAPIStubsDependencyTag struct { + blueprint.BaseDependencyTag + sdkKind android.SdkKind +} + +func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() { +} + +func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool { + return false +} + +// Avoid having to make stubs content explicitly visible to dependent modules. +// +// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules +// with proper dependencies. +// TODO(b/177892522): Remove this and add needed visibility. +func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() { +} + +var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{} +var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{} +var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{} + +// hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden +// API processing. +var hiddenAPIRelevantSdkKinds = []android.SdkKind{ + android.SdkPublic, + android.SdkSystem, + android.SdkTest, + android.SdkCorePlatform, +} + +// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs +// needed to produce the hidden API monolithic stub flags file. +func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[android.SdkKind][]string { + var publicStubModules []string + var systemStubModules []string + var testStubModules []string + var corePlatformStubModules []string + + if config.AlwaysUsePrebuiltSdks() { + // Build configuration mandates using prebuilt stub modules + publicStubModules = append(publicStubModules, "sdk_public_current_android") + systemStubModules = append(systemStubModules, "sdk_system_current_android") + testStubModules = append(testStubModules, "sdk_test_current_android") + } else { + // Use stub modules built from source + publicStubModules = append(publicStubModules, "android_stubs_current") + systemStubModules = append(systemStubModules, "android_system_stubs_current") + testStubModules = append(testStubModules, "android_test_stubs_current") + } + // We do not have prebuilts of the core platform api yet + corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs") + + // Allow products to define their own stubs for custom product jars that apps can use. + publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...) + systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...) + testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...) + if config.IsEnvTrue("EMMA_INSTRUMENT") { + publicStubModules = append(publicStubModules, "jacoco-stubs") + } + + m := map[android.SdkKind][]string{} + m[android.SdkPublic] = publicStubModules + m[android.SdkSystem] = systemStubModules + m[android.SdkTest] = testStubModules + m[android.SdkCorePlatform] = corePlatformStubModules + return m +} + +// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in +// sdkKindToStubLibModules. It adds them in a well known order and uses an SdkKind specific tag to +// identify the source of the dependency. +func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, sdkKindToStubLibModules map[android.SdkKind][]string) { + module := ctx.Module() + for _, sdkKind := range hiddenAPIRelevantSdkKinds { + modules := sdkKindToStubLibModules[sdkKind] + ctx.AddDependency(module, hiddenAPIStubsDependencyTag{sdkKind: sdkKind}, modules...) + } +} + +// hiddenAPIGatherStubLibDexJarPaths gathers the paths to the dex jars from the dependencies added +// in hiddenAPIAddStubLibDependencies. +func hiddenAPIGatherStubLibDexJarPaths(ctx android.ModuleContext) map[android.SdkKind]android.Paths { + m := map[android.SdkKind]android.Paths{} + ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) { + tag := ctx.OtherModuleDependencyTag(module) + if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok { + kind := hiddenAPIStubsTag.sdkKind + dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module) + if dexJar != nil { + m[kind] = append(m[kind], dexJar) + } + } + }) + return m +} + +// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if +// available, or reports an error. +func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module) android.Path { + if j, ok := module.(UsesLibraryDependency); ok { + dexJar := j.DexJarBuildPath() + if dexJar != nil { + return dexJar + } + ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module) + } else { + ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module)) + } + return nil +} + +var sdkKindToHiddenapiListOption = map[android.SdkKind]string{ + android.SdkPublic: "public-stub-classpath", + android.SdkSystem: "system-stub-classpath", + android.SdkTest: "test-stub-classpath", + android.SdkCorePlatform: "core-platform-stub-classpath", +} + +// ruleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file. +// +// The rule is initialized but not built so that the caller can modify it and select an appropriate +// name. +func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.OutputPath, bootDexJars android.Paths, sdkKindToPathList map[android.SdkKind]android.Paths) *android.RuleBuilder { + // Singleton rule which applies hiddenapi on all boot class path dex files. + rule := android.NewRuleBuilder(pctx, ctx) + + tempPath := tempPathForRestat(ctx, outputPath) + + command := rule.Command(). + Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")). + Text("list"). + FlagForEachInput("--boot-dex=", bootDexJars) + + // Iterate over the sdk kinds in a fixed order. + for _, sdkKind := range hiddenAPIRelevantSdkKinds { + paths := sdkKindToPathList[sdkKind] + if len(paths) > 0 { + option := sdkKindToHiddenapiListOption[sdkKind] + command.FlagWithInputList("--"+option+"=", paths, ":") + } + } + + // Add the output path. + command.FlagWithOutput("--out-api-flags=", tempPath) + + commitChangeForRestat(rule, tempPath, outputPath) + return rule +} + // HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the // information obtained from annotations within the source code in order to create the complete set // of flags that should be applied to the dex implementation jars on the bootclasspath. @@ -63,7 +216,7 @@ type HiddenAPIFlagFileProperties struct { func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo { info := hiddenAPIFlagFileInfo{categoryToPaths: map[*hiddenAPIFlagFileCategory]android.Paths{}} for _, category := range hiddenAPIFlagFileCategories { - paths := android.PathsForModuleSrc(ctx, category.propertyAccessor(p)) + paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p)) info.categoryToPaths[category] = paths } return info @@ -73,9 +226,9 @@ type hiddenAPIFlagFileCategory struct { // propertyName is the name of the property for this category. propertyName string - // propertyAccessor retrieves the value of the property for this category from the set of + // propertyValueReader retrieves the value of the property for this category from the set of // properties. - propertyAccessor func(properties *HiddenAPIFlagFileProperties) []string + propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string // commandMutator adds the appropriate command line options for this category to the supplied // command @@ -86,7 +239,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Unsupported { propertyName: "unsupported", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Unsupported }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -96,7 +249,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Removed { propertyName: "removed", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Removed }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -106,7 +259,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Max_target_r_low_priority { propertyName: "max_target_r_low_priority", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Max_target_r_low_priority }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -116,7 +269,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Max_target_q { propertyName: "max_target_q", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Max_target_q }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -126,7 +279,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Max_target_p { propertyName: "max_target_p", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Max_target_p }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -136,7 +289,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Max_target_o_low_priority { propertyName: "max_target_o_low_priority", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Max_target_o_low_priority }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -146,7 +299,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Blocked { propertyName: "blocked", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Blocked }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -156,7 +309,7 @@ var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // See HiddenAPIFlagFileProperties.Unsupported_packages { propertyName: "unsupported_packages", - propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { return properties.Unsupported_packages }, commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { @@ -172,6 +325,14 @@ type hiddenAPIFlagFileInfo struct { categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths } +func (i *hiddenAPIFlagFileInfo) append(other hiddenAPIFlagFileInfo) { + for _, category := range hiddenAPIFlagFileCategories { + i.categoryToPaths[category] = append(i.categoryToPaths[category], other.categoryToPaths[category]...) + } +} + +var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{}) + // ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the // flags from all the modules, the stub flags, augmented with some additional configuration files. // @@ -197,7 +358,7 @@ type hiddenAPIFlagFileInfo struct { // augmentationInfo is a struct containing paths to files that augment the information provided by // the moduleSpecificFlagsPaths. func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIFlagFileInfo) { - tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp") + tempPath := tempPathForRestat(ctx, outputPath) rule := android.NewRuleBuilder(pctx, ctx) command := rule.Command(). BuiltTool("generate_hiddenapi_lists"). diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index ed0b72250..3cc88e606 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -15,6 +15,8 @@ package java import ( + "strings" + "android/soong/android" ) @@ -125,8 +127,6 @@ func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) return } - stubFlagsRule(ctx) - // If there is a prebuilt hiddenapi dir, generate rules to use the // files within. Generally, we build the hiddenapi files from source // during the build, ensuring consistency. It's possible, in a split @@ -158,109 +158,6 @@ func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) { ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String()) } -// stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image -// modules. -func stubFlagsRule(ctx android.SingletonContext) { - var publicStubModules []string - var systemStubModules []string - var testStubModules []string - var corePlatformStubModules []string - - if ctx.Config().AlwaysUsePrebuiltSdks() { - // Build configuration mandates using prebuilt stub modules - publicStubModules = append(publicStubModules, "sdk_public_current_android") - systemStubModules = append(systemStubModules, "sdk_system_current_android") - testStubModules = append(testStubModules, "sdk_test_current_android") - } else { - // Use stub modules built from source - publicStubModules = append(publicStubModules, "android_stubs_current") - systemStubModules = append(systemStubModules, "android_system_stubs_current") - testStubModules = append(testStubModules, "android_test_stubs_current") - } - // We do not have prebuilts of the core platform api yet - corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs") - - // Allow products to define their own stubs for custom product jars that apps can use. - publicStubModules = append(publicStubModules, ctx.Config().ProductHiddenAPIStubs()...) - systemStubModules = append(systemStubModules, ctx.Config().ProductHiddenAPIStubsSystem()...) - testStubModules = append(testStubModules, ctx.Config().ProductHiddenAPIStubsTest()...) - if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") { - publicStubModules = append(publicStubModules, "jacoco-stubs") - } - - publicStubPaths := make(android.Paths, len(publicStubModules)) - systemStubPaths := make(android.Paths, len(systemStubModules)) - testStubPaths := make(android.Paths, len(testStubModules)) - corePlatformStubPaths := make(android.Paths, len(corePlatformStubModules)) - - moduleListToPathList := map[*[]string]android.Paths{ - &publicStubModules: publicStubPaths, - &systemStubModules: systemStubPaths, - &testStubModules: testStubPaths, - &corePlatformStubModules: corePlatformStubPaths, - } - - var bootDexJars android.Paths - - ctx.VisitAllModules(func(module android.Module) { - // Collect dex jar paths for the modules listed above. - if j, ok := module.(UsesLibraryDependency); ok { - name := ctx.ModuleName(module) - for moduleList, pathList := range moduleListToPathList { - if i := android.IndexList(name, *moduleList); i != -1 { - pathList[i] = j.DexJarBuildPath() - } - } - } - - // Collect dex jar paths for modules that had hiddenapi encode called on them. - if h, ok := module.(hiddenAPIIntf); ok { - if jar := h.bootDexJar(); jar != nil { - bootDexJars = append(bootDexJars, jar) - } - } - }) - - var missingDeps []string - // Ensure all modules were converted to paths - for moduleList, pathList := range moduleListToPathList { - for i := range pathList { - if pathList[i] == nil { - moduleName := (*moduleList)[i] - pathList[i] = android.PathForOutput(ctx, "missing/module", moduleName) - if ctx.Config().AllowMissingDependencies() { - missingDeps = append(missingDeps, moduleName) - } else { - ctx.Errorf("failed to find dex jar path for module %q", - moduleName) - } - } - } - } - - // Singleton rule which applies hiddenapi on all boot class path dex files. - rule := android.NewRuleBuilder(pctx, ctx) - - outputPath := hiddenAPISingletonPaths(ctx).stubFlags - tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp") - - rule.MissingDeps(missingDeps) - - rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")). - Text("list"). - FlagForEachInput("--boot-dex=", bootDexJars). - FlagWithInputList("--public-stub-classpath=", publicStubPaths, ":"). - FlagWithInputList("--system-stub-classpath=", systemStubPaths, ":"). - FlagWithInputList("--test-stub-classpath=", testStubPaths, ":"). - FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths, ":"). - FlagWithOutput("--out-api-flags=", tempPath) - - commitChangeForRestat(rule, tempPath, outputPath) - - rule.Build("hiddenAPIStubFlagsFile", "hiddenapi stub flags") -} - // Checks to see whether the supplied module variant is in the list of boot jars. // // This is similar to logic in getBootImageJar() so any changes needed here are likely to be needed @@ -348,6 +245,16 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } +// tempPathForRestat creates a path of the same type as the supplied type but with a name of +// <path>.tmp. +// +// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return +// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.tmp +func tempPathForRestat(ctx android.PathContext, path android.WritablePath) android.WritablePath { + extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".") + return path.ReplaceExtension(ctx, extWithoutLeadingDot+".tmp") +} + // commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It // also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of // the rule. diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index 5ea9a5bca..3ab22772a 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -23,12 +23,20 @@ import ( "github.com/google/blueprint/proptools" ) +// TODO(b/177892522): Move these tests into a more appropriate place. + func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer { return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir }) } +var prepareForTestWithDefaultPlatformBootclasspath = android.FixtureAddTextFile("frameworks/base/boot/Android.bp", ` + platform_bootclasspath { + name: "platform-bootclasspath", + } +`) + var hiddenApiFixtureFactory = android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithHiddenApiBuildComponents) @@ -36,6 +44,7 @@ func TestHiddenAPISingleton(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), + prepareForTestWithDefaultPlatformBootclasspath, ).RunTestWithBp(t, ` java_library { name: "foo", @@ -44,8 +53,8 @@ func TestHiddenAPISingleton(t *testing.T) { } `) - hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi") + hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } @@ -59,6 +68,7 @@ func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), + prepareForTestWithDefaultPlatformBootclasspath, ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)). RunTestWithBp(t, ` java_library { @@ -79,6 +89,7 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), + prepareForTestWithDefaultPlatformBootclasspath, ).RunTestWithBp(t, ` java_import { name: "foo", @@ -87,8 +98,8 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { } `) - hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi") + hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } @@ -97,6 +108,7 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), + prepareForTestWithDefaultPlatformBootclasspath, ).RunTestWithBp(t, ` java_library { name: "foo", @@ -112,8 +124,8 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { } `) - hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi") + hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) @@ -125,6 +137,7 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), + prepareForTestWithDefaultPlatformBootclasspath, ).RunTestWithBp(t, ` java_library { name: "foo", @@ -140,8 +153,8 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { } `) - hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi") + hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") prebuiltJarArg := "--boot-dex=out/soong/.intermediates/prebuilt_foo/android_common/dex/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) @@ -184,13 +197,14 @@ func TestHiddenAPISingletonSdks(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, tc.preparer, + prepareForTestWithDefaultPlatformBootclasspath, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild) }), ).RunTest(t) - hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi") + hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs) diff --git a/java/java.go b/java/java.go index ee4f2eb0b..adb0c5644 100644 --- a/java/java.go +++ b/java/java.go @@ -27,6 +27,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/cc" "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" @@ -708,6 +709,9 @@ type testProperties struct { // Test options. Test_options TestOptions + + // Names of modules containing JNI libraries that should be installed alongside the test. + Jni_libs []string } type hostTestProperties struct { @@ -769,6 +773,13 @@ func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) { } } + if len(j.testProperties.Jni_libs) > 0 { + for _, target := range ctx.MultiTargets() { + sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) + ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...) + } + } + j.deps(ctx) } @@ -793,6 +804,29 @@ func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) + ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) { + sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo) + if sharedLibInfo.SharedLibrary != nil { + // Copy to an intermediate output directory to append "lib[64]" to the path, + // so that it's compatible with the default rpath values. + var relPath string + if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" { + relPath = filepath.Join("lib64", sharedLibInfo.SharedLibrary.Base()) + } else { + relPath = filepath.Join("lib", sharedLibInfo.SharedLibrary.Base()) + } + relocatedLib := android.PathForModuleOut(ctx, "relocated").Join(ctx, relPath) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: sharedLibInfo.SharedLibrary, + Output: relocatedLib, + }) + j.data = append(j.data, relocatedLib) + } else { + ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) + } + }) + j.Library.GenerateAndroidBuildActions(ctx) } diff --git a/java/java_test.go b/java/java_test.go index 052345871..1b8aec286 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -20,6 +20,7 @@ import ( "path/filepath" "reflect" "regexp" + "runtime" "strconv" "strings" "testing" @@ -462,6 +463,38 @@ func TestBinary(t *testing.T) { } } +func TestTest(t *testing.T) { + ctx, _ := testJava(t, ` + java_test_host { + name: "foo", + srcs: ["a.java"], + jni_libs: ["libjni"], + } + + cc_library_shared { + name: "libjni", + host_supported: true, + device_supported: false, + stl: "none", + } + `) + + buildOS := android.BuildOs.String() + + foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost) + + expected := "lib64/libjni.so" + if runtime.GOOS == "darwin" { + expected = "lib64/libjni.dylib" + } + + fooTestData := foo.data + if len(fooTestData) != 1 || fooTestData[0].Rel() != expected { + t.Errorf(`expected foo test data relative path [%q], got %q`, + expected, fooTestData.Strings()) + } +} + func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) { bp := ` java_library { @@ -1170,107 +1203,6 @@ func TestIncludeSrcs(t *testing.T) { } } -func TestJavaLint(t *testing.T) { - ctx, _ := testJavaWithFS(t, ` - java_library { - name: "foo", - srcs: [ - "a.java", - "b.java", - "c.java", - ], - min_sdk_version: "29", - sdk_version: "system_current", - } - `, map[string][]byte{ - "lint-baseline.xml": nil, - }) - - foo := ctx.ModuleForTests("foo", "android_common") - - sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) - if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") { - t.Error("did not pass --baseline flag") - } -} - -func TestJavaLintWithoutBaseline(t *testing.T) { - ctx, _ := testJavaWithFS(t, ` - java_library { - name: "foo", - srcs: [ - "a.java", - "b.java", - "c.java", - ], - min_sdk_version: "29", - sdk_version: "system_current", - } - `, map[string][]byte{}) - - foo := ctx.ModuleForTests("foo", "android_common") - - sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) - if strings.Contains(*sboxProto.Commands[0].Command, "--baseline") { - t.Error("passed --baseline flag for non existent file") - } -} - -func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) { - android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - android.PrepareForTestDisallowNonExistentPaths, - ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{`source path "mybaseline.xml" does not exist`})). - RunTestWithBp(t, ` - java_library { - name: "foo", - srcs: [ - ], - min_sdk_version: "29", - sdk_version: "system_current", - lint: { - baseline_filename: "mybaseline.xml", - }, - } - `) -} - -func TestJavaLintUsesCorrectBpConfig(t *testing.T) { - ctx, _ := testJavaWithFS(t, ` - java_library { - name: "foo", - srcs: [ - "a.java", - "b.java", - "c.java", - ], - min_sdk_version: "29", - sdk_version: "system_current", - lint: { - error_checks: ["SomeCheck"], - baseline_filename: "mybaseline.xml", - }, - } - `, map[string][]byte{ - "mybaseline.xml": nil, - }) - - foo := ctx.ModuleForTests("foo", "android_common") - - sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) - if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") { - t.Error("did not use the correct file for baseline") - } - - if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") { - t.Error("should check NewApi errors") - } - - if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") { - t.Error("should combine NewApi errors with SomeCheck errors") - } -} - func TestGeneratedSources(t *testing.T) { ctx, _ := testJavaWithFS(t, ` java_library { @@ -1614,31 +1546,51 @@ func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { java_sdk_library { name: "sdklib", srcs: ["a.java"], - impl_only_libs: ["foo"], - stub_only_libs: ["bar"], + libs: ["lib"], + static_libs: ["static-lib"], + impl_only_libs: ["impl-only-lib"], + stub_only_libs: ["stub-only-lib"], + stub_only_static_libs: ["stub-only-static-lib"], } - java_library { - name: "foo", - srcs: ["a.java"], - sdk_version: "current", - } - java_library { - name: "bar", + java_defaults { + name: "defaults", srcs: ["a.java"], sdk_version: "current", } + java_library { name: "lib", defaults: ["defaults"] } + java_library { name: "static-lib", defaults: ["defaults"] } + java_library { name: "impl-only-lib", defaults: ["defaults"] } + java_library { name: "stub-only-lib", defaults: ["defaults"] } + java_library { name: "stub-only-static-lib", defaults: ["defaults"] } `) - - for _, implName := range []string{"sdklib", "sdklib.impl"} { - implJavacCp := result.ModuleForTests(implName, "android_common").Rule("javac").Args["classpath"] - if !strings.Contains(implJavacCp, "/foo.jar") || strings.Contains(implJavacCp, "/bar.jar") { - t.Errorf("%v javac classpath %v does not contain foo and not bar", implName, implJavacCp) - } + var expectations = []struct { + lib string + on_impl_classpath bool + on_stub_classpath bool + in_impl_combined bool + in_stub_combined bool + }{ + {lib: "lib", on_impl_classpath: true}, + {lib: "static-lib", in_impl_combined: true}, + {lib: "impl-only-lib", on_impl_classpath: true}, + {lib: "stub-only-lib", on_stub_classpath: true}, + {lib: "stub-only-static-lib", in_stub_combined: true}, + } + verify := func(sdklib, dep string, cp, combined bool) { + sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"] + expected := cp || combined // Every combined jar is also on the classpath. + android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected) + + combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings() + depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar") + android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined) } - stubName := apiScopePublic.stubsLibraryModuleName("sdklib") - stubsJavacCp := result.ModuleForTests(stubName, "android_common").Rule("javac").Args["classpath"] - if strings.Contains(stubsJavacCp, "/foo.jar") || !strings.Contains(stubsJavacCp, "/bar.jar") { - t.Errorf("stubs javac classpath %v does not contain bar and not foo", stubsJavacCp) + for _, expectation := range expectations { + verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) + verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) + + stubName := apiScopePublic.stubsLibraryModuleName("sdklib") + verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined) } } diff --git a/java/lint.go b/java/lint.go index aa308e669..862c9b4d9 100644 --- a/java/lint.go +++ b/java/lint.go @@ -26,6 +26,10 @@ import ( "android/soong/remoteexec" ) +// lint checks automatically enforced for modules that have different min_sdk_version than +// sdk_version +var updatabilityChecks = []string{"NewApi"} + type LintProperties struct { // Controls for running Android Lint on the module. Lint struct { @@ -53,6 +57,9 @@ type LintProperties struct { // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml". Baseline_filename *string + + // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false. + Strict_updatability_linting *bool } } @@ -200,7 +207,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars) cmd := rule.Command(). - BuiltTool("lint-project-xml"). + BuiltTool("lint_project_xml"). FlagWithOutput("--project_out ", projectXMLPath). FlagWithOutput("--config_out ", configXMLPath). FlagWithArg("--name ", ctx.ModuleName()) @@ -253,6 +260,13 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks) + if BoolDefault(l.properties.Lint.Strict_updatability_linting, false) { + if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() { + cmd.FlagWithInput("--baseline ", baselinePath.Path()) + cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks) + } + } + return lintPaths{ projectXML: projectXMLPath, configXML: configXMLPath, @@ -279,13 +293,36 @@ func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleB return manifestPath } +func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath { + var lintBaseline android.OptionalPath + if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" { + if String(l.properties.Lint.Baseline_filename) != "" { + // if manually specified, we require the file to exist + lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename)) + } else { + lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename) + } + } + return lintBaseline +} + func (l *linter) lint(ctx android.ModuleContext) { if !l.enabled() { return } if l.minSdkVersion != l.compileSdkVersion { - l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, "NewApi") + l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...) + _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks) + if len(filtered) != 0 { + ctx.PropertyErrorf("lint.warning_checks", + "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered) + } + _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks) + if len(filtered) != 0 { + ctx.PropertyErrorf("lint.disabled_checks", + "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered) + } } extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) @@ -381,17 +418,9 @@ func (l *linter) lint(ctx android.ModuleContext) { cmd.FlagWithArg("--check ", checkOnly) } - if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" { - var lintBaseline android.OptionalPath - if String(l.properties.Lint.Baseline_filename) != "" { - // if manually specified, we require the file to exist - lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename)) - } else { - lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename) - } - if lintBaseline.Valid() { - cmd.FlagWithInput("--baseline ", lintBaseline.Path()) - } + lintBaseline := l.getBaselineFilepath(ctx) + if lintBaseline.Valid() { + cmd.FlagWithInput("--baseline ", lintBaseline.Path()) } cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)") diff --git a/java/lint_test.go b/java/lint_test.go new file mode 100644 index 000000000..a253df979 --- /dev/null +++ b/java/lint_test.go @@ -0,0 +1,204 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "strings" + "testing" + + "android/soong/android" +) + +func TestJavaLint(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + srcs: [ + "a.java", + "b.java", + "c.java", + ], + min_sdk_version: "29", + sdk_version: "system_current", + } + `, map[string][]byte{ + "lint-baseline.xml": nil, + }) + + foo := ctx.ModuleForTests("foo", "android_common") + + sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) + if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") { + t.Error("did not pass --baseline flag") + } +} + +func TestJavaLintWithoutBaseline(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + srcs: [ + "a.java", + "b.java", + "c.java", + ], + min_sdk_version: "29", + sdk_version: "system_current", + } + `, map[string][]byte{}) + + foo := ctx.ModuleForTests("foo", "android_common") + + sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) + if strings.Contains(*sboxProto.Commands[0].Command, "--baseline") { + t.Error("passed --baseline flag for non existent file") + } +} + +func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) { + android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestDisallowNonExistentPaths, + ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{`source path "mybaseline.xml" does not exist`})). + RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: [ + ], + min_sdk_version: "29", + sdk_version: "system_current", + lint: { + baseline_filename: "mybaseline.xml", + }, + } + `) +} + +func TestJavaLintUsesCorrectBpConfig(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + srcs: [ + "a.java", + "b.java", + "c.java", + ], + min_sdk_version: "29", + sdk_version: "system_current", + lint: { + error_checks: ["SomeCheck"], + baseline_filename: "mybaseline.xml", + }, + } + `, map[string][]byte{ + "mybaseline.xml": nil, + }) + + foo := ctx.ModuleForTests("foo", "android_common") + + sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) + if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") { + t.Error("did not use the correct file for baseline") + } + + if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") { + t.Error("should check NewApi errors") + } + + if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") { + t.Error("should combine NewApi errors with SomeCheck errors") + } +} + +func TestJavaLintBypassUpdatableChecks(t *testing.T) { + testCases := []struct { + name string + bp string + error string + }{ + { + name: "warning_checks", + bp: ` + java_library { + name: "foo", + srcs: [ + "a.java", + ], + min_sdk_version: "29", + sdk_version: "current", + lint: { + warning_checks: ["NewApi"], + }, + } + `, + error: "lint.warning_checks: Can't treat \\[NewApi\\] checks as warnings if min_sdk_version is different from sdk_version.", + }, + { + name: "disable_checks", + bp: ` + java_library { + name: "foo", + srcs: [ + "a.java", + ], + min_sdk_version: "29", + sdk_version: "current", + lint: { + disabled_checks: ["NewApi"], + }, + } + `, + error: "lint.disabled_checks: Can't disable \\[NewApi\\] checks if min_sdk_version is different from sdk_version.", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + errorHandler := android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.error) + android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, testCase.bp) + }) + } +} + +func TestJavaLintStrictUpdatabilityLinting(t *testing.T) { + bp := ` + java_library { + name: "foo", + srcs: [ + "a.java", + ], + min_sdk_version: "29", + sdk_version: "current", + lint: { + strict_updatability_linting: true, + }, + } + ` + fs := android.MockFS{ + "lint-baseline.xml": nil, + } + + result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()). + RunTestWithBp(t, bp) + + foo := result.ModuleForTests("foo", "android_common") + sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto")) + if !strings.Contains(*sboxProto.Commands[0].Command, + "--baseline lint-baseline.xml --disallowed_issues NewApi") { + t.Error("did not restrict baselining NewApi") + } +} diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index cb8ad683b..568f5e406 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -140,6 +140,8 @@ func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, er } func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) { + b.hiddenAPIDepsMutator(ctx) + if SkipDexpreoptBootJars(ctx) { return } @@ -149,6 +151,16 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon dexpreopt.RegisterToolDeps(ctx) } +func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + return + } + + // Add dependencies onto the stub lib modules. + sdkKindToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) + hiddenAPIAddStubLibDependencies(ctx, sdkKindToStubLibModules) +} + func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { m := ctx.Module() if p, ok := m.(*platformBootclasspathModule); ok { @@ -258,7 +270,7 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo } }) - b.generateHiddenAPIBuildActions(ctx, b.configuredModules) + b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) // Nothing to do if skipping the dexpreopt of boot image jars. if SkipDexpreoptBootJars(ctx) { @@ -286,7 +298,7 @@ func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleCont } // generateHiddenAPIBuildActions generates all the hidden API related build rules. -func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) { +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) { // Save the paths to the monolithic files for retrieval via OutputFiles(). b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags @@ -338,16 +350,39 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV()) } - augmentationInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx) + flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx) + for _, fragment := range fragments { + if ctx.OtherModuleHasProvider(fragment, hiddenAPIFlagFileInfoProvider) { + info := ctx.OtherModuleProvider(fragment, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo) + flagFileInfo.append(info) + } + } + + // Store the information for testing. + ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo) outputPath := hiddenAPISingletonPaths(ctx).flags baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags - ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo) + ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, flagFileInfo) + b.generateHiddenAPIStubFlagsRules(ctx, hiddenAPISupportingModules) b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules) b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules) } +func (b *platformBootclasspathModule) generateHiddenAPIStubFlagsRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) { + bootDexJars := android.Paths{} + for _, module := range modules { + bootDexJars = append(bootDexJars, module.bootDexJar()) + } + + sdkKindToStubPaths := hiddenAPIGatherStubLibDexJarPaths(ctx) + + outputPath := hiddenAPISingletonPaths(ctx).stubFlags + rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, outputPath, bootDexJars, sdkKindToStubPaths) + rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags") +} + func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) { indexes := android.Paths{} for _, module := range modules { diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go index e51b0493a..955e387a9 100644 --- a/java/platform_bootclasspath_test.go +++ b/java/platform_bootclasspath_test.go @@ -15,6 +15,8 @@ package java import ( + "fmt" + "strings" "testing" "android/soong/android" @@ -132,6 +134,96 @@ func TestPlatformBootclasspath(t *testing.T) { }) } +func TestPlatformBootclasspath_Fragments(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithPlatformBootclasspath, + android.FixtureWithRootAndroidBp(` + platform_bootclasspath { + name: "platform-bootclasspath", + fragments: [ + {module:"bar-fragment"}, + ], + hidden_api: { + unsupported: [ + "unsupported.txt", + ], + removed: [ + "removed.txt", + ], + max_target_r_low_priority: [ + "max-target-r-low-priority.txt", + ], + max_target_q: [ + "max-target-q.txt", + ], + max_target_p: [ + "max-target-p.txt", + ], + max_target_o_low_priority: [ + "max-target-o-low-priority.txt", + ], + blocked: [ + "blocked.txt", + ], + unsupported_packages: [ + "unsupported-packages.txt", + ], + }, + } + + bootclasspath_fragment { + name: "bar-fragment", + contents: ["bar"], + hidden_api: { + unsupported: [ + "bar-unsupported.txt", + ], + removed: [ + "bar-removed.txt", + ], + max_target_r_low_priority: [ + "bar-max-target-r-low-priority.txt", + ], + max_target_q: [ + "bar-max-target-q.txt", + ], + max_target_p: [ + "bar-max-target-p.txt", + ], + max_target_o_low_priority: [ + "bar-max-target-o-low-priority.txt", + ], + blocked: [ + "bar-blocked.txt", + ], + unsupported_packages: [ + "bar-unsupported-packages.txt", + ], + }, + } + + java_library { + name: "bar", + srcs: ["a.java"], + system_modules: "none", + sdk_version: "none", + compile_dex: true, + } + `), + ).RunTest(t) + + pbcp := result.Module("platform-bootclasspath", "android_common") + info := result.ModuleProvider(pbcp, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo) + + for _, category := range hiddenAPIFlagFileCategories { + name := category.propertyName + message := fmt.Sprintf("category %s", name) + filename := strings.ReplaceAll(name, "_", "-") + expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)} + android.AssertPathsRelativeToTopEquals(t, message, expected, info.categoryToPaths[category]) + } +} + func TestPlatformBootclasspathVariant(t *testing.T) { result := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, diff --git a/java/sdk.go b/java/sdk.go index d6e20a78f..1c097d5b7 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -247,7 +247,7 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { } combinedAidl := sdkFrameworkAidlPath(ctx) - tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") + tempPath := tempPathForRestat(ctx, combinedAidl) rule := createFrameworkAidl(stubsModules, tempPath, ctx) @@ -261,7 +261,7 @@ func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) { stubsModules := []string{"android_module_lib_stubs_current"} combinedAidl := nonUpdatableFrameworkAidlPath(ctx) - tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") + tempPath := tempPathForRestat(ctx, combinedAidl) rule := createFrameworkAidl(stubsModules, tempPath, ctx) @@ -270,7 +270,7 @@ func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) { rule.Build("framework_non_updatable_aidl", "generate framework_non_updatable.aidl") } -func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx android.SingletonContext) *android.RuleBuilder { +func createFrameworkAidl(stubsModules []string, path android.WritablePath, ctx android.SingletonContext) *android.RuleBuilder { stubsJars := make([]android.Paths, len(stubsModules)) ctx.VisitAllModules(func(module android.Module) { diff --git a/java/sdk_library.go b/java/sdk_library.go index e5ee39705..05ce97aea 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -399,6 +399,9 @@ type sdkLibraryProperties struct { // List of Java libraries that will be in the classpath when building stubs Stub_only_libs []string `android:"arch_variant"` + // List of Java libraries that will included in stub libraries + Stub_only_static_libs []string `android:"arch_variant"` + // list of package names that will be documented and publicized as API. // This allows the API to be restricted to a subset of the source files provided. // If this is unspecified then all the source files will be treated as being part @@ -534,6 +537,11 @@ type scopePaths struct { // This is not the implementation jar, it still only contains stubs. stubsImplPath android.Paths + // The dex jar for the stubs. + // + // This is not the implementation jar, it still only contains stubs. + stubsDexJarPath android.Path + // The API specification file, e.g. system_current.txt. currentApiFilePath android.OptionalPath @@ -549,6 +557,9 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.Modul lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) paths.stubsHeaderPath = lib.HeaderJars paths.stubsImplPath = lib.ImplementationJars + + libDep := dep.(UsesLibraryDependency) + paths.stubsDexJarPath = libDep.DexJarBuildPath() return nil } else { return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") @@ -825,8 +836,22 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android. return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion) } + paths := c.selectScopePaths(ctx, sdkVersion.Kind) + if paths == nil { + return nil + } + + return paths.stubsHeaderPath +} + +// selectScopePaths returns the *scopePaths appropriate for the specific kind. +// +// If the module does not support the specific kind then it will return the *scopePaths for the +// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then +// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not. +func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths { var apiScope *apiScope - switch sdkVersion.Kind { + switch kind { case android.SdkSystem: apiScope = apiScopeSystem case android.SdkModule: @@ -851,7 +876,17 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android. return nil } - return paths.stubsHeaderPath + return paths +} + +// to satisfy SdkLibraryDependency interface +func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path { + paths := c.selectScopePaths(ctx, kind) + if paths == nil { + return nil + } + + return paths.stubsDexJarPath } func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} { @@ -944,6 +979,10 @@ type SdkLibraryDependency interface { // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise // they are identical to the corresponding header jars. SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths + + // SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing + // tool which processes dex files. + SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path } type SdkLibrary struct { @@ -1239,6 +1278,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext System_modules *string Patch_module *string Libs []string + Static_libs []string Compile_dex *bool Java_version *string Openjdk9 struct { @@ -1263,6 +1303,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext props.Patch_module = module.properties.Patch_module props.Installable = proptools.BoolPtr(false) props.Libs = module.sdkLibraryProperties.Stub_only_libs + props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs // The stub-annotations library contains special versions of the annotations // with CLASS retention policy, so that they're kept. if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { @@ -1781,6 +1822,9 @@ type sdkLibraryImportProperties struct { // List of shared java libs, common to all scopes, that this module has // dependencies to Libs []string + + // If set to true, compile dex files for the stubs. Defaults to false. + Compile_dex *bool } type SdkLibraryImport struct { @@ -1916,6 +1960,7 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl Libs []string Jars []string Prefer *bool + Compile_dex *bool }{} props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) props.Sdk_version = scopeProperties.Sdk_version @@ -1927,6 +1972,9 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl // The imports are preferred if the java_sdk_library_import is preferred. props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) + // The imports need to be compiled to dex if the java_sdk_library_import requests it. + props.Compile_dex = module.properties.Compile_dex + mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) } @@ -2348,6 +2396,9 @@ type sdkLibrarySdkMemberProperties struct { // otherwise. Shared_library *bool + // True if the stub imports should produce dex jars. + Compile_dex *bool + // The paths to the doctag files to add to the prebuilt. Doctag_paths android.Paths } @@ -2389,6 +2440,7 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Libs = sdk.properties.Libs s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary()) + s.Compile_dex = sdk.dexProperties.Compile_dex s.Doctag_paths = sdk.doctagPaths } @@ -2399,6 +2451,9 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo if s.Shared_library != nil { propertySet.AddProperty("shared_library", *s.Shared_library) } + if s.Compile_dex != nil { + propertySet.AddProperty("compile_dex", *s.Compile_dex) + } for _, apiScope := range allApiScopes { if properties, ok := s.Scopes[apiScope]; ok { diff --git a/java/testing.go b/java/testing.go index aee0710c4..08a71b880 100644 --- a/java/testing.go +++ b/java/testing.go @@ -200,6 +200,9 @@ func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer { }), dexpreopt.FixtureSetBootJars(bootJars...), dexpreopt.FixtureSetArtBootJars(artBootJars...), + + // Add a fake dex2oatd module. + dexpreopt.PrepareForTestWithFakeDex2oatd, ) } @@ -212,6 +215,9 @@ func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePrepar variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars) }), dexpreopt.FixtureSetUpdatableBootJars(bootJars...), + + // Add a fake dex2oatd module. + dexpreopt.PrepareForTestWithFakeDex2oatd, ) } |