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