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