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