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