From 51227d875b1ae91cde5af5b5b463c93a56c79f94 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Tue, 18 May 2021 12:54:27 +0100 Subject: [PATCH] Output bootclasspath_fragment's fragments property to sdk snapshot Adds support for printing a PropertySet that has a property whose value is an array of structs. Bug: 179354495 Test: m nothing m conscrypt-module-sdk - check generated Android.bp file Change-Id: I71be04188465610bcbea4d3c9a5e8204171a1eeb --- android/sdk.go | 16 ++++ java/bootclasspath.go | 2 + java/bootclasspath_fragment.go | 9 ++ sdk/bootclasspath_fragment_sdk_test.go | 121 +++++++++++++++++++++++++ sdk/update.go | 59 +++++++++--- 5 files changed, 194 insertions(+), 13 deletions(-) diff --git a/android/sdk.go b/android/sdk.go index 36c576d80..93beb6e21 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -300,6 +300,22 @@ type BpModule interface { Name() string } +// BpPrintable is a marker interface that must be implemented by any struct that is added as a +// property value. +type BpPrintable interface { + bpPrintable() +} + +// BpPrintableBase must be embedded within any struct that is added as a +// property value. +type BpPrintableBase struct { +} + +func (b BpPrintableBase) bpPrintable() { +} + +var _ BpPrintable = BpPrintableBase{} + // An individual member of the SDK, includes all of the variants that the SDK // requires. type SdkMember interface { diff --git a/java/bootclasspath.go b/java/bootclasspath.go index eddcc838b..ccb69a0ae 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -144,6 +144,8 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tag blueprin // ApexVariantReference specifies a particular apex variant of a module. type ApexVariantReference struct { + android.BpPrintableBase + // The name of the module apex variant, i.e. the apex containing the module variant. // // If this is not specified then it defaults to "platform" which will cause a dependency to be diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index c9d5917fa..c7249b0ca 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -749,6 +749,9 @@ type bootclasspathFragmentSdkMemberProperties struct { Stub_libs []string Core_platform_stub_libs []string + // Fragment properties + Fragments []ApexVariantReference + // Flag files by *hiddenAPIFlagFileCategory Flag_files_by_category FlagFilesByCategory @@ -789,6 +792,9 @@ func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx andro // Copy stub_libs properties. b.Stub_libs = module.properties.Api.Stub_libs b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs + + // Copy fragment properties. + b.Fragments = module.properties.Fragments } func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -811,6 +817,9 @@ func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android. corePlatformApiPropertySet := propertySet.AddPropertySet("core_platform_api") corePlatformApiPropertySet.AddPropertyWithTag("stub_libs", b.Core_platform_stub_libs, requiredMemberDependency) } + if len(b.Fragments) > 0 { + propertySet.AddProperty("fragments", b.Fragments) + } hiddenAPISet := propertySet.AddPropertySet("hidden_api") hiddenAPIDir := "hiddenapi" diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index 378f7cfaa..d47eb1fb5 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -511,6 +511,127 @@ sdk_snapshot { ) } +// TestSnapshotWithBootClasspathFragment_Fragments makes sure that the fragments property of a +// bootclasspath_fragment is correctly output to the sdk snapshot. +func TestSnapshotWithBootClasspathFragment_Fragments(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary"), + prepareForSdkTestWithApex, + + // Some additional files needed for the myotherapex. + android.FixtureMergeMockFs(android.MockFS{ + "system/sepolicy/apex/myotherapex-file_contexts": nil, + "myotherapex/apex_manifest.json": nil, + "myotherapex/Test.java": nil, + }), + + android.FixtureAddTextFile("myotherapex/Android.bp", ` + apex { + name: "myotherapex", + key: "myapex.key", + min_sdk_version: "2", + bootclasspath_fragments: ["myotherbootclasspathfragment"], + } + + bootclasspath_fragment { + name: "myotherbootclasspathfragment", + apex_available: ["myotherapex"], + contents: [ + "myotherlib", + ], + } + + java_library { + name: "myotherlib", + apex_available: ["myotherapex"], + srcs: ["Test.java"], + min_sdk_version: "2", + permitted_packages: ["myothersdklibrary"], + compile_dex: true, + } + `), + + android.FixtureWithRootAndroidBp(` + sdk { + name: "mysdk", + bootclasspath_fragments: ["mybootclasspathfragment"], + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: [ + "mysdklibrary", + ], + fragments: [ + { + apex: "myotherapex", + module: "myotherbootclasspathfragment" + }, + ], + } + + java_sdk_library { + name: "mysdklibrary", + srcs: ["Test.java"], + shared_library: false, + public: {enabled: true}, + min_sdk_version: "2", + } + `), + ).RunTest(t) + + // A preparer to update the test fixture used when processing an unpackage snapshot. + preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("myapex", "mybootclasspathfragment") + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +prebuilt_bootclasspath_fragment { + name: "mybootclasspathfragment", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + contents: ["mysdklibrary"], + fragments: [ + { + apex: "myotherapex", + module: "myotherbootclasspathfragment", + }, + ], + hidden_api: { + stub_flags: "hiddenapi/stub-flags.csv", + annotation_flags: "hiddenapi/annotation-flags.csv", + metadata: "hiddenapi/metadata.csv", + index: "hiddenapi/index.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: false, + 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", + }, +} + `), + snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot), + snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot), + snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot), + ) +} + // Test that bootclasspath_fragment works with sdk. func TestBasicSdkWithBootclasspathFragment(t *testing.T) { android.GroupFixturePreparers( diff --git a/sdk/update.go b/sdk/update.go index 7d6780a18..e2e59979e 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -824,32 +824,65 @@ func outputUnnamedValue(contents *generatedContents, value reflect.Value) { case reflect.String: contents.UnindentedPrintf("%q", value) + case reflect.Ptr: + outputUnnamedValue(contents, value.Elem()) + case reflect.Slice: length := value.Len() if length == 0 { contents.UnindentedPrintf("[]") - } else if length == 1 { - contents.UnindentedPrintf("[") - outputUnnamedValue(contents, value.Index(0)) - contents.UnindentedPrintf("]") } else { - contents.UnindentedPrintf("[\n") - contents.Indent() - for i := 0; i < length; i++ { - itemValue := value.Index(i) - contents.IndentedPrintf("") - outputUnnamedValue(contents, itemValue) - contents.UnindentedPrintf(",\n") + firstValue := value.Index(0) + if length == 1 && !multiLineValue(firstValue) { + contents.UnindentedPrintf("[") + outputUnnamedValue(contents, firstValue) + contents.UnindentedPrintf("]") + } else { + contents.UnindentedPrintf("[\n") + contents.Indent() + for i := 0; i < length; i++ { + itemValue := value.Index(i) + contents.IndentedPrintf("") + outputUnnamedValue(contents, itemValue) + contents.UnindentedPrintf(",\n") + } + contents.Dedent() + contents.IndentedPrintf("]") } - contents.Dedent() - contents.IndentedPrintf("]") } + case reflect.Struct: + // Avoid unlimited recursion by requiring every structure to implement android.BpPrintable. + v := value.Interface() + if _, ok := v.(android.BpPrintable); !ok { + panic(fmt.Errorf("property value %#v of type %T does not implement android.BpPrintable", v, v)) + } + contents.UnindentedPrintf("{\n") + contents.Indent() + for f := 0; f < valueType.NumField(); f++ { + fieldType := valueType.Field(f) + if fieldType.Anonymous { + continue + } + fieldValue := value.Field(f) + fieldName := fieldType.Name + propertyName := proptools.PropertyNameForField(fieldName) + outputNamedValue(contents, propertyName, fieldValue) + } + contents.Dedent() + contents.IndentedPrintf("}") + default: panic(fmt.Errorf("Unknown type: %T of value %#v", value, value)) } } +// multiLineValue returns true if the supplied value may require multiple lines in the output. +func multiLineValue(value reflect.Value) bool { + kind := value.Kind() + return kind == reflect.Slice || kind == reflect.Struct +} + func (s *sdk) GetAndroidBpContentsForTests() string { contents := &generatedContents{} generateBpContents(contents, s.builderForTests.bpFile)