Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b543097 authored by Paul Duffin's avatar Paul Duffin Committed by Gerrit Code Review
Browse files

Merge "For each sdk built generate a JSON file describing its contents"

parents b8f3f18c c6ba182f
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -795,6 +795,44 @@ sdk_snapshot {
.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
.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(`
[
  {
    "@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"
  },
  {
    "@type": "java_library",
    "@name": "system-module"
  }
]
`),
	)
}
+12 −5
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@ type sdk struct {

	snapshotFile android.OptionalPath

	infoFile android.OptionalPath

	// The builder, preserved for testing.
	builderForTests *snapshotBuilder
}
@@ -191,27 +193,32 @@ func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		}

		// 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())
			},
		},
	}}
+4 −1
Original line number Diff line number Diff line
@@ -263,7 +263,10 @@ func TestSdkInstall(t *testing.T) {
	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 {
+15 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk)
		androidBpContents:            sdk.GetAndroidBpContentsForTests(),
		androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
		androidVersionedBpContents:   sdk.GetVersionedAndroidBpContentsForTests(),
		infoContents:                 sdk.GetInfoContentsForTests(),
		snapshotTestCustomizations:   map[snapshotTest]*snapshotTestCustomization{},
		targetBuildRelease:           sdk.builderForTests.targetBuildRelease,
	}
@@ -402,6 +403,17 @@ func checkMergeZips(expected ...string) snapshotBuildInfoChecker {
	}
}

// Check that the snapshot's info contents are ciorrect.
//
// Both the expected and actual string are both trimmed before comparing.
func checkInfoContents(expected string) snapshotBuildInfoChecker {
	return func(info *snapshotBuildInfo) {
		info.t.Helper()
		android.AssertTrimmedStringEquals(info.t, "info contents do not match",
			expected, 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 @@ type snapshotBuildInfo struct {
	// 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
+143 −7
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
package sdk

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
@@ -219,9 +221,19 @@ func (s *sdk) collectMembers(ctx android.ModuleContext) {
				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 @@ func versionedSdkMemberName(ctx android.ModuleContext, memberName string, versio

// 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 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro
	// 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 @@ be unnecessary as every module in the sdk already has its own licenses property.
	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 @@ be unnecessary as every module in the sdk already has its own licenses property.
		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,120 @@ be unnecessary as every module in the sdk already has its own licenses property.
		})
	}

	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 dynamic properties.
	dynamic 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.dynamic) {
		v := m.dynamic[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(),
		dynamic:    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,
			}
			name2Info[name] = info
		}
		return info
	}

	for _, memberVariantDep := range memberVariantDeps {
		propertyName := memberVariantDep.memberType.SdkPropertyName()
		var list []string
		if v, ok := sdkInfo.dynamic[propertyName]; ok {
			list = v.([]string)
		}

		memberName := memberVariantDep.variant.Name()
		list = append(list, memberName)
		sdkInfo.dynamic[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 +1158,10 @@ func (s *sdk) GetAndroidBpContentsForTests() string {
	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 +1216,8 @@ type snapshotBuilder struct {

	// The target build release for which the snapshot is to be generated.
	targetBuildRelease *buildRelease

	infoContents string
}

func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -1322,6 +1453,11 @@ type sdkMemberVariantDep struct {
	// 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