diff --git a/android/sdk.go b/android/sdk.go index 42f95b76c..bd2f5d13f 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -738,6 +738,11 @@ type SdkMemberType interface { // A field annotated with a tag of `sdk:"ignore"` will be treated as if it // was not capitalized, i.e. ignored and not optimized for common values. // + // A field annotated with a tag of `sdk:"keep"` will not be cleared even if the value is common + // across multiple structs. Common values will still be copied into the common property struct. + // So, if the same value is placed in all structs populated from variants that value would be + // copied into all common property structs and so be available in every instance. + // // A field annotated with a tag of `android:"arch_variant"` will be allowed to have // values that differ by arch, fields not tagged as such must have common values across // all variants. diff --git a/java/sdk_library.go b/java/sdk_library.go index 8f499b101..d188133c6 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -539,7 +539,7 @@ type sdkLibraryProperties struct { } // TODO: determines whether to create HTML doc or not - //Html_doc *bool + // Html_doc *bool } // Paths to outputs from java_sdk_library and java_sdk_library_import. @@ -1354,7 +1354,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Provide additional information for inclusion in an sdk's generated .info file. additionalSdkInfo := map[string]interface{}{} additionalSdkInfo["dist_stem"] = module.distStem() - baseModuleName := module.BaseModuleName() + baseModuleName := module.distStem() scopes := map[string]interface{}{} additionalSdkInfo["scopes"] = scopes for scope, scopePaths := range module.scopePaths { @@ -2904,6 +2904,18 @@ var javaSdkLibrarySdkMemberType = &sdkLibrarySdkMemberType{ type sdkLibrarySdkMemberProperties struct { android.SdkMemberPropertiesBase + // Stem name for files in the sdk snapshot. + // + // This is used to construct the path names of various sdk library files in the sdk snapshot to + // make sure that they match the finalized versions of those files in prebuilts/sdk. + // + // This property is marked as keep so that it will be kept in all instances of this struct, will + // not be cleared but will be copied to common structs. That is needed because this field is used + // to construct many file names for other parts of this struct and so it needs to be present in + // all structs. If it was not marked as keep then it would be cleared in some structs and so would + // be unavailable for generating file names if there were other properties that were still set. + Stem string `sdk:"keep"` + // Scope to per scope properties. Scopes map[*apiScope]*scopeProperties @@ -2965,6 +2977,9 @@ type scopeProperties struct { func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { sdk := variant.(*SdkLibrary) + // Copy the stem name for files in the sdk snapshot. + s.Stem = sdk.distStem() + s.Scopes = make(map[*apiScope]*scopeProperties) for _, apiScope := range allApiScopes { paths := sdk.findScopePaths(apiScope) @@ -3017,6 +3032,8 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo propertySet.AddProperty("permitted_packages", s.Permitted_packages) } + stem := s.Stem + for _, apiScope := range allApiScopes { if properties, ok := s.Scopes[apiScope]; ok { scopeSet := propertySet.AddPropertySet(apiScope.propertyName) @@ -3025,7 +3042,7 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo var jars []string for _, p := range properties.Jars { - dest := filepath.Join(scopeDir, ctx.Name()+"-stubs.jar") + dest := filepath.Join(scopeDir, stem+"-stubs.jar") ctx.SnapshotBuilder().CopyToSnapshot(p, dest) jars = append(jars, dest) } @@ -3033,31 +3050,31 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo if ctx.SdkModuleContext().Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_USE_SRCJAR") { // Copy the stubs source jar into the snapshot zip as is. - srcJarSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".srcjar") + srcJarSnapshotPath := filepath.Join(scopeDir, stem+".srcjar") ctx.SnapshotBuilder().CopyToSnapshot(properties.StubsSrcJar, srcJarSnapshotPath) scopeSet.AddProperty("stub_srcs", []string{srcJarSnapshotPath}) } else { // Merge the stubs source jar into the snapshot zip so that when it is unpacked // the source files are also unpacked. - snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources") + snapshotRelativeDir := filepath.Join(scopeDir, stem+"_stub_sources") ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir) scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir}) } if properties.CurrentApiFile != nil { - currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(ctx.Name()) + currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(stem) ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath) scopeSet.AddProperty("current_api", currentApiSnapshotPath) } if properties.RemovedApiFile != nil { - removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(ctx.Name()) + removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(stem) ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath) scopeSet.AddProperty("removed_api", removedApiSnapshotPath) } if properties.AnnotationsZip != nil { - annotationsSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"_annotations.zip") + annotationsSnapshotPath := filepath.Join(scopeDir, stem+"_annotations.zip") ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath) scopeSet.AddProperty("annotations", annotationsSnapshotPath) } diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index d59883435..51903ce39 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -889,6 +889,56 @@ java_sdk_library_import { ) } +func TestSnapshotWithJavaSdkLibrary_DistStem(t *testing.T) { + result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` + sdk { + name: "mysdk", + java_sdk_libs: ["myjavalib-foo"], + } + + java_sdk_library { + name: "myjavalib-foo", + apex_available: ["//apex_available:anyapex"], + srcs: ["Test.java"], + sdk_version: "current", + shared_library: false, + public: { + enabled: true, + }, + dist_stem: "myjavalib", + } + `) + + CheckSnapshot(t, result, "mysdk", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +java_sdk_library_import { + name: "myjavalib-foo", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:anyapex"], + shared_library: false, + public: { + jars: ["sdk_library/public/myjavalib-stubs.jar"], + stub_srcs: ["sdk_library/public/myjavalib_stub_sources"], + current_api: "sdk_library/public/myjavalib.txt", + removed_api: "sdk_library/public/myjavalib-removed.txt", + sdk_version: "current", + }, +} +`), + checkAllCopyRules(` +.intermediates/myjavalib-foo.stubs/android_common/javac/myjavalib-foo.stubs.jar -> sdk_library/public/myjavalib-stubs.jar +.intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_api.txt -> sdk_library/public/myjavalib.txt +.intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt +`), + checkMergeZips( + ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip", + ), + ) +} + func TestSnapshotWithJavaSdkLibrary_UseSrcJar(t *testing.T) { result := android.GroupFixturePreparers( prepareForSdkTestWithJavaSdkLibrary, diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 4be1e79a4..2f9aee9da 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -221,6 +221,7 @@ type testPropertiesStruct struct { name string private string Public_Ignore string `sdk:"ignore"` + Public_Keep string `sdk:"keep"` S_Common string S_Different string `android:"arch_variant"` A_Common []string @@ -247,6 +248,7 @@ func TestCommonValueOptimization(t *testing.T) { name: "struct-0", private: "common", Public_Ignore: "common", + Public_Keep: "keep", S_Common: "common", S_Different: "upper", A_Common: []string{"first", "second"}, @@ -262,6 +264,7 @@ func TestCommonValueOptimization(t *testing.T) { name: "struct-1", private: "common", Public_Ignore: "common", + Public_Keep: "keep", S_Common: "common", S_Different: "lower", A_Common: []string{"first", "second"}, @@ -285,6 +288,7 @@ func TestCommonValueOptimization(t *testing.T) { name: "common", private: "", Public_Ignore: "", + Public_Keep: "keep", S_Common: "common", S_Different: "", A_Common: []string{"first", "second"}, @@ -303,6 +307,7 @@ func TestCommonValueOptimization(t *testing.T) { name: "struct-0", private: "common", Public_Ignore: "common", + Public_Keep: "keep", S_Common: "", S_Different: "upper", A_Common: nil, @@ -321,6 +326,7 @@ func TestCommonValueOptimization(t *testing.T) { name: "struct-1", private: "common", Public_Ignore: "common", + Public_Keep: "keep", S_Common: "", S_Different: "lower", A_Common: nil, diff --git a/sdk/update.go b/sdk/update.go index f20f1d6e9..92a13fa7f 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -2172,6 +2172,11 @@ type extractorProperty struct { // Retrieves the value on which common value optimization will be performed. getter fieldAccessorFunc + // True if the field should never be cleared. + // + // This is set to true if and only if the field is annotated with `sdk:"keep"`. + keep bool + // The empty value for the field. emptyValue reflect.Value @@ -2236,6 +2241,8 @@ func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingS } } + keep := proptools.HasTag(field, "sdk", "keep") + // Save a copy of the field index for use in the function. fieldIndex := f @@ -2275,6 +2282,7 @@ func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingS name, filter, fieldGetter, + keep, reflect.Zero(field.Type), proptools.HasTag(field, "android", "arch_variant"), } @@ -2394,11 +2402,13 @@ func (e *commonValueExtractor) extractCommonProperties(commonProperties interfac if commonValue != nil { emptyValue := property.emptyValue fieldGetter(commonStructValue).Set(*commonValue) - for i := 0; i < sliceValue.Len(); i++ { - container := sliceValue.Index(i).Interface().(propertiesContainer) - itemValue := reflect.ValueOf(container.optimizableProperties()) - fieldValue := fieldGetter(itemValue) - fieldValue.Set(emptyValue) + if !property.keep { + for i := 0; i < sliceValue.Len(); i++ { + container := sliceValue.Index(i).Interface().(propertiesContainer) + itemValue := reflect.ValueOf(container.optimizableProperties()) + fieldValue := fieldGetter(itemValue) + fieldValue.Set(emptyValue) + } } }