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 15 package sdk 16 17 import ( 18 "fmt" 19 "reflect" 20 "sort" 21 "strings" 22 23 "android/soong/apex" 24 "android/soong/cc" 25 26 "github.com/google/blueprint" 27 "github.com/google/blueprint/proptools" 28 29 "android/soong/android" 30 ) 31 32 var pctx = android.NewPackageContext("android/soong/sdk") 33 34 var ( 35 repackageZip = pctx.AndroidStaticRule("SnapshotRepackageZip", 36 blueprint.RuleParams{ 37 Command: `${config.Zip2ZipCmd} -i $in -o $out -x META-INF/**/* "**/*:$destdir"`, 38 CommandDeps: []string{ 39 "${config.Zip2ZipCmd}", 40 }, 41 }, 42 "destdir") 43 44 zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles", 45 blueprint.RuleParams{ 46 Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`, 47 CommandDeps: []string{ 48 "${config.SoongZipCmd}", 49 }, 50 Rspfile: "$out.rsp", 51 RspfileContent: "$in", 52 }, 53 "basedir") 54 55 mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips", 56 blueprint.RuleParams{ 57 Command: `${config.MergeZipsCmd} $out $in`, 58 CommandDeps: []string{ 59 "${config.MergeZipsCmd}", 60 }, 61 }) 62 ) 63 64 type generatedContents struct { 65 content strings.Builder 66 indentLevel int 67 } 68 69 // generatedFile abstracts operations for writing contents into a file and emit a build rule 70 // for the file. 71 type generatedFile struct { 72 generatedContents 73 path android.OutputPath 74 } 75 76 func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile { 77 return &generatedFile{ 78 path: android.PathForModuleOut(ctx, path...).OutputPath, 79 } 80 } 81 82 func (gc *generatedContents) Indent() { 83 gc.indentLevel++ 84 } 85 86 func (gc *generatedContents) Dedent() { 87 gc.indentLevel-- 88 } 89 90 func (gc *generatedContents) Printfln(format string, args ...interface{}) { 91 fmt.Fprintf(&(gc.content), strings.Repeat(" ", gc.indentLevel)+format+"\n", args...) 92 } 93 94 func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) { 95 rb := android.NewRuleBuilder() 96 97 content := gf.content.String() 98 99 // ninja consumes newline characters in rspfile_content. Prevent it by 100 // escaping the backslash in the newline character. The extra backslash 101 // is removed when the rspfile is written to the actual script file 102 content = strings.ReplaceAll(content, "\n", "\\n") 103 104 rb.Command(). 105 Implicits(implicits). 106 Text("echo").Text(proptools.ShellEscape(content)). 107 // convert \\n to \n 108 Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path) 109 rb.Command(). 110 Text("chmod a+x").Output(gf.path) 111 rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base()) 112 } 113 114 // Collect all the members. 115 // 116 // Returns a list containing type (extracted from the dependency tag) and the variant 117 // plus the multilib usages. 118 func (s *sdk) collectMembers(ctx android.ModuleContext) { 119 s.multilibUsages = multilibNone 120 ctx.WalkDeps(func(child android.Module, parent android.Module) bool { 121 tag := ctx.OtherModuleDependencyTag(child) 122 if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok { 123 memberType := memberTag.SdkMemberType() 124 125 // Make sure that the resolved module is allowed in the member list property. 126 if !memberType.IsInstance(child) { 127 ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName()) 128 } 129 130 // Keep track of which multilib variants are used by the sdk. 131 s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType) 132 133 s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)}) 134 135 // If the member type supports transitive sdk members then recurse down into 136 // its dependencies, otherwise exit traversal. 137 return memberType.HasTransitiveSdkMembers() 138 } 139 140 return false 141 }) 142 } 143 144 // Organize the members. 145 // 146 // The members are first grouped by type and then grouped by name. The order of 147 // the types is the order they are referenced in android.SdkMemberTypesRegistry. 148 // The names are in the order in which the dependencies were added. 149 // 150 // Returns the members as well as the multilib setting to use. 151 func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember { 152 byType := make(map[android.SdkMemberType][]*sdkMember) 153 byName := make(map[string]*sdkMember) 154 155 for _, memberRef := range memberRefs { 156 memberType := memberRef.memberType 157 variant := memberRef.variant 158 159 name := ctx.OtherModuleName(variant) 160 member := byName[name] 161 if member == nil { 162 member = &sdkMember{memberType: memberType, name: name} 163 byName[name] = member 164 byType[memberType] = append(byType[memberType], member) 165 } 166 167 // Only append new variants to the list. This is needed because a member can be both 168 // exported by the sdk and also be a transitive sdk member. 169 member.variants = appendUniqueVariants(member.variants, variant) 170 } 171 172 var members []*sdkMember 173 for _, memberListProperty := range s.memberListProperties() { 174 membersOfType := byType[memberListProperty.memberType] 175 members = append(members, membersOfType...) 176 } 177 178 return members 179 } 180 181 func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware { 182 for _, v := range variants { 183 if v == newVariant { 184 return variants 185 } 186 } 187 return append(variants, newVariant) 188 } 189 190 // SDK directory structure 191 // <sdk_root>/ 192 // Android.bp : definition of a 'sdk' module is here. This is a hand-made one. 193 // <api_ver>/ : below this directory are all auto-generated 194 // Android.bp : definition of 'sdk_snapshot' module is here 195 // aidl/ 196 // frameworks/base/core/..../IFoo.aidl : an exported AIDL file 197 // java/ 198 // <module_name>.jar : the stub jar for a java library 'module_name' 199 // include/ 200 // bionic/libc/include/stdlib.h : an exported header file 201 // include_gen/ 202 // <module_name>/com/android/.../IFoo.h : a generated header file 203 // <arch>/include/ : arch-specific exported headers 204 // <arch>/include_gen/ : arch-specific generated headers 205 // <arch>/lib/ 206 // libFoo.so : a stub library 207 208 // A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot 209 // This isn't visible to users, so could be changed in future. 210 func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string { 211 return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version 212 } 213 214 // buildSnapshot is the main function in this source file. It creates rules to copy 215 // the contents (header files, stub libraries, etc) into the zip file. 216 func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath { 217 218 allMembersByName := make(map[string]struct{}) 219 exportedMembersByName := make(map[string]struct{}) 220 var memberRefs []sdkMemberRef 221 for _, sdkVariant := range sdkVariants { 222 memberRefs = append(memberRefs, sdkVariant.memberRefs...) 223 224 // Record the names of all the members, both explicitly specified and implicitly 225 // included. 226 for _, memberRef := range sdkVariant.memberRefs { 227 allMembersByName[memberRef.variant.Name()] = struct{}{} 228 } 229 230 // Merge the exported member sets from all sdk variants. 231 for key, _ := range sdkVariant.getExportedMembers() { 232 exportedMembersByName[key] = struct{}{} 233 } 234 } 235 236 snapshotDir := android.PathForModuleOut(ctx, "snapshot") 237 238 bp := newGeneratedFile(ctx, "snapshot", "Android.bp") 239 240 bpFile := &bpFile{ 241 modules: make(map[string]*bpModule), 242 } 243 244 builder := &snapshotBuilder{ 245 ctx: ctx, 246 sdk: s, 247 version: "current", 248 snapshotDir: snapshotDir.OutputPath, 249 copies: make(map[string]string), 250 filesToZip: []android.Path{bp.path}, 251 bpFile: bpFile, 252 prebuiltModules: make(map[string]*bpModule), 253 allMembersByName: allMembersByName, 254 exportedMembersByName: exportedMembersByName, 255 } 256 s.builderForTests = builder 257 258 members := s.organizeMembers(ctx, memberRefs) 259 for _, member := range members { 260 memberType := member.memberType 261 262 memberCtx := &memberContext{ctx, builder, memberType, member.name} 263 264 prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member) 265 s.createMemberSnapshot(memberCtx, member, prebuiltModule) 266 } 267 268 // Create a transformer that will transform an unversioned module into a versioned module. 269 unversionedToVersionedTransformer := unversionedToVersionedTransformation{builder: builder} 270 271 // Create a transformer that will transform an unversioned module by replacing any references 272 // to internal members with a unique module name and setting prefer: false. 273 unversionedTransformer := unversionedTransformation{builder: builder} 274 275 for _, unversioned := range builder.prebuiltOrder { 276 // Prune any empty property sets. 277 unversioned = unversioned.transform(pruneEmptySetTransformer{}) 278 279 // Copy the unversioned module so it can be modified to make it versioned. 280 versioned := unversioned.deepCopy() 281 282 // Transform the unversioned module into a versioned one. 283 versioned.transform(unversionedToVersionedTransformer) 284 bpFile.AddModule(versioned) 285 286 // Transform the unversioned module to make it suitable for use in the snapshot. 287 unversioned.transform(unversionedTransformer) 288 bpFile.AddModule(unversioned) 289 } 290 291 // Create the snapshot module. 292 snapshotName := ctx.ModuleName() + string(android.SdkVersionSeparator) + builder.version 293 var snapshotModuleType string 294 if s.properties.Module_exports { 295 snapshotModuleType = "module_exports_snapshot" 296 } else { 297 snapshotModuleType = "sdk_snapshot" 298 } 299 snapshotModule := bpFile.newModule(snapshotModuleType) 300 snapshotModule.AddProperty("name", snapshotName) 301 302 // Make sure that the snapshot has the same visibility as the sdk. 303 visibility := android.EffectiveVisibilityRules(ctx, s) 304 if len(visibility) != 0 { 305 snapshotModule.AddProperty("visibility", visibility) 306 } 307 308 addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule) 309 310 var dynamicMemberPropertiesContainers []propertiesContainer 311 osTypeToMemberProperties := make(map[android.OsType]*sdk) 312 for _, sdkVariant := range sdkVariants { 313 properties := sdkVariant.dynamicMemberTypeListProperties 314 osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant 315 dynamicMemberPropertiesContainers = append(dynamicMemberPropertiesContainers, &dynamicMemberPropertiesContainer{sdkVariant, properties}) 316 } 317 318 // Extract the common lists of members into a separate struct. 319 commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties() 320 extractor := newCommonValueExtractor(commonDynamicMemberProperties) 321 extractCommonProperties(ctx, extractor, commonDynamicMemberProperties, dynamicMemberPropertiesContainers) 322 323 // Add properties common to all os types. 324 s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties) 325 326 // Iterate over the os types in a fixed order. 327 targetPropertySet := snapshotModule.AddPropertySet("target") 328 for _, osType := range s.getPossibleOsTypes() { 329 if sdkVariant, ok := osTypeToMemberProperties[osType]; ok { 330 osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name) 331 332 // Compile_multilib defaults to both and must always be set to both on the 333 // device and so only needs to be set when targeted at the host and is neither 334 // unspecified or both. 335 multilib := sdkVariant.multilibUsages 336 if (osType.Class == android.Host || osType.Class == android.HostCross) && 337 multilib != multilibNone && multilib != multilibBoth { 338 osPropertySet.AddProperty("compile_multilib", multilib.String()) 339 } 340 341 s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties) 342 } 343 } 344 345 // Prune any empty property sets. 346 snapshotModule.transform(pruneEmptySetTransformer{}) 347 348 bpFile.AddModule(snapshotModule) 349 350 // generate Android.bp 351 bp = newGeneratedFile(ctx, "snapshot", "Android.bp") 352 generateBpContents(&bp.generatedContents, bpFile) 353 354 contents := bp.content.String() 355 syntaxCheckSnapshotBpFile(ctx, contents) 356 357 bp.build(pctx, ctx, nil) 358 359 filesToZip := builder.filesToZip 360 361 // zip them all 362 outputZipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath 363 outputDesc := "Building snapshot for " + ctx.ModuleName() 364 365 // If there are no zips to merge then generate the output zip directly. 366 // Otherwise, generate an intermediate zip file into which other zips can be 367 // merged. 368 var zipFile android.OutputPath 369 var desc string 370 if len(builder.zipsToMerge) == 0 { 371 zipFile = outputZipFile 372 desc = outputDesc 373 } else { 374 zipFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.unmerged.zip").OutputPath 375 desc = "Building intermediate snapshot for " + ctx.ModuleName() 376 } 377 378 ctx.Build(pctx, android.BuildParams{ 379 Description: desc, 380 Rule: zipFiles, 381 Inputs: filesToZip, 382 Output: zipFile, 383 Args: map[string]string{ 384 "basedir": builder.snapshotDir.String(), 385 }, 386 }) 387 388 if len(builder.zipsToMerge) != 0 { 389 ctx.Build(pctx, android.BuildParams{ 390 Description: outputDesc, 391 Rule: mergeZips, 392 Input: zipFile, 393 Inputs: builder.zipsToMerge, 394 Output: outputZipFile, 395 }) 396 } 397 398 return outputZipFile 399 } 400 401 // Check the syntax of the generated Android.bp file contents and if they are 402 // invalid then log an error with the contents (tagged with line numbers) and the 403 // errors that were found so that it is easy to see where the problem lies. 404 func syntaxCheckSnapshotBpFile(ctx android.ModuleContext, contents string) { 405 errs := android.CheckBlueprintSyntax(ctx, "Android.bp", contents) 406 if len(errs) != 0 { 407 message := &strings.Builder{} 408 _, _ = fmt.Fprint(message, `errors in generated Android.bp snapshot: 409 410 Generated Android.bp contents 411 ======================================================================== 412 `) 413 for i, line := range strings.Split(contents, "\n") { 414 _, _ = fmt.Fprintf(message, "%6d: %s\n", i+1, line) 415 } 416 417 _, _ = fmt.Fprint(message, ` 418 ======================================================================== 419 420 Errors found: 421 `) 422 423 for _, err := range errs { 424 _, _ = fmt.Fprintf(message, "%s\n", err.Error()) 425 } 426 427 ctx.ModuleErrorf("%s", message.String()) 428 } 429 } 430 431 func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) { 432 err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice) 433 if err != nil { 434 ctx.ModuleErrorf("error extracting common properties: %s", err) 435 } 436 } 437 438 func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) { 439 for _, memberListProperty := range s.memberListProperties() { 440 names := memberListProperty.getter(dynamicMemberTypeListProperties) 441 if len(names) > 0 { 442 propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false)) 443 } 444 } 445 } 446 447 type propertyTag struct { 448 name string 449 } 450 451 // A BpPropertyTag to add to a property that contains references to other sdk members. 452 // 453 // This will cause the references to be rewritten to a versioned reference in the version 454 // specific instance of a snapshot module. 455 var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"} 456 var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"} 457 458 // A BpPropertyTag that indicates the property should only be present in the versioned 459 // module. 460 // 461 // This will cause the property to be removed from the unversioned instance of a 462 // snapshot module. 463 var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"} 464 465 type unversionedToVersionedTransformation struct { 466 identityTransformation 467 builder *snapshotBuilder 468 } 469 470 func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule { 471 // Use a versioned name for the module but remember the original name for the 472 // snapshot. 473 name := module.getValue("name").(string) 474 module.setProperty("name", t.builder.versionedSdkMemberName(name, true)) 475 module.insertAfter("name", "sdk_member_name", name) 476 return module 477 } 478 479 func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) { 480 if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag { 481 required := tag == requiredSdkMemberReferencePropertyTag 482 return t.builder.versionedSdkMemberNames(value.([]string), required), tag 483 } else { 484 return value, tag 485 } 486 } 487 488 type unversionedTransformation struct { 489 identityTransformation 490 builder *snapshotBuilder 491 } 492 493 func (t unversionedTransformation) transformModule(module *bpModule) *bpModule { 494 // If the module is an internal member then use a unique name for it. 495 name := module.getValue("name").(string) 496 module.setProperty("name", t.builder.unversionedSdkMemberName(name, true)) 497 498 // Set prefer: false - this is not strictly required as that is the default. 499 module.insertAfter("name", "prefer", false) 500 501 return module 502 } 503 504 func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) { 505 if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag { 506 required := tag == requiredSdkMemberReferencePropertyTag 507 return t.builder.unversionedSdkMemberNames(value.([]string), required), tag 508 } else if tag == sdkVersionedOnlyPropertyTag { 509 // The property is not allowed in the unversioned module so remove it. 510 return nil, nil 511 } else { 512 return value, tag 513 } 514 } 515 516 type pruneEmptySetTransformer struct { 517 identityTransformation 518 } 519 520 var _ bpTransformer = (*pruneEmptySetTransformer)(nil) 521 522 func (t pruneEmptySetTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) { 523 if len(propertySet.properties) == 0 { 524 return nil, nil 525 } else { 526 return propertySet, tag 527 } 528 } 529 530 func generateBpContents(contents *generatedContents, bpFile *bpFile) { 531 contents.Printfln("// This is auto-generated. DO NOT EDIT.") 532 for _, bpModule := range bpFile.order { 533 contents.Printfln("") 534 contents.Printfln("%s {", bpModule.moduleType) 535 outputPropertySet(contents, bpModule.bpPropertySet) 536 contents.Printfln("}") 537 } 538 } 539 540 func outputPropertySet(contents *generatedContents, set *bpPropertySet) { 541 contents.Indent() 542 543 // Output the properties first, followed by the nested sets. This ensures a 544 // consistent output irrespective of whether property sets are created before 545 // or after the properties. This simplifies the creation of the module. 546 for _, name := range set.order { 547 value := set.getValue(name) 548 549 switch v := value.(type) { 550 case []string: 551 length := len(v) 552 if length > 1 { 553 contents.Printfln("%s: [", name) 554 contents.Indent() 555 for i := 0; i < length; i = i + 1 { 556 contents.Printfln("%q,", v[i]) 557 } 558 contents.Dedent() 559 contents.Printfln("],") 560 } else if length == 0 { 561 contents.Printfln("%s: [],", name) 562 } else { 563 contents.Printfln("%s: [%q],", name, v[0]) 564 } 565 566 case bool: 567 contents.Printfln("%s: %t,", name, v) 568 569 case *bpPropertySet: 570 // Do not write property sets in the properties phase. 571 572 default: 573 contents.Printfln("%s: %q,", name, value) 574 } 575 } 576 577 for _, name := range set.order { 578 value := set.getValue(name) 579 580 // Only write property sets in the sets phase. 581 switch v := value.(type) { 582 case *bpPropertySet: 583 contents.Printfln("%s: {", name) 584 outputPropertySet(contents, v) 585 contents.Printfln("},") 586 } 587 } 588 589 contents.Dedent() 590 } 591 592 func (s *sdk) GetAndroidBpContentsForTests() string { 593 contents := &generatedContents{} 594 generateBpContents(contents, s.builderForTests.bpFile) 595 return contents.content.String() 596 } 597 598 type snapshotBuilder struct { 599 ctx android.ModuleContext 600 sdk *sdk 601 version string 602 snapshotDir android.OutputPath 603 bpFile *bpFile 604 605 // Map from destination to source of each copy - used to eliminate duplicates and 606 // detect conflicts. 607 copies map[string]string 608 609 filesToZip android.Paths 610 zipsToMerge android.Paths 611 612 prebuiltModules map[string]*bpModule 613 prebuiltOrder []*bpModule 614 615 // The set of all members by name. 616 allMembersByName map[string]struct{} 617 618 // The set of exported members by name. 619 exportedMembersByName map[string]struct{} 620 } 621 622 func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) { 623 if existing, ok := s.copies[dest]; ok { 624 if existing != src.String() { 625 s.ctx.ModuleErrorf("conflicting copy, %s copied from both %s and %s", dest, existing, src) 626 return 627 } 628 } else { 629 path := s.snapshotDir.Join(s.ctx, dest) 630 s.ctx.Build(pctx, android.BuildParams{ 631 Rule: android.Cp, 632 Input: src, 633 Output: path, 634 }) 635 s.filesToZip = append(s.filesToZip, path) 636 637 s.copies[dest] = src.String() 638 } 639 } 640 641 func (s *snapshotBuilder) UnzipToSnapshot(zipPath android.Path, destDir string) { 642 ctx := s.ctx 643 644 // Repackage the zip file so that the entries are in the destDir directory. 645 // This will allow the zip file to be merged into the snapshot. 646 tmpZipPath := android.PathForModuleOut(ctx, "tmp", destDir+".zip").OutputPath 647 648 ctx.Build(pctx, android.BuildParams{ 649 Description: "Repackaging zip file " + destDir + " for snapshot " + ctx.ModuleName(), 650 Rule: repackageZip, 651 Input: zipPath, 652 Output: tmpZipPath, 653 Args: map[string]string{ 654 "destdir": destDir, 655 }, 656 }) 657 658 // Add the repackaged zip file to the files to merge. 659 s.zipsToMerge = append(s.zipsToMerge, tmpZipPath) 660 } 661 662 func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule { 663 name := member.Name() 664 if s.prebuiltModules[name] != nil { 665 panic(fmt.Sprintf("Duplicate module detected, module %s has already been added", name)) 666 } 667 668 m := s.bpFile.newModule(moduleType) 669 m.AddProperty("name", name) 670 671 variant := member.Variants()[0] 672 673 if s.isInternalMember(name) { 674 // An internal member is only referenced from the sdk snapshot which is in the 675 // same package so can be marked as private. 676 m.AddProperty("visibility", []string{"//visibility:private"}) 677 } else { 678 // Extract visibility information from a member variant. All variants have the same 679 // visibility so it doesn't matter which one is used. 680 visibility := android.EffectiveVisibilityRules(s.ctx, variant) 681 if len(visibility) != 0 { 682 m.AddProperty("visibility", visibility) 683 } 684 } 685 686 deviceSupported := false 687 hostSupported := false 688 689 for _, variant := range member.Variants() { 690 osClass := variant.Target().Os.Class 691 if osClass == android.Host || osClass == android.HostCross { 692 hostSupported = true 693 } else if osClass == android.Device { 694 deviceSupported = true 695 } 696 } 697 698 addHostDeviceSupportedProperties(deviceSupported, hostSupported, m) 699 700 // Where available copy apex_available properties from the member. 701 if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok { 702 apexAvailable := apexAware.ApexAvailable() 703 704 // Add in any baseline apex available settings. 705 apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...) 706 707 if len(apexAvailable) > 0 { 708 // Remove duplicates and sort. 709 apexAvailable = android.FirstUniqueStrings(apexAvailable) 710 sort.Strings(apexAvailable) 711 712 m.AddProperty("apex_available", apexAvailable) 713 } 714 } 715 716 // Disable installation in the versioned module of those modules that are ever installable. 717 if installable, ok := variant.(interface{ EverInstallable() bool }); ok { 718 if installable.EverInstallable() { 719 m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag) 720 } 721 } 722 723 s.prebuiltModules[name] = m 724 s.prebuiltOrder = append(s.prebuiltOrder, m) 725 return m 726 } 727 728 func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) { 729 if !deviceSupported { 730 bpModule.AddProperty("device_supported", false) 731 } 732 if hostSupported { 733 bpModule.AddProperty("host_supported", true) 734 } 735 } 736 737 func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag { 738 if required { 739 return requiredSdkMemberReferencePropertyTag 740 } else { 741 return optionalSdkMemberReferencePropertyTag 742 } 743 } 744 745 func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag { 746 return optionalSdkMemberReferencePropertyTag 747 } 748 749 // Get a versioned name appropriate for the SDK snapshot version being taken. 750 func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string { 751 if _, ok := s.allMembersByName[unversionedName]; !ok { 752 if required { 753 s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName) 754 } 755 return unversionedName 756 } 757 return versionedSdkMemberName(s.ctx, unversionedName, s.version) 758 } 759 760 func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string { 761 var references []string = nil 762 for _, m := range members { 763 references = append(references, s.versionedSdkMemberName(m, required)) 764 } 765 return references 766 } 767 768 // Get an internal name unique to the sdk. 769 func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string { 770 if _, ok := s.allMembersByName[unversionedName]; !ok { 771 if required { 772 s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName) 773 } 774 return unversionedName 775 } 776 777 if s.isInternalMember(unversionedName) { 778 return s.ctx.ModuleName() + "_" + unversionedName 779 } else { 780 return unversionedName 781 } 782 } 783 784 func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string { 785 var references []string = nil 786 for _, m := range members { 787 references = append(references, s.unversionedSdkMemberName(m, required)) 788 } 789 return references 790 } 791 792 func (s *snapshotBuilder) isInternalMember(memberName string) bool { 793 _, ok := s.exportedMembersByName[memberName] 794 return !ok 795 } 796 797 // Add the properties from the given SdkMemberProperties to the blueprint 798 // property set. This handles common properties in SdkMemberPropertiesBase and 799 // calls the member-specific AddToPropertySet for the rest. 800 func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) { 801 if memberProperties.Base().Compile_multilib != "" { 802 targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib) 803 } 804 805 memberProperties.AddToPropertySet(ctx, targetPropertySet) 806 } 807 808 type sdkMemberRef struct { 809 memberType android.SdkMemberType 810 variant android.SdkAware 811 } 812 813 var _ android.SdkMember = (*sdkMember)(nil) 814 815 type sdkMember struct { 816 memberType android.SdkMemberType 817 name string 818 variants []android.SdkAware 819 } 820 821 func (m *sdkMember) Name() string { 822 return m.name 823 } 824 825 func (m *sdkMember) Variants() []android.SdkAware { 826 return m.variants 827 } 828 829 // Track usages of multilib variants. 830 type multilibUsage int 831 832 const ( 833 multilibNone multilibUsage = 0 834 multilib32 multilibUsage = 1 835 multilib64 multilibUsage = 2 836 multilibBoth = multilib32 | multilib64 837 ) 838 839 // Add the multilib that is used in the arch type. 840 func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage { 841 multilib := archType.Multilib 842 switch multilib { 843 case "": 844 return m 845 case "lib32": 846 return m | multilib32 847 case "lib64": 848 return m | multilib64 849 default: 850 panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib)) 851 } 852 } 853 854 func (m multilibUsage) String() string { 855 switch m { 856 case multilibNone: 857 return "" 858 case multilib32: 859 return "32" 860 case multilib64: 861 return "64" 862 case multilibBoth: 863 return "both" 864 default: 865 panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b", 866 m, multilibNone, multilib32, multilib64, multilibBoth)) 867 } 868 } 869 870 type baseInfo struct { 871 Properties android.SdkMemberProperties 872 } 873 874 func (b *baseInfo) optimizableProperties() interface{} { 875 return b.Properties 876 } 877 878 type osTypeSpecificInfo struct { 879 baseInfo 880 881 osType android.OsType 882 883 // The list of arch type specific info for this os type. 884 // 885 // Nil if there is one variant whose arch type is common 886 archInfos []*archTypeSpecificInfo 887 } 888 889 var _ propertiesContainer = (*osTypeSpecificInfo)(nil) 890 891 type variantPropertiesFactoryFunc func() android.SdkMemberProperties 892 893 // Create a new osTypeSpecificInfo for the specified os type and its properties 894 // structures populated with information from the variants. 895 func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo { 896 osInfo := &osTypeSpecificInfo{ 897 osType: osType, 898 } 899 900 osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties { 901 properties := variantPropertiesFactory() 902 properties.Base().Os = osType 903 return properties 904 } 905 906 // Create a structure into which properties common across the architectures in 907 // this os type will be stored. 908 osInfo.Properties = osSpecificVariantPropertiesFactory() 909 910 // Group the variants by arch type. 911 var variantsByArchName = make(map[string][]android.Module) 912 var archTypes []android.ArchType 913 for _, variant := range osTypeVariants { 914 archType := variant.Target().Arch.ArchType 915 archTypeName := archType.Name 916 if _, ok := variantsByArchName[archTypeName]; !ok { 917 archTypes = append(archTypes, archType) 918 } 919 920 variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant) 921 } 922 923 if commonVariants, ok := variantsByArchName["common"]; ok { 924 if len(osTypeVariants) != 1 { 925 panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants))) 926 } 927 928 // A common arch type only has one variant and its properties should be treated 929 // as common to the os type. 930 osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0]) 931 } else { 932 // Create an arch specific info for each supported architecture type. 933 for _, archType := range archTypes { 934 archTypeName := archType.Name 935 936 archVariants := variantsByArchName[archTypeName] 937 archInfo := newArchSpecificInfo(ctx, archType, osSpecificVariantPropertiesFactory, archVariants) 938 939 osInfo.archInfos = append(osInfo.archInfos, archInfo) 940 } 941 } 942 943 return osInfo 944 } 945 946 // Optimize the properties by extracting common properties from arch type specific 947 // properties into os type specific properties. 948 func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) { 949 // Nothing to do if there is only a single common architecture. 950 if len(osInfo.archInfos) == 0 { 951 return 952 } 953 954 multilib := multilibNone 955 for _, archInfo := range osInfo.archInfos { 956 multilib = multilib.addArchType(archInfo.archType) 957 958 // Optimize the arch properties first. 959 archInfo.optimizeProperties(ctx, commonValueExtractor) 960 } 961 962 extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, osInfo.Properties, osInfo.archInfos) 963 964 // Choose setting for compile_multilib that is appropriate for the arch variants supplied. 965 osInfo.Properties.Base().Compile_multilib = multilib.String() 966 } 967 968 // Add the properties for an os to a property set. 969 // 970 // Maps the properties related to the os variants through to an appropriate 971 // module structure that will produce equivalent set of variants when it is 972 // processed in a build. 973 func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) { 974 975 var osPropertySet android.BpPropertySet 976 var archPropertySet android.BpPropertySet 977 var archOsPrefix string 978 if osInfo.Properties.Base().Os_count == 1 { 979 // There is only one os type present in the variants so don't bother 980 // with adding target specific properties. 981 982 // Create a structure that looks like: 983 // module_type { 984 // name: "...", 985 // ... 986 // <common properties> 987 // ... 988 // <single os type specific properties> 989 // 990 // arch: { 991 // <arch specific sections> 992 // } 993 // 994 osPropertySet = bpModule 995 archPropertySet = osPropertySet.AddPropertySet("arch") 996 997 // Arch specific properties need to be added to an arch specific section 998 // within arch. 999 archOsPrefix = "" 1000 } else { 1001 // Create a structure that looks like: 1002 // module_type { 1003 // name: "...", 1004 // ... 1005 // <common properties> 1006 // ... 1007 // target: { 1008 // <arch independent os specific sections, e.g. android> 1009 // ... 1010 // <arch and os specific sections, e.g. android_x86> 1011 // } 1012 // 1013 osType := osInfo.osType 1014 osPropertySet = targetPropertySet.AddPropertySet(osType.Name) 1015 archPropertySet = targetPropertySet 1016 1017 // Arch specific properties need to be added to an os and arch specific 1018 // section prefixed with <os>_. 1019 archOsPrefix = osType.Name + "_" 1020 } 1021 1022 // Add the os specific but arch independent properties to the module. 1023 addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet) 1024 1025 // Add arch (and possibly os) specific sections for each set of arch (and possibly 1026 // os) specific properties. 1027 // 1028 // The archInfos list will be empty if the os contains variants for the common 1029 // architecture. 1030 for _, archInfo := range osInfo.archInfos { 1031 archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix) 1032 } 1033 } 1034 1035 func (osInfo *osTypeSpecificInfo) isHostVariant() bool { 1036 osClass := osInfo.osType.Class 1037 return osClass == android.Host || osClass == android.HostCross 1038 } 1039 1040 var _ isHostVariant = (*osTypeSpecificInfo)(nil) 1041 1042 func (osInfo *osTypeSpecificInfo) String() string { 1043 return fmt.Sprintf("OsType{%s}", osInfo.osType) 1044 } 1045 1046 type archTypeSpecificInfo struct { 1047 baseInfo 1048 1049 archType android.ArchType 1050 1051 linkInfos []*linkTypeSpecificInfo 1052 } 1053 1054 var _ propertiesContainer = (*archTypeSpecificInfo)(nil) 1055 1056 // Create a new archTypeSpecificInfo for the specified arch type and its properties 1057 // structures populated with information from the variants. 1058 func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo { 1059 1060 // Create an arch specific info into which the variant properties can be copied. 1061 archInfo := &archTypeSpecificInfo{archType: archType} 1062 1063 // Create the properties into which the arch type specific properties will be 1064 // added. 1065 archInfo.Properties = variantPropertiesFactory() 1066 1067 if len(archVariants) == 1 { 1068 archInfo.Properties.PopulateFromVariant(ctx, archVariants[0]) 1069 } else { 1070 // There is more than one variant for this arch type which must be differentiated 1071 // by link type. 1072 for _, linkVariant := range archVariants { 1073 linkType := getLinkType(linkVariant) 1074 if linkType == "" { 1075 panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants))) 1076 } else { 1077 linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant) 1078 1079 archInfo.linkInfos = append(archInfo.linkInfos, linkInfo) 1080 } 1081 } 1082 } 1083 1084 return archInfo 1085 } 1086 1087 func (archInfo *archTypeSpecificInfo) optimizableProperties() interface{} { 1088 return archInfo.Properties 1089 } 1090 1091 // Get the link type of the variant 1092 // 1093 // If the variant is not differentiated by link type then it returns "", 1094 // otherwise it returns one of "static" or "shared". 1095 func getLinkType(variant android.Module) string { 1096 linkType := "" 1097 if linkable, ok := variant.(cc.LinkableInterface); ok { 1098 if linkable.Shared() && linkable.Static() { 1099 panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String())) 1100 } else if linkable.Shared() { 1101 linkType = "shared" 1102 } else if linkable.Static() { 1103 linkType = "static" 1104 } else { 1105 panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String())) 1106 } 1107 } 1108 return linkType 1109 } 1110 1111 // Optimize the properties by extracting common properties from link type specific 1112 // properties into arch type specific properties. 1113 func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) { 1114 if len(archInfo.linkInfos) == 0 { 1115 return 1116 } 1117 1118 extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.linkInfos) 1119 } 1120 1121 // Add the properties for an arch type to a property set. 1122 func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) { 1123 archTypeName := archInfo.archType.Name 1124 archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName) 1125 addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet) 1126 1127 for _, linkInfo := range archInfo.linkInfos { 1128 linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType) 1129 addSdkMemberPropertiesToSet(ctx, linkInfo.Properties, linkPropertySet) 1130 } 1131 } 1132 1133 func (archInfo *archTypeSpecificInfo) String() string { 1134 return fmt.Sprintf("ArchType{%s}", archInfo.archType) 1135 } 1136 1137 type linkTypeSpecificInfo struct { 1138 baseInfo 1139 1140 linkType string 1141 } 1142 1143 var _ propertiesContainer = (*linkTypeSpecificInfo)(nil) 1144 1145 // Create a new linkTypeSpecificInfo for the specified link type and its properties 1146 // structures populated with information from the variant. 1147 func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo { 1148 linkInfo := &linkTypeSpecificInfo{ 1149 baseInfo: baseInfo{ 1150 // Create the properties into which the link type specific properties will be 1151 // added. 1152 Properties: variantPropertiesFactory(), 1153 }, 1154 linkType: linkType, 1155 } 1156 linkInfo.Properties.PopulateFromVariant(ctx, linkVariant) 1157 return linkInfo 1158 } 1159 1160 func (l *linkTypeSpecificInfo) String() string { 1161 return fmt.Sprintf("LinkType{%s}", l.linkType) 1162 } 1163 1164 type memberContext struct { 1165 sdkMemberContext android.ModuleContext 1166 builder *snapshotBuilder 1167 memberType android.SdkMemberType 1168 name string 1169 } 1170 1171 func (m *memberContext) SdkModuleContext() android.ModuleContext { 1172 return m.sdkMemberContext 1173 } 1174 1175 func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder { 1176 return m.builder 1177 } 1178 1179 func (m *memberContext) MemberType() android.SdkMemberType { 1180 return m.memberType 1181 } 1182 1183 func (m *memberContext) Name() string { 1184 return m.name 1185 } 1186 1187 func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) { 1188 1189 memberType := member.memberType 1190 1191 // Group the variants by os type. 1192 variantsByOsType := make(map[android.OsType][]android.Module) 1193 variants := member.Variants() 1194 for _, variant := range variants { 1195 osType := variant.Target().Os 1196 variantsByOsType[osType] = append(variantsByOsType[osType], variant) 1197 } 1198 1199 osCount := len(variantsByOsType) 1200 variantPropertiesFactory := func() android.SdkMemberProperties { 1201 properties := memberType.CreateVariantPropertiesStruct() 1202 base := properties.Base() 1203 base.Os_count = osCount 1204 return properties 1205 } 1206 1207 osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo) 1208 1209 // The set of properties that are common across all architectures and os types. 1210 commonProperties := variantPropertiesFactory() 1211 commonProperties.Base().Os = android.CommonOS 1212 1213 // Create common value extractor that can be used to optimize the properties. 1214 commonValueExtractor := newCommonValueExtractor(commonProperties) 1215 1216 // The list of property structures which are os type specific but common across 1217 // architectures within that os type. 1218 var osSpecificPropertiesContainers []*osTypeSpecificInfo 1219 1220 for osType, osTypeVariants := range variantsByOsType { 1221 osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants) 1222 osTypeToInfo[osType] = osInfo 1223 // Add the os specific properties to a list of os type specific yet architecture 1224 // independent properties structs. 1225 osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo) 1226 1227 // Optimize the properties across all the variants for a specific os type. 1228 osInfo.optimizeProperties(ctx, commonValueExtractor) 1229 } 1230 1231 // Extract properties which are common across all architectures and os types. 1232 extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers) 1233 1234 // Add the common properties to the module. 1235 addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule) 1236 1237 // Create a target property set into which target specific properties can be 1238 // added. 1239 targetPropertySet := bpModule.AddPropertySet("target") 1240 1241 // Iterate over the os types in a fixed order. 1242 for _, osType := range s.getPossibleOsTypes() { 1243 osInfo := osTypeToInfo[osType] 1244 if osInfo == nil { 1245 continue 1246 } 1247 1248 osInfo.addToPropertySet(ctx, bpModule, targetPropertySet) 1249 } 1250 } 1251 1252 // Compute the list of possible os types that this sdk could support. 1253 func (s *sdk) getPossibleOsTypes() []android.OsType { 1254 var osTypes []android.OsType 1255 for _, osType := range android.OsTypeList { 1256 if s.DeviceSupported() { 1257 if osType.Class == android.Device && osType != android.Fuchsia { 1258 osTypes = append(osTypes, osType) 1259 } 1260 } 1261 if s.HostSupported() { 1262 if osType.Class == android.Host || osType.Class == android.HostCross { 1263 osTypes = append(osTypes, osType) 1264 } 1265 } 1266 } 1267 sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name }) 1268 return osTypes 1269 } 1270 1271 // Given a set of properties (struct value), return the value of the field within that 1272 // struct (or one of its embedded structs). 1273 type fieldAccessorFunc func(structValue reflect.Value) reflect.Value 1274 1275 // Checks the metadata to determine whether the property should be ignored for the 1276 // purposes of common value extraction or not. 1277 type extractorMetadataPredicate func(metadata propertiesContainer) bool 1278 1279 // Indicates whether optimizable properties are provided by a host variant or 1280 // not. 1281 type isHostVariant interface { 1282 isHostVariant() bool 1283 } 1284 1285 // A property that can be optimized by the commonValueExtractor. 1286 type extractorProperty struct { 1287 // The name of the field for this property. 1288 name string 1289 1290 // Filter that can use metadata associated with the properties being optimized 1291 // to determine whether the field should be ignored during common value 1292 // optimization. 1293 filter extractorMetadataPredicate 1294 1295 // Retrieves the value on which common value optimization will be performed. 1296 getter fieldAccessorFunc 1297 1298 // The empty value for the field. 1299 emptyValue reflect.Value 1300 1301 // True if the property can support arch variants false otherwise. 1302 archVariant bool 1303 } 1304 1305 func (p extractorProperty) String() string { 1306 return p.name 1307 } 1308 1309 // Supports extracting common values from a number of instances of a properties 1310 // structure into a separate common set of properties. 1311 type commonValueExtractor struct { 1312 // The properties that the extractor can optimize. 1313 properties []extractorProperty 1314 } 1315 1316 // Create a new common value extractor for the structure type for the supplied 1317 // properties struct. 1318 // 1319 // The returned extractor can be used on any properties structure of the same type 1320 // as the supplied set of properties. 1321 func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor { 1322 structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type() 1323 extractor := &commonValueExtractor{} 1324 extractor.gatherFields(structType, nil) 1325 return extractor 1326 } 1327 1328 // Gather the fields from the supplied structure type from which common values will 1329 // be extracted. 1330 // 1331 // This is recursive function. If it encounters an embedded field (no field name) 1332 // that is a struct then it will recurse into that struct passing in the accessor 1333 // for the field. That will then be used in the accessors for the fields in the 1334 // embedded struct. 1335 func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc) { 1336 for f := 0; f < structType.NumField(); f++ { 1337 field := structType.Field(f) 1338 if field.PkgPath != "" { 1339 // Ignore unexported fields. 1340 continue 1341 } 1342 1343 // Ignore fields whose value should be kept. 1344 if proptools.HasTag(field, "sdk", "keep") { 1345 continue 1346 } 1347 1348 var filter extractorMetadataPredicate 1349 1350 // Add a filter 1351 if proptools.HasTag(field, "sdk", "ignored-on-host") { 1352 filter = func(metadata propertiesContainer) bool { 1353 if m, ok := metadata.(isHostVariant); ok { 1354 if m.isHostVariant() { 1355 return false 1356 } 1357 } 1358 return true 1359 } 1360 } 1361 1362 // Save a copy of the field index for use in the function. 1363 fieldIndex := f 1364 1365 name := field.Name 1366 1367 fieldGetter := func(value reflect.Value) reflect.Value { 1368 if containingStructAccessor != nil { 1369 // This is an embedded structure so first access the field for the embedded 1370 // structure. 1371 value = containingStructAccessor(value) 1372 } 1373 1374 // Skip through interface and pointer values to find the structure. 1375 value = getStructValue(value) 1376 1377 defer func() { 1378 if r := recover(); r != nil { 1379 panic(fmt.Errorf("%s for fieldIndex %d of field %s of value %#v", r, fieldIndex, name, value.Interface())) 1380 } 1381 }() 1382 1383 // Return the field. 1384 return value.Field(fieldIndex) 1385 } 1386 1387 if field.Type.Kind() == reflect.Struct && field.Anonymous { 1388 // Gather fields from the embedded structure. 1389 e.gatherFields(field.Type, fieldGetter) 1390 } else { 1391 property := extractorProperty{ 1392 name, 1393 filter, 1394 fieldGetter, 1395 reflect.Zero(field.Type), 1396 proptools.HasTag(field, "android", "arch_variant"), 1397 } 1398 e.properties = append(e.properties, property) 1399 } 1400 } 1401 } 1402 1403 func getStructValue(value reflect.Value) reflect.Value { 1404 foundStruct: 1405 for { 1406 kind := value.Kind() 1407 switch kind { 1408 case reflect.Interface, reflect.Ptr: 1409 value = value.Elem() 1410 case reflect.Struct: 1411 break foundStruct 1412 default: 1413 panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind)) 1414 } 1415 } 1416 return value 1417 } 1418 1419 // A container of properties to be optimized. 1420 // 1421 // Allows additional information to be associated with the properties, e.g. for 1422 // filtering. 1423 type propertiesContainer interface { 1424 fmt.Stringer 1425 1426 // Get the properties that need optimizing. 1427 optimizableProperties() interface{} 1428 } 1429 1430 // A wrapper for dynamic member properties to allow them to be optimized. 1431 type dynamicMemberPropertiesContainer struct { 1432 sdkVariant *sdk 1433 dynamicMemberProperties interface{} 1434 } 1435 1436 func (c dynamicMemberPropertiesContainer) optimizableProperties() interface{} { 1437 return c.dynamicMemberProperties 1438 } 1439 1440 func (c dynamicMemberPropertiesContainer) String() string { 1441 return c.sdkVariant.String() 1442 } 1443 1444 // Extract common properties from a slice of property structures of the same type. 1445 // 1446 // All the property structures must be of the same type. 1447 // commonProperties - must be a pointer to the structure into which common properties will be added. 1448 // inputPropertiesSlice - must be a slice of propertiesContainer interfaces. 1449 // 1450 // Iterates over each exported field (capitalized name) and checks to see whether they 1451 // have the same value (using DeepEquals) across all the input properties. If it does not then no 1452 // change is made. Otherwise, the common value is stored in the field in the commonProperties 1453 // and the field in each of the input properties structure is set to its default value. 1454 func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) error { 1455 commonPropertiesValue := reflect.ValueOf(commonProperties) 1456 commonStructValue := commonPropertiesValue.Elem() 1457 1458 sliceValue := reflect.ValueOf(inputPropertiesSlice) 1459 1460 for _, property := range e.properties { 1461 fieldGetter := property.getter 1462 filter := property.filter 1463 if filter == nil { 1464 filter = func(metadata propertiesContainer) bool { 1465 return true 1466 } 1467 } 1468 1469 // Check to see if all the structures have the same value for the field. The commonValue 1470 // is nil on entry to the loop and if it is nil on exit then there is no common value or 1471 // all the values have been filtered out, otherwise it points to the common value. 1472 var commonValue *reflect.Value 1473 1474 // Assume that all the values will be the same. 1475 // 1476 // While similar to this is not quite the same as commonValue == nil. If all the values 1477 // have been filtered out then this will be false but commonValue == nil will be true. 1478 valuesDiffer := false 1479 1480 for i := 0; i < sliceValue.Len(); i++ { 1481 container := sliceValue.Index(i).Interface().(propertiesContainer) 1482 itemValue := reflect.ValueOf(container.optimizableProperties()) 1483 fieldValue := fieldGetter(itemValue) 1484 1485 if !filter(container) { 1486 expectedValue := property.emptyValue.Interface() 1487 actualValue := fieldValue.Interface() 1488 if !reflect.DeepEqual(expectedValue, actualValue) { 1489 return fmt.Errorf("field %q is supposed to be ignored for %q but is set to %#v instead of %#v", property, container, actualValue, expectedValue) 1490 } 1491 continue 1492 } 1493 1494 if commonValue == nil { 1495 // Use the first value as the commonProperties value. 1496 commonValue = &fieldValue 1497 } else { 1498 // If the value does not match the current common value then there is 1499 // no value in common so break out. 1500 if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) { 1501 commonValue = nil 1502 valuesDiffer = true 1503 break 1504 } 1505 } 1506 } 1507 1508 // If the fields all have common value then store it in the common struct field 1509 // and set the input struct's field to the empty value. 1510 if commonValue != nil { 1511 emptyValue := property.emptyValue 1512 fieldGetter(commonStructValue).Set(*commonValue) 1513 for i := 0; i < sliceValue.Len(); i++ { 1514 container := sliceValue.Index(i).Interface().(propertiesContainer) 1515 itemValue := reflect.ValueOf(container.optimizableProperties()) 1516 fieldValue := fieldGetter(itemValue) 1517 fieldValue.Set(emptyValue) 1518 } 1519 } 1520 1521 if valuesDiffer && !property.archVariant { 1522 // The values differ but the property does not support arch variants so it 1523 // is an error. 1524 var details strings.Builder 1525 for i := 0; i < sliceValue.Len(); i++ { 1526 container := sliceValue.Index(i).Interface().(propertiesContainer) 1527 itemValue := reflect.ValueOf(container.optimizableProperties()) 1528 fieldValue := fieldGetter(itemValue) 1529 1530 _, _ = fmt.Fprintf(&details, "\n %q has value %q", container.String(), fieldValue.Interface()) 1531 } 1532 1533 return fmt.Errorf("field %q is not tagged as \"arch_variant\" but has arch specific properties:%s", property.String(), details.String()) 1534 } 1535 } 1536 1537 return nil 1538 } 1539