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