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