diff --git a/android/api_levels.go b/android/api_levels.go index fab5fc7bf..dc17238f3 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -291,6 +291,8 @@ var ApiLevelR = uncheckedFinalApiLevel(30) var ApiLevelUpsideDownCake = uncheckedFinalApiLevel(34) +var ApiLevelVanillaIceCream = uncheckedFinalApiLevel(35) + // ReplaceFinalizedCodenames returns the API level number associated with that API level // if the `raw` input is the codename of an API level has been finalized. // If the input is *not* a finalized codename, the input is returned unmodified. diff --git a/java/java.go b/java/java.go index ccccbacdb..08fb6782c 100644 --- a/java/java.go +++ b/java/java.go @@ -2180,7 +2180,7 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { // Map where key is the api scope name and value is the int value // representing the order of the api scope, narrowest to the widest -var scopeOrderMap = allApiScopes.MapToIndex( +var scopeOrderMap = AllApiScopes.MapToIndex( func(s *apiScope) string { return s.name }) func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo { diff --git a/java/sdk_library.go b/java/sdk_library.go index 72eb6e346..6c1a38d7d 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -324,6 +324,16 @@ func (scopes apiScopes) MapToIndex(accessor func(*apiScope) string) map[string]i return ret } +func (scopes apiScopes) ConvertStubsLibraryExportableToEverything(name string) string { + for _, scope := range scopes { + if strings.HasSuffix(name, scope.exportableStubsLibraryModuleNameSuffix()) { + return strings.TrimSuffix(name, scope.exportableStubsLibraryModuleNameSuffix()) + + scope.stubsLibraryModuleNameSuffix() + } + } + return name +} + var ( scopeByName = make(map[string]*apiScope) allScopeNames []string @@ -418,7 +428,7 @@ var ( }, kind: android.SdkSystemServer, }) - allApiScopes = apiScopes{ + AllApiScopes = apiScopes{ apiScopePublic, apiScopeSystem, apiScopeTest, @@ -1204,7 +1214,7 @@ func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleCon paths := c.findClosestScopePath(apiScope) if paths == nil { var scopes []string - for _, s := range allApiScopes { + for _, s := range AllApiScopes { if c.findScopePaths(s) != nil { scopes = append(scopes, s.name) } @@ -1421,7 +1431,7 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) // Check to see if any scopes have been explicitly enabled. If any have then all // must be. anyScopesExplicitlyEnabled := false - for _, scope := range allApiScopes { + for _, scope := range AllApiScopes { scopeProperties := module.scopeToProperties[scope] if scopeProperties.Enabled != nil { anyScopesExplicitlyEnabled = true @@ -1431,7 +1441,7 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) var generatedScopes apiScopes enabledScopes := make(map[*apiScope]struct{}) - for _, scope := range allApiScopes { + for _, scope := range AllApiScopes { scopeProperties := module.scopeToProperties[scope] // If any scopes are explicitly enabled then ignore the legacy enabled status. // This is to ensure that any new usages of this module type do not rely on legacy @@ -1451,7 +1461,7 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) // Now check to make sure that any scope that is extended by an enabled scope is also // enabled. - for _, scope := range allApiScopes { + for _, scope := range AllApiScopes { if _, ok := enabledScopes[scope]; ok { extends := scope.extends if extends != nil { @@ -2580,7 +2590,7 @@ func SdkLibraryFactory() android.Module { // Initialize the map from scope to scope specific properties. scopeToProperties := make(map[*apiScope]*ApiScopeProperties) - for _, scope := range allApiScopes { + for _, scope := range AllApiScopes { scopeToProperties[scope] = scope.scopeSpecificProperties(module) } module.scopeToProperties = scopeToProperties @@ -2697,7 +2707,7 @@ var allScopeStructType = createAllScopePropertiesStructType() // Dynamically create a structure type for each apiscope in allApiScopes. func createAllScopePropertiesStructType() reflect.Type { var fields []reflect.StructField - for _, apiScope := range allApiScopes { + for _, apiScope := range AllApiScopes { field := reflect.StructField{ Name: apiScope.fieldName, Type: reflect.TypeOf(sdkLibraryScopeProperties{}), @@ -2715,7 +2725,7 @@ func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProp allScopePropertiesStruct := allScopePropertiesPtr.Elem() scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties) - for _, apiScope := range allApiScopes { + for _, apiScope := range AllApiScopes { field := allScopePropertiesStruct.FieldByName(apiScope.fieldName) scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties) } @@ -3597,7 +3607,7 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Stem = sdk.distStem() s.Scopes = make(map[*apiScope]*scopeProperties) - for _, apiScope := range allApiScopes { + for _, apiScope := range AllApiScopes { paths := sdk.findScopePaths(apiScope) if paths == nil { continue @@ -3659,7 +3669,7 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo stem := s.Stem - for _, apiScope := range allApiScopes { + for _, apiScope := range AllApiScopes { if properties, ok := s.Scopes[apiScope]; ok { scopeSet := propertySet.AddPropertySet(apiScope.propertyName) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index f9d49d98d..4894210d4 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -515,6 +515,142 @@ java_sdk_library_import { .intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar .intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt .intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt +`), + ) + }) + + t.Run("test replacing exportable module", func(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureWithLastReleaseApis("mysdklibrary", "anothersdklibrary"), + android.FixtureWithRootAndroidBp(` + sdk { + name: "mysdk", + bootclasspath_fragments: ["mybootclasspathfragment"], + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + apex_available: ["myapex"], + contents: ["mysdklibrary"], + hidden_api: { + split_packages: ["*"], + }, + core_platform_api: { + stub_libs: [ + "anothersdklibrary.stubs.exportable", + ], + }, + api: { + stub_libs: [ + "anothersdklibrary", + ], + }, + } + + java_sdk_library { + name: "mysdklibrary", + srcs: ["Test.java"], + compile_dex: true, + min_sdk_version: "S", + public: {enabled: true}, + permitted_packages: ["mysdklibrary"], + } + + java_sdk_library { + name: "anothersdklibrary", + srcs: ["Test.java"], + compile_dex: true, + min_sdk_version: "S", + public: {enabled: true}, + system: {enabled: true}, + module_lib: {enabled: true}, + } + `), + android.FixtureMergeEnv(map[string]string{ + "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S", + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true", + } + variables.Platform_version_active_codenames = []string{"UpsideDownCake", "Tiramisu", "S-V2"} + }), + ).RunTest(t) + + CheckSnapshot(t, result, "mysdk", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +prebuilt_bootclasspath_fragment { + name: "mybootclasspathfragment", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + contents: ["mysdklibrary"], + api: { + stub_libs: ["anothersdklibrary"], + }, + core_platform_api: { + stub_libs: ["anothersdklibrary.stubs"], + }, + hidden_api: { + annotation_flags: "hiddenapi/annotation-flags.csv", + metadata: "hiddenapi/metadata.csv", + index: "hiddenapi/index.csv", + stub_flags: "hiddenapi/stub-flags.csv", + all_flags: "hiddenapi/all-flags.csv", + }, +} + +java_sdk_library_import { + name: "mysdklibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + shared_library: true, + compile_dex: true, + permitted_packages: ["mysdklibrary"], + public: { + jars: ["sdk_library/public/mysdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"], + current_api: "sdk_library/public/mysdklibrary.txt", + removed_api: "sdk_library/public/mysdklibrary-removed.txt", + sdk_version: "current", + }, +} + +java_sdk_library_import { + name: "anothersdklibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + shared_library: true, + compile_dex: true, + public: { + jars: ["sdk_library/public/anothersdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/anothersdklibrary_stub_sources"], + current_api: "sdk_library/public/anothersdklibrary.txt", + removed_api: "sdk_library/public/anothersdklibrary-removed.txt", + sdk_version: "current", + }, + system: { + jars: ["sdk_library/system/anothersdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/system/anothersdklibrary_stub_sources"], + current_api: "sdk_library/system/anothersdklibrary.txt", + removed_api: "sdk_library/system/anothersdklibrary-removed.txt", + sdk_version: "system_current", + }, + module_lib: { + jars: ["sdk_library/module-lib/anothersdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/module-lib/anothersdklibrary_stub_sources"], + current_api: "sdk_library/module-lib/anothersdklibrary.txt", + removed_api: "sdk_library/module-lib/anothersdklibrary-removed.txt", + sdk_version: "module_current", + }, +} `), ) }) diff --git a/sdk/update.go b/sdk/update.go index afecf9fe2..0a97fd9ee 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -480,6 +480,12 @@ be unnecessary as every module in the sdk already has its own licenses property. // Transform the module module to make it suitable for use in the snapshot. module = transformModule(module, snapshotTransformer) module = transformModule(module, emptyClasspathContentsTransformation{}) + + targetApiLevel, err := android.ApiLevelFromUserWithConfig(ctx.Config(), s.targetBuildRelease(ctx).name) + if err == nil && targetApiLevel.LessThan(android.ApiLevelVanillaIceCream) { + module = transformModule(module, replaceExportablePropertiesTransformer{}) + } + if module != nil { bpFile.AddModule(module) } @@ -804,6 +810,50 @@ func (t pruneEmptySetTransformer) transformPropertySetAfterContents(_ string, pr } } +type replaceExportablePropertiesTransformer struct { + identityTransformation +} + +var _ bpTransformer = (*replaceExportablePropertiesTransformer)(nil) + +func handleExportableProperties[T any](value T) any { + switch v := any(value).(type) { + case string: + return java.AllApiScopes.ConvertStubsLibraryExportableToEverything(v) + case *bpPropertySet: + v.properties = handleExportableProperties(v.properties).(map[string]interface{}) + return v + case []string: + result := make([]string, len(v)) + for i, elem := range v { + result[i] = handleExportableProperties(elem).(string) + } + return result + case []any: + result := make([]any, len(v)) + for i, elem := range v { + result[i] = handleExportableProperties(elem) + } + return result + case map[string]any: + result := make(map[string]any) + for k, val := range v { + result[k] = handleExportableProperties(val) + } + return result + default: + return value + } +} + +func (t replaceExportablePropertiesTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) { + if name == "name" { + return propertySet, tag + } + propertySet.properties = handleExportableProperties(propertySet.properties).(map[string]interface{}) + return propertySet, tag +} + func generateBpContents(bpFile *bpFile) string { contents := &generatedContents{} contents.IndentedPrintf("// This is auto-generated. DO NOT EDIT.\n")