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