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