[automerge] java_sdk_library_import: Delegate OutputFiles to impl library if needed 2p: e89f3e22e5 am: 7b885d7ab1
Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/18579281
Change-Id: Ib75511d3c100e411af0a634589188c6f0535eca3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/android/sdk.go b/android/sdk.go
index 3a56240..9317910 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -961,3 +961,10 @@
}
var ExportedComponentsInfoProvider = blueprint.NewProvider(ExportedComponentsInfo{})
+
+// AdditionalSdkInfo contains additional properties to add to the generated SDK info file.
+type AdditionalSdkInfo struct {
+ Properties map[string]interface{}
+}
+
+var AdditionalSdkInfoProvider = blueprint.NewProvider(AdditionalSdkInfo{})
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 44650a6..9449707 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -212,6 +212,10 @@
mctx.CreateModule(systemModulesImportFactory, &props)
}
+func PrebuiltApiModuleName(module, scope, version string) string {
+ return module + ".api." + scope + "." + version
+}
+
func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
// <apiver>/<scope>/api/<module>.txt
apiLevelFiles := globApiDirs(mctx, p, "api/*.txt")
@@ -220,12 +224,9 @@
}
// Create modules for all (<module>, <scope, <version>) triplets,
- apiModuleName := func(module, scope, version string) string {
- return module + ".api." + scope + "." + version
- }
for _, f := range apiLevelFiles {
module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
- createApiModule(mctx, apiModuleName(module, scope, strconv.Itoa(version)), f)
+ createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
}
// Figure out the latest version of each module/scope
@@ -266,7 +267,7 @@
// Sort the keys in order to make build.ninja stable
for _, k := range android.SortedStringKeys(latest) {
info := latest[k]
- name := apiModuleName(info.module, info.scope, "latest")
+ name := PrebuiltApiModuleName(info.module, info.scope, "latest")
createApiModule(mctx, name, info.path)
}
@@ -278,7 +279,7 @@
filename, _, scope := parsePrebuiltPath(mctx, f)
referencedModule := strings.TrimSuffix(filename, "-incompatibilities")
- createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), f)
+ createApiModule(mctx, PrebuiltApiModuleName(referencedModule+"-incompatibilities", scope, "latest"), f)
incompatibilities[referencedModule+"."+scope] = true
}
@@ -286,7 +287,7 @@
// Create empty incompatibilities files for remaining modules
for _, k := range android.SortedStringKeys(latest) {
if _, ok := incompatibilities[k]; !ok {
- createEmptyFile(mctx, apiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
+ createEmptyFile(mctx, PrebuiltApiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
}
}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index cd8e875..8778937 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -97,6 +97,13 @@
// The tag to use to depend on the stubs source and API module.
stubsSourceAndApiTag scopeDependencyTag
+ // The tag to use to depend on the module that provides the latest version of the API .txt file.
+ latestApiModuleTag scopeDependencyTag
+
+ // The tag to use to depend on the module that provides the latest version of the API removed.txt
+ // file.
+ latestRemovedApiModuleTag scopeDependencyTag
+
// The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
apiFilePrefix string
@@ -158,6 +165,16 @@
apiScope: scope,
depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
}
+ scope.latestApiModuleTag = scopeDependencyTag{
+ name: name + "-latest-api",
+ apiScope: scope,
+ depInfoExtractor: (*scopePaths).extractLatestApiPath,
+ }
+ scope.latestRemovedApiModuleTag = scopeDependencyTag{
+ name: name + "-latest-removed-api",
+ apiScope: scope,
+ depInfoExtractor: (*scopePaths).extractLatestRemovedApiPath,
+ }
// To get the args needed to generate the stubs source append all the args from
// this scope and all the scopes it extends as each set of args adds additional
@@ -203,6 +220,24 @@
return scope.name
}
+// snapshotRelativeDir returns the snapshot directory into which the files related to scopes will
+// be stored.
+func (scope *apiScope) snapshotRelativeDir() string {
+ return filepath.Join("sdk_library", scope.name)
+}
+
+// snapshotRelativeCurrentApiTxtPath returns the snapshot path to the API .txt file for the named
+// library.
+func (scope *apiScope) snapshotRelativeCurrentApiTxtPath(name string) string {
+ return filepath.Join(scope.snapshotRelativeDir(), name+".txt")
+}
+
+// snapshotRelativeRemovedApiTxtPath returns the snapshot path to the removed API .txt file for the
+// named library.
+func (scope *apiScope) snapshotRelativeRemovedApiTxtPath(name string) string {
+ return filepath.Join(scope.snapshotRelativeDir(), name+"-removed.txt")
+}
+
type apiScopes []*apiScope
func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
@@ -539,6 +574,12 @@
// Extracted annotations.
annotationsZip android.OptionalPath
+
+ // The path to the latest API file.
+ latestApiPath android.OptionalPath
+
+ // The path to the latest removed API file.
+ latestRemovedApiPath android.OptionalPath
}
func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
@@ -602,6 +643,31 @@
})
}
+func extractSingleOptionalOutputPath(dep android.Module) (android.OptionalPath, error) {
+ var paths android.Paths
+ if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok {
+ paths = sourceFileProducer.Srcs()
+ } else {
+ return android.OptionalPath{}, fmt.Errorf("module %q does not produce source files", dep)
+ }
+ if len(paths) != 1 {
+ return android.OptionalPath{}, fmt.Errorf("expected one path from %q, got %q", dep, paths)
+ }
+ return android.OptionalPathForPath(paths[0]), nil
+}
+
+func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error {
+ outputPath, err := extractSingleOptionalOutputPath(dep)
+ paths.latestApiPath = outputPath
+ return err
+}
+
+func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error {
+ outputPath, err := extractSingleOptionalOutputPath(dep)
+ paths.latestRemovedApiPath = outputPath
+ return err
+}
+
type commonToSdkLibraryAndImportProperties struct {
// The naming scheme to use for the components that this module creates.
//
@@ -1174,6 +1240,16 @@
// Add a dependency on the stubs source in order to access both stubs source and api information.
ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
+
+ if module.compareAgainstLatestApi(apiScope) {
+ // Add dependencies on the latest finalized version of the API .txt file.
+ latestApiModuleName := module.latestApiModuleName(apiScope)
+ ctx.AddDependency(module, apiScope.latestApiModuleTag, latestApiModuleName)
+
+ // Add dependencies on the latest finalized version of the remove API .txt file.
+ latestRemovedApiModuleName := module.latestRemovedApiModuleName(apiScope)
+ ctx.AddDependency(module, apiScope.latestRemovedApiModuleTag, latestRemovedApiModuleName)
+ }
}
if module.requiresRuntimeImplementationLibrary() {
@@ -1194,13 +1270,13 @@
if apiScope.unstable {
continue
}
- if m := android.SrcIsModule(module.latestApiFilegroupName(apiScope)); !ctx.OtherModuleExists(m) {
+ if m := module.latestApiModuleName(apiScope); !ctx.OtherModuleExists(m) {
missingApiModules = append(missingApiModules, m)
}
- if m := android.SrcIsModule(module.latestRemovedApiFilegroupName(apiScope)); !ctx.OtherModuleExists(m) {
+ if m := module.latestRemovedApiModuleName(apiScope); !ctx.OtherModuleExists(m) {
missingApiModules = append(missingApiModules, m)
}
- if m := android.SrcIsModule(module.latestIncompatibilitiesFilegroupName(apiScope)); !ctx.OtherModuleExists(m) {
+ if m := module.latestIncompatibilitiesModuleName(apiScope); !ctx.OtherModuleExists(m) {
missingApiModules = append(missingApiModules, m)
}
}
@@ -1274,6 +1350,26 @@
// Make the set of components exported by this module available for use elsewhere.
exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedStringKeys(exportedComponents)}
ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
+
+ // Provide additional information for inclusion in an sdk's generated .info file.
+ additionalSdkInfo := map[string]interface{}{}
+ additionalSdkInfo["dist_stem"] = module.distStem()
+ baseModuleName := module.BaseModuleName()
+ scopes := map[string]interface{}{}
+ additionalSdkInfo["scopes"] = scopes
+ for scope, scopePaths := range module.scopePaths {
+ scopeInfo := map[string]interface{}{}
+ scopes[scope.name] = scopeInfo
+ scopeInfo["current_api"] = scope.snapshotRelativeCurrentApiTxtPath(baseModuleName)
+ scopeInfo["removed_api"] = scope.snapshotRelativeRemovedApiTxtPath(baseModuleName)
+ if p := scopePaths.latestApiPath; p.Valid() {
+ scopeInfo["latest_api"] = p.Path().String()
+ }
+ if p := scopePaths.latestRemovedApiPath; p.Valid() {
+ scopeInfo["latest_removed_api"] = p.Path().String()
+ }
+ }
+ ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
}
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
@@ -1319,16 +1415,32 @@
return proptools.StringDefault(module.sdkLibraryProperties.Dist_group, "unknown")
}
+func latestPrebuiltApiModuleName(name string, apiScope *apiScope) string {
+ return PrebuiltApiModuleName(name, apiScope.name, "latest")
+}
+
func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
- return ":" + module.distStem() + ".api." + apiScope.name + ".latest"
+ return ":" + module.latestApiModuleName(apiScope)
+}
+
+func (module *SdkLibrary) latestApiModuleName(apiScope *apiScope) string {
+ return latestPrebuiltApiModuleName(module.distStem(), apiScope)
}
func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
- return ":" + module.distStem() + "-removed.api." + apiScope.name + ".latest"
+ return ":" + module.latestRemovedApiModuleName(apiScope)
+}
+
+func (module *SdkLibrary) latestRemovedApiModuleName(apiScope *apiScope) string {
+ return latestPrebuiltApiModuleName(module.distStem()+"-removed", apiScope)
}
func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string {
- return ":" + module.distStem() + "-incompatibilities.api." + apiScope.name + ".latest"
+ return ":" + module.latestIncompatibilitiesModuleName(apiScope)
+}
+
+func (module *SdkLibrary) latestIncompatibilitiesModuleName(apiScope *apiScope) string {
+ return latestPrebuiltApiModuleName(module.distStem()+"-incompatibilities", apiScope)
}
func childModuleVisibility(childVisibility []string) []string {
@@ -1557,7 +1669,7 @@
props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
- if !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api) {
+ if module.compareAgainstLatestApi(apiScope) {
// check against the latest released API
latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
props.Previous_api = latestApiFilegroupName
@@ -1609,6 +1721,10 @@
mctx.CreateModule(DroidstubsFactory, &props)
}
+func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
+ return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api)
+}
+
// Implements android.ApexModule
func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
depTag := mctx.OtherModuleDependencyTag(dep)
@@ -2903,7 +3019,7 @@
if properties, ok := s.Scopes[apiScope]; ok {
scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
- scopeDir := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name)
+ scopeDir := apiScope.snapshotRelativeDir()
var jars []string
for _, p := range properties.Jars {
@@ -2927,13 +3043,13 @@
}
if properties.CurrentApiFile != nil {
- currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
+ currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(ctx.Name())
ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath)
scopeSet.AddProperty("current_api", currentApiSnapshotPath)
}
if properties.RemovedApiFile != nil {
- removedApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"-removed.txt")
+ removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(ctx.Name())
ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath)
scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 3500c84..805bc22 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -126,6 +126,10 @@
exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
expectedFooExportedComponents := []string{
+ "foo-removed.api.public.latest",
+ "foo-removed.api.system.latest",
+ "foo.api.public.latest",
+ "foo.api.system.latest",
"foo.stubs",
"foo.stubs.source",
"foo.stubs.source.system",
@@ -529,6 +533,8 @@
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
+ `sdklib-removed.api.public.latest`,
+ `sdklib.api.public.latest`,
`sdklib.impl`,
`sdklib.stubs`,
`sdklib.stubs.source`,
@@ -851,6 +857,8 @@
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
`prebuilt_sdklib`,
+ `sdklib-removed.api.public.latest`,
+ `sdklib.api.public.latest`,
`sdklib.impl`,
`sdklib.stubs`,
`sdklib.stubs.source`,
@@ -894,6 +902,8 @@
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`prebuilt_sdklib`,
+ `sdklib-removed.api.public.latest`,
+ `sdklib.api.public.latest`,
`sdklib.impl`,
`sdklib.stubs`,
`sdklib.stubs.source`,
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index a99fa1f..f33aa26 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -651,7 +651,19 @@
}
func TestSnapshotWithJavaSystemModules(t *testing.T) {
- result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
+ result := android.GroupFixturePreparers(
+ prepareForSdkTestWithJava,
+ java.PrepareForTestWithJavaDefaultModules,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithPrebuiltApisAndExtensions(map[string][]string{
+ "31": {"myjavalib"},
+ "32": {"myjavalib"},
+ "current": {"myjavalib"},
+ }, map[string][]string{
+ "1": {"myjavalib"},
+ "2": {"myjavalib"},
+ }),
+ ).RunTestWithBp(t, `
sdk {
name: "mysdk",
java_header_libs: ["exported-system-module"],
@@ -796,6 +808,53 @@
.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
`),
+ checkInfoContents(result.Config, `
+[
+ {
+ "@type": "sdk",
+ "@name": "mysdk",
+ "java_header_libs": [
+ "exported-system-module",
+ "system-module"
+ ],
+ "java_sdk_libs": [
+ "myjavalib"
+ ],
+ "java_system_modules": [
+ "my-system-modules"
+ ]
+ },
+ {
+ "@type": "java_library",
+ "@name": "exported-system-module"
+ },
+ {
+ "@type": "java_system_modules",
+ "@name": "my-system-modules",
+ "@deps": [
+ "exported-system-module",
+ "system-module"
+ ]
+ },
+ {
+ "@type": "java_sdk_library",
+ "@name": "myjavalib",
+ "dist_stem": "myjavalib",
+ "scopes": {
+ "public": {
+ "current_api": "sdk_library/public/myjavalib.txt",
+ "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.public.latest/gen/myjavalib.api.public.latest",
+ "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.public.latest/gen/myjavalib-removed.api.public.latest",
+ "removed_api": "sdk_library/public/myjavalib-removed.txt"
+ }
+ }
+ },
+ {
+ "@type": "java_library",
+ "@name": "system-module"
+ }
+]
+`),
)
}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index c8c7b79..b37eaad 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -75,6 +75,8 @@
snapshotFile android.OptionalPath
+ infoFile android.OptionalPath
+
// The builder, preserved for testing.
builderForTests *snapshotBuilder
}
@@ -191,27 +193,32 @@
}
// Generate the snapshot from the member info.
- p := s.buildSnapshot(ctx, sdkVariants)
- zip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), p.Base(), p)
- s.snapshotFile = android.OptionalPathForPath(zip)
+ s.buildSnapshot(ctx, sdkVariants)
}
}
func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries {
- if !s.snapshotFile.Valid() {
+ if !s.snapshotFile.Valid() != !s.infoFile.Valid() {
+ panic("Snapshot (%q) and info file (%q) should both be set or neither should be set.")
+ } else if !s.snapshotFile.Valid() {
return []android.AndroidMkEntries{}
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "FAKE",
OutputFile: s.snapshotFile,
- DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()),
+ DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path(), s.infoFile.Path()),
Include: "$(BUILD_PHONY_PACKAGE)",
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {
// Allow the sdk to be built by simply passing its name on the command line.
fmt.Fprintln(w, ".PHONY:", s.Name())
fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String())
+
+ // Allow the sdk info to be built by simply passing its name on the command line.
+ infoTarget := s.Name() + ".info"
+ fmt.Fprintln(w, ".PHONY:", infoTarget)
+ fmt.Fprintln(w, infoTarget+":", s.infoFile.String())
},
},
}}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 40de150..ccbeb8d 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -263,7 +263,10 @@
result := testSdkWithFs(t, sdk, nil)
CheckSnapshot(t, result, "mysdk", "",
- checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`))
+ checkAllOtherCopyRules(`
+.intermediates/mysdk/common_os/mysdk-current.info -> mysdk-current.info
+.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip
+`))
}
type EmbeddedPropertiesStruct struct {
diff --git a/sdk/testing.go b/sdk/testing.go
index 062f200..72344de 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -142,6 +142,7 @@
androidBpContents: sdk.GetAndroidBpContentsForTests(),
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
+ infoContents: sdk.GetInfoContentsForTests(),
snapshotTestCustomizations: map[snapshotTest]*snapshotTestCustomization{},
targetBuildRelease: sdk.builderForTests.targetBuildRelease,
}
@@ -402,6 +403,17 @@
}
}
+// Check that the snapshot's info contents are ciorrect.
+//
+// Both the expected and actual string are both trimmed before comparing.
+func checkInfoContents(config android.Config, expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "info contents do not match",
+ expected, android.StringRelativeToTop(config, info.infoContents))
+ }
+}
+
type resultChecker func(t *testing.T, result *android.TestResult)
// snapshotTestPreparer registers a preparer that will be used to customize the specified
@@ -479,6 +491,9 @@
// The contents of the versioned Android.bp file
androidVersionedBpContents string
+ // The contents of the info file.
+ infoContents string
+
// The paths, relative to the snapshot root, of all files and directories copied into the
// snapshot.
snapshotContents []string
diff --git a/sdk/update.go b/sdk/update.go
index 5db604b..e61ae0d 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -15,6 +15,8 @@
package sdk
import (
+ "bytes"
+ "encoding/json"
"fmt"
"reflect"
"sort"
@@ -219,9 +221,19 @@
exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
}
+ var container android.SdkAware
+ if parent != ctx.Module() {
+ container = parent.(android.SdkAware)
+ }
+
export := memberTag.ExportMember()
s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
- s, memberType, child.(android.SdkAware), export, exportedComponentsInfo,
+ sdkVariant: s,
+ memberType: memberType,
+ variant: child.(android.SdkAware),
+ container: container,
+ export: export,
+ exportedComponentsInfo: exportedComponentsInfo,
})
// Recurse down into the member's dependencies as it may have dependencies that need to be
@@ -311,7 +323,7 @@
// buildSnapshot is the main function in this source file. It creates rules to copy
// the contents (header files, stub libraries, etc) into the zip file.
-func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
+func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) {
// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
hasLicenses := false
@@ -370,9 +382,9 @@
// Unversioned modules are not required in that case because the numbered version will be a
// finalized version of the snapshot that is intended to be kept separate from the
generateUnversioned := version == soongSdkSnapshotVersionUnversioned || version == soongSdkSnapshotVersionCurrent
- snapshotZipFileSuffix := ""
+ snapshotFileSuffix := ""
if generateVersioned {
- snapshotZipFileSuffix = "-" + version
+ snapshotFileSuffix = "-" + version
}
currentBuildRelease := latestBuildRelease()
@@ -489,7 +501,7 @@
filesToZip := builder.filesToZip
// zip them all
- zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotFileSuffix)
outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
outputDesc := "Building snapshot for " + ctx.ModuleName()
@@ -502,7 +514,7 @@
zipFile = outputZipFile
desc = outputDesc
} else {
- intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotFileSuffix)
zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
desc = "Building intermediate snapshot for " + ctx.ModuleName()
}
@@ -527,7 +539,125 @@
})
}
- return outputZipFile
+ modules := s.generateInfoData(ctx, memberVariantDeps)
+
+ // Output the modules information as pretty printed JSON.
+ info := newGeneratedFile(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
+ output, err := json.MarshalIndent(modules, "", " ")
+ if err != nil {
+ ctx.ModuleErrorf("error generating %q: %s", info, err)
+ }
+ builder.infoContents = string(output)
+ info.generatedContents.UnindentedPrintf("%s", output)
+ info.build(pctx, ctx, nil)
+ infoPath := info.path
+ installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), infoPath.Base(), infoPath)
+ s.infoFile = android.OptionalPathForPath(installedInfo)
+
+ // Install the zip, making sure that the info file has been installed as well.
+ installedZip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
+ s.snapshotFile = android.OptionalPathForPath(installedZip)
+}
+
+type moduleInfo struct {
+ // The type of the module, e.g. java_sdk_library
+ moduleType string
+ // The name of the module.
+ name string
+ // A list of additional dependencies of the module.
+ deps []string
+ // Additional member specific properties.
+ // These will be added into the generated JSON alongside the above properties.
+ memberSpecific map[string]interface{}
+}
+
+func (m *moduleInfo) MarshalJSON() ([]byte, error) {
+ buffer := bytes.Buffer{}
+
+ separator := ""
+ writeObjectPair := func(key string, value interface{}) {
+ buffer.WriteString(fmt.Sprintf("%s%q: ", separator, key))
+ b, err := json.Marshal(value)
+ if err != nil {
+ panic(err)
+ }
+ buffer.Write(b)
+ separator = ","
+ }
+
+ buffer.WriteString("{")
+ writeObjectPair("@type", m.moduleType)
+ writeObjectPair("@name", m.name)
+ if m.deps != nil {
+ writeObjectPair("@deps", m.deps)
+ }
+ for _, k := range android.SortedStringKeys(m.memberSpecific) {
+ v := m.memberSpecific[k]
+ writeObjectPair(k, v)
+ }
+ buffer.WriteString("}")
+ return buffer.Bytes(), nil
+}
+
+var _ json.Marshaler = (*moduleInfo)(nil)
+
+// generateInfoData creates a list of moduleInfo structures that will be marshalled into JSON.
+func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) interface{} {
+ modules := []*moduleInfo{}
+ sdkInfo := moduleInfo{
+ moduleType: "sdk",
+ name: ctx.ModuleName(),
+ memberSpecific: map[string]interface{}{},
+ }
+ modules = append(modules, &sdkInfo)
+
+ name2Info := map[string]*moduleInfo{}
+ getModuleInfo := func(module android.Module) *moduleInfo {
+ name := module.Name()
+ info := name2Info[name]
+ if info == nil {
+ moduleType := ctx.OtherModuleType(module)
+ // Remove any suffix added when creating modules dynamically.
+ moduleType = strings.Split(moduleType, "__")[0]
+ info = &moduleInfo{
+ moduleType: moduleType,
+ name: name,
+ }
+
+ additionalSdkInfo := ctx.OtherModuleProvider(module, android.AdditionalSdkInfoProvider).(android.AdditionalSdkInfo)
+ info.memberSpecific = additionalSdkInfo.Properties
+
+ name2Info[name] = info
+ }
+ return info
+ }
+
+ for _, memberVariantDep := range memberVariantDeps {
+ propertyName := memberVariantDep.memberType.SdkPropertyName()
+ var list []string
+ if v, ok := sdkInfo.memberSpecific[propertyName]; ok {
+ list = v.([]string)
+ }
+
+ memberName := memberVariantDep.variant.Name()
+ list = append(list, memberName)
+ sdkInfo.memberSpecific[propertyName] = android.SortedUniqueStrings(list)
+
+ if memberVariantDep.container != nil {
+ containerInfo := getModuleInfo(memberVariantDep.container)
+ containerInfo.deps = android.SortedUniqueStrings(append(containerInfo.deps, memberName))
+ }
+
+ // Make sure that the module info is created for each module.
+ getModuleInfo(memberVariantDep.variant)
+ }
+
+ for _, memberName := range android.SortedStringKeys(name2Info) {
+ info := name2Info[memberName]
+ modules = append(modules, info)
+ }
+
+ return modules
}
// filterOutComponents removes any item from the deps list that is a component of another item in
@@ -1033,6 +1163,10 @@
return contents.content.String()
}
+func (s *sdk) GetInfoContentsForTests() string {
+ return s.builderForTests.infoContents
+}
+
func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
@@ -1087,6 +1221,9 @@
// The target build release for which the snapshot is to be generated.
targetBuildRelease *buildRelease
+
+ // The contents of the .info file that describes the sdk contents.
+ infoContents string
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -1322,6 +1459,11 @@
// The variant that is added to the sdk.
variant android.SdkAware
+ // The optional container of this member, i.e. the module that is depended upon by the sdk
+ // (possibly transitively) and whose dependency on this module is why it was added to the sdk.
+ // Is nil if this a direct dependency of the sdk.
+ container android.SdkAware
+
// True if the member should be exported, i.e. accessible, from outside the sdk.
export bool