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