1// Copyright (C) 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package sdk
16
17import (
18	"fmt"
19	"reflect"
20	"sort"
21	"strings"
22
23	"android/soong/apex"
24	"android/soong/cc"
25	"github.com/google/blueprint"
26	"github.com/google/blueprint/proptools"
27
28	"android/soong/android"
29)
30
31// Environment variables that affect the generated snapshot
32// ========================================================
33//
34// SOONG_SDK_SNAPSHOT_PREFER
35//     By default every unversioned module in the generated snapshot has prefer: false. Building it
36//     with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
37//
38// SOONG_SDK_SNAPSHOT_VERSION
39//     This provides control over the version of the generated snapshot.
40//
41//     SOONG_SDK_SNAPSHOT_VERSION=current will generate unversioned and versioned prebuilts and a
42//     versioned snapshot module. This is the default behavior. The zip file containing the
43//     generated snapshot will be <sdk-name>-current.zip.
44//
45//     SOONG_SDK_SNAPSHOT_VERSION=unversioned will generate unversioned prebuilts only and the zip
46//     file containing the generated snapshot will be <sdk-name>.zip.
47//
48//     SOONG_SDK_SNAPSHOT_VERSION=<number> will generate versioned prebuilts and a versioned
49//     snapshot module only. The zip file containing the generated snapshot will be
50//     <sdk-name>-<number>.zip.
51//
52
53var pctx = android.NewPackageContext("android/soong/sdk")
54
55var (
56	repackageZip = pctx.AndroidStaticRule("SnapshotRepackageZip",
57		blueprint.RuleParams{
58			Command: `${config.Zip2ZipCmd} -i $in -o $out -x META-INF/**/* "**/*:$destdir"`,
59			CommandDeps: []string{
60				"${config.Zip2ZipCmd}",
61			},
62		},
63		"destdir")
64
65	zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles",
66		blueprint.RuleParams{
67			Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`,
68			CommandDeps: []string{
69				"${config.SoongZipCmd}",
70			},
71			Rspfile:        "$out.rsp",
72			RspfileContent: "$in",
73		},
74		"basedir")
75
76	mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips",
77		blueprint.RuleParams{
78			Command: `${config.MergeZipsCmd} $out $in`,
79			CommandDeps: []string{
80				"${config.MergeZipsCmd}",
81			},
82		})
83)
84
85const (
86	soongSdkSnapshotVersionUnversioned = "unversioned"
87	soongSdkSnapshotVersionCurrent     = "current"
88)
89
90type generatedContents struct {
91	content     strings.Builder
92	indentLevel int
93}
94
95// generatedFile abstracts operations for writing contents into a file and emit a build rule
96// for the file.
97type generatedFile struct {
98	generatedContents
99	path android.OutputPath
100}
101
102func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
103	return &generatedFile{
104		path: android.PathForModuleOut(ctx, path...).OutputPath,
105	}
106}
107
108func (gc *generatedContents) Indent() {
109	gc.indentLevel++
110}
111
112func (gc *generatedContents) Dedent() {
113	gc.indentLevel--
114}
115
116func (gc *generatedContents) Printfln(format string, args ...interface{}) {
117	fmt.Fprintf(&(gc.content), strings.Repeat("    ", gc.indentLevel)+format+"\n", args...)
118}
119
120func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
121	rb := android.NewRuleBuilder(pctx, ctx)
122
123	content := gf.content.String()
124
125	// ninja consumes newline characters in rspfile_content. Prevent it by
126	// escaping the backslash in the newline character. The extra backslash
127	// is removed when the rspfile is written to the actual script file
128	content = strings.ReplaceAll(content, "\n", "\\n")
129
130	rb.Command().
131		Implicits(implicits).
132		Text("echo -n").Text(proptools.ShellEscape(content)).
133		// convert \\n to \n
134		Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
135	rb.Command().
136		Text("chmod a+x").Output(gf.path)
137	rb.Build(gf.path.Base(), "Build "+gf.path.Base())
138}
139
140// Collect all the members.
141//
142// Updates the sdk module with a list of sdkMemberVariantDep instances and details as to which
143// multilibs (32/64/both) are used by this sdk variant.
144func (s *sdk) collectMembers(ctx android.ModuleContext) {
145	s.multilibUsages = multilibNone
146	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
147		tag := ctx.OtherModuleDependencyTag(child)
148		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
149			memberType := memberTag.SdkMemberType(child)
150
151			// If a nil SdkMemberType was returned then this module should not be added to the sdk.
152			if memberType == nil {
153				return false
154			}
155
156			// Make sure that the resolved module is allowed in the member list property.
157			if !memberType.IsInstance(child) {
158				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
159			}
160
161			// Keep track of which multilib variants are used by the sdk.
162			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
163
164			var exportedComponentsInfo android.ExportedComponentsInfo
165			if ctx.OtherModuleHasProvider(child, android.ExportedComponentsInfoProvider) {
166				exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
167			}
168
169			export := memberTag.ExportMember()
170			s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
171				s, memberType, child.(android.SdkAware), export, exportedComponentsInfo,
172			})
173
174			// Recurse down into the member's dependencies as it may have dependencies that need to be
175			// automatically added to the sdk.
176			return true
177		}
178
179		return false
180	})
181}
182
183// groupMemberVariantsByMemberThenType groups the member variant dependencies so that all the
184// variants of each member are grouped together within an sdkMember instance.
185//
186// The sdkMember instances are then grouped into slices by member type. Within each such slice the
187// sdkMember instances appear in the order they were added as dependencies.
188//
189// Finally, the member type slices are concatenated together to form a single slice. The order in
190// which they are concatenated is the order in which the member types were registered in the
191// android.SdkMemberTypesRegistry.
192func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
193	byType := make(map[android.SdkMemberType][]*sdkMember)
194	byName := make(map[string]*sdkMember)
195
196	for _, memberVariantDep := range memberVariantDeps {
197		memberType := memberVariantDep.memberType
198		variant := memberVariantDep.variant
199
200		name := ctx.OtherModuleName(variant)
201		member := byName[name]
202		if member == nil {
203			member = &sdkMember{memberType: memberType, name: name}
204			byName[name] = member
205			byType[memberType] = append(byType[memberType], member)
206		}
207
208		// Only append new variants to the list. This is needed because a member can be both
209		// exported by the sdk and also be a transitive sdk member.
210		member.variants = appendUniqueVariants(member.variants, variant)
211	}
212
213	var members []*sdkMember
214	for _, memberListProperty := range s.memberListProperties() {
215		membersOfType := byType[memberListProperty.memberType]
216		members = append(members, membersOfType...)
217	}
218
219	return members
220}
221
222func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
223	for _, v := range variants {
224		if v == newVariant {
225			return variants
226		}
227	}
228	return append(variants, newVariant)
229}
230
231// SDK directory structure
232// <sdk_root>/
233//     Android.bp   : definition of a 'sdk' module is here. This is a hand-made one.
234//     <api_ver>/   : below this directory are all auto-generated
235//         Android.bp   : definition of 'sdk_snapshot' module is here
236//         aidl/
237//            frameworks/base/core/..../IFoo.aidl   : an exported AIDL file
238//         java/
239//            <module_name>.jar    : the stub jar for a java library 'module_name'
240//         include/
241//            bionic/libc/include/stdlib.h   : an exported header file
242//         include_gen/
243//            <module_name>/com/android/.../IFoo.h : a generated header file
244//         <arch>/include/   : arch-specific exported headers
245//         <arch>/include_gen/   : arch-specific generated headers
246//         <arch>/lib/
247//            libFoo.so   : a stub library
248
249// A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot
250// This isn't visible to users, so could be changed in future.
251func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string {
252	return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version
253}
254
255// buildSnapshot is the main function in this source file. It creates rules to copy
256// the contents (header files, stub libraries, etc) into the zip file.
257func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
258
259	// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
260	hasLicenses := false
261	var memberVariantDeps []sdkMemberVariantDep
262	for _, sdkVariant := range sdkVariants {
263		memberVariantDeps = append(memberVariantDeps, sdkVariant.memberVariantDeps...)
264	}
265
266	// Filter out any sdkMemberVariantDep that is a component of another.
267	memberVariantDeps = filterOutComponents(ctx, memberVariantDeps)
268
269	// Record the names of all the members, both explicitly specified and implicitly
270	// included.
271	allMembersByName := make(map[string]struct{})
272	exportedMembersByName := make(map[string]struct{})
273
274	addMember := func(name string, export bool) {
275		allMembersByName[name] = struct{}{}
276		if export {
277			exportedMembersByName[name] = struct{}{}
278		}
279	}
280
281	for _, memberVariantDep := range memberVariantDeps {
282		name := memberVariantDep.variant.Name()
283		export := memberVariantDep.export
284
285		addMember(name, export)
286
287		// Add any components provided by the module.
288		for _, component := range memberVariantDep.exportedComponentsInfo.Components {
289			addMember(component, export)
290		}
291
292		if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
293			hasLicenses = true
294		}
295	}
296
297	snapshotDir := android.PathForModuleOut(ctx, "snapshot")
298
299	bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
300
301	bpFile := &bpFile{
302		modules: make(map[string]*bpModule),
303	}
304
305	config := ctx.Config()
306	version := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_VERSION", "current")
307
308	// Generate versioned modules in the snapshot unless an unversioned snapshot has been requested.
309	generateVersioned := version != soongSdkSnapshotVersionUnversioned
310
311	// Generate unversioned modules in the snapshot unless a numbered snapshot has been requested.
312	//
313	// Unversioned modules are not required in that case because the numbered version will be a
314	// finalized version of the snapshot that is intended to be kept separate from the
315	generateUnversioned := version == soongSdkSnapshotVersionUnversioned || version == soongSdkSnapshotVersionCurrent
316	snapshotZipFileSuffix := ""
317	if generateVersioned {
318		snapshotZipFileSuffix = "-" + version
319	}
320
321	builder := &snapshotBuilder{
322		ctx:                   ctx,
323		sdk:                   s,
324		version:               version,
325		snapshotDir:           snapshotDir.OutputPath,
326		copies:                make(map[string]string),
327		filesToZip:            []android.Path{bp.path},
328		bpFile:                bpFile,
329		prebuiltModules:       make(map[string]*bpModule),
330		allMembersByName:      allMembersByName,
331		exportedMembersByName: exportedMembersByName,
332	}
333	s.builderForTests = builder
334
335	// If the sdk snapshot includes any license modules then add a package module which has a
336	// default_applicable_licenses property. That will prevent the LSC license process from updating
337	// the generated Android.bp file to add a package module that includes all licenses used by all
338	// the modules in that package. That would be unnecessary as every module in the sdk should have
339	// their own licenses property specified.
340	if hasLicenses {
341		pkg := bpFile.newModule("package")
342		property := "default_applicable_licenses"
343		pkg.AddCommentForProperty(property, `
344A default list here prevents the license LSC from adding its own list which would
345be unnecessary as every module in the sdk already has its own licenses property.
346`)
347		pkg.AddProperty(property, []string{"Android-Apache-2.0"})
348		bpFile.AddModule(pkg)
349	}
350
351	// Group the variants for each member module together and then group the members of each member
352	// type together.
353	members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
354
355	// Create the prebuilt modules for each of the member modules.
356	for _, member := range members {
357		memberType := member.memberType
358
359		memberCtx := &memberContext{ctx, builder, memberType, member.name}
360
361		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
362		s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
363	}
364
365	// Create a transformer that will transform an unversioned module into a versioned module.
366	unversionedToVersionedTransformer := unversionedToVersionedTransformation{builder: builder}
367
368	// Create a transformer that will transform an unversioned module by replacing any references
369	// to internal members with a unique module name and setting prefer: false.
370	unversionedTransformer := unversionedTransformation{
371		builder: builder,
372	}
373
374	for _, unversioned := range builder.prebuiltOrder {
375		// Prune any empty property sets.
376		unversioned = unversioned.transform(pruneEmptySetTransformer{})
377
378		if generateVersioned {
379			// Copy the unversioned module so it can be modified to make it versioned.
380			versioned := unversioned.deepCopy()
381
382			// Transform the unversioned module into a versioned one.
383			versioned.transform(unversionedToVersionedTransformer)
384			bpFile.AddModule(versioned)
385		}
386
387		if generateUnversioned {
388			// Transform the unversioned module to make it suitable for use in the snapshot.
389			unversioned.transform(unversionedTransformer)
390			bpFile.AddModule(unversioned)
391		}
392	}
393
394	if generateVersioned {
395		// Add the sdk/module_exports_snapshot module to the bp file.
396		s.addSnapshotModule(ctx, builder, sdkVariants, memberVariantDeps)
397	}
398
399	// generate Android.bp
400	bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
401	generateBpContents(&bp.generatedContents, bpFile)
402
403	contents := bp.content.String()
404	syntaxCheckSnapshotBpFile(ctx, contents)
405
406	bp.build(pctx, ctx, nil)
407
408	filesToZip := builder.filesToZip
409
410	// zip them all
411	zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotZipFileSuffix)
412	outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
413	outputDesc := "Building snapshot for " + ctx.ModuleName()
414
415	// If there are no zips to merge then generate the output zip directly.
416	// Otherwise, generate an intermediate zip file into which other zips can be
417	// merged.
418	var zipFile android.OutputPath
419	var desc string
420	if len(builder.zipsToMerge) == 0 {
421		zipFile = outputZipFile
422		desc = outputDesc
423	} else {
424		intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotZipFileSuffix)
425		zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
426		desc = "Building intermediate snapshot for " + ctx.ModuleName()
427	}
428
429	ctx.Build(pctx, android.BuildParams{
430		Description: desc,
431		Rule:        zipFiles,
432		Inputs:      filesToZip,
433		Output:      zipFile,
434		Args: map[string]string{
435			"basedir": builder.snapshotDir.String(),
436		},
437	})
438
439	if len(builder.zipsToMerge) != 0 {
440		ctx.Build(pctx, android.BuildParams{
441			Description: outputDesc,
442			Rule:        mergeZips,
443			Input:       zipFile,
444			Inputs:      builder.zipsToMerge,
445			Output:      outputZipFile,
446		})
447	}
448
449	return outputZipFile
450}
451
452// filterOutComponents removes any item from the deps list that is a component of another item in
453// the deps list, e.g. if the deps list contains "foo" and "foo.stubs" which is component of "foo"
454// then it will remove "foo.stubs" from the deps.
455func filterOutComponents(ctx android.ModuleContext, deps []sdkMemberVariantDep) []sdkMemberVariantDep {
456	// Collate the set of components that all the modules added to the sdk provide.
457	components := map[string]*sdkMemberVariantDep{}
458	for i, _ := range deps {
459		dep := &deps[i]
460		for _, c := range dep.exportedComponentsInfo.Components {
461			components[c] = dep
462		}
463	}
464
465	// If no module provides components then return the input deps unfiltered.
466	if len(components) == 0 {
467		return deps
468	}
469
470	filtered := make([]sdkMemberVariantDep, 0, len(deps))
471	for _, dep := range deps {
472		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(dep.variant))
473		if owner, ok := components[name]; ok {
474			// This is a component of another module that is a member of the sdk.
475
476			// If the component is exported but the owning module is not then the configuration is not
477			// supported.
478			if dep.export && !owner.export {
479				ctx.ModuleErrorf("Module %s is internal to the SDK but provides component %s which is used outside the SDK")
480				continue
481			}
482
483			// This module must not be added to the list of members of the sdk as that would result in a
484			// duplicate module in the sdk snapshot.
485			continue
486		}
487
488		filtered = append(filtered, dep)
489	}
490	return filtered
491}
492
493// addSnapshotModule adds the sdk_snapshot/module_exports_snapshot module to the builder.
494func (s *sdk) addSnapshotModule(ctx android.ModuleContext, builder *snapshotBuilder, sdkVariants []*sdk, memberVariantDeps []sdkMemberVariantDep) {
495	bpFile := builder.bpFile
496
497	snapshotName := ctx.ModuleName() + string(android.SdkVersionSeparator) + builder.version
498	var snapshotModuleType string
499	if s.properties.Module_exports {
500		snapshotModuleType = "module_exports_snapshot"
501	} else {
502		snapshotModuleType = "sdk_snapshot"
503	}
504	snapshotModule := bpFile.newModule(snapshotModuleType)
505	snapshotModule.AddProperty("name", snapshotName)
506
507	// Make sure that the snapshot has the same visibility as the sdk.
508	visibility := android.EffectiveVisibilityRules(ctx, s).Strings()
509	if len(visibility) != 0 {
510		snapshotModule.AddProperty("visibility", visibility)
511	}
512
513	addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
514
515	combinedPropertiesList := s.collateSnapshotModuleInfo(ctx, sdkVariants, memberVariantDeps)
516	commonCombinedProperties := s.optimizeSnapshotModuleProperties(ctx, combinedPropertiesList)
517
518	s.addSnapshotPropertiesToPropertySet(builder, snapshotModule, commonCombinedProperties)
519
520	targetPropertySet := snapshotModule.AddPropertySet("target")
521
522	// Create a mapping from osType to combined properties.
523	osTypeToCombinedProperties := map[android.OsType]*combinedSnapshotModuleProperties{}
524	for _, combined := range combinedPropertiesList {
525		osTypeToCombinedProperties[combined.sdkVariant.Os()] = combined
526	}
527
528	// Iterate over the os types in a fixed order.
529	for _, osType := range s.getPossibleOsTypes() {
530		if combined, ok := osTypeToCombinedProperties[osType]; ok {
531			osPropertySet := targetPropertySet.AddPropertySet(osType.Name)
532
533			s.addSnapshotPropertiesToPropertySet(builder, osPropertySet, combined)
534		}
535	}
536
537	// If host is supported and any member is host OS dependent then disable host
538	// by default, so that we can enable each host OS variant explicitly. This
539	// avoids problems with implicitly enabled OS variants when the snapshot is
540	// used, which might be different from this run (e.g. different build OS).
541	if s.HostSupported() {
542		var supportedHostTargets []string
543		for _, memberVariantDep := range memberVariantDeps {
544			if memberVariantDep.memberType.IsHostOsDependent() && memberVariantDep.variant.Target().Os.Class == android.Host {
545				targetString := memberVariantDep.variant.Target().Os.String() + "_" + memberVariantDep.variant.Target().Arch.ArchType.String()
546				if !android.InList(targetString, supportedHostTargets) {
547					supportedHostTargets = append(supportedHostTargets, targetString)
548				}
549			}
550		}
551		if len(supportedHostTargets) > 0 {
552			hostPropertySet := targetPropertySet.AddPropertySet("host")
553			hostPropertySet.AddProperty("enabled", false)
554		}
555		// Enable the <os>_<arch> variant explicitly when we've disabled it by default on host.
556		for _, hostTarget := range supportedHostTargets {
557			propertySet := targetPropertySet.AddPropertySet(hostTarget)
558			propertySet.AddProperty("enabled", true)
559		}
560	}
561
562	// Prune any empty property sets.
563	snapshotModule.transform(pruneEmptySetTransformer{})
564
565	bpFile.AddModule(snapshotModule)
566}
567
568// Check the syntax of the generated Android.bp file contents and if they are
569// invalid then log an error with the contents (tagged with line numbers) and the
570// errors that were found so that it is easy to see where the problem lies.
571func syntaxCheckSnapshotBpFile(ctx android.ModuleContext, contents string) {
572	errs := android.CheckBlueprintSyntax(ctx, "Android.bp", contents)
573	if len(errs) != 0 {
574		message := &strings.Builder{}
575		_, _ = fmt.Fprint(message, `errors in generated Android.bp snapshot:
576
577Generated Android.bp contents
578========================================================================
579`)
580		for i, line := range strings.Split(contents, "\n") {
581			_, _ = fmt.Fprintf(message, "%6d:    %s\n", i+1, line)
582		}
583
584		_, _ = fmt.Fprint(message, `
585========================================================================
586
587Errors found:
588`)
589
590		for _, err := range errs {
591			_, _ = fmt.Fprintf(message, "%s\n", err.Error())
592		}
593
594		ctx.ModuleErrorf("%s", message.String())
595	}
596}
597
598func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) {
599	err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice)
600	if err != nil {
601		ctx.ModuleErrorf("error extracting common properties: %s", err)
602	}
603}
604
605// snapshotModuleStaticProperties contains snapshot static (i.e. not dynamically generated) properties.
606type snapshotModuleStaticProperties struct {
607	Compile_multilib string `android:"arch_variant"`
608}
609
610// combinedSnapshotModuleProperties are the properties that are associated with the snapshot module.
611type combinedSnapshotModuleProperties struct {
612	// The sdk variant from which this information was collected.
613	sdkVariant *sdk
614
615	// Static snapshot module properties.
616	staticProperties *snapshotModuleStaticProperties
617
618	// The dynamically generated member list properties.
619	dynamicProperties interface{}
620}
621
622// collateSnapshotModuleInfo collates all the snapshot module info from supplied sdk variants.
623func (s *sdk) collateSnapshotModuleInfo(ctx android.BaseModuleContext, sdkVariants []*sdk, memberVariantDeps []sdkMemberVariantDep) []*combinedSnapshotModuleProperties {
624	sdkVariantToCombinedProperties := map[*sdk]*combinedSnapshotModuleProperties{}
625	var list []*combinedSnapshotModuleProperties
626	for _, sdkVariant := range sdkVariants {
627		staticProperties := &snapshotModuleStaticProperties{
628			Compile_multilib: sdkVariant.multilibUsages.String(),
629		}
630		dynamicProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
631
632		combinedProperties := &combinedSnapshotModuleProperties{
633			sdkVariant:        sdkVariant,
634			staticProperties:  staticProperties,
635			dynamicProperties: dynamicProperties,
636		}
637		sdkVariantToCombinedProperties[sdkVariant] = combinedProperties
638
639		list = append(list, combinedProperties)
640	}
641
642	for _, memberVariantDep := range memberVariantDeps {
643		// If the member dependency is internal then do not add the dependency to the snapshot member
644		// list properties.
645		if !memberVariantDep.export {
646			continue
647		}
648
649		combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
650		memberListProperty := s.memberListProperty(memberVariantDep.memberType)
651		memberName := ctx.OtherModuleName(memberVariantDep.variant)
652
653		if memberListProperty.getter == nil {
654			continue
655		}
656
657		// Append the member to the appropriate list, if it is not already present in the list.
658		memberList := memberListProperty.getter(combined.dynamicProperties)
659		if !android.InList(memberName, memberList) {
660			memberList = append(memberList, memberName)
661		}
662		memberListProperty.setter(combined.dynamicProperties, memberList)
663	}
664
665	return list
666}
667
668func (s *sdk) optimizeSnapshotModuleProperties(ctx android.ModuleContext, list []*combinedSnapshotModuleProperties) *combinedSnapshotModuleProperties {
669
670	// Extract the dynamic properties and add them to a list of propertiesContainer.
671	propertyContainers := []propertiesContainer{}
672	for _, i := range list {
673		propertyContainers = append(propertyContainers, sdkVariantPropertiesContainer{
674			sdkVariant: i.sdkVariant,
675			properties: i.dynamicProperties,
676		})
677	}
678
679	// Extract the common members, removing them from the original properties.
680	commonDynamicProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
681	extractor := newCommonValueExtractor(commonDynamicProperties)
682	extractCommonProperties(ctx, extractor, commonDynamicProperties, propertyContainers)
683
684	// Extract the static properties and add them to a list of propertiesContainer.
685	propertyContainers = []propertiesContainer{}
686	for _, i := range list {
687		propertyContainers = append(propertyContainers, sdkVariantPropertiesContainer{
688			sdkVariant: i.sdkVariant,
689			properties: i.staticProperties,
690		})
691	}
692
693	commonStaticProperties := &snapshotModuleStaticProperties{}
694	extractor = newCommonValueExtractor(commonStaticProperties)
695	extractCommonProperties(ctx, extractor, &commonStaticProperties, propertyContainers)
696
697	return &combinedSnapshotModuleProperties{
698		sdkVariant:        nil,
699		staticProperties:  commonStaticProperties,
700		dynamicProperties: commonDynamicProperties,
701	}
702}
703
704func (s *sdk) addSnapshotPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, combined *combinedSnapshotModuleProperties) {
705	staticProperties := combined.staticProperties
706	multilib := staticProperties.Compile_multilib
707	if multilib != "" && multilib != "both" {
708		// Compile_multilib defaults to both so only needs to be set when it's specified and not both.
709		propertySet.AddProperty("compile_multilib", multilib)
710	}
711
712	dynamicMemberTypeListProperties := combined.dynamicProperties
713	for _, memberListProperty := range s.memberListProperties() {
714		if memberListProperty.getter == nil {
715			continue
716		}
717		names := memberListProperty.getter(dynamicMemberTypeListProperties)
718		if len(names) > 0 {
719			propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
720		}
721	}
722}
723
724type propertyTag struct {
725	name string
726}
727
728// A BpPropertyTag to add to a property that contains references to other sdk members.
729//
730// This will cause the references to be rewritten to a versioned reference in the version
731// specific instance of a snapshot module.
732var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
733var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
734
735// A BpPropertyTag that indicates the property should only be present in the versioned
736// module.
737//
738// This will cause the property to be removed from the unversioned instance of a
739// snapshot module.
740var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"}
741
742type unversionedToVersionedTransformation struct {
743	identityTransformation
744	builder *snapshotBuilder
745}
746
747func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
748	// Use a versioned name for the module but remember the original name for the
749	// snapshot.
750	name := module.Name()
751	module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
752	module.insertAfter("name", "sdk_member_name", name)
753	// Remove the prefer property if present as versioned modules never need marking with prefer.
754	module.removeProperty("prefer")
755	return module
756}
757
758func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
759	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
760		required := tag == requiredSdkMemberReferencePropertyTag
761		return t.builder.versionedSdkMemberNames(value.([]string), required), tag
762	} else {
763		return value, tag
764	}
765}
766
767type unversionedTransformation struct {
768	identityTransformation
769	builder *snapshotBuilder
770}
771
772func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
773	// If the module is an internal member then use a unique name for it.
774	name := module.Name()
775	module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
776	return module
777}
778
779func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
780	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
781		required := tag == requiredSdkMemberReferencePropertyTag
782		return t.builder.unversionedSdkMemberNames(value.([]string), required), tag
783	} else if tag == sdkVersionedOnlyPropertyTag {
784		// The property is not allowed in the unversioned module so remove it.
785		return nil, nil
786	} else {
787		return value, tag
788	}
789}
790
791type pruneEmptySetTransformer struct {
792	identityTransformation
793}
794
795var _ bpTransformer = (*pruneEmptySetTransformer)(nil)
796
797func (t pruneEmptySetTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
798	if len(propertySet.properties) == 0 {
799		return nil, nil
800	} else {
801		return propertySet, tag
802	}
803}
804
805func generateBpContents(contents *generatedContents, bpFile *bpFile) {
806	generateFilteredBpContents(contents, bpFile, func(*bpModule) bool {
807		return true
808	})
809}
810
811func generateFilteredBpContents(contents *generatedContents, bpFile *bpFile, moduleFilter func(module *bpModule) bool) {
812	contents.Printfln("// This is auto-generated. DO NOT EDIT.")
813	for _, bpModule := range bpFile.order {
814		if moduleFilter(bpModule) {
815			contents.Printfln("")
816			contents.Printfln("%s {", bpModule.moduleType)
817			outputPropertySet(contents, bpModule.bpPropertySet)
818			contents.Printfln("}")
819		}
820	}
821}
822
823func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
824	contents.Indent()
825
826	addComment := func(name string) {
827		if text, ok := set.comments[name]; ok {
828			for _, line := range strings.Split(text, "\n") {
829				contents.Printfln("// %s", line)
830			}
831		}
832	}
833
834	// Output the properties first, followed by the nested sets. This ensures a
835	// consistent output irrespective of whether property sets are created before
836	// or after the properties. This simplifies the creation of the module.
837	for _, name := range set.order {
838		value := set.getValue(name)
839
840		// Do not write property sets in the properties phase.
841		if _, ok := value.(*bpPropertySet); ok {
842			continue
843		}
844
845		addComment(name)
846		switch v := value.(type) {
847		case []string:
848			length := len(v)
849			if length > 1 {
850				contents.Printfln("%s: [", name)
851				contents.Indent()
852				for i := 0; i < length; i = i + 1 {
853					contents.Printfln("%q,", v[i])
854				}
855				contents.Dedent()
856				contents.Printfln("],")
857			} else if length == 0 {
858				contents.Printfln("%s: [],", name)
859			} else {
860				contents.Printfln("%s: [%q],", name, v[0])
861			}
862
863		case bool:
864			contents.Printfln("%s: %t,", name, v)
865
866		default:
867			contents.Printfln("%s: %q,", name, value)
868		}
869	}
870
871	for _, name := range set.order {
872		value := set.getValue(name)
873
874		// Only write property sets in the sets phase.
875		switch v := value.(type) {
876		case *bpPropertySet:
877			addComment(name)
878			contents.Printfln("%s: {", name)
879			outputPropertySet(contents, v)
880			contents.Printfln("},")
881		}
882	}
883
884	contents.Dedent()
885}
886
887func (s *sdk) GetAndroidBpContentsForTests() string {
888	contents := &generatedContents{}
889	generateBpContents(contents, s.builderForTests.bpFile)
890	return contents.content.String()
891}
892
893func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
894	contents := &generatedContents{}
895	generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
896		name := module.Name()
897		// Include modules that are either unversioned or have no name.
898		return !strings.Contains(name, "@")
899	})
900	return contents.content.String()
901}
902
903func (s *sdk) GetVersionedAndroidBpContentsForTests() string {
904	contents := &generatedContents{}
905	generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
906		name := module.Name()
907		// Include modules that are either versioned or have no name.
908		return name == "" || strings.Contains(name, "@")
909	})
910	return contents.content.String()
911}
912
913type snapshotBuilder struct {
914	ctx android.ModuleContext
915	sdk *sdk
916
917	// The version of the generated snapshot.
918	//
919	// See the documentation of SOONG_SDK_SNAPSHOT_VERSION above for details of the valid values of
920	// this field.
921	version string
922
923	snapshotDir android.OutputPath
924	bpFile      *bpFile
925
926	// Map from destination to source of each copy - used to eliminate duplicates and
927	// detect conflicts.
928	copies map[string]string
929
930	filesToZip  android.Paths
931	zipsToMerge android.Paths
932
933	prebuiltModules map[string]*bpModule
934	prebuiltOrder   []*bpModule
935
936	// The set of all members by name.
937	allMembersByName map[string]struct{}
938
939	// The set of exported members by name.
940	exportedMembersByName map[string]struct{}
941}
942
943func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
944	if existing, ok := s.copies[dest]; ok {
945		if existing != src.String() {
946			s.ctx.ModuleErrorf("conflicting copy, %s copied from both %s and %s", dest, existing, src)
947			return
948		}
949	} else {
950		path := s.snapshotDir.Join(s.ctx, dest)
951		s.ctx.Build(pctx, android.BuildParams{
952			Rule:   android.Cp,
953			Input:  src,
954			Output: path,
955		})
956		s.filesToZip = append(s.filesToZip, path)
957
958		s.copies[dest] = src.String()
959	}
960}
961
962func (s *snapshotBuilder) UnzipToSnapshot(zipPath android.Path, destDir string) {
963	ctx := s.ctx
964
965	// Repackage the zip file so that the entries are in the destDir directory.
966	// This will allow the zip file to be merged into the snapshot.
967	tmpZipPath := android.PathForModuleOut(ctx, "tmp", destDir+".zip").OutputPath
968
969	ctx.Build(pctx, android.BuildParams{
970		Description: "Repackaging zip file " + destDir + " for snapshot " + ctx.ModuleName(),
971		Rule:        repackageZip,
972		Input:       zipPath,
973		Output:      tmpZipPath,
974		Args: map[string]string{
975			"destdir": destDir,
976		},
977	})
978
979	// Add the repackaged zip file to the files to merge.
980	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
981}
982
983func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
984	name := member.Name()
985	if s.prebuiltModules[name] != nil {
986		panic(fmt.Sprintf("Duplicate module detected, module %s has already been added", name))
987	}
988
989	m := s.bpFile.newModule(moduleType)
990	m.AddProperty("name", name)
991
992	variant := member.Variants()[0]
993
994	if s.isInternalMember(name) {
995		// An internal member is only referenced from the sdk snapshot which is in the
996		// same package so can be marked as private.
997		m.AddProperty("visibility", []string{"//visibility:private"})
998	} else {
999		// Extract visibility information from a member variant. All variants have the same
1000		// visibility so it doesn't matter which one is used.
1001		visibilityRules := android.EffectiveVisibilityRules(s.ctx, variant)
1002
1003		// Add any additional visibility rules needed for the prebuilts to reference each other.
1004		err := visibilityRules.Widen(s.sdk.properties.Prebuilt_visibility)
1005		if err != nil {
1006			s.ctx.PropertyErrorf("prebuilt_visibility", "%s", err)
1007		}
1008
1009		visibility := visibilityRules.Strings()
1010		if len(visibility) != 0 {
1011			m.AddProperty("visibility", visibility)
1012		}
1013	}
1014
1015	// Where available copy apex_available properties from the member.
1016	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
1017		apexAvailable := apexAware.ApexAvailable()
1018		if len(apexAvailable) == 0 {
1019			// //apex_available:platform is the default.
1020			apexAvailable = []string{android.AvailableToPlatform}
1021		}
1022
1023		// Add in any baseline apex available settings.
1024		apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
1025
1026		// Remove duplicates and sort.
1027		apexAvailable = android.FirstUniqueStrings(apexAvailable)
1028		sort.Strings(apexAvailable)
1029
1030		m.AddProperty("apex_available", apexAvailable)
1031	}
1032
1033	// The licenses are the same for all variants.
1034	mctx := s.ctx
1035	licenseInfo := mctx.OtherModuleProvider(variant, android.LicenseInfoProvider).(android.LicenseInfo)
1036	if len(licenseInfo.Licenses) > 0 {
1037		m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag())
1038	}
1039
1040	deviceSupported := false
1041	hostSupported := false
1042
1043	for _, variant := range member.Variants() {
1044		osClass := variant.Target().Os.Class
1045		if osClass == android.Host {
1046			hostSupported = true
1047		} else if osClass == android.Device {
1048			deviceSupported = true
1049		}
1050	}
1051
1052	addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
1053
1054	// Disable installation in the versioned module of those modules that are ever installable.
1055	if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
1056		if installable.EverInstallable() {
1057			m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag)
1058		}
1059	}
1060
1061	s.prebuiltModules[name] = m
1062	s.prebuiltOrder = append(s.prebuiltOrder, m)
1063	return m
1064}
1065
1066func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
1067	// If neither device or host is supported then this module does not support either so will not
1068	// recognize the properties.
1069	if !deviceSupported && !hostSupported {
1070		return
1071	}
1072
1073	if !deviceSupported {
1074		bpModule.AddProperty("device_supported", false)
1075	}
1076	if hostSupported {
1077		bpModule.AddProperty("host_supported", true)
1078	}
1079}
1080
1081func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
1082	if required {
1083		return requiredSdkMemberReferencePropertyTag
1084	} else {
1085		return optionalSdkMemberReferencePropertyTag
1086	}
1087}
1088
1089func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
1090	return optionalSdkMemberReferencePropertyTag
1091}
1092
1093// Get a versioned name appropriate for the SDK snapshot version being taken.
1094func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string {
1095	if _, ok := s.allMembersByName[unversionedName]; !ok {
1096		if required {
1097			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
1098		}
1099		return unversionedName
1100	}
1101	return versionedSdkMemberName(s.ctx, unversionedName, s.version)
1102}
1103
1104func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string {
1105	var references []string = nil
1106	for _, m := range members {
1107		references = append(references, s.versionedSdkMemberName(m, required))
1108	}
1109	return references
1110}
1111
1112// Get an internal name unique to the sdk.
1113func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string {
1114	if _, ok := s.allMembersByName[unversionedName]; !ok {
1115		if required {
1116			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
1117		}
1118		return unversionedName
1119	}
1120
1121	if s.isInternalMember(unversionedName) {
1122		return s.ctx.ModuleName() + "_" + unversionedName
1123	} else {
1124		return unversionedName
1125	}
1126}
1127
1128func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string {
1129	var references []string = nil
1130	for _, m := range members {
1131		references = append(references, s.unversionedSdkMemberName(m, required))
1132	}
1133	return references
1134}
1135
1136func (s *snapshotBuilder) isInternalMember(memberName string) bool {
1137	_, ok := s.exportedMembersByName[memberName]
1138	return !ok
1139}
1140
1141// Add the properties from the given SdkMemberProperties to the blueprint
1142// property set. This handles common properties in SdkMemberPropertiesBase and
1143// calls the member-specific AddToPropertySet for the rest.
1144func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) {
1145	if memberProperties.Base().Compile_multilib != "" {
1146		targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib)
1147	}
1148
1149	memberProperties.AddToPropertySet(ctx, targetPropertySet)
1150}
1151
1152// sdkMemberVariantDep represents a dependency from an sdk variant onto a member variant.
1153type sdkMemberVariantDep struct {
1154	// The sdk variant that depends (possibly indirectly) on the member variant.
1155	sdkVariant *sdk
1156
1157	// The type of sdk member the variant is to be treated as.
1158	memberType android.SdkMemberType
1159
1160	// The variant that is added to the sdk.
1161	variant android.SdkAware
1162
1163	// True if the member should be exported, i.e. accessible, from outside the sdk.
1164	export bool
1165
1166	// The names of additional component modules provided by the variant.
1167	exportedComponentsInfo android.ExportedComponentsInfo
1168}
1169
1170var _ android.SdkMember = (*sdkMember)(nil)
1171
1172// sdkMember groups all the variants of a specific member module together along with the name of the
1173// module and the member type. This is used to generate the prebuilt modules for a specific member.
1174type sdkMember struct {
1175	memberType android.SdkMemberType
1176	name       string
1177	variants   []android.SdkAware
1178}
1179
1180func (m *sdkMember) Name() string {
1181	return m.name
1182}
1183
1184func (m *sdkMember) Variants() []android.SdkAware {
1185	return m.variants
1186}
1187
1188// Track usages of multilib variants.
1189type multilibUsage int
1190
1191const (
1192	multilibNone multilibUsage = 0
1193	multilib32   multilibUsage = 1
1194	multilib64   multilibUsage = 2
1195	multilibBoth               = multilib32 | multilib64
1196)
1197
1198// Add the multilib that is used in the arch type.
1199func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
1200	multilib := archType.Multilib
1201	switch multilib {
1202	case "":
1203		return m
1204	case "lib32":
1205		return m | multilib32
1206	case "lib64":
1207		return m | multilib64
1208	default:
1209		panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
1210	}
1211}
1212
1213func (m multilibUsage) String() string {
1214	switch m {
1215	case multilibNone:
1216		return ""
1217	case multilib32:
1218		return "32"
1219	case multilib64:
1220		return "64"
1221	case multilibBoth:
1222		return "both"
1223	default:
1224		panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
1225			m, multilibNone, multilib32, multilib64, multilibBoth))
1226	}
1227}
1228
1229type baseInfo struct {
1230	Properties android.SdkMemberProperties
1231}
1232
1233func (b *baseInfo) optimizableProperties() interface{} {
1234	return b.Properties
1235}
1236
1237type osTypeSpecificInfo struct {
1238	baseInfo
1239
1240	osType android.OsType
1241
1242	// The list of arch type specific info for this os type.
1243	//
1244	// Nil if there is one variant whose arch type is common
1245	archInfos []*archTypeSpecificInfo
1246}
1247
1248var _ propertiesContainer = (*osTypeSpecificInfo)(nil)
1249
1250type variantPropertiesFactoryFunc func() android.SdkMemberProperties
1251
1252// Create a new osTypeSpecificInfo for the specified os type and its properties
1253// structures populated with information from the variants.
1254func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
1255	osInfo := &osTypeSpecificInfo{
1256		osType: osType,
1257	}
1258
1259	osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
1260		properties := variantPropertiesFactory()
1261		properties.Base().Os = osType
1262		return properties
1263	}
1264
1265	// Create a structure into which properties common across the architectures in
1266	// this os type will be stored.
1267	osInfo.Properties = osSpecificVariantPropertiesFactory()
1268
1269	// Group the variants by arch type.
1270	var variantsByArchName = make(map[string][]android.Module)
1271	var archTypes []android.ArchType
1272	for _, variant := range osTypeVariants {
1273		archType := variant.Target().Arch.ArchType
1274		archTypeName := archType.Name
1275		if _, ok := variantsByArchName[archTypeName]; !ok {
1276			archTypes = append(archTypes, archType)
1277		}
1278
1279		variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
1280	}
1281
1282	if commonVariants, ok := variantsByArchName["common"]; ok {
1283		if len(osTypeVariants) != 1 {
1284			panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
1285		}
1286
1287		// A common arch type only has one variant and its properties should be treated
1288		// as common to the os type.
1289		osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
1290	} else {
1291		// Create an arch specific info for each supported architecture type.
1292		for _, archType := range archTypes {
1293			archTypeName := archType.Name
1294
1295			archVariants := variantsByArchName[archTypeName]
1296			archInfo := newArchSpecificInfo(ctx, archType, osType, osSpecificVariantPropertiesFactory, archVariants)
1297
1298			osInfo.archInfos = append(osInfo.archInfos, archInfo)
1299		}
1300	}
1301
1302	return osInfo
1303}
1304
1305// Optimize the properties by extracting common properties from arch type specific
1306// properties into os type specific properties.
1307func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
1308	// Nothing to do if there is only a single common architecture.
1309	if len(osInfo.archInfos) == 0 {
1310		return
1311	}
1312
1313	multilib := multilibNone
1314	for _, archInfo := range osInfo.archInfos {
1315		multilib = multilib.addArchType(archInfo.archType)
1316
1317		// Optimize the arch properties first.
1318		archInfo.optimizeProperties(ctx, commonValueExtractor)
1319	}
1320
1321	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, osInfo.Properties, osInfo.archInfos)
1322
1323	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
1324	osInfo.Properties.Base().Compile_multilib = multilib.String()
1325}
1326
1327// Add the properties for an os to a property set.
1328//
1329// Maps the properties related to the os variants through to an appropriate
1330// module structure that will produce equivalent set of variants when it is
1331// processed in a build.
1332func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
1333
1334	var osPropertySet android.BpPropertySet
1335	var archPropertySet android.BpPropertySet
1336	var archOsPrefix string
1337	if osInfo.Properties.Base().Os_count == 1 &&
1338		(osInfo.osType.Class == android.Device || !ctx.memberType.IsHostOsDependent()) {
1339		// There is only one OS type present in the variants and it shouldn't have a
1340		// variant-specific target. The latter is the case if it's either for device
1341		// where there is only one OS (android), or for host and the member type
1342		// isn't host OS dependent.
1343
1344		// Create a structure that looks like:
1345		// module_type {
1346		//   name: "...",
1347		//   ...
1348		//   <common properties>
1349		//   ...
1350		//   <single os type specific properties>
1351		//
1352		//   arch: {
1353		//     <arch specific sections>
1354		//   }
1355		//
1356		osPropertySet = bpModule
1357		archPropertySet = osPropertySet.AddPropertySet("arch")
1358
1359		// Arch specific properties need to be added to an arch specific section
1360		// within arch.
1361		archOsPrefix = ""
1362	} else {
1363		// Create a structure that looks like:
1364		// module_type {
1365		//   name: "...",
1366		//   ...
1367		//   <common properties>
1368		//   ...
1369		//   target: {
1370		//     <arch independent os specific sections, e.g. android>
1371		//     ...
1372		//     <arch and os specific sections, e.g. android_x86>
1373		//   }
1374		//
1375		osType := osInfo.osType
1376		osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
1377		archPropertySet = targetPropertySet
1378
1379		// Arch specific properties need to be added to an os and arch specific
1380		// section prefixed with <os>_.
1381		archOsPrefix = osType.Name + "_"
1382	}
1383
1384	// Add the os specific but arch independent properties to the module.
1385	addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet)
1386
1387	// Add arch (and possibly os) specific sections for each set of arch (and possibly
1388	// os) specific properties.
1389	//
1390	// The archInfos list will be empty if the os contains variants for the common
1391	// architecture.
1392	for _, archInfo := range osInfo.archInfos {
1393		archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
1394	}
1395}
1396
1397func (osInfo *osTypeSpecificInfo) isHostVariant() bool {
1398	osClass := osInfo.osType.Class
1399	return osClass == android.Host
1400}
1401
1402var _ isHostVariant = (*osTypeSpecificInfo)(nil)
1403
1404func (osInfo *osTypeSpecificInfo) String() string {
1405	return fmt.Sprintf("OsType{%s}", osInfo.osType)
1406}
1407
1408type archTypeSpecificInfo struct {
1409	baseInfo
1410
1411	archType android.ArchType
1412	osType   android.OsType
1413
1414	linkInfos []*linkTypeSpecificInfo
1415}
1416
1417var _ propertiesContainer = (*archTypeSpecificInfo)(nil)
1418
1419// Create a new archTypeSpecificInfo for the specified arch type and its properties
1420// structures populated with information from the variants.
1421func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
1422
1423	// Create an arch specific info into which the variant properties can be copied.
1424	archInfo := &archTypeSpecificInfo{archType: archType, osType: osType}
1425
1426	// Create the properties into which the arch type specific properties will be
1427	// added.
1428	archInfo.Properties = variantPropertiesFactory()
1429
1430	if len(archVariants) == 1 {
1431		archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
1432	} else {
1433		// There is more than one variant for this arch type which must be differentiated
1434		// by link type.
1435		for _, linkVariant := range archVariants {
1436			linkType := getLinkType(linkVariant)
1437			if linkType == "" {
1438				panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
1439			} else {
1440				linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
1441
1442				archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
1443			}
1444		}
1445	}
1446
1447	return archInfo
1448}
1449
1450func (archInfo *archTypeSpecificInfo) optimizableProperties() interface{} {
1451	return archInfo.Properties
1452}
1453
1454// Get the link type of the variant
1455//
1456// If the variant is not differentiated by link type then it returns "",
1457// otherwise it returns one of "static" or "shared".
1458func getLinkType(variant android.Module) string {
1459	linkType := ""
1460	if linkable, ok := variant.(cc.LinkableInterface); ok {
1461		if linkable.Shared() && linkable.Static() {
1462			panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
1463		} else if linkable.Shared() {
1464			linkType = "shared"
1465		} else if linkable.Static() {
1466			linkType = "static"
1467		} else {
1468			panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
1469		}
1470	}
1471	return linkType
1472}
1473
1474// Optimize the properties by extracting common properties from link type specific
1475// properties into arch type specific properties.
1476func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
1477	if len(archInfo.linkInfos) == 0 {
1478		return
1479	}
1480
1481	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.linkInfos)
1482}
1483
1484// Add the properties for an arch type to a property set.
1485func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
1486	archTypeName := archInfo.archType.Name
1487	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
1488	// Enable the <os>_<arch> variant explicitly when we've disabled it by default on host.
1489	if ctx.memberType.IsHostOsDependent() && archInfo.osType.Class == android.Host {
1490		archTypePropertySet.AddProperty("enabled", true)
1491	}
1492	addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet)
1493
1494	for _, linkInfo := range archInfo.linkInfos {
1495		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
1496		addSdkMemberPropertiesToSet(ctx, linkInfo.Properties, linkPropertySet)
1497	}
1498}
1499
1500func (archInfo *archTypeSpecificInfo) String() string {
1501	return fmt.Sprintf("ArchType{%s}", archInfo.archType)
1502}
1503
1504type linkTypeSpecificInfo struct {
1505	baseInfo
1506
1507	linkType string
1508}
1509
1510var _ propertiesContainer = (*linkTypeSpecificInfo)(nil)
1511
1512// Create a new linkTypeSpecificInfo for the specified link type and its properties
1513// structures populated with information from the variant.
1514func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
1515	linkInfo := &linkTypeSpecificInfo{
1516		baseInfo: baseInfo{
1517			// Create the properties into which the link type specific properties will be
1518			// added.
1519			Properties: variantPropertiesFactory(),
1520		},
1521		linkType: linkType,
1522	}
1523	linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
1524	return linkInfo
1525}
1526
1527func (l *linkTypeSpecificInfo) String() string {
1528	return fmt.Sprintf("LinkType{%s}", l.linkType)
1529}
1530
1531type memberContext struct {
1532	sdkMemberContext android.ModuleContext
1533	builder          *snapshotBuilder
1534	memberType       android.SdkMemberType
1535	name             string
1536}
1537
1538func (m *memberContext) SdkModuleContext() android.ModuleContext {
1539	return m.sdkMemberContext
1540}
1541
1542func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
1543	return m.builder
1544}
1545
1546func (m *memberContext) MemberType() android.SdkMemberType {
1547	return m.memberType
1548}
1549
1550func (m *memberContext) Name() string {
1551	return m.name
1552}
1553
1554func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
1555
1556	memberType := member.memberType
1557
1558	// Do not add the prefer property if the member snapshot module is a source module type.
1559	if !memberType.UsesSourceModuleTypeInSnapshot() {
1560		// Set the prefer based on the environment variable. This is a temporary work around to allow a
1561		// snapshot to be created that sets prefer: true.
1562		// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
1563		//  dynamically at build time not at snapshot generation time.
1564		prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
1565
1566		// Set prefer. Setting this to false is not strictly required as that is the default but it does
1567		// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
1568		// check the behavior when a prebuilt is preferred. It also makes it explicit what the default
1569		// behavior is for the module.
1570		bpModule.insertAfter("name", "prefer", prefer)
1571	}
1572
1573	// Group the variants by os type.
1574	variantsByOsType := make(map[android.OsType][]android.Module)
1575	variants := member.Variants()
1576	for _, variant := range variants {
1577		osType := variant.Target().Os
1578		variantsByOsType[osType] = append(variantsByOsType[osType], variant)
1579	}
1580
1581	osCount := len(variantsByOsType)
1582	variantPropertiesFactory := func() android.SdkMemberProperties {
1583		properties := memberType.CreateVariantPropertiesStruct()
1584		base := properties.Base()
1585		base.Os_count = osCount
1586		return properties
1587	}
1588
1589	osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
1590
1591	// The set of properties that are common across all architectures and os types.
1592	commonProperties := variantPropertiesFactory()
1593	commonProperties.Base().Os = android.CommonOS
1594
1595	// Create common value extractor that can be used to optimize the properties.
1596	commonValueExtractor := newCommonValueExtractor(commonProperties)
1597
1598	// The list of property structures which are os type specific but common across
1599	// architectures within that os type.
1600	var osSpecificPropertiesContainers []*osTypeSpecificInfo
1601
1602	for osType, osTypeVariants := range variantsByOsType {
1603		osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
1604		osTypeToInfo[osType] = osInfo
1605		// Add the os specific properties to a list of os type specific yet architecture
1606		// independent properties structs.
1607		osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo)
1608
1609		// Optimize the properties across all the variants for a specific os type.
1610		osInfo.optimizeProperties(ctx, commonValueExtractor)
1611	}
1612
1613	// Extract properties which are common across all architectures and os types.
1614	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
1615
1616	// Add the common properties to the module.
1617	addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
1618
1619	// Create a target property set into which target specific properties can be
1620	// added.
1621	targetPropertySet := bpModule.AddPropertySet("target")
1622
1623	// If the member is host OS dependent and has host_supported then disable by
1624	// default and enable each host OS variant explicitly. This avoids problems
1625	// with implicitly enabled OS variants when the snapshot is used, which might
1626	// be different from this run (e.g. different build OS).
1627	if ctx.memberType.IsHostOsDependent() {
1628		hostSupported := bpModule.getValue("host_supported") == true // Missing means false.
1629		if hostSupported {
1630			hostPropertySet := targetPropertySet.AddPropertySet("host")
1631			hostPropertySet.AddProperty("enabled", false)
1632		}
1633	}
1634
1635	// Iterate over the os types in a fixed order.
1636	for _, osType := range s.getPossibleOsTypes() {
1637		osInfo := osTypeToInfo[osType]
1638		if osInfo == nil {
1639			continue
1640		}
1641
1642		osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
1643	}
1644}
1645
1646// Compute the list of possible os types that this sdk could support.
1647func (s *sdk) getPossibleOsTypes() []android.OsType {
1648	var osTypes []android.OsType
1649	for _, osType := range android.OsTypeList() {
1650		if s.DeviceSupported() {
1651			if osType.Class == android.Device && osType != android.Fuchsia {
1652				osTypes = append(osTypes, osType)
1653			}
1654		}
1655		if s.HostSupported() {
1656			if osType.Class == android.Host {
1657				osTypes = append(osTypes, osType)
1658			}
1659		}
1660	}
1661	sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
1662	return osTypes
1663}
1664
1665// Given a set of properties (struct value), return the value of the field within that
1666// struct (or one of its embedded structs).
1667type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
1668
1669// Checks the metadata to determine whether the property should be ignored for the
1670// purposes of common value extraction or not.
1671type extractorMetadataPredicate func(metadata propertiesContainer) bool
1672
1673// Indicates whether optimizable properties are provided by a host variant or
1674// not.
1675type isHostVariant interface {
1676	isHostVariant() bool
1677}
1678
1679// A property that can be optimized by the commonValueExtractor.
1680type extractorProperty struct {
1681	// The name of the field for this property. It is a "."-separated path for
1682	// fields in non-anonymous substructs.
1683	name string
1684
1685	// Filter that can use metadata associated with the properties being optimized
1686	// to determine whether the field should be ignored during common value
1687	// optimization.
1688	filter extractorMetadataPredicate
1689
1690	// Retrieves the value on which common value optimization will be performed.
1691	getter fieldAccessorFunc
1692
1693	// The empty value for the field.
1694	emptyValue reflect.Value
1695
1696	// True if the property can support arch variants false otherwise.
1697	archVariant bool
1698}
1699
1700func (p extractorProperty) String() string {
1701	return p.name
1702}
1703
1704// Supports extracting common values from a number of instances of a properties
1705// structure into a separate common set of properties.
1706type commonValueExtractor struct {
1707	// The properties that the extractor can optimize.
1708	properties []extractorProperty
1709}
1710
1711// Create a new common value extractor for the structure type for the supplied
1712// properties struct.
1713//
1714// The returned extractor can be used on any properties structure of the same type
1715// as the supplied set of properties.
1716func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
1717	structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
1718	extractor := &commonValueExtractor{}
1719	extractor.gatherFields(structType, nil, "")
1720	return extractor
1721}
1722
1723// Gather the fields from the supplied structure type from which common values will
1724// be extracted.
1725//
1726// This is recursive function. If it encounters a struct then it will recurse
1727// into it, passing in the accessor for the field and the struct name as prefix
1728// for the nested fields. That will then be used in the accessors for the fields
1729// in the embedded struct.
1730func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc, namePrefix string) {
1731	for f := 0; f < structType.NumField(); f++ {
1732		field := structType.Field(f)
1733		if field.PkgPath != "" {
1734			// Ignore unexported fields.
1735			continue
1736		}
1737
1738		// Ignore fields whose value should be kept.
1739		if proptools.HasTag(field, "sdk", "keep") {
1740			continue
1741		}
1742
1743		var filter extractorMetadataPredicate
1744
1745		// Add a filter
1746		if proptools.HasTag(field, "sdk", "ignored-on-host") {
1747			filter = func(metadata propertiesContainer) bool {
1748				if m, ok := metadata.(isHostVariant); ok {
1749					if m.isHostVariant() {
1750						return false
1751					}
1752				}
1753				return true
1754			}
1755		}
1756
1757		// Save a copy of the field index for use in the function.
1758		fieldIndex := f
1759
1760		name := namePrefix + field.Name
1761
1762		fieldGetter := func(value reflect.Value) reflect.Value {
1763			if containingStructAccessor != nil {
1764				// This is an embedded structure so first access the field for the embedded
1765				// structure.
1766				value = containingStructAccessor(value)
1767			}
1768
1769			// Skip through interface and pointer values to find the structure.
1770			value = getStructValue(value)
1771
1772			defer func() {
1773				if r := recover(); r != nil {
1774					panic(fmt.Errorf("%s for fieldIndex %d of field %s of value %#v", r, fieldIndex, name, value.Interface()))
1775				}
1776			}()
1777
1778			// Return the field.
1779			return value.Field(fieldIndex)
1780		}
1781
1782		if field.Type.Kind() == reflect.Struct {
1783			// Gather fields from the nested or embedded structure.
1784			var subNamePrefix string
1785			if field.Anonymous {
1786				subNamePrefix = namePrefix
1787			} else {
1788				subNamePrefix = name + "."
1789			}
1790			e.gatherFields(field.Type, fieldGetter, subNamePrefix)
1791		} else {
1792			property := extractorProperty{
1793				name,
1794				filter,
1795				fieldGetter,
1796				reflect.Zero(field.Type),
1797				proptools.HasTag(field, "android", "arch_variant"),
1798			}
1799			e.properties = append(e.properties, property)
1800		}
1801	}
1802}
1803
1804func getStructValue(value reflect.Value) reflect.Value {
1805foundStruct:
1806	for {
1807		kind := value.Kind()
1808		switch kind {
1809		case reflect.Interface, reflect.Ptr:
1810			value = value.Elem()
1811		case reflect.Struct:
1812			break foundStruct
1813		default:
1814			panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
1815		}
1816	}
1817	return value
1818}
1819
1820// A container of properties to be optimized.
1821//
1822// Allows additional information to be associated with the properties, e.g. for
1823// filtering.
1824type propertiesContainer interface {
1825	fmt.Stringer
1826
1827	// Get the properties that need optimizing.
1828	optimizableProperties() interface{}
1829}
1830
1831// A wrapper for sdk variant related properties to allow them to be optimized.
1832type sdkVariantPropertiesContainer struct {
1833	sdkVariant *sdk
1834	properties interface{}
1835}
1836
1837func (c sdkVariantPropertiesContainer) optimizableProperties() interface{} {
1838	return c.properties
1839}
1840
1841func (c sdkVariantPropertiesContainer) String() string {
1842	return c.sdkVariant.String()
1843}
1844
1845// Extract common properties from a slice of property structures of the same type.
1846//
1847// All the property structures must be of the same type.
1848// commonProperties - must be a pointer to the structure into which common properties will be added.
1849// inputPropertiesSlice - must be a slice of propertiesContainer interfaces.
1850//
1851// Iterates over each exported field (capitalized name) and checks to see whether they
1852// have the same value (using DeepEquals) across all the input properties. If it does not then no
1853// change is made. Otherwise, the common value is stored in the field in the commonProperties
1854// and the field in each of the input properties structure is set to its default value. Nested
1855// structs are visited recursively and their non-struct fields are compared.
1856func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) error {
1857	commonPropertiesValue := reflect.ValueOf(commonProperties)
1858	commonStructValue := commonPropertiesValue.Elem()
1859
1860	sliceValue := reflect.ValueOf(inputPropertiesSlice)
1861
1862	for _, property := range e.properties {
1863		fieldGetter := property.getter
1864		filter := property.filter
1865		if filter == nil {
1866			filter = func(metadata propertiesContainer) bool {
1867				return true
1868			}
1869		}
1870
1871		// Check to see if all the structures have the same value for the field. The commonValue
1872		// is nil on entry to the loop and if it is nil on exit then there is no common value or
1873		// all the values have been filtered out, otherwise it points to the common value.
1874		var commonValue *reflect.Value
1875
1876		// Assume that all the values will be the same.
1877		//
1878		// While similar to this is not quite the same as commonValue == nil. If all the values
1879		// have been filtered out then this will be false but commonValue == nil will be true.
1880		valuesDiffer := false
1881
1882		for i := 0; i < sliceValue.Len(); i++ {
1883			container := sliceValue.Index(i).Interface().(propertiesContainer)
1884			itemValue := reflect.ValueOf(container.optimizableProperties())
1885			fieldValue := fieldGetter(itemValue)
1886
1887			if !filter(container) {
1888				expectedValue := property.emptyValue.Interface()
1889				actualValue := fieldValue.Interface()
1890				if !reflect.DeepEqual(expectedValue, actualValue) {
1891					return fmt.Errorf("field %q is supposed to be ignored for %q but is set to %#v instead of %#v", property, container, actualValue, expectedValue)
1892				}
1893				continue
1894			}
1895
1896			if commonValue == nil {
1897				// Use the first value as the commonProperties value.
1898				commonValue = &fieldValue
1899			} else {
1900				// If the value does not match the current common value then there is
1901				// no value in common so break out.
1902				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
1903					commonValue = nil
1904					valuesDiffer = true
1905					break
1906				}
1907			}
1908		}
1909
1910		// If the fields all have common value then store it in the common struct field
1911		// and set the input struct's field to the empty value.
1912		if commonValue != nil {
1913			emptyValue := property.emptyValue
1914			fieldGetter(commonStructValue).Set(*commonValue)
1915			for i := 0; i < sliceValue.Len(); i++ {
1916				container := sliceValue.Index(i).Interface().(propertiesContainer)
1917				itemValue := reflect.ValueOf(container.optimizableProperties())
1918				fieldValue := fieldGetter(itemValue)
1919				fieldValue.Set(emptyValue)
1920			}
1921		}
1922
1923		if valuesDiffer && !property.archVariant {
1924			// The values differ but the property does not support arch variants so it
1925			// is an error.
1926			var details strings.Builder
1927			for i := 0; i < sliceValue.Len(); i++ {
1928				container := sliceValue.Index(i).Interface().(propertiesContainer)
1929				itemValue := reflect.ValueOf(container.optimizableProperties())
1930				fieldValue := fieldGetter(itemValue)
1931
1932				_, _ = fmt.Fprintf(&details, "\n    %q has value %q", container.String(), fieldValue.Interface())
1933			}
1934
1935			return fmt.Errorf("field %q is not tagged as \"arch_variant\" but has arch specific properties:%s", property.String(), details.String())
1936		}
1937	}
1938
1939	return nil
1940}
1941