1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package sdk
16 
17 import (
18 	"fmt"
19 	"reflect"
20 	"sort"
21 	"strings"
22 
23 	"android/soong/apex"
24 	"android/soong/cc"
25 
26 	"github.com/google/blueprint"
27 	"github.com/google/blueprint/proptools"
28 
29 	"android/soong/android"
30 )
31 
32 var pctx = android.NewPackageContext("android/soong/sdk")
33 
34 var (
35 	repackageZip = pctx.AndroidStaticRule("SnapshotRepackageZip",
36 		blueprint.RuleParams{
37 			Command: `${config.Zip2ZipCmd} -i $in -o $out -x META-INF/**/* "**/*:$destdir"`,
38 			CommandDeps: []string{
39 				"${config.Zip2ZipCmd}",
40 			},
41 		},
42 		"destdir")
43 
44 	zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles",
45 		blueprint.RuleParams{
46 			Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`,
47 			CommandDeps: []string{
48 				"${config.SoongZipCmd}",
49 			},
50 			Rspfile:        "$out.rsp",
51 			RspfileContent: "$in",
52 		},
53 		"basedir")
54 
55 	mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips",
56 		blueprint.RuleParams{
57 			Command: `${config.MergeZipsCmd} $out $in`,
58 			CommandDeps: []string{
59 				"${config.MergeZipsCmd}",
60 			},
61 		})
62 )
63 
64 type generatedContents struct {
65 	content     strings.Builder
66 	indentLevel int
67 }
68 
69 // generatedFile abstracts operations for writing contents into a file and emit a build rule
70 // for the file.
71 type generatedFile struct {
72 	generatedContents
73 	path android.OutputPath
74 }
75 
76 func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
77 	return &generatedFile{
78 		path: android.PathForModuleOut(ctx, path...).OutputPath,
79 	}
80 }
81 
82 func (gc *generatedContents) Indent() {
83 	gc.indentLevel++
84 }
85 
86 func (gc *generatedContents) Dedent() {
87 	gc.indentLevel--
88 }
89 
90 func (gc *generatedContents) Printfln(format string, args ...interface{}) {
91 	fmt.Fprintf(&(gc.content), strings.Repeat("    ", gc.indentLevel)+format+"\n", args...)
92 }
93 
94 func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
95 	rb := android.NewRuleBuilder()
96 
97 	content := gf.content.String()
98 
99 	// ninja consumes newline characters in rspfile_content. Prevent it by
100 	// escaping the backslash in the newline character. The extra backslash
101 	// is removed when the rspfile is written to the actual script file
102 	content = strings.ReplaceAll(content, "\n", "\\n")
103 
104 	rb.Command().
105 		Implicits(implicits).
106 		Text("echo").Text(proptools.ShellEscape(content)).
107 		// convert \\n to \n
108 		Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
109 	rb.Command().
110 		Text("chmod a+x").Output(gf.path)
111 	rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base())
112 }
113 
114 // Collect all the members.
115 //
116 // Returns a list containing type (extracted from the dependency tag) and the variant
117 // plus the multilib usages.
118 func (s *sdk) collectMembers(ctx android.ModuleContext) {
119 	s.multilibUsages = multilibNone
120 	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
121 		tag := ctx.OtherModuleDependencyTag(child)
122 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
123 			memberType := memberTag.SdkMemberType()
124 
125 			// Make sure that the resolved module is allowed in the member list property.
126 			if !memberType.IsInstance(child) {
127 				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
128 			}
129 
130 			// Keep track of which multilib variants are used by the sdk.
131 			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
132 
133 			s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
134 
135 			// If the member type supports transitive sdk members then recurse down into
136 			// its dependencies, otherwise exit traversal.
137 			return memberType.HasTransitiveSdkMembers()
138 		}
139 
140 		return false
141 	})
142 }
143 
144 // Organize the members.
145 //
146 // The members are first grouped by type and then grouped by name. The order of
147 // the types is the order they are referenced in android.SdkMemberTypesRegistry.
148 // The names are in the order in which the dependencies were added.
149 //
150 // Returns the members as well as the multilib setting to use.
151 func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember {
152 	byType := make(map[android.SdkMemberType][]*sdkMember)
153 	byName := make(map[string]*sdkMember)
154 
155 	for _, memberRef := range memberRefs {
156 		memberType := memberRef.memberType
157 		variant := memberRef.variant
158 
159 		name := ctx.OtherModuleName(variant)
160 		member := byName[name]
161 		if member == nil {
162 			member = &sdkMember{memberType: memberType, name: name}
163 			byName[name] = member
164 			byType[memberType] = append(byType[memberType], member)
165 		}
166 
167 		// Only append new variants to the list. This is needed because a member can be both
168 		// exported by the sdk and also be a transitive sdk member.
169 		member.variants = appendUniqueVariants(member.variants, variant)
170 	}
171 
172 	var members []*sdkMember
173 	for _, memberListProperty := range s.memberListProperties() {
174 		membersOfType := byType[memberListProperty.memberType]
175 		members = append(members, membersOfType...)
176 	}
177 
178 	return members
179 }
180 
181 func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
182 	for _, v := range variants {
183 		if v == newVariant {
184 			return variants
185 		}
186 	}
187 	return append(variants, newVariant)
188 }
189 
190 // SDK directory structure
191 // <sdk_root>/
192 //     Android.bp   : definition of a 'sdk' module is here. This is a hand-made one.
193 //     <api_ver>/   : below this directory are all auto-generated
194 //         Android.bp   : definition of 'sdk_snapshot' module is here
195 //         aidl/
196 //            frameworks/base/core/..../IFoo.aidl   : an exported AIDL file
197 //         java/
198 //            <module_name>.jar    : the stub jar for a java library 'module_name'
199 //         include/
200 //            bionic/libc/include/stdlib.h   : an exported header file
201 //         include_gen/
202 //            <module_name>/com/android/.../IFoo.h : a generated header file
203 //         <arch>/include/   : arch-specific exported headers
204 //         <arch>/include_gen/   : arch-specific generated headers
205 //         <arch>/lib/
206 //            libFoo.so   : a stub library
207 
208 // A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot
209 // This isn't visible to users, so could be changed in future.
210 func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string {
211 	return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version
212 }
213 
214 // buildSnapshot is the main function in this source file. It creates rules to copy
215 // the contents (header files, stub libraries, etc) into the zip file.
216 func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
217 
218 	allMembersByName := make(map[string]struct{})
219 	exportedMembersByName := make(map[string]struct{})
220 	var memberRefs []sdkMemberRef
221 	for _, sdkVariant := range sdkVariants {
222 		memberRefs = append(memberRefs, sdkVariant.memberRefs...)
223 
224 		// Record the names of all the members, both explicitly specified and implicitly
225 		// included.
226 		for _, memberRef := range sdkVariant.memberRefs {
227 			allMembersByName[memberRef.variant.Name()] = struct{}{}
228 		}
229 
230 		// Merge the exported member sets from all sdk variants.
231 		for key, _ := range sdkVariant.getExportedMembers() {
232 			exportedMembersByName[key] = struct{}{}
233 		}
234 	}
235 
236 	snapshotDir := android.PathForModuleOut(ctx, "snapshot")
237 
238 	bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
239 
240 	bpFile := &bpFile{
241 		modules: make(map[string]*bpModule),
242 	}
243 
244 	builder := &snapshotBuilder{
245 		ctx:                   ctx,
246 		sdk:                   s,
247 		version:               "current",
248 		snapshotDir:           snapshotDir.OutputPath,
249 		copies:                make(map[string]string),
250 		filesToZip:            []android.Path{bp.path},
251 		bpFile:                bpFile,
252 		prebuiltModules:       make(map[string]*bpModule),
253 		allMembersByName:      allMembersByName,
254 		exportedMembersByName: exportedMembersByName,
255 	}
256 	s.builderForTests = builder
257 
258 	members := s.organizeMembers(ctx, memberRefs)
259 	for _, member := range members {
260 		memberType := member.memberType
261 
262 		memberCtx := &memberContext{ctx, builder, memberType, member.name}
263 
264 		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
265 		s.createMemberSnapshot(memberCtx, member, prebuiltModule)
266 	}
267 
268 	// Create a transformer that will transform an unversioned module into a versioned module.
269 	unversionedToVersionedTransformer := unversionedToVersionedTransformation{builder: builder}
270 
271 	// Create a transformer that will transform an unversioned module by replacing any references
272 	// to internal members with a unique module name and setting prefer: false.
273 	unversionedTransformer := unversionedTransformation{builder: builder}
274 
275 	for _, unversioned := range builder.prebuiltOrder {
276 		// Prune any empty property sets.
277 		unversioned = unversioned.transform(pruneEmptySetTransformer{})
278 
279 		// Copy the unversioned module so it can be modified to make it versioned.
280 		versioned := unversioned.deepCopy()
281 
282 		// Transform the unversioned module into a versioned one.
283 		versioned.transform(unversionedToVersionedTransformer)
284 		bpFile.AddModule(versioned)
285 
286 		// Transform the unversioned module to make it suitable for use in the snapshot.
287 		unversioned.transform(unversionedTransformer)
288 		bpFile.AddModule(unversioned)
289 	}
290 
291 	// Create the snapshot module.
292 	snapshotName := ctx.ModuleName() + string(android.SdkVersionSeparator) + builder.version
293 	var snapshotModuleType string
294 	if s.properties.Module_exports {
295 		snapshotModuleType = "module_exports_snapshot"
296 	} else {
297 		snapshotModuleType = "sdk_snapshot"
298 	}
299 	snapshotModule := bpFile.newModule(snapshotModuleType)
300 	snapshotModule.AddProperty("name", snapshotName)
301 
302 	// Make sure that the snapshot has the same visibility as the sdk.
303 	visibility := android.EffectiveVisibilityRules(ctx, s)
304 	if len(visibility) != 0 {
305 		snapshotModule.AddProperty("visibility", visibility)
306 	}
307 
308 	addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
309 
310 	var dynamicMemberPropertiesContainers []propertiesContainer
311 	osTypeToMemberProperties := make(map[android.OsType]*sdk)
312 	for _, sdkVariant := range sdkVariants {
313 		properties := sdkVariant.dynamicMemberTypeListProperties
314 		osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant
315 		dynamicMemberPropertiesContainers = append(dynamicMemberPropertiesContainers, &dynamicMemberPropertiesContainer{sdkVariant, properties})
316 	}
317 
318 	// Extract the common lists of members into a separate struct.
319 	commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
320 	extractor := newCommonValueExtractor(commonDynamicMemberProperties)
321 	extractCommonProperties(ctx, extractor, commonDynamicMemberProperties, dynamicMemberPropertiesContainers)
322 
323 	// Add properties common to all os types.
324 	s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
325 
326 	// Iterate over the os types in a fixed order.
327 	targetPropertySet := snapshotModule.AddPropertySet("target")
328 	for _, osType := range s.getPossibleOsTypes() {
329 		if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
330 			osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
331 
332 			// Compile_multilib defaults to both and must always be set to both on the
333 			// device and so only needs to be set when targeted at the host and is neither
334 			// unspecified or both.
335 			multilib := sdkVariant.multilibUsages
336 			if (osType.Class == android.Host || osType.Class == android.HostCross) &&
337 				multilib != multilibNone && multilib != multilibBoth {
338 				osPropertySet.AddProperty("compile_multilib", multilib.String())
339 			}
340 
341 			s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
342 		}
343 	}
344 
345 	// Prune any empty property sets.
346 	snapshotModule.transform(pruneEmptySetTransformer{})
347 
348 	bpFile.AddModule(snapshotModule)
349 
350 	// generate Android.bp
351 	bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
352 	generateBpContents(&bp.generatedContents, bpFile)
353 
354 	contents := bp.content.String()
355 	syntaxCheckSnapshotBpFile(ctx, contents)
356 
357 	bp.build(pctx, ctx, nil)
358 
359 	filesToZip := builder.filesToZip
360 
361 	// zip them all
362 	outputZipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
363 	outputDesc := "Building snapshot for " + ctx.ModuleName()
364 
365 	// If there are no zips to merge then generate the output zip directly.
366 	// Otherwise, generate an intermediate zip file into which other zips can be
367 	// merged.
368 	var zipFile android.OutputPath
369 	var desc string
370 	if len(builder.zipsToMerge) == 0 {
371 		zipFile = outputZipFile
372 		desc = outputDesc
373 	} else {
374 		zipFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.unmerged.zip").OutputPath
375 		desc = "Building intermediate snapshot for " + ctx.ModuleName()
376 	}
377 
378 	ctx.Build(pctx, android.BuildParams{
379 		Description: desc,
380 		Rule:        zipFiles,
381 		Inputs:      filesToZip,
382 		Output:      zipFile,
383 		Args: map[string]string{
384 			"basedir": builder.snapshotDir.String(),
385 		},
386 	})
387 
388 	if len(builder.zipsToMerge) != 0 {
389 		ctx.Build(pctx, android.BuildParams{
390 			Description: outputDesc,
391 			Rule:        mergeZips,
392 			Input:       zipFile,
393 			Inputs:      builder.zipsToMerge,
394 			Output:      outputZipFile,
395 		})
396 	}
397 
398 	return outputZipFile
399 }
400 
401 // Check the syntax of the generated Android.bp file contents and if they are
402 // invalid then log an error with the contents (tagged with line numbers) and the
403 // errors that were found so that it is easy to see where the problem lies.
404 func syntaxCheckSnapshotBpFile(ctx android.ModuleContext, contents string) {
405 	errs := android.CheckBlueprintSyntax(ctx, "Android.bp", contents)
406 	if len(errs) != 0 {
407 		message := &strings.Builder{}
408 		_, _ = fmt.Fprint(message, `errors in generated Android.bp snapshot:
409 
410 Generated Android.bp contents
411 ========================================================================
412 `)
413 		for i, line := range strings.Split(contents, "\n") {
414 			_, _ = fmt.Fprintf(message, "%6d:    %s\n", i+1, line)
415 		}
416 
417 		_, _ = fmt.Fprint(message, `
418 ========================================================================
419 
420 Errors found:
421 `)
422 
423 		for _, err := range errs {
424 			_, _ = fmt.Fprintf(message, "%s\n", err.Error())
425 		}
426 
427 		ctx.ModuleErrorf("%s", message.String())
428 	}
429 }
430 
431 func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) {
432 	err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice)
433 	if err != nil {
434 		ctx.ModuleErrorf("error extracting common properties: %s", err)
435 	}
436 }
437 
438 func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) {
439 	for _, memberListProperty := range s.memberListProperties() {
440 		names := memberListProperty.getter(dynamicMemberTypeListProperties)
441 		if len(names) > 0 {
442 			propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
443 		}
444 	}
445 }
446 
447 type propertyTag struct {
448 	name string
449 }
450 
451 // A BpPropertyTag to add to a property that contains references to other sdk members.
452 //
453 // This will cause the references to be rewritten to a versioned reference in the version
454 // specific instance of a snapshot module.
455 var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
456 var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
457 
458 // A BpPropertyTag that indicates the property should only be present in the versioned
459 // module.
460 //
461 // This will cause the property to be removed from the unversioned instance of a
462 // snapshot module.
463 var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"}
464 
465 type unversionedToVersionedTransformation struct {
466 	identityTransformation
467 	builder *snapshotBuilder
468 }
469 
470 func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
471 	// Use a versioned name for the module but remember the original name for the
472 	// snapshot.
473 	name := module.getValue("name").(string)
474 	module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
475 	module.insertAfter("name", "sdk_member_name", name)
476 	return module
477 }
478 
479 func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
480 	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
481 		required := tag == requiredSdkMemberReferencePropertyTag
482 		return t.builder.versionedSdkMemberNames(value.([]string), required), tag
483 	} else {
484 		return value, tag
485 	}
486 }
487 
488 type unversionedTransformation struct {
489 	identityTransformation
490 	builder *snapshotBuilder
491 }
492 
493 func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
494 	// If the module is an internal member then use a unique name for it.
495 	name := module.getValue("name").(string)
496 	module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
497 
498 	// Set prefer: false - this is not strictly required as that is the default.
499 	module.insertAfter("name", "prefer", false)
500 
501 	return module
502 }
503 
504 func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
505 	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
506 		required := tag == requiredSdkMemberReferencePropertyTag
507 		return t.builder.unversionedSdkMemberNames(value.([]string), required), tag
508 	} else if tag == sdkVersionedOnlyPropertyTag {
509 		// The property is not allowed in the unversioned module so remove it.
510 		return nil, nil
511 	} else {
512 		return value, tag
513 	}
514 }
515 
516 type pruneEmptySetTransformer struct {
517 	identityTransformation
518 }
519 
520 var _ bpTransformer = (*pruneEmptySetTransformer)(nil)
521 
522 func (t pruneEmptySetTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
523 	if len(propertySet.properties) == 0 {
524 		return nil, nil
525 	} else {
526 		return propertySet, tag
527 	}
528 }
529 
530 func generateBpContents(contents *generatedContents, bpFile *bpFile) {
531 	contents.Printfln("// This is auto-generated. DO NOT EDIT.")
532 	for _, bpModule := range bpFile.order {
533 		contents.Printfln("")
534 		contents.Printfln("%s {", bpModule.moduleType)
535 		outputPropertySet(contents, bpModule.bpPropertySet)
536 		contents.Printfln("}")
537 	}
538 }
539 
540 func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
541 	contents.Indent()
542 
543 	// Output the properties first, followed by the nested sets. This ensures a
544 	// consistent output irrespective of whether property sets are created before
545 	// or after the properties. This simplifies the creation of the module.
546 	for _, name := range set.order {
547 		value := set.getValue(name)
548 
549 		switch v := value.(type) {
550 		case []string:
551 			length := len(v)
552 			if length > 1 {
553 				contents.Printfln("%s: [", name)
554 				contents.Indent()
555 				for i := 0; i < length; i = i + 1 {
556 					contents.Printfln("%q,", v[i])
557 				}
558 				contents.Dedent()
559 				contents.Printfln("],")
560 			} else if length == 0 {
561 				contents.Printfln("%s: [],", name)
562 			} else {
563 				contents.Printfln("%s: [%q],", name, v[0])
564 			}
565 
566 		case bool:
567 			contents.Printfln("%s: %t,", name, v)
568 
569 		case *bpPropertySet:
570 			// Do not write property sets in the properties phase.
571 
572 		default:
573 			contents.Printfln("%s: %q,", name, value)
574 		}
575 	}
576 
577 	for _, name := range set.order {
578 		value := set.getValue(name)
579 
580 		// Only write property sets in the sets phase.
581 		switch v := value.(type) {
582 		case *bpPropertySet:
583 			contents.Printfln("%s: {", name)
584 			outputPropertySet(contents, v)
585 			contents.Printfln("},")
586 		}
587 	}
588 
589 	contents.Dedent()
590 }
591 
592 func (s *sdk) GetAndroidBpContentsForTests() string {
593 	contents := &generatedContents{}
594 	generateBpContents(contents, s.builderForTests.bpFile)
595 	return contents.content.String()
596 }
597 
598 type snapshotBuilder struct {
599 	ctx         android.ModuleContext
600 	sdk         *sdk
601 	version     string
602 	snapshotDir android.OutputPath
603 	bpFile      *bpFile
604 
605 	// Map from destination to source of each copy - used to eliminate duplicates and
606 	// detect conflicts.
607 	copies map[string]string
608 
609 	filesToZip  android.Paths
610 	zipsToMerge android.Paths
611 
612 	prebuiltModules map[string]*bpModule
613 	prebuiltOrder   []*bpModule
614 
615 	// The set of all members by name.
616 	allMembersByName map[string]struct{}
617 
618 	// The set of exported members by name.
619 	exportedMembersByName map[string]struct{}
620 }
621 
622 func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
623 	if existing, ok := s.copies[dest]; ok {
624 		if existing != src.String() {
625 			s.ctx.ModuleErrorf("conflicting copy, %s copied from both %s and %s", dest, existing, src)
626 			return
627 		}
628 	} else {
629 		path := s.snapshotDir.Join(s.ctx, dest)
630 		s.ctx.Build(pctx, android.BuildParams{
631 			Rule:   android.Cp,
632 			Input:  src,
633 			Output: path,
634 		})
635 		s.filesToZip = append(s.filesToZip, path)
636 
637 		s.copies[dest] = src.String()
638 	}
639 }
640 
641 func (s *snapshotBuilder) UnzipToSnapshot(zipPath android.Path, destDir string) {
642 	ctx := s.ctx
643 
644 	// Repackage the zip file so that the entries are in the destDir directory.
645 	// This will allow the zip file to be merged into the snapshot.
646 	tmpZipPath := android.PathForModuleOut(ctx, "tmp", destDir+".zip").OutputPath
647 
648 	ctx.Build(pctx, android.BuildParams{
649 		Description: "Repackaging zip file " + destDir + " for snapshot " + ctx.ModuleName(),
650 		Rule:        repackageZip,
651 		Input:       zipPath,
652 		Output:      tmpZipPath,
653 		Args: map[string]string{
654 			"destdir": destDir,
655 		},
656 	})
657 
658 	// Add the repackaged zip file to the files to merge.
659 	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
660 }
661 
662 func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
663 	name := member.Name()
664 	if s.prebuiltModules[name] != nil {
665 		panic(fmt.Sprintf("Duplicate module detected, module %s has already been added", name))
666 	}
667 
668 	m := s.bpFile.newModule(moduleType)
669 	m.AddProperty("name", name)
670 
671 	variant := member.Variants()[0]
672 
673 	if s.isInternalMember(name) {
674 		// An internal member is only referenced from the sdk snapshot which is in the
675 		// same package so can be marked as private.
676 		m.AddProperty("visibility", []string{"//visibility:private"})
677 	} else {
678 		// Extract visibility information from a member variant. All variants have the same
679 		// visibility so it doesn't matter which one is used.
680 		visibility := android.EffectiveVisibilityRules(s.ctx, variant)
681 		if len(visibility) != 0 {
682 			m.AddProperty("visibility", visibility)
683 		}
684 	}
685 
686 	deviceSupported := false
687 	hostSupported := false
688 
689 	for _, variant := range member.Variants() {
690 		osClass := variant.Target().Os.Class
691 		if osClass == android.Host || osClass == android.HostCross {
692 			hostSupported = true
693 		} else if osClass == android.Device {
694 			deviceSupported = true
695 		}
696 	}
697 
698 	addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
699 
700 	// Where available copy apex_available properties from the member.
701 	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
702 		apexAvailable := apexAware.ApexAvailable()
703 
704 		// Add in any baseline apex available settings.
705 		apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
706 
707 		if len(apexAvailable) > 0 {
708 			// Remove duplicates and sort.
709 			apexAvailable = android.FirstUniqueStrings(apexAvailable)
710 			sort.Strings(apexAvailable)
711 
712 			m.AddProperty("apex_available", apexAvailable)
713 		}
714 	}
715 
716 	// Disable installation in the versioned module of those modules that are ever installable.
717 	if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
718 		if installable.EverInstallable() {
719 			m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag)
720 		}
721 	}
722 
723 	s.prebuiltModules[name] = m
724 	s.prebuiltOrder = append(s.prebuiltOrder, m)
725 	return m
726 }
727 
728 func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
729 	if !deviceSupported {
730 		bpModule.AddProperty("device_supported", false)
731 	}
732 	if hostSupported {
733 		bpModule.AddProperty("host_supported", true)
734 	}
735 }
736 
737 func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
738 	if required {
739 		return requiredSdkMemberReferencePropertyTag
740 	} else {
741 		return optionalSdkMemberReferencePropertyTag
742 	}
743 }
744 
745 func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
746 	return optionalSdkMemberReferencePropertyTag
747 }
748 
749 // Get a versioned name appropriate for the SDK snapshot version being taken.
750 func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string {
751 	if _, ok := s.allMembersByName[unversionedName]; !ok {
752 		if required {
753 			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
754 		}
755 		return unversionedName
756 	}
757 	return versionedSdkMemberName(s.ctx, unversionedName, s.version)
758 }
759 
760 func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string {
761 	var references []string = nil
762 	for _, m := range members {
763 		references = append(references, s.versionedSdkMemberName(m, required))
764 	}
765 	return references
766 }
767 
768 // Get an internal name unique to the sdk.
769 func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string {
770 	if _, ok := s.allMembersByName[unversionedName]; !ok {
771 		if required {
772 			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
773 		}
774 		return unversionedName
775 	}
776 
777 	if s.isInternalMember(unversionedName) {
778 		return s.ctx.ModuleName() + "_" + unversionedName
779 	} else {
780 		return unversionedName
781 	}
782 }
783 
784 func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string {
785 	var references []string = nil
786 	for _, m := range members {
787 		references = append(references, s.unversionedSdkMemberName(m, required))
788 	}
789 	return references
790 }
791 
792 func (s *snapshotBuilder) isInternalMember(memberName string) bool {
793 	_, ok := s.exportedMembersByName[memberName]
794 	return !ok
795 }
796 
797 // Add the properties from the given SdkMemberProperties to the blueprint
798 // property set. This handles common properties in SdkMemberPropertiesBase and
799 // calls the member-specific AddToPropertySet for the rest.
800 func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) {
801 	if memberProperties.Base().Compile_multilib != "" {
802 		targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib)
803 	}
804 
805 	memberProperties.AddToPropertySet(ctx, targetPropertySet)
806 }
807 
808 type sdkMemberRef struct {
809 	memberType android.SdkMemberType
810 	variant    android.SdkAware
811 }
812 
813 var _ android.SdkMember = (*sdkMember)(nil)
814 
815 type sdkMember struct {
816 	memberType android.SdkMemberType
817 	name       string
818 	variants   []android.SdkAware
819 }
820 
821 func (m *sdkMember) Name() string {
822 	return m.name
823 }
824 
825 func (m *sdkMember) Variants() []android.SdkAware {
826 	return m.variants
827 }
828 
829 // Track usages of multilib variants.
830 type multilibUsage int
831 
832 const (
833 	multilibNone multilibUsage = 0
834 	multilib32   multilibUsage = 1
835 	multilib64   multilibUsage = 2
836 	multilibBoth               = multilib32 | multilib64
837 )
838 
839 // Add the multilib that is used in the arch type.
840 func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
841 	multilib := archType.Multilib
842 	switch multilib {
843 	case "":
844 		return m
845 	case "lib32":
846 		return m | multilib32
847 	case "lib64":
848 		return m | multilib64
849 	default:
850 		panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
851 	}
852 }
853 
854 func (m multilibUsage) String() string {
855 	switch m {
856 	case multilibNone:
857 		return ""
858 	case multilib32:
859 		return "32"
860 	case multilib64:
861 		return "64"
862 	case multilibBoth:
863 		return "both"
864 	default:
865 		panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
866 			m, multilibNone, multilib32, multilib64, multilibBoth))
867 	}
868 }
869 
870 type baseInfo struct {
871 	Properties android.SdkMemberProperties
872 }
873 
874 func (b *baseInfo) optimizableProperties() interface{} {
875 	return b.Properties
876 }
877 
878 type osTypeSpecificInfo struct {
879 	baseInfo
880 
881 	osType android.OsType
882 
883 	// The list of arch type specific info for this os type.
884 	//
885 	// Nil if there is one variant whose arch type is common
886 	archInfos []*archTypeSpecificInfo
887 }
888 
889 var _ propertiesContainer = (*osTypeSpecificInfo)(nil)
890 
891 type variantPropertiesFactoryFunc func() android.SdkMemberProperties
892 
893 // Create a new osTypeSpecificInfo for the specified os type and its properties
894 // structures populated with information from the variants.
895 func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
896 	osInfo := &osTypeSpecificInfo{
897 		osType: osType,
898 	}
899 
900 	osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
901 		properties := variantPropertiesFactory()
902 		properties.Base().Os = osType
903 		return properties
904 	}
905 
906 	// Create a structure into which properties common across the architectures in
907 	// this os type will be stored.
908 	osInfo.Properties = osSpecificVariantPropertiesFactory()
909 
910 	// Group the variants by arch type.
911 	var variantsByArchName = make(map[string][]android.Module)
912 	var archTypes []android.ArchType
913 	for _, variant := range osTypeVariants {
914 		archType := variant.Target().Arch.ArchType
915 		archTypeName := archType.Name
916 		if _, ok := variantsByArchName[archTypeName]; !ok {
917 			archTypes = append(archTypes, archType)
918 		}
919 
920 		variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
921 	}
922 
923 	if commonVariants, ok := variantsByArchName["common"]; ok {
924 		if len(osTypeVariants) != 1 {
925 			panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
926 		}
927 
928 		// A common arch type only has one variant and its properties should be treated
929 		// as common to the os type.
930 		osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
931 	} else {
932 		// Create an arch specific info for each supported architecture type.
933 		for _, archType := range archTypes {
934 			archTypeName := archType.Name
935 
936 			archVariants := variantsByArchName[archTypeName]
937 			archInfo := newArchSpecificInfo(ctx, archType, osSpecificVariantPropertiesFactory, archVariants)
938 
939 			osInfo.archInfos = append(osInfo.archInfos, archInfo)
940 		}
941 	}
942 
943 	return osInfo
944 }
945 
946 // Optimize the properties by extracting common properties from arch type specific
947 // properties into os type specific properties.
948 func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
949 	// Nothing to do if there is only a single common architecture.
950 	if len(osInfo.archInfos) == 0 {
951 		return
952 	}
953 
954 	multilib := multilibNone
955 	for _, archInfo := range osInfo.archInfos {
956 		multilib = multilib.addArchType(archInfo.archType)
957 
958 		// Optimize the arch properties first.
959 		archInfo.optimizeProperties(ctx, commonValueExtractor)
960 	}
961 
962 	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, osInfo.Properties, osInfo.archInfos)
963 
964 	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
965 	osInfo.Properties.Base().Compile_multilib = multilib.String()
966 }
967 
968 // Add the properties for an os to a property set.
969 //
970 // Maps the properties related to the os variants through to an appropriate
971 // module structure that will produce equivalent set of variants when it is
972 // processed in a build.
973 func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
974 
975 	var osPropertySet android.BpPropertySet
976 	var archPropertySet android.BpPropertySet
977 	var archOsPrefix string
978 	if osInfo.Properties.Base().Os_count == 1 {
979 		// There is only one os type present in the variants so don't bother
980 		// with adding target specific properties.
981 
982 		// Create a structure that looks like:
983 		// module_type {
984 		//   name: "...",
985 		//   ...
986 		//   <common properties>
987 		//   ...
988 		//   <single os type specific properties>
989 		//
990 		//   arch: {
991 		//     <arch specific sections>
992 		//   }
993 		//
994 		osPropertySet = bpModule
995 		archPropertySet = osPropertySet.AddPropertySet("arch")
996 
997 		// Arch specific properties need to be added to an arch specific section
998 		// within arch.
999 		archOsPrefix = ""
1000 	} else {
1001 		// Create a structure that looks like:
1002 		// module_type {
1003 		//   name: "...",
1004 		//   ...
1005 		//   <common properties>
1006 		//   ...
1007 		//   target: {
1008 		//     <arch independent os specific sections, e.g. android>
1009 		//     ...
1010 		//     <arch and os specific sections, e.g. android_x86>
1011 		//   }
1012 		//
1013 		osType := osInfo.osType
1014 		osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
1015 		archPropertySet = targetPropertySet
1016 
1017 		// Arch specific properties need to be added to an os and arch specific
1018 		// section prefixed with <os>_.
1019 		archOsPrefix = osType.Name + "_"
1020 	}
1021 
1022 	// Add the os specific but arch independent properties to the module.
1023 	addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet)
1024 
1025 	// Add arch (and possibly os) specific sections for each set of arch (and possibly
1026 	// os) specific properties.
1027 	//
1028 	// The archInfos list will be empty if the os contains variants for the common
1029 	// architecture.
1030 	for _, archInfo := range osInfo.archInfos {
1031 		archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
1032 	}
1033 }
1034 
1035 func (osInfo *osTypeSpecificInfo) isHostVariant() bool {
1036 	osClass := osInfo.osType.Class
1037 	return osClass == android.Host || osClass == android.HostCross
1038 }
1039 
1040 var _ isHostVariant = (*osTypeSpecificInfo)(nil)
1041 
1042 func (osInfo *osTypeSpecificInfo) String() string {
1043 	return fmt.Sprintf("OsType{%s}", osInfo.osType)
1044 }
1045 
1046 type archTypeSpecificInfo struct {
1047 	baseInfo
1048 
1049 	archType android.ArchType
1050 
1051 	linkInfos []*linkTypeSpecificInfo
1052 }
1053 
1054 var _ propertiesContainer = (*archTypeSpecificInfo)(nil)
1055 
1056 // Create a new archTypeSpecificInfo for the specified arch type and its properties
1057 // structures populated with information from the variants.
1058 func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
1059 
1060 	// Create an arch specific info into which the variant properties can be copied.
1061 	archInfo := &archTypeSpecificInfo{archType: archType}
1062 
1063 	// Create the properties into which the arch type specific properties will be
1064 	// added.
1065 	archInfo.Properties = variantPropertiesFactory()
1066 
1067 	if len(archVariants) == 1 {
1068 		archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
1069 	} else {
1070 		// There is more than one variant for this arch type which must be differentiated
1071 		// by link type.
1072 		for _, linkVariant := range archVariants {
1073 			linkType := getLinkType(linkVariant)
1074 			if linkType == "" {
1075 				panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
1076 			} else {
1077 				linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
1078 
1079 				archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
1080 			}
1081 		}
1082 	}
1083 
1084 	return archInfo
1085 }
1086 
1087 func (archInfo *archTypeSpecificInfo) optimizableProperties() interface{} {
1088 	return archInfo.Properties
1089 }
1090 
1091 // Get the link type of the variant
1092 //
1093 // If the variant is not differentiated by link type then it returns "",
1094 // otherwise it returns one of "static" or "shared".
1095 func getLinkType(variant android.Module) string {
1096 	linkType := ""
1097 	if linkable, ok := variant.(cc.LinkableInterface); ok {
1098 		if linkable.Shared() && linkable.Static() {
1099 			panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
1100 		} else if linkable.Shared() {
1101 			linkType = "shared"
1102 		} else if linkable.Static() {
1103 			linkType = "static"
1104 		} else {
1105 			panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
1106 		}
1107 	}
1108 	return linkType
1109 }
1110 
1111 // Optimize the properties by extracting common properties from link type specific
1112 // properties into arch type specific properties.
1113 func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
1114 	if len(archInfo.linkInfos) == 0 {
1115 		return
1116 	}
1117 
1118 	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.linkInfos)
1119 }
1120 
1121 // Add the properties for an arch type to a property set.
1122 func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
1123 	archTypeName := archInfo.archType.Name
1124 	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
1125 	addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet)
1126 
1127 	for _, linkInfo := range archInfo.linkInfos {
1128 		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
1129 		addSdkMemberPropertiesToSet(ctx, linkInfo.Properties, linkPropertySet)
1130 	}
1131 }
1132 
1133 func (archInfo *archTypeSpecificInfo) String() string {
1134 	return fmt.Sprintf("ArchType{%s}", archInfo.archType)
1135 }
1136 
1137 type linkTypeSpecificInfo struct {
1138 	baseInfo
1139 
1140 	linkType string
1141 }
1142 
1143 var _ propertiesContainer = (*linkTypeSpecificInfo)(nil)
1144 
1145 // Create a new linkTypeSpecificInfo for the specified link type and its properties
1146 // structures populated with information from the variant.
1147 func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
1148 	linkInfo := &linkTypeSpecificInfo{
1149 		baseInfo: baseInfo{
1150 			// Create the properties into which the link type specific properties will be
1151 			// added.
1152 			Properties: variantPropertiesFactory(),
1153 		},
1154 		linkType: linkType,
1155 	}
1156 	linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
1157 	return linkInfo
1158 }
1159 
1160 func (l *linkTypeSpecificInfo) String() string {
1161 	return fmt.Sprintf("LinkType{%s}", l.linkType)
1162 }
1163 
1164 type memberContext struct {
1165 	sdkMemberContext android.ModuleContext
1166 	builder          *snapshotBuilder
1167 	memberType       android.SdkMemberType
1168 	name             string
1169 }
1170 
1171 func (m *memberContext) SdkModuleContext() android.ModuleContext {
1172 	return m.sdkMemberContext
1173 }
1174 
1175 func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
1176 	return m.builder
1177 }
1178 
1179 func (m *memberContext) MemberType() android.SdkMemberType {
1180 	return m.memberType
1181 }
1182 
1183 func (m *memberContext) Name() string {
1184 	return m.name
1185 }
1186 
1187 func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
1188 
1189 	memberType := member.memberType
1190 
1191 	// Group the variants by os type.
1192 	variantsByOsType := make(map[android.OsType][]android.Module)
1193 	variants := member.Variants()
1194 	for _, variant := range variants {
1195 		osType := variant.Target().Os
1196 		variantsByOsType[osType] = append(variantsByOsType[osType], variant)
1197 	}
1198 
1199 	osCount := len(variantsByOsType)
1200 	variantPropertiesFactory := func() android.SdkMemberProperties {
1201 		properties := memberType.CreateVariantPropertiesStruct()
1202 		base := properties.Base()
1203 		base.Os_count = osCount
1204 		return properties
1205 	}
1206 
1207 	osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
1208 
1209 	// The set of properties that are common across all architectures and os types.
1210 	commonProperties := variantPropertiesFactory()
1211 	commonProperties.Base().Os = android.CommonOS
1212 
1213 	// Create common value extractor that can be used to optimize the properties.
1214 	commonValueExtractor := newCommonValueExtractor(commonProperties)
1215 
1216 	// The list of property structures which are os type specific but common across
1217 	// architectures within that os type.
1218 	var osSpecificPropertiesContainers []*osTypeSpecificInfo
1219 
1220 	for osType, osTypeVariants := range variantsByOsType {
1221 		osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
1222 		osTypeToInfo[osType] = osInfo
1223 		// Add the os specific properties to a list of os type specific yet architecture
1224 		// independent properties structs.
1225 		osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo)
1226 
1227 		// Optimize the properties across all the variants for a specific os type.
1228 		osInfo.optimizeProperties(ctx, commonValueExtractor)
1229 	}
1230 
1231 	// Extract properties which are common across all architectures and os types.
1232 	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
1233 
1234 	// Add the common properties to the module.
1235 	addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
1236 
1237 	// Create a target property set into which target specific properties can be
1238 	// added.
1239 	targetPropertySet := bpModule.AddPropertySet("target")
1240 
1241 	// Iterate over the os types in a fixed order.
1242 	for _, osType := range s.getPossibleOsTypes() {
1243 		osInfo := osTypeToInfo[osType]
1244 		if osInfo == nil {
1245 			continue
1246 		}
1247 
1248 		osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
1249 	}
1250 }
1251 
1252 // Compute the list of possible os types that this sdk could support.
1253 func (s *sdk) getPossibleOsTypes() []android.OsType {
1254 	var osTypes []android.OsType
1255 	for _, osType := range android.OsTypeList {
1256 		if s.DeviceSupported() {
1257 			if osType.Class == android.Device && osType != android.Fuchsia {
1258 				osTypes = append(osTypes, osType)
1259 			}
1260 		}
1261 		if s.HostSupported() {
1262 			if osType.Class == android.Host || osType.Class == android.HostCross {
1263 				osTypes = append(osTypes, osType)
1264 			}
1265 		}
1266 	}
1267 	sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
1268 	return osTypes
1269 }
1270 
1271 // Given a set of properties (struct value), return the value of the field within that
1272 // struct (or one of its embedded structs).
1273 type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
1274 
1275 // Checks the metadata to determine whether the property should be ignored for the
1276 // purposes of common value extraction or not.
1277 type extractorMetadataPredicate func(metadata propertiesContainer) bool
1278 
1279 // Indicates whether optimizable properties are provided by a host variant or
1280 // not.
1281 type isHostVariant interface {
1282 	isHostVariant() bool
1283 }
1284 
1285 // A property that can be optimized by the commonValueExtractor.
1286 type extractorProperty struct {
1287 	// The name of the field for this property.
1288 	name string
1289 
1290 	// Filter that can use metadata associated with the properties being optimized
1291 	// to determine whether the field should be ignored during common value
1292 	// optimization.
1293 	filter extractorMetadataPredicate
1294 
1295 	// Retrieves the value on which common value optimization will be performed.
1296 	getter fieldAccessorFunc
1297 
1298 	// The empty value for the field.
1299 	emptyValue reflect.Value
1300 
1301 	// True if the property can support arch variants false otherwise.
1302 	archVariant bool
1303 }
1304 
1305 func (p extractorProperty) String() string {
1306 	return p.name
1307 }
1308 
1309 // Supports extracting common values from a number of instances of a properties
1310 // structure into a separate common set of properties.
1311 type commonValueExtractor struct {
1312 	// The properties that the extractor can optimize.
1313 	properties []extractorProperty
1314 }
1315 
1316 // Create a new common value extractor for the structure type for the supplied
1317 // properties struct.
1318 //
1319 // The returned extractor can be used on any properties structure of the same type
1320 // as the supplied set of properties.
1321 func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
1322 	structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
1323 	extractor := &commonValueExtractor{}
1324 	extractor.gatherFields(structType, nil)
1325 	return extractor
1326 }
1327 
1328 // Gather the fields from the supplied structure type from which common values will
1329 // be extracted.
1330 //
1331 // This is recursive function. If it encounters an embedded field (no field name)
1332 // that is a struct then it will recurse into that struct passing in the accessor
1333 // for the field. That will then be used in the accessors for the fields in the
1334 // embedded struct.
1335 func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc) {
1336 	for f := 0; f < structType.NumField(); f++ {
1337 		field := structType.Field(f)
1338 		if field.PkgPath != "" {
1339 			// Ignore unexported fields.
1340 			continue
1341 		}
1342 
1343 		// Ignore fields whose value should be kept.
1344 		if proptools.HasTag(field, "sdk", "keep") {
1345 			continue
1346 		}
1347 
1348 		var filter extractorMetadataPredicate
1349 
1350 		// Add a filter
1351 		if proptools.HasTag(field, "sdk", "ignored-on-host") {
1352 			filter = func(metadata propertiesContainer) bool {
1353 				if m, ok := metadata.(isHostVariant); ok {
1354 					if m.isHostVariant() {
1355 						return false
1356 					}
1357 				}
1358 				return true
1359 			}
1360 		}
1361 
1362 		// Save a copy of the field index for use in the function.
1363 		fieldIndex := f
1364 
1365 		name := field.Name
1366 
1367 		fieldGetter := func(value reflect.Value) reflect.Value {
1368 			if containingStructAccessor != nil {
1369 				// This is an embedded structure so first access the field for the embedded
1370 				// structure.
1371 				value = containingStructAccessor(value)
1372 			}
1373 
1374 			// Skip through interface and pointer values to find the structure.
1375 			value = getStructValue(value)
1376 
1377 			defer func() {
1378 				if r := recover(); r != nil {
1379 					panic(fmt.Errorf("%s for fieldIndex %d of field %s of value %#v", r, fieldIndex, name, value.Interface()))
1380 				}
1381 			}()
1382 
1383 			// Return the field.
1384 			return value.Field(fieldIndex)
1385 		}
1386 
1387 		if field.Type.Kind() == reflect.Struct && field.Anonymous {
1388 			// Gather fields from the embedded structure.
1389 			e.gatherFields(field.Type, fieldGetter)
1390 		} else {
1391 			property := extractorProperty{
1392 				name,
1393 				filter,
1394 				fieldGetter,
1395 				reflect.Zero(field.Type),
1396 				proptools.HasTag(field, "android", "arch_variant"),
1397 			}
1398 			e.properties = append(e.properties, property)
1399 		}
1400 	}
1401 }
1402 
1403 func getStructValue(value reflect.Value) reflect.Value {
1404 foundStruct:
1405 	for {
1406 		kind := value.Kind()
1407 		switch kind {
1408 		case reflect.Interface, reflect.Ptr:
1409 			value = value.Elem()
1410 		case reflect.Struct:
1411 			break foundStruct
1412 		default:
1413 			panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
1414 		}
1415 	}
1416 	return value
1417 }
1418 
1419 // A container of properties to be optimized.
1420 //
1421 // Allows additional information to be associated with the properties, e.g. for
1422 // filtering.
1423 type propertiesContainer interface {
1424 	fmt.Stringer
1425 
1426 	// Get the properties that need optimizing.
1427 	optimizableProperties() interface{}
1428 }
1429 
1430 // A wrapper for dynamic member properties to allow them to be optimized.
1431 type dynamicMemberPropertiesContainer struct {
1432 	sdkVariant              *sdk
1433 	dynamicMemberProperties interface{}
1434 }
1435 
1436 func (c dynamicMemberPropertiesContainer) optimizableProperties() interface{} {
1437 	return c.dynamicMemberProperties
1438 }
1439 
1440 func (c dynamicMemberPropertiesContainer) String() string {
1441 	return c.sdkVariant.String()
1442 }
1443 
1444 // Extract common properties from a slice of property structures of the same type.
1445 //
1446 // All the property structures must be of the same type.
1447 // commonProperties - must be a pointer to the structure into which common properties will be added.
1448 // inputPropertiesSlice - must be a slice of propertiesContainer interfaces.
1449 //
1450 // Iterates over each exported field (capitalized name) and checks to see whether they
1451 // have the same value (using DeepEquals) across all the input properties. If it does not then no
1452 // change is made. Otherwise, the common value is stored in the field in the commonProperties
1453 // and the field in each of the input properties structure is set to its default value.
1454 func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) error {
1455 	commonPropertiesValue := reflect.ValueOf(commonProperties)
1456 	commonStructValue := commonPropertiesValue.Elem()
1457 
1458 	sliceValue := reflect.ValueOf(inputPropertiesSlice)
1459 
1460 	for _, property := range e.properties {
1461 		fieldGetter := property.getter
1462 		filter := property.filter
1463 		if filter == nil {
1464 			filter = func(metadata propertiesContainer) bool {
1465 				return true
1466 			}
1467 		}
1468 
1469 		// Check to see if all the structures have the same value for the field. The commonValue
1470 		// is nil on entry to the loop and if it is nil on exit then there is no common value or
1471 		// all the values have been filtered out, otherwise it points to the common value.
1472 		var commonValue *reflect.Value
1473 
1474 		// Assume that all the values will be the same.
1475 		//
1476 		// While similar to this is not quite the same as commonValue == nil. If all the values
1477 		// have been filtered out then this will be false but commonValue == nil will be true.
1478 		valuesDiffer := false
1479 
1480 		for i := 0; i < sliceValue.Len(); i++ {
1481 			container := sliceValue.Index(i).Interface().(propertiesContainer)
1482 			itemValue := reflect.ValueOf(container.optimizableProperties())
1483 			fieldValue := fieldGetter(itemValue)
1484 
1485 			if !filter(container) {
1486 				expectedValue := property.emptyValue.Interface()
1487 				actualValue := fieldValue.Interface()
1488 				if !reflect.DeepEqual(expectedValue, actualValue) {
1489 					return fmt.Errorf("field %q is supposed to be ignored for %q but is set to %#v instead of %#v", property, container, actualValue, expectedValue)
1490 				}
1491 				continue
1492 			}
1493 
1494 			if commonValue == nil {
1495 				// Use the first value as the commonProperties value.
1496 				commonValue = &fieldValue
1497 			} else {
1498 				// If the value does not match the current common value then there is
1499 				// no value in common so break out.
1500 				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
1501 					commonValue = nil
1502 					valuesDiffer = true
1503 					break
1504 				}
1505 			}
1506 		}
1507 
1508 		// If the fields all have common value then store it in the common struct field
1509 		// and set the input struct's field to the empty value.
1510 		if commonValue != nil {
1511 			emptyValue := property.emptyValue
1512 			fieldGetter(commonStructValue).Set(*commonValue)
1513 			for i := 0; i < sliceValue.Len(); i++ {
1514 				container := sliceValue.Index(i).Interface().(propertiesContainer)
1515 				itemValue := reflect.ValueOf(container.optimizableProperties())
1516 				fieldValue := fieldGetter(itemValue)
1517 				fieldValue.Set(emptyValue)
1518 			}
1519 		}
1520 
1521 		if valuesDiffer && !property.archVariant {
1522 			// The values differ but the property does not support arch variants so it
1523 			// is an error.
1524 			var details strings.Builder
1525 			for i := 0; i < sliceValue.Len(); i++ {
1526 				container := sliceValue.Index(i).Interface().(propertiesContainer)
1527 				itemValue := reflect.ValueOf(container.optimizableProperties())
1528 				fieldValue := fieldGetter(itemValue)
1529 
1530 				_, _ = fmt.Fprintf(&details, "\n    %q has value %q", container.String(), fieldValue.Interface())
1531 			}
1532 
1533 			return fmt.Errorf("field %q is not tagged as \"arch_variant\" but has arch specific properties:%s", property.String(), details.String())
1534 		}
1535 	}
1536 
1537 	return nil
1538 }
1539