diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 2 | ||||
| -rw-r--r-- | java/boot_image.go | 82 | ||||
| -rw-r--r-- | java/hiddenapi.go | 28 | ||||
| -rw-r--r-- | java/hiddenapi_modular.go | 176 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 117 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 34 | ||||
| -rw-r--r-- | java/java_test.go | 161 | ||||
| -rw-r--r-- | java/lint.go | 55 | ||||
| -rw-r--r-- | java/lint_test.go | 204 | ||||
| -rw-r--r-- | java/platform_bootclasspath.go | 26 | ||||
| -rw-r--r-- | java/sdk.go | 6 | ||||
| -rw-r--r-- | java/sdk_library.go | 5 | ||||
| -rw-r--r-- | java/testing.go | 6 |
13 files changed, 620 insertions, 282 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/boot_image.go b/java/boot_image.go index 78215f05a..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 { @@ -187,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 } @@ -202,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 @@ -295,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/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 e5dba33e8..8cc6f8f23 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -21,6 +21,158 @@ import ( // 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. @@ -64,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 @@ -74,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 @@ -87,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) { @@ -97,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) { @@ -107,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) { @@ -117,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) { @@ -127,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) { @@ -137,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) { @@ -147,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) { @@ -157,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) { @@ -206,7 +358,7 @@ var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{ // 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_test.go b/java/java_test.go index e7ea4ef54..1b8aec286 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1203,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 { @@ -1647,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) - } - } - 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) + 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) + } + 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 ba758ddfb..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 { @@ -353,10 +365,24 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags 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/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 223be5cf7..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 @@ -1275,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 { @@ -1299,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) { 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, ) } |