xref: /aosp_15_r20/build/soong/sdk/update.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"bytes"
19	"encoding/json"
20	"fmt"
21	"reflect"
22	"sort"
23	"strings"
24
25	"android/soong/cc"
26	"android/soong/java"
27
28	"github.com/google/blueprint"
29	"github.com/google/blueprint/proptools"
30
31	"android/soong/android"
32)
33
34// Environment variables that affect the generated snapshot
35// ========================================================
36//
37// SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE
38//     This allows the target build release (i.e. the release version of the build within which
39//     the snapshot will be used) of the snapshot to be specified. If unspecified then it defaults
40//     to the current build release version. Otherwise, it must be the name of one of the build
41//     releases defined in nameToBuildRelease, e.g. S, T, etc..
42//
43//     The generated snapshot must only be used in the specified target release. If the target
44//     build release is not the current build release then the generated Android.bp file not be
45//     checked for compatibility.
46//
47//     e.g. if setting SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S will cause the generated snapshot
48//     to be compatible with S.
49//
50
51var pctx = android.NewPackageContext("android/soong/sdk")
52
53var (
54	repackageZip = pctx.AndroidStaticRule("SnapshotRepackageZip",
55		blueprint.RuleParams{
56			Command: `${config.Zip2ZipCmd} -i $in -o $out -x META-INF/**/* "**/*:$destdir"`,
57			CommandDeps: []string{
58				"${config.Zip2ZipCmd}",
59			},
60		},
61		"destdir")
62
63	zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles",
64		blueprint.RuleParams{
65			Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`,
66			CommandDeps: []string{
67				"${config.SoongZipCmd}",
68			},
69			Rspfile:        "$out.rsp",
70			RspfileContent: "$in",
71		},
72		"basedir")
73
74	mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips",
75		blueprint.RuleParams{
76			Command: `${config.MergeZipsCmd} -s $out $in`,
77			CommandDeps: []string{
78				"${config.MergeZipsCmd}",
79			},
80		})
81)
82
83const (
84	soongSdkSnapshotVersionCurrent = "current"
85)
86
87type generatedContents struct {
88	content     strings.Builder
89	indentLevel int
90}
91
92func (gc *generatedContents) Indent() {
93	gc.indentLevel++
94}
95
96func (gc *generatedContents) Dedent() {
97	gc.indentLevel--
98}
99
100// IndentedPrintf will add spaces to indent the line to the appropriate level before printing the
101// arguments.
102func (gc *generatedContents) IndentedPrintf(format string, args ...interface{}) {
103	_, _ = fmt.Fprintf(&(gc.content), strings.Repeat("    ", gc.indentLevel)+format, args...)
104}
105
106// UnindentedPrintf does not add spaces to indent the line to the appropriate level before printing
107// the arguments.
108func (gc *generatedContents) UnindentedPrintf(format string, args ...interface{}) {
109	_, _ = fmt.Fprintf(&(gc.content), format, args...)
110}
111
112// Collect all the members.
113//
114// Updates the sdk module with a list of sdkMemberVariantDep instances and details as to which
115// multilibs (32/64/both) are used by this sdk variant.
116func (s *sdk) collectMembers(ctx android.ModuleContext) {
117	s.multilibUsages = multilibNone
118	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
119		tag := ctx.OtherModuleDependencyTag(child)
120		if memberTag, ok := tag.(android.SdkMemberDependencyTag); ok {
121			memberType := memberTag.SdkMemberType(child)
122
123			// If a nil SdkMemberType was returned then this module should not be added to the sdk.
124			if memberType == nil {
125				return false
126			}
127
128			// Make sure that the resolved module is allowed in the member list property.
129			if !memberType.IsInstance(child) {
130				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
131			}
132
133			// Keep track of which multilib variants are used by the sdk.
134			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
135
136			exportedComponentsInfo, _ := android.OtherModuleProvider(ctx, child, android.ExportedComponentsInfoProvider)
137
138			var container android.Module
139			if parent != ctx.Module() {
140				container = parent
141			}
142
143			minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child)
144
145			export := memberTag.ExportMember()
146			s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
147				sdkVariant:             s,
148				memberType:             memberType,
149				variant:                child,
150				minApiLevel:            minApiLevel,
151				container:              container,
152				export:                 export,
153				exportedComponentsInfo: exportedComponentsInfo,
154			})
155
156			// Recurse down into the member's dependencies as it may have dependencies that need to be
157			// automatically added to the sdk.
158			return true
159		}
160
161		return false
162	})
163}
164
165// A denylist of modules whose host variants will be removed from the generated snapshots above the ApiLevel
166// even if they are listed in the corresponding `sdk`.
167// The key is the module name
168// The value is the _last_ dessert where the host variant of the module will be present
169// This is a workaround to ensure that these modules are generated in <=$ApiLevel, but not in in >=$ApiLevel
170var ignoreHostModuleVariantsAboveDessert = map[string]android.ApiLevel{
171	// ignore host variant of libdexfile and its transitive dependencies.
172	// The platform test that depends on them (`libunwindstack_unit_test` at the time of writing)
173	// no longer requires a prebuilt variant of libdexfile.
174	"libdexfile":    android.ApiLevelUpsideDownCake,
175	"libartpalette": android.ApiLevelUpsideDownCake,
176	"libartbase":    android.ApiLevelUpsideDownCake,
177}
178
179// groupMemberVariantsByMemberThenType groups the member variant dependencies so that all the
180// variants of each member are grouped together within an sdkMember instance.
181//
182// The sdkMember instances are then grouped into slices by member type. Within each such slice the
183// sdkMember instances appear in the order they were added as dependencies.
184//
185// Finally, the member type slices are concatenated together to form a single slice. The order in
186// which they are concatenated is the order in which the member types were registered in the
187// android.SdkMemberTypesRegistry.
188func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, targetBuildRelease *buildRelease, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
189	byType := make(map[android.SdkMemberType][]*sdkMember)
190	byName := make(map[string]*sdkMember)
191
192	for _, memberVariantDep := range memberVariantDeps {
193		memberType := memberVariantDep.memberType
194		variant := memberVariantDep.variant
195
196		name := ctx.OtherModuleName(variant)
197		targetApiLevel, err := android.ApiLevelFromUser(ctx, targetBuildRelease.name)
198		if err != nil {
199			targetApiLevel = android.FutureApiLevel
200		}
201		if lastApiLevel, exists := ignoreHostModuleVariantsAboveDessert[name]; exists && targetApiLevel.GreaterThan(lastApiLevel) && memberVariantDep.Host() {
202			// ignore host variant of this module if the targetApiLevel is V and above.
203			continue
204		}
205		member := byName[name]
206		if member == nil {
207			member = &sdkMember{memberType: memberType, name: name}
208			byName[name] = member
209			byType[memberType] = append(byType[memberType], member)
210		} else if member.memberType != memberType {
211			// validate whether this is the same member type or and overriding member type
212			if memberType.Overrides(member.memberType) {
213				member.memberType = memberType
214			} else if !member.memberType.Overrides(memberType) {
215				ctx.ModuleErrorf("Incompatible member types %q %q", member.memberType, memberType)
216			}
217		}
218
219		// Only append new variants to the list. This is needed because a member can be both
220		// exported by the sdk and also be a transitive sdk member.
221		member.variants = appendUniqueVariants(member.variants, variant)
222	}
223	var members []*sdkMember
224	for _, memberListProperty := range s.memberTypeListProperties() {
225		memberType := memberListProperty.memberType
226
227		if !isMemberTypeSupportedByTargetBuildRelease(memberType, targetBuildRelease) {
228			continue
229		}
230
231		membersOfType := byType[memberType]
232		members = append(members, membersOfType...)
233	}
234
235	return members
236}
237
238// isMemberTypeSupportedByTargetBuildRelease returns true if the member type is supported by the
239// target build release.
240func isMemberTypeSupportedByTargetBuildRelease(memberType android.SdkMemberType, targetBuildRelease *buildRelease) bool {
241	supportedByTargetBuildRelease := true
242	supportedBuildReleases := memberType.SupportedBuildReleases()
243	if supportedBuildReleases == "" {
244		supportedBuildReleases = "S+"
245	}
246
247	set, err := parseBuildReleaseSet(supportedBuildReleases)
248	if err != nil {
249		panic(fmt.Errorf("member type %s has invalid supported build releases %q: %s",
250			memberType.SdkPropertyName(), supportedBuildReleases, err))
251	}
252	if !set.contains(targetBuildRelease) {
253		supportedByTargetBuildRelease = false
254	}
255	return supportedByTargetBuildRelease
256}
257
258func appendUniqueVariants(variants []android.Module, newVariant android.Module) []android.Module {
259	for _, v := range variants {
260		if v == newVariant {
261			return variants
262		}
263	}
264	return append(variants, newVariant)
265}
266
267// BUILD_NUMBER_FILE is the name of the file in the snapshot zip that will contain the number of
268// the build from which the snapshot was produced.
269const BUILD_NUMBER_FILE = "snapshot-creation-build-number.txt"
270
271// SDK directory structure
272// <sdk_root>/
273//     Android.bp   : definition of a 'sdk' module is here. This is a hand-made one.
274//     <api_ver>/   : below this directory are all auto-generated
275//         Android.bp   : definition of 'sdk_snapshot' module is here
276//         aidl/
277//            frameworks/base/core/..../IFoo.aidl   : an exported AIDL file
278//         java/
279//            <module_name>.jar    : the stub jar for a java library 'module_name'
280//         include/
281//            bionic/libc/include/stdlib.h   : an exported header file
282//         include_gen/
283//            <module_name>/com/android/.../IFoo.h : a generated header file
284//         <arch>/include/   : arch-specific exported headers
285//         <arch>/include_gen/   : arch-specific generated headers
286//         <arch>/lib/
287//            libFoo.so   : a stub library
288
289func (s sdk) targetBuildRelease(ctx android.ModuleContext) *buildRelease {
290	config := ctx.Config()
291	targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name)
292	targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
293	if err != nil {
294		ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
295		targetBuildRelease = buildReleaseCurrent
296	}
297
298	return targetBuildRelease
299}
300
301// buildSnapshot is the main function in this source file. It creates rules to copy
302// the contents (header files, stub libraries, etc) into the zip file.
303func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) {
304
305	targetBuildRelease := s.targetBuildRelease(ctx)
306	targetApiLevel, err := android.ApiLevelFromUser(ctx, targetBuildRelease.name)
307	if err != nil {
308		targetApiLevel = android.FutureApiLevel
309	}
310
311	// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
312	hasLicenses := false
313	var memberVariantDeps []sdkMemberVariantDep
314	for _, sdkVariant := range sdkVariants {
315		memberVariantDeps = append(memberVariantDeps, sdkVariant.memberVariantDeps...)
316	}
317
318	// Filter out any sdkMemberVariantDep that is a component of another.
319	memberVariantDeps = filterOutComponents(ctx, memberVariantDeps)
320
321	// Record the names of all the members, both explicitly specified and implicitly included. Also,
322	// record the names of any members that should be excluded from this snapshot.
323	allMembersByName := make(map[string]struct{})
324	exportedMembersByName := make(map[string]struct{})
325	excludedMembersByName := make(map[string]struct{})
326
327	addMember := func(name string, export bool, exclude bool) {
328		if exclude {
329			excludedMembersByName[name] = struct{}{}
330			return
331		}
332
333		allMembersByName[name] = struct{}{}
334		if export {
335			exportedMembersByName[name] = struct{}{}
336		}
337	}
338
339	for _, memberVariantDep := range memberVariantDeps {
340		name := memberVariantDep.variant.Name()
341		export := memberVariantDep.export
342
343		// If the minApiLevel of the member is greater than the target API level then exclude it from
344		// this snapshot.
345		exclude := memberVariantDep.minApiLevel.GreaterThan(targetApiLevel)
346		// Always include host variants (e.g. host tools) in the snapshot.
347		// Host variants should not be guarded by a min_sdk_version check. In fact, host variants
348		// do not have a `min_sdk_version`.
349		if memberVariantDep.Host() {
350			exclude = false
351		}
352
353		addMember(name, export, exclude)
354
355		// Add any components provided by the module.
356		for _, component := range memberVariantDep.exportedComponentsInfo.Components {
357			addMember(component, export, exclude)
358		}
359
360		if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
361			hasLicenses = true
362		}
363	}
364
365	snapshotDir := android.PathForModuleOut(ctx, "snapshot")
366
367	bp := android.PathForModuleOut(ctx, "snapshot", "Android.bp")
368
369	bpFile := &bpFile{
370		modules: make(map[string]*bpModule),
371	}
372
373	// Always add -current to the end
374	snapshotFileSuffix := "-current"
375
376	builder := &snapshotBuilder{
377		ctx:                   ctx,
378		sdk:                   s,
379		snapshotDir:           snapshotDir.OutputPath,
380		copies:                make(map[string]string),
381		filesToZip:            []android.Path{bp},
382		bpFile:                bpFile,
383		prebuiltModules:       make(map[string]*bpModule),
384		allMembersByName:      allMembersByName,
385		exportedMembersByName: exportedMembersByName,
386		excludedMembersByName: excludedMembersByName,
387		targetBuildRelease:    targetBuildRelease,
388	}
389	s.builderForTests = builder
390
391	// If the sdk snapshot includes any license modules then add a package module which has a
392	// default_applicable_licenses property. That will prevent the LSC license process from updating
393	// the generated Android.bp file to add a package module that includes all licenses used by all
394	// the modules in that package. That would be unnecessary as every module in the sdk should have
395	// their own licenses property specified.
396	if hasLicenses {
397		pkg := bpFile.newModule("package")
398		property := "default_applicable_licenses"
399		pkg.AddCommentForProperty(property, `
400A default list here prevents the license LSC from adding its own list which would
401be unnecessary as every module in the sdk already has its own licenses property.
402`)
403		pkg.AddProperty(property, []string{"Android-Apache-2.0"})
404		bpFile.AddModule(pkg)
405	}
406
407	// Group the variants for each member module together and then group the members of each member
408	// type together.
409	members := s.groupMemberVariantsByMemberThenType(ctx, targetBuildRelease, memberVariantDeps)
410
411	// Create the prebuilt modules for each of the member modules.
412	traits := s.gatherTraits()
413	memberNames := []string{} // soong module names of the members. contains the prebuilt_ prefix.
414	for _, member := range members {
415		memberType := member.memberType
416		if !memberType.ArePrebuiltsRequired() {
417			continue
418		}
419
420		name := member.name
421		if _, ok := excludedMembersByName[name]; ok {
422			continue
423		}
424
425		requiredTraits := traits[name]
426		if requiredTraits == nil {
427			requiredTraits = android.EmptySdkMemberTraitSet()
428		}
429
430		// Create the snapshot for the member.
431		memberCtx := &memberContext{ctx, builder, memberType, name, requiredTraits}
432
433		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
434		s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
435
436		// Set stripper to none to skip stripping for generated snapshots.
437		// Mainline prebuilts (cc_prebuilt_library_shared) are not strippable in older platforms.
438		// Thus, stripping should be skipped when being used as prebuilts.
439		if memberType.DisablesStrip() {
440			stripPropertySet := prebuiltModule.(*bpModule).AddPropertySet("strip")
441			stripPropertySet.AddProperty("none", true)
442		}
443
444		if member.memberType != android.LicenseModuleSdkMemberType && !builder.isInternalMember(member.name) {
445			// More exceptions
446			// 1. Skip BCP and SCCP fragments
447			// 2. Skip non-sdk contents of BCP and SCCP fragments
448			//
449			// The non-sdk contents of BCP/SSCP fragments should only be used for dexpreopt and hiddenapi,
450			// and are not available to the rest of the build.
451			if android.InList(member.memberType,
452				[]android.SdkMemberType{
453					// bcp
454					java.BootclasspathFragmentSdkMemberType,
455					java.JavaBootLibsSdkMemberType,
456					// sscp
457					java.SystemServerClasspathFragmentSdkMemberType,
458					java.JavaSystemserverLibsSdkMemberType,
459				},
460			) {
461				continue
462			}
463
464			memberNames = append(memberNames, android.PrebuiltNameFromSource(member.name))
465		}
466	}
467
468	// create an apex_contributions_defaults for this module's sdk.
469	// this module type is supported in V and above.
470	if targetApiLevel.GreaterThan(android.ApiLevelUpsideDownCake) {
471		ac := newModule("apex_contributions_defaults")
472		ac.AddProperty("name", s.Name()+".contributions")
473		ac.AddProperty("contents", memberNames)
474		bpFile.AddModule(ac)
475	}
476
477	// Create a transformer that will transform a module by replacing any references
478	// to internal members with a unique module name and setting prefer: false.
479	snapshotTransformer := snapshotTransformation{
480		builder: builder,
481	}
482
483	for _, module := range builder.prebuiltOrder {
484		// Prune any empty property sets.
485		module = transformModule(module, pruneEmptySetTransformer{})
486
487		// Transform the module module to make it suitable for use in the snapshot.
488		module = transformModule(module, snapshotTransformer)
489		module = transformModule(module, emptyClasspathContentsTransformation{})
490
491		targetApiLevel, err := android.ApiLevelFromUserWithConfig(ctx.Config(), s.targetBuildRelease(ctx).name)
492		if err == nil && targetApiLevel.LessThan(android.ApiLevelVanillaIceCream) {
493			module = transformModule(module, replaceExportablePropertiesTransformer{})
494		}
495
496		if module != nil {
497			bpFile.AddModule(module)
498		}
499	}
500
501	// generate Android.bp
502	contents := generateBpContents(bpFile)
503	// If the snapshot is being generated for the current build release then check the syntax to make
504	// sure that it is compatible.
505	if targetBuildRelease == buildReleaseCurrent {
506		syntaxCheckSnapshotBpFile(ctx, contents)
507	}
508
509	android.WriteFileRuleVerbatim(ctx, bp, contents)
510
511	// Copy the build number file into the snapshot.
512	builder.CopyToSnapshot(ctx.Config().BuildNumberFile(ctx), BUILD_NUMBER_FILE)
513
514	filesToZip := android.SortedUniquePaths(builder.filesToZip)
515
516	// zip them all
517	zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotFileSuffix)
518	outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
519	outputDesc := "Building snapshot for " + ctx.ModuleName()
520
521	// If there are no zips to merge then generate the output zip directly.
522	// Otherwise, generate an intermediate zip file into which other zips can be
523	// merged.
524	var zipFile android.OutputPath
525	var desc string
526	if len(builder.zipsToMerge) == 0 {
527		zipFile = outputZipFile
528		desc = outputDesc
529	} else {
530		intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotFileSuffix)
531		zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
532		desc = "Building intermediate snapshot for " + ctx.ModuleName()
533	}
534
535	ctx.Build(pctx, android.BuildParams{
536		Description: desc,
537		Rule:        zipFiles,
538		Inputs:      filesToZip,
539		Output:      zipFile,
540		Args: map[string]string{
541			"basedir": builder.snapshotDir.String(),
542		},
543	})
544
545	if len(builder.zipsToMerge) != 0 {
546		ctx.Build(pctx, android.BuildParams{
547			Description: outputDesc,
548			Rule:        mergeZips,
549			Input:       zipFile,
550			Inputs:      android.SortedUniquePaths(builder.zipsToMerge),
551			Output:      outputZipFile,
552		})
553	}
554
555	modules := s.generateInfoData(ctx, memberVariantDeps)
556
557	// Output the modules information as pretty printed JSON.
558	info := android.PathForModuleOut(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
559	output, err := json.MarshalIndent(modules, "", "  ")
560	if err != nil {
561		ctx.ModuleErrorf("error generating %q: %s", info, err)
562	}
563	builder.infoContents = string(output)
564	android.WriteFileRuleVerbatim(ctx, info, builder.infoContents)
565	installedInfo := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
566	s.infoFile = android.OptionalPathForPath(installedInfo)
567
568	// Install the zip, making sure that the info file has been installed as well.
569	installedZip := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
570	s.snapshotFile = android.OptionalPathForPath(installedZip)
571}
572
573type moduleInfo struct {
574	// The type of the module, e.g. java_sdk_library
575	moduleType string
576	// The name of the module.
577	name string
578	// A list of additional dependencies of the module.
579	deps []string
580	// Additional member specific properties.
581	// These will be added into the generated JSON alongside the above properties.
582	memberSpecific map[string]interface{}
583}
584
585func (m *moduleInfo) MarshalJSON() ([]byte, error) {
586	buffer := bytes.Buffer{}
587
588	separator := ""
589	writeObjectPair := func(key string, value interface{}) {
590		buffer.WriteString(fmt.Sprintf("%s%q: ", separator, key))
591		b, err := json.Marshal(value)
592		if err != nil {
593			panic(err)
594		}
595		buffer.Write(b)
596		separator = ","
597	}
598
599	buffer.WriteString("{")
600	writeObjectPair("@type", m.moduleType)
601	writeObjectPair("@name", m.name)
602	if m.deps != nil {
603		writeObjectPair("@deps", m.deps)
604	}
605	for _, k := range android.SortedKeys(m.memberSpecific) {
606		v := m.memberSpecific[k]
607		writeObjectPair(k, v)
608	}
609	buffer.WriteString("}")
610	return buffer.Bytes(), nil
611}
612
613var _ json.Marshaler = (*moduleInfo)(nil)
614
615// generateInfoData creates a list of moduleInfo structures that will be marshalled into JSON.
616func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) interface{} {
617	modules := []*moduleInfo{}
618	sdkInfo := moduleInfo{
619		moduleType:     "sdk",
620		name:           ctx.ModuleName(),
621		memberSpecific: map[string]interface{}{},
622	}
623	modules = append(modules, &sdkInfo)
624
625	name2Info := map[string]*moduleInfo{}
626	getModuleInfo := func(module android.Module) *moduleInfo {
627		name := module.Name()
628		info := name2Info[name]
629		if info == nil {
630			moduleType := ctx.OtherModuleType(module)
631			// Remove any suffix added when creating modules dynamically.
632			moduleType = strings.Split(moduleType, "__")[0]
633			info = &moduleInfo{
634				moduleType: moduleType,
635				name:       name,
636			}
637
638			additionalSdkInfo, _ := android.OtherModuleProvider(ctx, module, android.AdditionalSdkInfoProvider)
639			info.memberSpecific = additionalSdkInfo.Properties
640
641			name2Info[name] = info
642		}
643		return info
644	}
645
646	for _, memberVariantDep := range memberVariantDeps {
647		propertyName := memberVariantDep.memberType.SdkPropertyName()
648		var list []string
649		if v, ok := sdkInfo.memberSpecific[propertyName]; ok {
650			list = v.([]string)
651		}
652
653		memberName := memberVariantDep.variant.Name()
654		list = append(list, memberName)
655		sdkInfo.memberSpecific[propertyName] = android.SortedUniqueStrings(list)
656
657		if memberVariantDep.container != nil {
658			containerInfo := getModuleInfo(memberVariantDep.container)
659			containerInfo.deps = android.SortedUniqueStrings(append(containerInfo.deps, memberName))
660		}
661
662		// Make sure that the module info is created for each module.
663		getModuleInfo(memberVariantDep.variant)
664	}
665
666	for _, memberName := range android.SortedKeys(name2Info) {
667		info := name2Info[memberName]
668		modules = append(modules, info)
669	}
670
671	return modules
672}
673
674// filterOutComponents removes any item from the deps list that is a component of another item in
675// the deps list, e.g. if the deps list contains "foo" and "foo.stubs" which is component of "foo"
676// then it will remove "foo.stubs" from the deps.
677func filterOutComponents(ctx android.ModuleContext, deps []sdkMemberVariantDep) []sdkMemberVariantDep {
678	// Collate the set of components that all the modules added to the sdk provide.
679	components := map[string]*sdkMemberVariantDep{}
680	for i := range deps {
681		dep := &deps[i]
682		for _, c := range dep.exportedComponentsInfo.Components {
683			components[c] = dep
684		}
685	}
686
687	// If no module provides components then return the input deps unfiltered.
688	if len(components) == 0 {
689		return deps
690	}
691
692	filtered := make([]sdkMemberVariantDep, 0, len(deps))
693	for _, dep := range deps {
694		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(dep.variant))
695		if owner, ok := components[name]; ok {
696			// This is a component of another module that is a member of the sdk.
697
698			// If the component is exported but the owning module is not then the configuration is not
699			// supported.
700			if dep.export && !owner.export {
701				ctx.ModuleErrorf("Module %s is internal to the SDK but provides component %s which is used outside the SDK")
702				continue
703			}
704
705			// This module must not be added to the list of members of the sdk as that would result in a
706			// duplicate module in the sdk snapshot.
707			continue
708		}
709
710		filtered = append(filtered, dep)
711	}
712	return filtered
713}
714
715// Check the syntax of the generated Android.bp file contents and if they are
716// invalid then log an error with the contents (tagged with line numbers) and the
717// errors that were found so that it is easy to see where the problem lies.
718func syntaxCheckSnapshotBpFile(ctx android.ModuleContext, contents string) {
719	errs := android.CheckBlueprintSyntax(ctx, "Android.bp", contents)
720	if len(errs) != 0 {
721		message := &strings.Builder{}
722		_, _ = fmt.Fprint(message, `errors in generated Android.bp snapshot:
723
724Generated Android.bp contents
725========================================================================
726`)
727		for i, line := range strings.Split(contents, "\n") {
728			_, _ = fmt.Fprintf(message, "%6d:    %s\n", i+1, line)
729		}
730
731		_, _ = fmt.Fprint(message, `
732========================================================================
733
734Errors found:
735`)
736
737		for _, err := range errs {
738			_, _ = fmt.Fprintf(message, "%s\n", err.Error())
739		}
740
741		ctx.ModuleErrorf("%s", message.String())
742	}
743}
744
745func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) {
746	err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice)
747	if err != nil {
748		ctx.ModuleErrorf("error extracting common properties: %s", err)
749	}
750}
751
752type propertyTag struct {
753	name string
754}
755
756var _ android.BpPropertyTag = propertyTag{}
757
758// BpPropertyTag instances to add to a property that contains references to other sdk members.
759//
760// These will ensure that the referenced modules are available, if required.
761var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
762var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
763
764type snapshotTransformation struct {
765	identityTransformation
766	builder *snapshotBuilder
767}
768
769func (t snapshotTransformation) transformModule(module *bpModule) *bpModule {
770	if module != nil {
771		// If the module is an internal member then use a unique name for it.
772		name := module.Name()
773		module.setProperty("name", t.builder.snapshotSdkMemberName(name, true))
774	}
775	return module
776}
777
778func (t snapshotTransformation) transformProperty(_ string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
779	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
780		required := tag == requiredSdkMemberReferencePropertyTag
781		return t.builder.snapshotSdkMemberNames(value.([]string), required), tag
782	} else {
783		return value, tag
784	}
785}
786
787type emptyClasspathContentsTransformation struct {
788	identityTransformation
789}
790
791func (t emptyClasspathContentsTransformation) transformModule(module *bpModule) *bpModule {
792	classpathModuleTypes := []string{
793		"prebuilt_bootclasspath_fragment",
794		"prebuilt_systemserverclasspath_fragment",
795	}
796	if module != nil && android.InList(module.moduleType, classpathModuleTypes) {
797		if contents, ok := module.bpPropertySet.properties["contents"].([]string); ok {
798			if len(contents) == 0 {
799				return nil
800			}
801		}
802	}
803	return module
804}
805
806type pruneEmptySetTransformer struct {
807	identityTransformation
808}
809
810var _ bpTransformer = (*pruneEmptySetTransformer)(nil)
811
812func (t pruneEmptySetTransformer) transformPropertySetAfterContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
813	if len(propertySet.properties) == 0 {
814		return nil, nil
815	} else {
816		return propertySet, tag
817	}
818}
819
820type replaceExportablePropertiesTransformer struct {
821	identityTransformation
822}
823
824var _ bpTransformer = (*replaceExportablePropertiesTransformer)(nil)
825
826func handleExportableProperties[T any](value T) any {
827	switch v := any(value).(type) {
828	case string:
829		return java.AllApiScopes.ConvertStubsLibraryExportableToEverything(v)
830	case *bpPropertySet:
831		v.properties = handleExportableProperties(v.properties).(map[string]interface{})
832		return v
833	case []string:
834		result := make([]string, len(v))
835		for i, elem := range v {
836			result[i] = handleExportableProperties(elem).(string)
837		}
838		return result
839	case []any:
840		result := make([]any, len(v))
841		for i, elem := range v {
842			result[i] = handleExportableProperties(elem)
843		}
844		return result
845	case map[string]any:
846		result := make(map[string]any)
847		for k, val := range v {
848			result[k] = handleExportableProperties(val)
849		}
850		return result
851	default:
852		return value
853	}
854}
855
856func (t replaceExportablePropertiesTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
857	if name == "name" {
858		return propertySet, tag
859	}
860	propertySet.properties = handleExportableProperties(propertySet.properties).(map[string]interface{})
861	return propertySet, tag
862}
863
864func generateBpContents(bpFile *bpFile) string {
865	contents := &generatedContents{}
866	contents.IndentedPrintf("// This is auto-generated. DO NOT EDIT.\n")
867	for _, bpModule := range bpFile.order {
868		contents.IndentedPrintf("\n")
869		contents.IndentedPrintf("%s {\n", bpModule.moduleType)
870		outputPropertySet(contents, bpModule.bpPropertySet)
871		contents.IndentedPrintf("}\n")
872	}
873	return contents.content.String()
874}
875
876func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
877	contents.Indent()
878
879	addComment := func(name string) {
880		if text, ok := set.comments[name]; ok {
881			for _, line := range strings.Split(text, "\n") {
882				contents.IndentedPrintf("// %s\n", line)
883			}
884		}
885	}
886
887	// Output the properties first, followed by the nested sets. This ensures a
888	// consistent output irrespective of whether property sets are created before
889	// or after the properties. This simplifies the creation of the module.
890	for _, name := range set.order {
891		value := set.getValue(name)
892
893		// Do not write property sets in the properties phase.
894		if _, ok := value.(*bpPropertySet); ok {
895			continue
896		}
897
898		addComment(name)
899		reflectValue := reflect.ValueOf(value)
900		outputNamedValue(contents, name, reflectValue)
901	}
902
903	for _, name := range set.order {
904		value := set.getValue(name)
905
906		// Only write property sets in the sets phase.
907		switch v := value.(type) {
908		case *bpPropertySet:
909			addComment(name)
910			contents.IndentedPrintf("%s: {\n", name)
911			outputPropertySet(contents, v)
912			contents.IndentedPrintf("},\n")
913		}
914	}
915
916	contents.Dedent()
917}
918
919// outputNamedValue outputs a value that has an associated name. The name will be indented, followed
920// by the value and then followed by a , and a newline.
921func outputNamedValue(contents *generatedContents, name string, value reflect.Value) {
922	contents.IndentedPrintf("%s: ", name)
923	outputUnnamedValue(contents, value)
924	contents.UnindentedPrintf(",\n")
925}
926
927// outputUnnamedValue outputs a single value. The value is not indented and is not followed by
928// either a , or a newline. With multi-line values, e.g. slices, all but the first line will be
929// indented and all but the last line will end with a newline.
930func outputUnnamedValue(contents *generatedContents, value reflect.Value) {
931	valueType := value.Type()
932	switch valueType.Kind() {
933	case reflect.Bool:
934		contents.UnindentedPrintf("%t", value.Bool())
935
936	case reflect.String:
937		contents.UnindentedPrintf("%q", value)
938
939	case reflect.Ptr:
940		outputUnnamedValue(contents, value.Elem())
941
942	case reflect.Slice:
943		length := value.Len()
944		if length == 0 {
945			contents.UnindentedPrintf("[]")
946		} else {
947			firstValue := value.Index(0)
948			if length == 1 && !multiLineValue(firstValue) {
949				contents.UnindentedPrintf("[")
950				outputUnnamedValue(contents, firstValue)
951				contents.UnindentedPrintf("]")
952			} else {
953				contents.UnindentedPrintf("[\n")
954				contents.Indent()
955				for i := 0; i < length; i++ {
956					itemValue := value.Index(i)
957					contents.IndentedPrintf("")
958					outputUnnamedValue(contents, itemValue)
959					contents.UnindentedPrintf(",\n")
960				}
961				contents.Dedent()
962				contents.IndentedPrintf("]")
963			}
964		}
965
966	case reflect.Struct:
967		// Avoid unlimited recursion by requiring every structure to implement android.BpPrintable.
968		v := value.Interface()
969		if _, ok := v.(android.BpPrintable); !ok {
970			panic(fmt.Errorf("property value %#v of type %T does not implement android.BpPrintable", v, v))
971		}
972		contents.UnindentedPrintf("{\n")
973		contents.Indent()
974		for f := 0; f < valueType.NumField(); f++ {
975			fieldType := valueType.Field(f)
976			if fieldType.Anonymous {
977				continue
978			}
979			fieldValue := value.Field(f)
980			fieldName := fieldType.Name
981			propertyName := proptools.PropertyNameForField(fieldName)
982			outputNamedValue(contents, propertyName, fieldValue)
983		}
984		contents.Dedent()
985		contents.IndentedPrintf("}")
986
987	default:
988		panic(fmt.Errorf("unknown type: %T of value %#v", value, value))
989	}
990}
991
992// multiLineValue returns true if the supplied value may require multiple lines in the output.
993func multiLineValue(value reflect.Value) bool {
994	kind := value.Kind()
995	return kind == reflect.Slice || kind == reflect.Struct
996}
997
998func (s *sdk) GetAndroidBpContentsForTests() string {
999	return generateBpContents(s.builderForTests.bpFile)
1000}
1001
1002func (s *sdk) GetInfoContentsForTests() string {
1003	return s.builderForTests.infoContents
1004}
1005
1006type snapshotBuilder struct {
1007	ctx android.ModuleContext
1008	sdk *sdk
1009
1010	snapshotDir android.OutputPath
1011	bpFile      *bpFile
1012
1013	// Map from destination to source of each copy - used to eliminate duplicates and
1014	// detect conflicts.
1015	copies map[string]string
1016
1017	filesToZip  android.Paths
1018	zipsToMerge android.Paths
1019
1020	// The path to an empty file.
1021	emptyFile android.WritablePath
1022
1023	prebuiltModules map[string]*bpModule
1024	prebuiltOrder   []*bpModule
1025
1026	// The set of all members by name.
1027	allMembersByName map[string]struct{}
1028
1029	// The set of exported members by name.
1030	exportedMembersByName map[string]struct{}
1031
1032	// The set of members which have been excluded from this snapshot; by name.
1033	excludedMembersByName map[string]struct{}
1034
1035	// The target build release for which the snapshot is to be generated.
1036	targetBuildRelease *buildRelease
1037
1038	// The contents of the .info file that describes the sdk contents.
1039	infoContents string
1040}
1041
1042func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
1043	if existing, ok := s.copies[dest]; ok {
1044		if existing != src.String() {
1045			s.ctx.ModuleErrorf("conflicting copy, %s copied from both %s and %s", dest, existing, src)
1046			return
1047		}
1048	} else {
1049		path := s.snapshotDir.Join(s.ctx, dest)
1050		s.ctx.Build(pctx, android.BuildParams{
1051			Rule:   android.Cp,
1052			Input:  src,
1053			Output: path,
1054		})
1055		s.filesToZip = append(s.filesToZip, path)
1056
1057		s.copies[dest] = src.String()
1058	}
1059}
1060
1061func (s *snapshotBuilder) UnzipToSnapshot(zipPath android.Path, destDir string) {
1062	ctx := s.ctx
1063
1064	// Repackage the zip file so that the entries are in the destDir directory.
1065	// This will allow the zip file to be merged into the snapshot.
1066	tmpZipPath := android.PathForModuleOut(ctx, "tmp", destDir+".zip").OutputPath
1067
1068	ctx.Build(pctx, android.BuildParams{
1069		Description: "Repackaging zip file " + destDir + " for snapshot " + ctx.ModuleName(),
1070		Rule:        repackageZip,
1071		Input:       zipPath,
1072		Output:      tmpZipPath,
1073		Args: map[string]string{
1074			"destdir": destDir,
1075		},
1076	})
1077
1078	// Add the repackaged zip file to the files to merge.
1079	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
1080}
1081
1082func (s *snapshotBuilder) EmptyFile() android.Path {
1083	if s.emptyFile == nil {
1084		ctx := s.ctx
1085		s.emptyFile = android.PathForModuleOut(ctx, "empty")
1086		s.ctx.Build(pctx, android.BuildParams{
1087			Rule:   android.Touch,
1088			Output: s.emptyFile,
1089		})
1090	}
1091
1092	return s.emptyFile
1093}
1094
1095func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
1096	name := member.Name()
1097	if s.prebuiltModules[name] != nil {
1098		panic(fmt.Sprintf("Duplicate module detected, module %s has already been added", name))
1099	}
1100
1101	m := s.bpFile.newModule(moduleType)
1102	m.AddProperty("name", name)
1103
1104	variant := member.Variants()[0]
1105
1106	if s.isInternalMember(name) {
1107		// An internal member is only referenced from the sdk snapshot which is in the
1108		// same package so can be marked as private.
1109		m.AddProperty("visibility", []string{"//visibility:private"})
1110	} else {
1111		// Change the visibility of the module SDK prebuilts to public.
1112		// This includes
1113		// 1. Stub libraries of `sdk` modules
1114		// 2. Binaries and libraries of `module_exports` modules
1115		//
1116		// This is a workaround to improve maintainlibility of the module SDK.
1117		// Since module sdks are generated from release branches and dropped to development
1118		// branches, there might be a visibility skew between the sources and prebuilts
1119		// of a specific module.
1120		// To reconcile this potential skew, change the visibility to public.
1121		//
1122		// This means dependencies can bypass visibility restrictions when prebuilts are used, so we rely
1123		// on source builds in CI to check them.
1124		//
1125		// TODO (b/361303067): This special case for category (2) can be removed if existing usages
1126		// of host/test prebuilts of modules like conscrypt,tzdata,i18n are switched to source builds.
1127		// It will also require ART switching to full manifests.
1128		m.AddProperty("visibility", []string{"//visibility:public"})
1129	}
1130
1131	// Where available copy apex_available properties from the member.
1132	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
1133		apexAvailable := apexAware.ApexAvailable()
1134		if len(apexAvailable) == 0 {
1135			// //apex_available:platform is the default.
1136			apexAvailable = []string{android.AvailableToPlatform}
1137		}
1138
1139		// Remove duplicates and sort.
1140		apexAvailable = android.FirstUniqueStrings(apexAvailable)
1141		sort.Strings(apexAvailable)
1142
1143		m.AddProperty("apex_available", apexAvailable)
1144	}
1145
1146	// The licenses are the same for all variants.
1147	mctx := s.ctx
1148	licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicenseInfoProvider)
1149	if len(licenseInfo.Licenses) > 0 {
1150		m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag())
1151	}
1152
1153	deviceSupported := false
1154	hostSupported := false
1155
1156	for _, variant := range member.Variants() {
1157		osClass := variant.Target().Os.Class
1158		if osClass == android.Host {
1159			hostSupported = true
1160		} else if osClass == android.Device {
1161			deviceSupported = true
1162		}
1163	}
1164
1165	addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
1166
1167	s.prebuiltModules[name] = m
1168	s.prebuiltOrder = append(s.prebuiltOrder, m)
1169	return m
1170}
1171
1172func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
1173	// If neither device or host is supported then this module does not support either so will not
1174	// recognize the properties.
1175	if !deviceSupported && !hostSupported {
1176		return
1177	}
1178
1179	if !deviceSupported {
1180		bpModule.AddProperty("device_supported", false)
1181	}
1182	if hostSupported {
1183		bpModule.AddProperty("host_supported", true)
1184	}
1185}
1186
1187func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
1188	if required {
1189		return requiredSdkMemberReferencePropertyTag
1190	} else {
1191		return optionalSdkMemberReferencePropertyTag
1192	}
1193}
1194
1195func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
1196	return optionalSdkMemberReferencePropertyTag
1197}
1198
1199// Get a name for sdk snapshot member. If the member is private then generate a snapshot specific
1200// name. As part of the processing this checks to make sure that any required members are part of
1201// the snapshot.
1202func (s *snapshotBuilder) snapshotSdkMemberName(name string, required bool) string {
1203	if _, ok := s.allMembersByName[name]; !ok {
1204		if required && !s.ctx.Config().AllowMissingDependencies() {
1205			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", name)
1206		}
1207		return name
1208	}
1209
1210	if s.isInternalMember(name) {
1211		return s.ctx.ModuleName() + "_" + name
1212	} else {
1213		return name
1214	}
1215}
1216
1217func (s *snapshotBuilder) snapshotSdkMemberNames(members []string, required bool) []string {
1218	var references []string = nil
1219	for _, m := range members {
1220		if _, ok := s.excludedMembersByName[m]; ok {
1221			continue
1222		}
1223		references = append(references, s.snapshotSdkMemberName(m, required))
1224	}
1225	return references
1226}
1227
1228func (s *snapshotBuilder) isInternalMember(memberName string) bool {
1229	_, ok := s.exportedMembersByName[memberName]
1230	return !ok
1231}
1232
1233// Add the properties from the given SdkMemberProperties to the blueprint
1234// property set. This handles common properties in SdkMemberPropertiesBase and
1235// calls the member-specific AddToPropertySet for the rest.
1236func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) {
1237	if memberProperties.Base().Compile_multilib != "" {
1238		targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib)
1239	}
1240
1241	memberProperties.AddToPropertySet(ctx, targetPropertySet)
1242}
1243
1244// sdkMemberVariantDep represents a dependency from an sdk variant onto a member variant.
1245type sdkMemberVariantDep struct {
1246	// The sdk variant that depends (possibly indirectly) on the member variant.
1247	sdkVariant *sdk
1248
1249	// The type of sdk member the variant is to be treated as.
1250	memberType android.SdkMemberType
1251
1252	// The variant that is added to the sdk.
1253	variant android.Module
1254
1255	// The optional container of this member, i.e. the module that is depended upon by the sdk
1256	// (possibly transitively) and whose dependency on this module is why it was added to the sdk.
1257	// Is nil if this a direct dependency of the sdk.
1258	container android.Module
1259
1260	// True if the member should be exported, i.e. accessible, from outside the sdk.
1261	export bool
1262
1263	// The names of additional component modules provided by the variant.
1264	exportedComponentsInfo android.ExportedComponentsInfo
1265
1266	// The minimum API level on which this module is supported.
1267	minApiLevel android.ApiLevel
1268}
1269
1270// Host returns true if the sdk member is a host variant (e.g. host tool)
1271func (s *sdkMemberVariantDep) Host() bool {
1272	return s.variant.Target().Os.Class == android.Host
1273}
1274
1275var _ android.SdkMember = (*sdkMember)(nil)
1276
1277// sdkMember groups all the variants of a specific member module together along with the name of the
1278// module and the member type. This is used to generate the prebuilt modules for a specific member.
1279type sdkMember struct {
1280	memberType android.SdkMemberType
1281	name       string
1282	variants   []android.Module
1283}
1284
1285func (m *sdkMember) Name() string {
1286	return m.name
1287}
1288
1289func (m *sdkMember) Variants() []android.Module {
1290	return m.variants
1291}
1292
1293// Track usages of multilib variants.
1294type multilibUsage int
1295
1296const (
1297	multilibNone multilibUsage = 0
1298	multilib32   multilibUsage = 1
1299	multilib64   multilibUsage = 2
1300	multilibBoth               = multilib32 | multilib64
1301)
1302
1303// Add the multilib that is used in the arch type.
1304func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
1305	multilib := archType.Multilib
1306	switch multilib {
1307	case "":
1308		return m
1309	case "lib32":
1310		return m | multilib32
1311	case "lib64":
1312		return m | multilib64
1313	default:
1314		panic(fmt.Errorf("unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
1315	}
1316}
1317
1318func (m multilibUsage) String() string {
1319	switch m {
1320	case multilibNone:
1321		return ""
1322	case multilib32:
1323		return "32"
1324	case multilib64:
1325		return "64"
1326	case multilibBoth:
1327		return "both"
1328	default:
1329		panic(fmt.Errorf("unknown multilib value, found %b, expected one of %b, %b, %b or %b",
1330			m, multilibNone, multilib32, multilib64, multilibBoth))
1331	}
1332}
1333
1334// TODO(187910671): BEGIN - Remove once modules do not have an APEX and default variant.
1335// variantCoordinate contains the coordinates used to identify a variant of an SDK member.
1336type variantCoordinate struct {
1337	// osType identifies the OS target of a variant.
1338	osType android.OsType
1339	// archId identifies the architecture and whether it is for the native bridge.
1340	archId archId
1341	// image is the image variant name.
1342	image string
1343	// linkType is the link type name.
1344	linkType string
1345}
1346
1347func getVariantCoordinate(ctx *memberContext, variant android.Module) variantCoordinate {
1348	linkType := ""
1349	if len(ctx.MemberType().SupportedLinkages()) > 0 {
1350		linkType = getLinkType(variant)
1351	}
1352	return variantCoordinate{
1353		osType:   variant.Target().Os,
1354		archId:   archIdFromTarget(variant.Target()),
1355		image:    variant.ImageVariation().Variation,
1356		linkType: linkType,
1357	}
1358}
1359
1360// selectApexVariantsWhereAvailable filters the input list of variants by selecting the APEX
1361// specific variant for a specific variantCoordinate when there is both an APEX and default variant.
1362//
1363// There is a long-standing issue where a module that is added to an APEX has both an APEX and
1364// default/platform variant created even when the module does not require a platform variant. As a
1365// result an indirect dependency onto a module via the APEX will use the APEX variant, whereas a
1366// direct dependency onto the module will use the default/platform variant. That would result in a
1367// failure while attempting to optimize the properties for a member as it would have two variants
1368// when only one was expected.
1369//
1370// This function mitigates that problem by detecting when there are two variants that differ only
1371// by apex variant, where one is the default/platform variant and one is the APEX variant. In that
1372// case it picks the APEX variant. It picks the APEX variant because that is the behavior that would
1373// be expected
1374func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.Module) []android.Module {
1375	moduleCtx := ctx.sdkMemberContext
1376
1377	// Group the variants by coordinates.
1378	variantsByCoord := make(map[variantCoordinate][]android.Module)
1379	for _, variant := range variants {
1380		coord := getVariantCoordinate(ctx, variant)
1381		variantsByCoord[coord] = append(variantsByCoord[coord], variant)
1382	}
1383
1384	toDiscard := make(map[android.Module]struct{})
1385	for coord, list := range variantsByCoord {
1386		count := len(list)
1387		if count == 1 {
1388			continue
1389		}
1390
1391		variantsByApex := make(map[string]android.Module)
1392		conflictDetected := false
1393		for _, variant := range list {
1394			apexInfo, _ := android.OtherModuleProvider(moduleCtx, variant, android.ApexInfoProvider)
1395			apexVariationName := apexInfo.ApexVariationName
1396			// If there are two variants for a specific APEX variation then there is conflict.
1397			if _, ok := variantsByApex[apexVariationName]; ok {
1398				conflictDetected = true
1399				break
1400			}
1401			variantsByApex[apexVariationName] = variant
1402		}
1403
1404		// If there are more than 2 apex variations or one of the apex variations is not the
1405		// default/platform variation then there is a conflict.
1406		if len(variantsByApex) != 2 {
1407			conflictDetected = true
1408		} else if _, ok := variantsByApex[""]; !ok {
1409			conflictDetected = true
1410		}
1411
1412		// If there are no conflicts then add the default/platform variation to the list to remove.
1413		if !conflictDetected {
1414			toDiscard[variantsByApex[""]] = struct{}{}
1415			continue
1416		}
1417
1418		// There are duplicate variants at this coordinate and they are not the default and APEX variant
1419		// so fail.
1420		variantDescriptions := []string{}
1421		for _, m := range list {
1422			variantDescriptions = append(variantDescriptions, fmt.Sprintf("    %s", m.String()))
1423		}
1424
1425		moduleCtx.ModuleErrorf("multiple conflicting variants detected for OsType{%s}, %s, Image{%s}, Link{%s}\n%s",
1426			coord.osType, coord.archId.String(), coord.image, coord.linkType,
1427			strings.Join(variantDescriptions, "\n"))
1428	}
1429
1430	// If there are any variants to discard then remove them from the list of variants, while
1431	// preserving the order.
1432	if len(toDiscard) > 0 {
1433		filtered := []android.Module{}
1434		for _, variant := range variants {
1435			if _, ok := toDiscard[variant]; !ok {
1436				filtered = append(filtered, variant)
1437			}
1438		}
1439		variants = filtered
1440	}
1441
1442	return variants
1443}
1444
1445// TODO(187910671): END - Remove once modules do not have an APEX and default variant.
1446
1447type baseInfo struct {
1448	Properties android.SdkMemberProperties
1449}
1450
1451func (b *baseInfo) optimizableProperties() interface{} {
1452	return b.Properties
1453}
1454
1455type osTypeSpecificInfo struct {
1456	baseInfo
1457
1458	osType android.OsType
1459
1460	// The list of arch type specific info for this os type.
1461	//
1462	// Nil if there is one variant whose arch type is common
1463	archInfos []*archTypeSpecificInfo
1464}
1465
1466var _ propertiesContainer = (*osTypeSpecificInfo)(nil)
1467
1468type variantPropertiesFactoryFunc func() android.SdkMemberProperties
1469
1470// Create a new osTypeSpecificInfo for the specified os type and its properties
1471// structures populated with information from the variants.
1472func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
1473	osInfo := &osTypeSpecificInfo{
1474		osType: osType,
1475	}
1476
1477	osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
1478		properties := variantPropertiesFactory()
1479		properties.Base().Os = osType
1480		return properties
1481	}
1482
1483	// Create a structure into which properties common across the architectures in
1484	// this os type will be stored.
1485	osInfo.Properties = osSpecificVariantPropertiesFactory()
1486
1487	// Group the variants by arch type.
1488	var variantsByArchId = make(map[archId][]android.Module)
1489	var archIds []archId
1490	for _, variant := range osTypeVariants {
1491		target := variant.Target()
1492		id := archIdFromTarget(target)
1493		if _, ok := variantsByArchId[id]; !ok {
1494			archIds = append(archIds, id)
1495		}
1496
1497		variantsByArchId[id] = append(variantsByArchId[id], variant)
1498	}
1499
1500	if commonVariants, ok := variantsByArchId[commonArchId]; ok {
1501		if len(osTypeVariants) != 1 {
1502			variants := []string{}
1503			for _, m := range osTypeVariants {
1504				variants = append(variants, fmt.Sprintf("    %s", m.String()))
1505			}
1506			panic(fmt.Errorf("expected to only have 1 variant of %q when arch type is common but found %d\n%s",
1507				ctx.Name(),
1508				len(osTypeVariants),
1509				strings.Join(variants, "\n")))
1510		}
1511
1512		// A common arch type only has one variant and its properties should be treated
1513		// as common to the os type.
1514		osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
1515	} else {
1516		// Create an arch specific info for each supported architecture type.
1517		for _, id := range archIds {
1518			archVariants := variantsByArchId[id]
1519			archInfo := newArchSpecificInfo(ctx, id, osType, osSpecificVariantPropertiesFactory, archVariants)
1520
1521			osInfo.archInfos = append(osInfo.archInfos, archInfo)
1522		}
1523	}
1524
1525	return osInfo
1526}
1527
1528func (osInfo *osTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
1529	if len(osInfo.archInfos) == 0 {
1530		pruner.pruneProperties(osInfo.Properties)
1531	} else {
1532		for _, archInfo := range osInfo.archInfos {
1533			archInfo.pruneUnsupportedProperties(pruner)
1534		}
1535	}
1536}
1537
1538// Optimize the properties by extracting common properties from arch type specific
1539// properties into os type specific properties.
1540func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
1541	// Nothing to do if there is only a single common architecture.
1542	if len(osInfo.archInfos) == 0 {
1543		return
1544	}
1545
1546	multilib := multilibNone
1547	for _, archInfo := range osInfo.archInfos {
1548		multilib = multilib.addArchType(archInfo.archId.archType)
1549
1550		// Optimize the arch properties first.
1551		archInfo.optimizeProperties(ctx, commonValueExtractor)
1552	}
1553
1554	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, osInfo.Properties, osInfo.archInfos)
1555
1556	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
1557	osInfo.Properties.Base().Compile_multilib = multilib.String()
1558}
1559
1560// Add the properties for an os to a property set.
1561//
1562// Maps the properties related to the os variants through to an appropriate
1563// module structure that will produce equivalent set of variants when it is
1564// processed in a build.
1565func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
1566
1567	var osPropertySet android.BpPropertySet
1568	var archPropertySet android.BpPropertySet
1569	var archOsPrefix string
1570	if osInfo.Properties.Base().Os_count == 1 &&
1571		(osInfo.osType.Class == android.Device || !ctx.memberType.IsHostOsDependent()) {
1572		// There is only one OS type present in the variants and it shouldn't have a
1573		// variant-specific target. The latter is the case if it's either for device
1574		// where there is only one OS (android), or for host and the member type
1575		// isn't host OS dependent.
1576
1577		// Create a structure that looks like:
1578		// module_type {
1579		//   name: "...",
1580		//   ...
1581		//   <common properties>
1582		//   ...
1583		//   <single os type specific properties>
1584		//
1585		//   arch: {
1586		//     <arch specific sections>
1587		//   }
1588		//
1589		osPropertySet = bpModule
1590		archPropertySet = osPropertySet.AddPropertySet("arch")
1591
1592		// Arch specific properties need to be added to an arch specific section
1593		// within arch.
1594		archOsPrefix = ""
1595	} else {
1596		// Create a structure that looks like:
1597		// module_type {
1598		//   name: "...",
1599		//   ...
1600		//   <common properties>
1601		//   ...
1602		//   target: {
1603		//     <arch independent os specific sections, e.g. android>
1604		//     ...
1605		//     <arch and os specific sections, e.g. android_x86>
1606		//   }
1607		//
1608		osType := osInfo.osType
1609		osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
1610		archPropertySet = targetPropertySet
1611
1612		// Arch specific properties need to be added to an os and arch specific
1613		// section prefixed with <os>_.
1614		archOsPrefix = osType.Name + "_"
1615	}
1616
1617	// Add the os specific but arch independent properties to the module.
1618	addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet)
1619
1620	// Add arch (and possibly os) specific sections for each set of arch (and possibly
1621	// os) specific properties.
1622	//
1623	// The archInfos list will be empty if the os contains variants for the common
1624	// architecture.
1625	for _, archInfo := range osInfo.archInfos {
1626		archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
1627	}
1628}
1629
1630func (osInfo *osTypeSpecificInfo) isHostVariant() bool {
1631	osClass := osInfo.osType.Class
1632	return osClass == android.Host
1633}
1634
1635var _ isHostVariant = (*osTypeSpecificInfo)(nil)
1636
1637func (osInfo *osTypeSpecificInfo) String() string {
1638	return fmt.Sprintf("OsType{%s}", osInfo.osType)
1639}
1640
1641// archId encapsulates the information needed to identify a combination of arch type and native
1642// bridge support.
1643//
1644// Conceptually, native bridge support is a facet of an android.Target, not an android.Arch as it is
1645// essentially using one android.Arch to implement another. However, in terms of the handling of
1646// the variants native bridge is treated as part of the arch variation. See the ArchVariation method
1647// on android.Target.
1648//
1649// So, it makes sense when optimizing the variants to combine native bridge with the arch type.
1650type archId struct {
1651	// The arch type of the variant's target.
1652	archType android.ArchType
1653
1654	// True if the variants is for the native bridge, false otherwise.
1655	nativeBridge bool
1656}
1657
1658// propertyName returns the name of the property corresponding to use for this arch id.
1659func (i *archId) propertyName() string {
1660	name := i.archType.Name
1661	if i.nativeBridge {
1662		// Note: This does not result in a valid property because there is no architecture specific
1663		// native bridge property, only a generic "native_bridge" property. However, this will be used
1664		// in error messages if there is an attempt to use this in a generated bp file.
1665		name += "_native_bridge"
1666	}
1667	return name
1668}
1669
1670func (i *archId) String() string {
1671	return fmt.Sprintf("ArchType{%s}, NativeBridge{%t}", i.archType, i.nativeBridge)
1672}
1673
1674// archIdFromTarget returns an archId initialized from information in the supplied target.
1675func archIdFromTarget(target android.Target) archId {
1676	return archId{
1677		archType:     target.Arch.ArchType,
1678		nativeBridge: target.NativeBridge == android.NativeBridgeEnabled,
1679	}
1680}
1681
1682// commonArchId is the archId for the common architecture.
1683var commonArchId = archId{archType: android.Common}
1684
1685type archTypeSpecificInfo struct {
1686	baseInfo
1687
1688	archId archId
1689	osType android.OsType
1690
1691	imageVariantInfos []*imageVariantSpecificInfo
1692}
1693
1694var _ propertiesContainer = (*archTypeSpecificInfo)(nil)
1695
1696// Create a new archTypeSpecificInfo for the specified arch type and its properties
1697// structures populated with information from the variants.
1698func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
1699
1700	// Create an arch specific info into which the variant properties can be copied.
1701	archInfo := &archTypeSpecificInfo{archId: archId, osType: osType}
1702
1703	// Create the properties into which the arch type specific properties will be
1704	// added.
1705	archInfo.Properties = variantPropertiesFactory()
1706
1707	// if there are multiple supported link variants, we want to nest based on linkage even if there
1708	// is only one variant, otherwise, if there is only one variant we can populate based on the arch
1709	if len(archVariants) == 1 && len(ctx.MemberType().SupportedLinkages()) <= 1 {
1710		archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
1711	} else {
1712		// Group the variants by image type.
1713		variantsByImage := make(map[string][]android.Module)
1714		for _, variant := range archVariants {
1715			image := variant.ImageVariation().Variation
1716			variantsByImage[image] = append(variantsByImage[image], variant)
1717		}
1718
1719		// Create the image variant info in a fixed order.
1720		for _, imageVariantName := range android.SortedKeys(variantsByImage) {
1721			variants := variantsByImage[imageVariantName]
1722			archInfo.imageVariantInfos = append(archInfo.imageVariantInfos, newImageVariantSpecificInfo(ctx, imageVariantName, variantPropertiesFactory, variants))
1723		}
1724	}
1725
1726	return archInfo
1727}
1728
1729// Get the link type of the variant
1730//
1731// If the variant is not differentiated by link type then it returns "",
1732// otherwise it returns one of "static" or "shared".
1733func getLinkType(variant android.Module) string {
1734	linkType := ""
1735	if linkable, ok := variant.(cc.LinkableInterface); ok {
1736		if linkable.Shared() && linkable.Static() {
1737			panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
1738		} else if linkable.Shared() {
1739			linkType = "shared"
1740		} else if linkable.Static() {
1741			linkType = "static"
1742		} else {
1743			panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
1744		}
1745	}
1746	return linkType
1747}
1748
1749func (archInfo *archTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
1750	if len(archInfo.imageVariantInfos) == 0 {
1751		pruner.pruneProperties(archInfo.Properties)
1752	} else {
1753		for _, imageVariantInfo := range archInfo.imageVariantInfos {
1754			imageVariantInfo.pruneUnsupportedProperties(pruner)
1755		}
1756	}
1757}
1758
1759// Optimize the properties by extracting common properties from link type specific
1760// properties into arch type specific properties.
1761func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
1762	if len(archInfo.imageVariantInfos) == 0 {
1763		return
1764	}
1765
1766	// Optimize the image variant properties first.
1767	for _, imageVariantInfo := range archInfo.imageVariantInfos {
1768		imageVariantInfo.optimizeProperties(ctx, commonValueExtractor)
1769	}
1770
1771	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.imageVariantInfos)
1772}
1773
1774// Add the properties for an arch type to a property set.
1775func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
1776	archPropertySuffix := archInfo.archId.propertyName()
1777	propertySetName := archOsPrefix + archPropertySuffix
1778	archTypePropertySet := archPropertySet.AddPropertySet(propertySetName)
1779	// Enable the <os>_<arch> variant explicitly when we've disabled it by default on host.
1780	if ctx.memberType.IsHostOsDependent() && archInfo.osType.Class == android.Host {
1781		archTypePropertySet.AddProperty("enabled", true)
1782	}
1783	addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet)
1784
1785	for _, imageVariantInfo := range archInfo.imageVariantInfos {
1786		imageVariantInfo.addToPropertySet(ctx, archTypePropertySet)
1787	}
1788
1789	// If this is for a native bridge architecture then make sure that the property set does not
1790	// contain any properties as providing native bridge specific properties is not currently
1791	// supported.
1792	if archInfo.archId.nativeBridge {
1793		propertySetContents := getPropertySetContents(archTypePropertySet)
1794		if propertySetContents != "" {
1795			ctx.SdkModuleContext().ModuleErrorf("Architecture variant %q of sdk member %q has properties distinct from other variants; this is not yet supported. The properties are:\n%s",
1796				propertySetName, ctx.name, propertySetContents)
1797		}
1798	}
1799}
1800
1801// getPropertySetContents returns the string representation of the contents of a property set, after
1802// recursively pruning any empty nested property sets.
1803func getPropertySetContents(propertySet android.BpPropertySet) string {
1804	set := propertySet.(*bpPropertySet)
1805	set.transformContents(pruneEmptySetTransformer{})
1806	if len(set.properties) != 0 {
1807		contents := &generatedContents{}
1808		contents.Indent()
1809		outputPropertySet(contents, set)
1810		setAsString := contents.content.String()
1811		return setAsString
1812	}
1813	return ""
1814}
1815
1816func (archInfo *archTypeSpecificInfo) String() string {
1817	return archInfo.archId.String()
1818}
1819
1820type imageVariantSpecificInfo struct {
1821	baseInfo
1822
1823	imageVariant string
1824
1825	linkInfos []*linkTypeSpecificInfo
1826}
1827
1828func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant string, variantPropertiesFactory variantPropertiesFactoryFunc, imageVariants []android.Module) *imageVariantSpecificInfo {
1829
1830	// Create an image variant specific info into which the variant properties can be copied.
1831	imageInfo := &imageVariantSpecificInfo{imageVariant: imageVariant}
1832
1833	// Create the properties into which the image variant specific properties will be added.
1834	imageInfo.Properties = variantPropertiesFactory()
1835
1836	// if there are multiple supported link variants, we want to nest even if there is only one
1837	// variant, otherwise, if there is only one variant we can populate based on the image
1838	if len(imageVariants) == 1 && len(ctx.MemberType().SupportedLinkages()) <= 1 {
1839		imageInfo.Properties.PopulateFromVariant(ctx, imageVariants[0])
1840	} else {
1841		// There is more than one variant for this image variant which must be differentiated by link
1842		// type. Or there are multiple supported linkages and we need to nest based on link type.
1843		for _, linkVariant := range imageVariants {
1844			linkType := getLinkType(linkVariant)
1845			if linkType == "" {
1846				panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(imageVariants)))
1847			} else {
1848				linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
1849
1850				imageInfo.linkInfos = append(imageInfo.linkInfos, linkInfo)
1851			}
1852		}
1853	}
1854
1855	return imageInfo
1856}
1857
1858func (imageInfo *imageVariantSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
1859	if len(imageInfo.linkInfos) == 0 {
1860		pruner.pruneProperties(imageInfo.Properties)
1861	} else {
1862		for _, linkInfo := range imageInfo.linkInfos {
1863			linkInfo.pruneUnsupportedProperties(pruner)
1864		}
1865	}
1866}
1867
1868// Optimize the properties by extracting common properties from link type specific
1869// properties into arch type specific properties.
1870func (imageInfo *imageVariantSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
1871	if len(imageInfo.linkInfos) == 0 {
1872		return
1873	}
1874
1875	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, imageInfo.Properties, imageInfo.linkInfos)
1876}
1877
1878// Add the properties for an arch type to a property set.
1879func (imageInfo *imageVariantSpecificInfo) addToPropertySet(ctx *memberContext, propertySet android.BpPropertySet) {
1880	if imageInfo.imageVariant != android.CoreVariation {
1881		propertySet = propertySet.AddPropertySet(imageInfo.imageVariant)
1882	}
1883
1884	addSdkMemberPropertiesToSet(ctx, imageInfo.Properties, propertySet)
1885
1886	usedLinkages := make(map[string]bool, len(imageInfo.linkInfos))
1887	for _, linkInfo := range imageInfo.linkInfos {
1888		usedLinkages[linkInfo.linkType] = true
1889		linkInfo.addToPropertySet(ctx, propertySet)
1890	}
1891
1892	// If not all supported linkages had existing variants, we need to disable the unsupported variant
1893	if len(imageInfo.linkInfos) < len(ctx.MemberType().SupportedLinkages()) {
1894		for _, l := range ctx.MemberType().SupportedLinkages() {
1895			if _, ok := usedLinkages[l]; !ok {
1896				otherLinkagePropertySet := propertySet.AddPropertySet(l)
1897				otherLinkagePropertySet.AddProperty("enabled", false)
1898			}
1899		}
1900	}
1901
1902	// If this is for a non-core image variant then make sure that the property set does not contain
1903	// any properties as providing non-core image variant specific properties for prebuilts is not
1904	// currently supported.
1905	if imageInfo.imageVariant != android.CoreVariation {
1906		propertySetContents := getPropertySetContents(propertySet)
1907		if propertySetContents != "" {
1908			ctx.SdkModuleContext().ModuleErrorf("Image variant %q of sdk member %q has properties distinct from other variants; this is not yet supported. The properties are:\n%s",
1909				imageInfo.imageVariant, ctx.name, propertySetContents)
1910		}
1911	}
1912}
1913
1914func (imageInfo *imageVariantSpecificInfo) String() string {
1915	return imageInfo.imageVariant
1916}
1917
1918type linkTypeSpecificInfo struct {
1919	baseInfo
1920
1921	linkType string
1922}
1923
1924var _ propertiesContainer = (*linkTypeSpecificInfo)(nil)
1925
1926// Create a new linkTypeSpecificInfo for the specified link type and its properties
1927// structures populated with information from the variant.
1928func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
1929	linkInfo := &linkTypeSpecificInfo{
1930		baseInfo: baseInfo{
1931			// Create the properties into which the link type specific properties will be
1932			// added.
1933			Properties: variantPropertiesFactory(),
1934		},
1935		linkType: linkType,
1936	}
1937	linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
1938	return linkInfo
1939}
1940
1941func (l *linkTypeSpecificInfo) addToPropertySet(ctx *memberContext, propertySet android.BpPropertySet) {
1942	linkPropertySet := propertySet.AddPropertySet(l.linkType)
1943	addSdkMemberPropertiesToSet(ctx, l.Properties, linkPropertySet)
1944}
1945
1946func (l *linkTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
1947	pruner.pruneProperties(l.Properties)
1948}
1949
1950func (l *linkTypeSpecificInfo) String() string {
1951	return fmt.Sprintf("LinkType{%s}", l.linkType)
1952}
1953
1954type memberContext struct {
1955	sdkMemberContext android.ModuleContext
1956	builder          *snapshotBuilder
1957	memberType       android.SdkMemberType
1958	name             string
1959
1960	// The set of traits required of this member.
1961	requiredTraits android.SdkMemberTraitSet
1962}
1963
1964func (m *memberContext) ModuleErrorf(fmt string, args ...interface{}) {
1965	m.sdkMemberContext.ModuleErrorf(fmt, args...)
1966}
1967
1968func (m *memberContext) SdkModuleContext() android.ModuleContext {
1969	return m.sdkMemberContext
1970}
1971
1972func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
1973	return m.builder
1974}
1975
1976func (m *memberContext) MemberType() android.SdkMemberType {
1977	return m.memberType
1978}
1979
1980func (m *memberContext) Name() string {
1981	return m.name
1982}
1983
1984func (m *memberContext) RequiresTrait(trait android.SdkMemberTrait) bool {
1985	return m.requiredTraits.Contains(trait)
1986}
1987
1988func (m *memberContext) IsTargetBuildBeforeTiramisu() bool {
1989	return m.builder.targetBuildRelease.EarlierThan(buildReleaseT)
1990}
1991
1992var _ android.SdkMemberContext = (*memberContext)(nil)
1993
1994func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
1995
1996	memberType := member.memberType
1997
1998	// Do not add the prefer property if the member snapshot module is a source module type.
1999	moduleCtx := ctx.sdkMemberContext
2000	if !memberType.UsesSourceModuleTypeInSnapshot() {
2001		// Set prefer. Setting this to false is not strictly required as that is the default but it does
2002		// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
2003		// check the behavior when a prebuilt is preferred. It also makes it explicit what the default
2004		// behavior is for the module.
2005		bpModule.insertAfter("name", "prefer", false)
2006	}
2007
2008	variants := selectApexVariantsWhereAvailable(ctx, member.variants)
2009
2010	// Group the variants by os type.
2011	variantsByOsType := make(map[android.OsType][]android.Module)
2012	for _, variant := range variants {
2013		osType := variant.Target().Os
2014		variantsByOsType[osType] = append(variantsByOsType[osType], variant)
2015	}
2016
2017	osCount := len(variantsByOsType)
2018	variantPropertiesFactory := func() android.SdkMemberProperties {
2019		properties := memberType.CreateVariantPropertiesStruct()
2020		base := properties.Base()
2021		base.Os_count = osCount
2022		return properties
2023	}
2024
2025	osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
2026
2027	// The set of properties that are common across all architectures and os types.
2028	commonProperties := variantPropertiesFactory()
2029	commonProperties.Base().Os = android.CommonOS
2030
2031	// Create a property pruner that will prune any properties unsupported by the target build
2032	// release.
2033	targetBuildRelease := ctx.builder.targetBuildRelease
2034	unsupportedPropertyPruner := newPropertyPrunerByBuildRelease(commonProperties, targetBuildRelease)
2035
2036	// Create common value extractor that can be used to optimize the properties.
2037	commonValueExtractor := newCommonValueExtractor(commonProperties)
2038
2039	// The list of property structures which are os type specific but common across
2040	// architectures within that os type.
2041	var osSpecificPropertiesContainers []*osTypeSpecificInfo
2042
2043	for osType, osTypeVariants := range variantsByOsType {
2044		osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
2045		osTypeToInfo[osType] = osInfo
2046		// Add the os specific properties to a list of os type specific yet architecture
2047		// independent properties structs.
2048		osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo)
2049
2050		osInfo.pruneUnsupportedProperties(unsupportedPropertyPruner)
2051
2052		// Optimize the properties across all the variants for a specific os type.
2053		osInfo.optimizeProperties(ctx, commonValueExtractor)
2054	}
2055
2056	// Extract properties which are common across all architectures and os types.
2057	extractCommonProperties(moduleCtx, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
2058
2059	// Add the common properties to the module.
2060	addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
2061
2062	// Create a target property set into which target specific properties can be
2063	// added.
2064	targetPropertySet := bpModule.AddPropertySet("target")
2065
2066	// If the member is host OS dependent and has host_supported then disable by
2067	// default and enable each host OS variant explicitly. This avoids problems
2068	// with implicitly enabled OS variants when the snapshot is used, which might
2069	// be different from this run (e.g. different build OS).
2070	if ctx.memberType.IsHostOsDependent() {
2071		hostSupported := bpModule.getValue("host_supported") == true // Missing means false.
2072		if hostSupported {
2073			hostPropertySet := targetPropertySet.AddPropertySet("host")
2074			hostPropertySet.AddProperty("enabled", false)
2075		}
2076	}
2077
2078	// Iterate over the os types in a fixed order.
2079	for _, osType := range s.getPossibleOsTypes() {
2080		osInfo := osTypeToInfo[osType]
2081		if osInfo == nil {
2082			continue
2083		}
2084
2085		osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
2086	}
2087}
2088
2089// Compute the list of possible os types that this sdk could support.
2090func (s *sdk) getPossibleOsTypes() []android.OsType {
2091	var osTypes []android.OsType
2092	for _, osType := range android.OsTypeList() {
2093		if s.DeviceSupported() {
2094			if osType.Class == android.Device {
2095				osTypes = append(osTypes, osType)
2096			}
2097		}
2098		if s.HostSupported() {
2099			if osType.Class == android.Host {
2100				osTypes = append(osTypes, osType)
2101			}
2102		}
2103	}
2104	sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
2105	return osTypes
2106}
2107
2108// Given a set of properties (struct value), return the value of the field within that
2109// struct (or one of its embedded structs).
2110type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
2111
2112// Checks the metadata to determine whether the property should be ignored for the
2113// purposes of common value extraction or not.
2114type extractorMetadataPredicate func(metadata propertiesContainer) bool
2115
2116// Indicates whether optimizable properties are provided by a host variant or
2117// not.
2118type isHostVariant interface {
2119	isHostVariant() bool
2120}
2121
2122// A property that can be optimized by the commonValueExtractor.
2123type extractorProperty struct {
2124	// The name of the field for this property. It is a "."-separated path for
2125	// fields in non-anonymous substructs.
2126	name string
2127
2128	// Filter that can use metadata associated with the properties being optimized
2129	// to determine whether the field should be ignored during common value
2130	// optimization.
2131	filter extractorMetadataPredicate
2132
2133	// Retrieves the value on which common value optimization will be performed.
2134	getter fieldAccessorFunc
2135
2136	// True if the field should never be cleared.
2137	//
2138	// This is set to true if and only if the field is annotated with `sdk:"keep"`.
2139	keep bool
2140
2141	// The empty value for the field.
2142	emptyValue reflect.Value
2143
2144	// True if the property can support arch variants false otherwise.
2145	archVariant bool
2146}
2147
2148func (p extractorProperty) String() string {
2149	return p.name
2150}
2151
2152// Supports extracting common values from a number of instances of a properties
2153// structure into a separate common set of properties.
2154type commonValueExtractor struct {
2155	// The properties that the extractor can optimize.
2156	properties []extractorProperty
2157}
2158
2159// Create a new common value extractor for the structure type for the supplied
2160// properties struct.
2161//
2162// The returned extractor can be used on any properties structure of the same type
2163// as the supplied set of properties.
2164func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
2165	structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
2166	extractor := &commonValueExtractor{}
2167	extractor.gatherFields(structType, nil, "")
2168	return extractor
2169}
2170
2171// Gather the fields from the supplied structure type from which common values will
2172// be extracted.
2173//
2174// This is recursive function. If it encounters a struct then it will recurse
2175// into it, passing in the accessor for the field and the struct name as prefix
2176// for the nested fields. That will then be used in the accessors for the fields
2177// in the embedded struct.
2178func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc, namePrefix string) {
2179	for f := 0; f < structType.NumField(); f++ {
2180		field := structType.Field(f)
2181		if field.PkgPath != "" {
2182			// Ignore unexported fields.
2183			continue
2184		}
2185
2186		// Ignore fields tagged with sdk:"ignore".
2187		if proptools.HasTag(field, "sdk", "ignore") {
2188			continue
2189		}
2190
2191		var filter extractorMetadataPredicate
2192
2193		// Add a filter
2194		if proptools.HasTag(field, "sdk", "ignored-on-host") {
2195			filter = func(metadata propertiesContainer) bool {
2196				if m, ok := metadata.(isHostVariant); ok {
2197					if m.isHostVariant() {
2198						return false
2199					}
2200				}
2201				return true
2202			}
2203		}
2204
2205		keep := proptools.HasTag(field, "sdk", "keep")
2206
2207		// Save a copy of the field index for use in the function.
2208		fieldIndex := f
2209
2210		name := namePrefix + field.Name
2211
2212		fieldGetter := func(value reflect.Value) reflect.Value {
2213			if containingStructAccessor != nil {
2214				// This is an embedded structure so first access the field for the embedded
2215				// structure.
2216				value = containingStructAccessor(value)
2217			}
2218
2219			// Skip through interface and pointer values to find the structure.
2220			value = getStructValue(value)
2221
2222			defer func() {
2223				if r := recover(); r != nil {
2224					panic(fmt.Errorf("%s for fieldIndex %d of field %s of value %#v", r, fieldIndex, name, value.Interface()))
2225				}
2226			}()
2227
2228			// Return the field.
2229			return value.Field(fieldIndex)
2230		}
2231
2232		if field.Type.Kind() == reflect.Struct {
2233			// Gather fields from the nested or embedded structure.
2234			var subNamePrefix string
2235			if field.Anonymous {
2236				subNamePrefix = namePrefix
2237			} else {
2238				subNamePrefix = name + "."
2239			}
2240			e.gatherFields(field.Type, fieldGetter, subNamePrefix)
2241		} else {
2242			property := extractorProperty{
2243				name,
2244				filter,
2245				fieldGetter,
2246				keep,
2247				reflect.Zero(field.Type),
2248				proptools.HasTag(field, "android", "arch_variant"),
2249			}
2250			e.properties = append(e.properties, property)
2251		}
2252	}
2253}
2254
2255func getStructValue(value reflect.Value) reflect.Value {
2256foundStruct:
2257	for {
2258		kind := value.Kind()
2259		switch kind {
2260		case reflect.Interface, reflect.Ptr:
2261			value = value.Elem()
2262		case reflect.Struct:
2263			break foundStruct
2264		default:
2265			panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
2266		}
2267	}
2268	return value
2269}
2270
2271// A container of properties to be optimized.
2272//
2273// Allows additional information to be associated with the properties, e.g. for
2274// filtering.
2275type propertiesContainer interface {
2276	fmt.Stringer
2277
2278	// Get the properties that need optimizing.
2279	optimizableProperties() interface{}
2280}
2281
2282// Extract common properties from a slice of property structures of the same type.
2283//
2284// All the property structures must be of the same type.
2285// commonProperties - must be a pointer to the structure into which common properties will be added.
2286// inputPropertiesSlice - must be a slice of propertiesContainer interfaces.
2287//
2288// Iterates over each exported field (capitalized name) and checks to see whether they
2289// have the same value (using DeepEquals) across all the input properties. If it does not then no
2290// change is made. Otherwise, the common value is stored in the field in the commonProperties
2291// and the field in each of the input properties structure is set to its default value. Nested
2292// structs are visited recursively and their non-struct fields are compared.
2293func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) error {
2294	commonPropertiesValue := reflect.ValueOf(commonProperties)
2295	commonStructValue := commonPropertiesValue.Elem()
2296
2297	sliceValue := reflect.ValueOf(inputPropertiesSlice)
2298
2299	for _, property := range e.properties {
2300		fieldGetter := property.getter
2301		filter := property.filter
2302		if filter == nil {
2303			filter = func(metadata propertiesContainer) bool {
2304				return true
2305			}
2306		}
2307
2308		// Check to see if all the structures have the same value for the field. The commonValue
2309		// is nil on entry to the loop and if it is nil on exit then there is no common value or
2310		// all the values have been filtered out, otherwise it points to the common value.
2311		var commonValue *reflect.Value
2312
2313		// Assume that all the values will be the same.
2314		//
2315		// While similar to this is not quite the same as commonValue == nil. If all the values
2316		// have been filtered out then this will be false but commonValue == nil will be true.
2317		valuesDiffer := false
2318
2319		for i := 0; i < sliceValue.Len(); i++ {
2320			container := sliceValue.Index(i).Interface().(propertiesContainer)
2321			itemValue := reflect.ValueOf(container.optimizableProperties())
2322			fieldValue := fieldGetter(itemValue)
2323
2324			if !filter(container) {
2325				expectedValue := property.emptyValue.Interface()
2326				actualValue := fieldValue.Interface()
2327				if !reflect.DeepEqual(expectedValue, actualValue) {
2328					return fmt.Errorf("field %q is supposed to be ignored for %q but is set to %#v instead of %#v", property, container, actualValue, expectedValue)
2329				}
2330				continue
2331			}
2332
2333			if commonValue == nil {
2334				// Use the first value as the commonProperties value.
2335				commonValue = &fieldValue
2336			} else {
2337				// If the value does not match the current common value then there is
2338				// no value in common so break out.
2339				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
2340					commonValue = nil
2341					valuesDiffer = true
2342					break
2343				}
2344			}
2345		}
2346
2347		// If the fields all have common value then store it in the common struct field
2348		// and set the input struct's field to the empty value.
2349		if commonValue != nil {
2350			emptyValue := property.emptyValue
2351			fieldGetter(commonStructValue).Set(*commonValue)
2352			if !property.keep {
2353				for i := 0; i < sliceValue.Len(); i++ {
2354					container := sliceValue.Index(i).Interface().(propertiesContainer)
2355					itemValue := reflect.ValueOf(container.optimizableProperties())
2356					fieldValue := fieldGetter(itemValue)
2357					fieldValue.Set(emptyValue)
2358				}
2359			}
2360		}
2361
2362		if valuesDiffer && !property.archVariant {
2363			// The values differ but the property does not support arch variants so it
2364			// is an error.
2365			var details strings.Builder
2366			for i := 0; i < sliceValue.Len(); i++ {
2367				container := sliceValue.Index(i).Interface().(propertiesContainer)
2368				itemValue := reflect.ValueOf(container.optimizableProperties())
2369				fieldValue := fieldGetter(itemValue)
2370
2371				_, _ = fmt.Fprintf(&details, "\n    %q has value %q", container.String(), fieldValue.Interface())
2372			}
2373
2374			return fmt.Errorf("field %q is not tagged as \"arch_variant\" but has arch specific properties:%s", property.String(), details.String())
2375		}
2376	}
2377
2378	return nil
2379}
2380