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 "io" 20 "reflect" 21 "strconv" 22 23 "github.com/google/blueprint" 24 "github.com/google/blueprint/proptools" 25 26 "android/soong/android" 27 // This package doesn't depend on the apex package, but import it to make its mutators to be 28 // registered before mutators in this package. See RegisterPostDepsMutators for more details. 29 _ "android/soong/apex" 30) 31 32func init() { 33 pctx.Import("android/soong/android") 34 pctx.Import("android/soong/java/config") 35 36 registerSdkBuildComponents(android.InitRegistrationContext) 37} 38 39func registerSdkBuildComponents(ctx android.RegistrationContext) { 40 ctx.RegisterModuleType("sdk", SdkModuleFactory) 41 ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory) 42 ctx.PreDepsMutators(RegisterPreDepsMutators) 43 ctx.PostDepsMutators(RegisterPostDepsMutators) 44} 45 46type sdk struct { 47 android.ModuleBase 48 android.DefaultableModuleBase 49 50 // The dynamically generated information about the registered SdkMemberType 51 dynamicSdkMemberTypes *dynamicSdkMemberTypes 52 53 // The dynamically created instance of the properties struct containing the sdk member 54 // list properties, e.g. java_libs. 55 dynamicMemberTypeListProperties interface{} 56 57 // Information about the OsType specific member variants depended upon by this variant. 58 // 59 // Set by OsType specific variants in the collectMembers() method and used by the 60 // CommonOS variant when building the snapshot. That work is all done on separate 61 // calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be 62 // called for the OsType specific variants before the CommonOS variant (because 63 // the latter depends on the former). 64 memberVariantDeps []sdkMemberVariantDep 65 66 // The multilib variants that are used by this sdk variant. 67 multilibUsages multilibUsage 68 69 properties sdkProperties 70 71 snapshotFile android.OptionalPath 72 73 // The builder, preserved for testing. 74 builderForTests *snapshotBuilder 75} 76 77type sdkProperties struct { 78 Snapshot bool `blueprint:"mutated"` 79 80 // True if this is a module_exports (or module_exports_snapshot) module type. 81 Module_exports bool `blueprint:"mutated"` 82 83 // The additional visibility to add to the prebuilt modules to allow them to 84 // reference each other. 85 // 86 // This can only be used to widen the visibility of the members: 87 // 88 // * Specifying //visibility:public here will make all members visible and 89 // essentially ignore their own visibility. 90 // * Specifying //visibility:private here is an error. 91 // * Specifying any other rule here will add it to the members visibility and 92 // be output to the member prebuilt in the snapshot. Duplicates will be 93 // dropped. Adding a rule to members that have //visibility:private will 94 // cause the //visibility:private to be discarded. 95 Prebuilt_visibility []string 96} 97 98// Contains information about the sdk properties that list sdk members, e.g. 99// Java_header_libs. 100type sdkMemberListProperty struct { 101 // getter for the list of member names 102 getter func(properties interface{}) []string 103 104 // setter for the list of member names 105 setter func(properties interface{}, list []string) 106 107 // the type of member referenced in the list 108 memberType android.SdkMemberType 109 110 // the dependency tag used for items in this list that can be used to determine the memberType 111 // for a resolved dependency. 112 dependencyTag android.SdkMemberTypeDependencyTag 113} 114 115func (p *sdkMemberListProperty) propertyName() string { 116 return p.memberType.SdkPropertyName() 117} 118 119// Cache of dynamically generated dynamicSdkMemberTypes objects. The key is the pointer 120// to a slice of SdkMemberType instances held in android.SdkMemberTypes. 121var dynamicSdkMemberTypesMap android.OncePer 122 123// A dynamically generated set of member list properties and associated structure type. 124type dynamicSdkMemberTypes struct { 125 // The dynamically generated structure type. 126 // 127 // Contains one []string exported field for each android.SdkMemberTypes. The name of the field 128 // is the exported form of the value returned by SdkMemberType.SdkPropertyName(). 129 propertiesStructType reflect.Type 130 131 // Information about each of the member type specific list properties. 132 memberListProperties []*sdkMemberListProperty 133 134 memberTypeToProperty map[android.SdkMemberType]*sdkMemberListProperty 135} 136 137func (d *dynamicSdkMemberTypes) createMemberListProperties() interface{} { 138 return reflect.New(d.propertiesStructType).Interface() 139} 140 141func getDynamicSdkMemberTypes(registry *android.SdkMemberTypesRegistry) *dynamicSdkMemberTypes { 142 143 // Get a key that uniquely identifies the registry contents. 144 key := registry.UniqueOnceKey() 145 146 // Get the registered types. 147 registeredTypes := registry.RegisteredTypes() 148 149 // Get the cached value, creating new instance if necessary. 150 return dynamicSdkMemberTypesMap.Once(key, func() interface{} { 151 return createDynamicSdkMemberTypes(registeredTypes) 152 }).(*dynamicSdkMemberTypes) 153} 154 155// Create the dynamicSdkMemberTypes from the list of registered member types. 156// 157// A struct is created which contains one exported field per member type corresponding to 158// the SdkMemberType.SdkPropertyName() value. 159// 160// A list of sdkMemberListProperty instances is created, one per member type that provides: 161// * a reference to the member type. 162// * a getter for the corresponding field in the properties struct. 163// * a dependency tag that identifies the member type of a resolved dependency. 164// 165func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynamicSdkMemberTypes { 166 167 var listProperties []*sdkMemberListProperty 168 memberTypeToProperty := map[android.SdkMemberType]*sdkMemberListProperty{} 169 var fields []reflect.StructField 170 171 // Iterate over the member types creating StructField and sdkMemberListProperty objects. 172 nextFieldIndex := 0 173 for _, memberType := range sdkMemberTypes { 174 175 p := memberType.SdkPropertyName() 176 177 var getter func(properties interface{}) []string 178 var setter func(properties interface{}, list []string) 179 if memberType.RequiresBpProperty() { 180 // Create a dynamic exported field for the member type's property. 181 fields = append(fields, reflect.StructField{ 182 Name: proptools.FieldNameForProperty(p), 183 Type: reflect.TypeOf([]string{}), 184 Tag: `android:"arch_variant"`, 185 }) 186 187 // Copy the field index for use in the getter func as using the loop variable directly will 188 // cause all funcs to use the last value. 189 fieldIndex := nextFieldIndex 190 nextFieldIndex += 1 191 192 getter = func(properties interface{}) []string { 193 // The properties is expected to be of the following form (where 194 // <Module_types> is the name of an SdkMemberType.SdkPropertyName(). 195 // properties *struct {<Module_types> []string, ....} 196 // 197 // Although it accesses the field by index the following reflection code is equivalent to: 198 // *properties.<Module_types> 199 // 200 list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string) 201 return list 202 } 203 204 setter = func(properties interface{}, list []string) { 205 // The properties is expected to be of the following form (where 206 // <Module_types> is the name of an SdkMemberType.SdkPropertyName(). 207 // properties *struct {<Module_types> []string, ....} 208 // 209 // Although it accesses the field by index the following reflection code is equivalent to: 210 // *properties.<Module_types> = list 211 // 212 reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list)) 213 } 214 } 215 216 // Create an sdkMemberListProperty for the member type. 217 memberListProperty := &sdkMemberListProperty{ 218 getter: getter, 219 setter: setter, 220 memberType: memberType, 221 222 // Dependencies added directly from member properties are always exported. 223 dependencyTag: android.DependencyTagForSdkMemberType(memberType, true), 224 } 225 226 memberTypeToProperty[memberType] = memberListProperty 227 listProperties = append(listProperties, memberListProperty) 228 } 229 230 // Create a dynamic struct from the collated fields. 231 propertiesStructType := reflect.StructOf(fields) 232 233 return &dynamicSdkMemberTypes{ 234 memberListProperties: listProperties, 235 memberTypeToProperty: memberTypeToProperty, 236 propertiesStructType: propertiesStructType, 237 } 238} 239 240// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.) 241// which Mainline modules like APEX can choose to build with. 242func SdkModuleFactory() android.Module { 243 return newSdkModule(false) 244} 245 246func newSdkModule(moduleExports bool) *sdk { 247 s := &sdk{} 248 s.properties.Module_exports = moduleExports 249 // Get the dynamic sdk member type data for the currently registered sdk member types. 250 var registry *android.SdkMemberTypesRegistry 251 if moduleExports { 252 registry = android.ModuleExportsMemberTypes 253 } else { 254 registry = android.SdkMemberTypes 255 } 256 s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(registry) 257 // Create an instance of the dynamically created struct that contains all the 258 // properties for the member type specific list properties. 259 s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties() 260 s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties) 261 262 // Make sure that the prebuilt visibility property is verified for errors. 263 android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility) 264 android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon) 265 android.InitDefaultableModule(s) 266 android.AddLoadHook(s, func(ctx android.LoadHookContext) { 267 type props struct { 268 Compile_multilib *string 269 } 270 p := &props{Compile_multilib: proptools.StringPtr("both")} 271 ctx.PrependProperties(p) 272 }) 273 return s 274} 275 276// sdk_snapshot is a versioned snapshot of an SDK. This is an auto-generated module. 277func SnapshotModuleFactory() android.Module { 278 s := newSdkModule(false) 279 s.properties.Snapshot = true 280 return s 281} 282 283func (s *sdk) memberListProperties() []*sdkMemberListProperty { 284 return s.dynamicSdkMemberTypes.memberListProperties 285} 286 287func (s *sdk) memberListProperty(memberType android.SdkMemberType) *sdkMemberListProperty { 288 return s.dynamicSdkMemberTypes.memberTypeToProperty[memberType] 289} 290 291func (s *sdk) snapshot() bool { 292 return s.properties.Snapshot 293} 294 295func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) { 296 if s.snapshot() { 297 // We don't need to create a snapshot out of sdk_snapshot. 298 // That doesn't make sense. We need a snapshot to create sdk_snapshot. 299 return 300 } 301 302 // This method is guaranteed to be called on OsType specific variants before it is called 303 // on their corresponding CommonOS variant. 304 if !s.IsCommonOSVariant() { 305 // Update the OsType specific sdk variant with information about its members. 306 s.collectMembers(ctx) 307 } else { 308 // Get the OsType specific variants on which the CommonOS depends. 309 osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx) 310 var sdkVariants []*sdk 311 for _, m := range osSpecificVariants { 312 if sdkVariant, ok := m.(*sdk); ok { 313 sdkVariants = append(sdkVariants, sdkVariant) 314 } 315 } 316 317 // Generate the snapshot from the member info. 318 p := s.buildSnapshot(ctx, sdkVariants) 319 zip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), p.Base(), p) 320 s.snapshotFile = android.OptionalPathForPath(zip) 321 } 322} 323 324func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries { 325 if !s.snapshotFile.Valid() { 326 return []android.AndroidMkEntries{} 327 } 328 329 return []android.AndroidMkEntries{android.AndroidMkEntries{ 330 Class: "FAKE", 331 OutputFile: s.snapshotFile, 332 DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()), 333 Include: "$(BUILD_PHONY_PACKAGE)", 334 ExtraFooters: []android.AndroidMkExtraFootersFunc{ 335 func(w io.Writer, name, prefix, moduleDir string) { 336 // Allow the sdk to be built by simply passing its name on the command line. 337 fmt.Fprintln(w, ".PHONY:", s.Name()) 338 fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String()) 339 }, 340 }, 341 }} 342} 343 344// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware 345// interface and the sdk module type. This function has been made public to be called by tests 346// outside of the sdk package 347func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { 348 ctx.BottomUp("SdkMember", memberMutator).Parallel() 349 ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel() 350 ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel() 351} 352 353// RegisterPostDepsMutators registers post-deps mutators to support modules implementing SdkAware 354// interface and the sdk module type. This function has been made public to be called by tests 355// outside of the sdk package 356func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { 357 // These must run AFTER apexMutator. Note that the apex package is imported even though there is 358 // no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an 359 // APEX to its dependents. Since different versions of the same SDK can be used by different 360 // APEXes, the apex and its dependents (which includes the dependencies to the sdk members) 361 // should have been mutated for the apex before the SDK requirements are set. 362 ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel() 363 ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel() 364 ctx.TopDown("SdkRequirementCheck", sdkRequirementsMutator).Parallel() 365} 366 367type dependencyTag struct { 368 blueprint.BaseDependencyTag 369} 370 371// Mark this tag so dependencies that use it are excluded from APEX contents. 372func (t dependencyTag) ExcludeFromApexContents() {} 373 374var _ android.ExcludeFromApexContentsTag = dependencyTag{} 375 376// For dependencies from an in-development version of an SDK member to frozen versions of the same member 377// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12 378// 379// The dependency represented by this tag requires that for every APEX variant created for the 380// `from` module that an equivalent APEX variant is created for the 'to' module. This is because an 381// APEX that requires a specific version of an sdk (via the `uses_sdks` property will replace 382// dependencies on the unversioned sdk member with a dependency on the appropriate versioned sdk 383// member. In order for that to work the versioned sdk member needs to have a variant for that APEX. 384// As it is not known at the time that the APEX variants are created which specific APEX variants of 385// a versioned sdk members will be required it is necessary for the versioned sdk members to have 386// variants for any APEX that it could be used within. 387// 388// If the APEX selects a versioned sdk member then it will not have a dependency on the `from` 389// module at all so any dependencies of that module will not affect the APEX. However, if the APEX 390// selects the unversioned sdk member then it must exclude all the versioned sdk members. In no 391// situation would this dependency cause the `to` module to be added to the APEX hence why this tag 392// also excludes the `to` module from being added to the APEX contents. 393type sdkMemberVersionedDepTag struct { 394 dependencyTag 395 member string 396 version string 397} 398 399func (t sdkMemberVersionedDepTag) AlwaysRequireApexVariant() bool { 400 return true 401} 402 403// Mark this tag so dependencies that use it are excluded from visibility enforcement. 404func (t sdkMemberVersionedDepTag) ExcludeFromVisibilityEnforcement() {} 405 406var _ android.AlwaysRequireApexVariantTag = sdkMemberVersionedDepTag{} 407 408// Step 1: create dependencies from an SDK module to its members. 409func memberMutator(mctx android.BottomUpMutatorContext) { 410 if s, ok := mctx.Module().(*sdk); ok { 411 // Add dependencies from enabled and non CommonOS variants to the sdk member variants. 412 if s.Enabled() && !s.IsCommonOSVariant() { 413 for _, memberListProperty := range s.memberListProperties() { 414 if memberListProperty.getter == nil { 415 continue 416 } 417 names := memberListProperty.getter(s.dynamicMemberTypeListProperties) 418 if len(names) > 0 { 419 tag := memberListProperty.dependencyTag 420 memberListProperty.memberType.AddDependencies(mctx, tag, names) 421 } 422 } 423 } 424 } 425} 426 427// Step 2: record that dependencies of SDK modules are members of the SDK modules 428func memberDepsMutator(mctx android.TopDownMutatorContext) { 429 if s, ok := mctx.Module().(*sdk); ok { 430 mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name") 431 if s.snapshot() && mySdkRef.Unversioned() { 432 mctx.PropertyErrorf("name", "sdk_snapshot should be named as <name>@<version>. "+ 433 "Did you manually modify Android.bp?") 434 } 435 if !s.snapshot() && !mySdkRef.Unversioned() { 436 mctx.PropertyErrorf("name", "sdk shouldn't be named as <name>@<version>.") 437 } 438 if mySdkRef.Version != "" && mySdkRef.Version != "current" { 439 if _, err := strconv.Atoi(mySdkRef.Version); err != nil { 440 mctx.PropertyErrorf("name", "version %q is neither a number nor \"current\"", mySdkRef.Version) 441 } 442 } 443 444 mctx.VisitDirectDeps(func(child android.Module) { 445 if member, ok := child.(android.SdkAware); ok { 446 member.MakeMemberOf(mySdkRef) 447 } 448 }) 449 } 450} 451 452// Step 3: create dependencies from the unversioned SDK member to snapshot versions 453// of the same member. By having these dependencies, they are mutated for multiple Mainline modules 454// (apex and apk), each of which might want different sdks to be built with. For example, if both 455// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be 456// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are 457// using. 458func memberInterVersionMutator(mctx android.BottomUpMutatorContext) { 459 if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() && m.IsVersioned() { 460 if !m.ContainingSdk().Unversioned() { 461 memberName := m.MemberName() 462 tag := sdkMemberVersionedDepTag{member: memberName, version: m.ContainingSdk().Version} 463 mctx.AddReverseDependency(mctx.Module(), tag, memberName) 464 } 465 } 466} 467 468// An interface that encapsulates all the functionality needed to manage the sdk dependencies. 469// 470// It is a mixture of apex and sdk module functionality. 471type sdkAndApexModule interface { 472 android.Module 473 android.DepIsInSameApex 474 android.RequiredSdks 475} 476 477// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its 478// descendants 479func sdkDepsMutator(mctx android.TopDownMutatorContext) { 480 if parent, ok := mctx.Module().(sdkAndApexModule); ok { 481 // Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks() 482 // by reading its own properties like `uses_sdks`. 483 requiredSdks := parent.RequiredSdks() 484 if len(requiredSdks) > 0 { 485 mctx.VisitDirectDeps(func(m android.Module) { 486 // Only propagate required sdks from the apex onto its contents. 487 if dep, ok := m.(android.SdkAware); ok && android.IsDepInSameApex(mctx, parent, dep) { 488 dep.BuildWithSdks(requiredSdks) 489 } 490 }) 491 } 492 } 493} 494 495// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the 496// versioned module is used instead of the un-versioned (in-development) module libfoo 497func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) { 498 if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() && versionedSdkMember.IsVersioned() { 499 if sdk := versionedSdkMember.ContainingSdk(); !sdk.Unversioned() { 500 // Only replace dependencies to <sdkmember> with <sdkmember@required-version> 501 // if the depending module requires it. e.g. 502 // foo -> sdkmember 503 // will be transformed to: 504 // foo -> sdkmember@1 505 // if and only if foo is a member of an APEX that requires version 1 of the 506 // sdk containing sdkmember. 507 memberName := versionedSdkMember.MemberName() 508 509 // Convert a panic into a normal error to allow it to be more easily tested for. This is a 510 // temporary workaround, once http://b/183204176 has been fixed this can be removed. 511 // TODO(b/183204176): Remove this after fixing. 512 defer func() { 513 if r := recover(); r != nil { 514 mctx.ModuleErrorf("sdkDepsReplaceMutator %s", r) 515 } 516 }() 517 518 // Replace dependencies on sdkmember with a dependency on the current module which 519 // is a versioned prebuilt of the sdkmember if required. 520 mctx.ReplaceDependenciesIf(memberName, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool { 521 // from - foo 522 // to - sdkmember 523 replace := false 524 if parent, ok := from.(android.RequiredSdks); ok { 525 replace = parent.RequiredSdks().Contains(sdk) 526 } 527 return replace 528 }) 529 } 530 } 531} 532 533// Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs 534func sdkRequirementsMutator(mctx android.TopDownMutatorContext) { 535 if m, ok := mctx.Module().(sdkAndApexModule); ok { 536 requiredSdks := m.RequiredSdks() 537 if len(requiredSdks) == 0 { 538 return 539 } 540 mctx.VisitDirectDeps(func(dep android.Module) { 541 tag := mctx.OtherModuleDependencyTag(dep) 542 if tag == android.DefaultsDepTag { 543 // dependency to defaults is always okay 544 return 545 } 546 547 // Ignore the dependency from the unversioned member to any versioned members as an 548 // apex that depends on the unversioned member will not also be depending on a versioned 549 // member. 550 if _, ok := tag.(sdkMemberVersionedDepTag); ok { 551 return 552 } 553 554 // If the dep is outside of the APEX, but is not in any of the required SDKs, we know that the 555 // dep is a violation. 556 if sa, ok := dep.(android.SdkAware); ok { 557 // It is not an error if a dependency that is excluded from the apex due to the tag is not 558 // in one of the required SDKs. That is because all of the existing tags that implement it 559 // do not depend on modules which can or should belong to an sdk_snapshot. 560 if _, ok := tag.(android.ExcludeFromApexContentsTag); ok { 561 // The tag defines a dependency that never requires the child module to be part of the 562 // same apex. 563 return 564 } 565 566 if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) { 567 mctx.ModuleErrorf("depends on %q (in SDK %q) that isn't part of the required SDKs: %v", 568 sa.Name(), sa.ContainingSdk(), requiredSdks) 569 } 570 } 571 }) 572 } 573} 574