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 "strconv" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/proptools" 24 25 "android/soong/android" 26 // This package doesn't depend on the apex package, but import it to make its mutators to be 27 // registered before mutators in this package. See RegisterPostDepsMutators for more details. 28 _ "android/soong/apex" 29) 30 31func init() { 32 pctx.Import("android/soong/android") 33 pctx.Import("android/soong/java/config") 34 35 registerSdkBuildComponents(android.InitRegistrationContext) 36} 37 38func registerSdkBuildComponents(ctx android.RegistrationContext) { 39 ctx.RegisterModuleType("sdk", SdkModuleFactory) 40 ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory) 41 ctx.PreDepsMutators(RegisterPreDepsMutators) 42} 43 44type sdk struct { 45 android.ModuleBase 46 android.DefaultableModuleBase 47 48 // The dynamically generated information about the registered SdkMemberType 49 dynamicSdkMemberTypes *dynamicSdkMemberTypes 50 51 // The dynamically created instance of the properties struct containing the sdk member type 52 // list properties, e.g. java_libs. 53 dynamicMemberTypeListProperties interface{} 54 55 // The dynamically generated information about the registered SdkMemberTrait 56 dynamicSdkMemberTraits *dynamicSdkMemberTraits 57 58 // The dynamically created instance of the properties struct containing the sdk member trait 59 // list properties. 60 dynamicMemberTraitListProperties interface{} 61 62 // Information about the OsType specific member variants depended upon by this variant. 63 // 64 // Set by OsType specific variants in the collectMembers() method and used by the 65 // CommonOS variant when building the snapshot. That work is all done on separate 66 // calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be 67 // called for the OsType specific variants before the CommonOS variant (because 68 // the latter depends on the former). 69 memberVariantDeps []sdkMemberVariantDep 70 71 // The multilib variants that are used by this sdk variant. 72 multilibUsages multilibUsage 73 74 properties sdkProperties 75 76 snapshotFile android.OptionalPath 77 78 // The builder, preserved for testing. 79 builderForTests *snapshotBuilder 80} 81 82type sdkProperties struct { 83 Snapshot bool `blueprint:"mutated"` 84 85 // True if this is a module_exports (or module_exports_snapshot) module type. 86 Module_exports bool `blueprint:"mutated"` 87 88 // The additional visibility to add to the prebuilt modules to allow them to 89 // reference each other. 90 // 91 // This can only be used to widen the visibility of the members: 92 // 93 // * Specifying //visibility:public here will make all members visible and 94 // essentially ignore their own visibility. 95 // * Specifying //visibility:private here is an error. 96 // * Specifying any other rule here will add it to the members visibility and 97 // be output to the member prebuilt in the snapshot. Duplicates will be 98 // dropped. Adding a rule to members that have //visibility:private will 99 // cause the //visibility:private to be discarded. 100 Prebuilt_visibility []string 101} 102 103// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.) 104// which Mainline modules like APEX can choose to build with. 105func SdkModuleFactory() android.Module { 106 return newSdkModule(false) 107} 108 109func newSdkModule(moduleExports bool) *sdk { 110 s := &sdk{} 111 s.properties.Module_exports = moduleExports 112 // Get the dynamic sdk member type data for the currently registered sdk member types. 113 sdkMemberTypeKey, sdkMemberTypes := android.RegisteredSdkMemberTypes(moduleExports) 114 s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(sdkMemberTypeKey, sdkMemberTypes) 115 // Create an instance of the dynamically created struct that contains all the 116 // properties for the member type specific list properties. 117 s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberTypeListProperties() 118 119 sdkMemberTraitsKey, sdkMemberTraits := android.RegisteredSdkMemberTraits() 120 s.dynamicSdkMemberTraits = getDynamicSdkMemberTraits(sdkMemberTraitsKey, sdkMemberTraits) 121 // Create an instance of the dynamically created struct that contains all the properties for the 122 // member trait specific list properties. 123 s.dynamicMemberTraitListProperties = s.dynamicSdkMemberTraits.createMemberTraitListProperties() 124 125 // Create a wrapper around the dynamic trait specific properties so that they have to be 126 // specified within a traits:{} section in the .bp file. 127 traitsWrapper := struct { 128 Traits interface{} 129 }{s.dynamicMemberTraitListProperties} 130 131 s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties, &traitsWrapper) 132 133 // Make sure that the prebuilt visibility property is verified for errors. 134 android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility) 135 android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon) 136 android.InitDefaultableModule(s) 137 android.AddLoadHook(s, func(ctx android.LoadHookContext) { 138 type props struct { 139 Compile_multilib *string 140 } 141 p := &props{Compile_multilib: proptools.StringPtr("both")} 142 ctx.PrependProperties(p) 143 }) 144 return s 145} 146 147// sdk_snapshot is a versioned snapshot of an SDK. This is an auto-generated module. 148func SnapshotModuleFactory() android.Module { 149 s := newSdkModule(false) 150 s.properties.Snapshot = true 151 return s 152} 153 154func (s *sdk) memberTypeListProperties() []*sdkMemberTypeListProperty { 155 return s.dynamicSdkMemberTypes.memberTypeListProperties 156} 157 158func (s *sdk) memberTypeListProperty(memberType android.SdkMemberType) *sdkMemberTypeListProperty { 159 return s.dynamicSdkMemberTypes.memberTypeToProperty[memberType] 160} 161 162// memberTraitListProperties returns the list of *sdkMemberTraitListProperty instances for this sdk. 163func (s *sdk) memberTraitListProperties() []*sdkMemberTraitListProperty { 164 return s.dynamicSdkMemberTraits.memberTraitListProperties 165} 166 167func (s *sdk) snapshot() bool { 168 return s.properties.Snapshot 169} 170 171func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) { 172 if s.snapshot() { 173 // We don't need to create a snapshot out of sdk_snapshot. 174 // That doesn't make sense. We need a snapshot to create sdk_snapshot. 175 return 176 } 177 178 // This method is guaranteed to be called on OsType specific variants before it is called 179 // on their corresponding CommonOS variant. 180 if !s.IsCommonOSVariant() { 181 // Update the OsType specific sdk variant with information about its members. 182 s.collectMembers(ctx) 183 } else { 184 // Get the OsType specific variants on which the CommonOS depends. 185 osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx) 186 var sdkVariants []*sdk 187 for _, m := range osSpecificVariants { 188 if sdkVariant, ok := m.(*sdk); ok { 189 sdkVariants = append(sdkVariants, sdkVariant) 190 } 191 } 192 193 // Generate the snapshot from the member info. 194 p := s.buildSnapshot(ctx, sdkVariants) 195 zip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), p.Base(), p) 196 s.snapshotFile = android.OptionalPathForPath(zip) 197 } 198} 199 200func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries { 201 if !s.snapshotFile.Valid() { 202 return []android.AndroidMkEntries{} 203 } 204 205 return []android.AndroidMkEntries{android.AndroidMkEntries{ 206 Class: "FAKE", 207 OutputFile: s.snapshotFile, 208 DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()), 209 Include: "$(BUILD_PHONY_PACKAGE)", 210 ExtraFooters: []android.AndroidMkExtraFootersFunc{ 211 func(w io.Writer, name, prefix, moduleDir string) { 212 // Allow the sdk to be built by simply passing its name on the command line. 213 fmt.Fprintln(w, ".PHONY:", s.Name()) 214 fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String()) 215 }, 216 }, 217 }} 218} 219 220// gatherTraits gathers the traits from the dynamically generated trait specific properties. 221// 222// Returns a map from member name to the set of required traits. 223func (s *sdk) gatherTraits() map[string]android.SdkMemberTraitSet { 224 traitListByMember := map[string][]android.SdkMemberTrait{} 225 for _, memberListProperty := range s.memberTraitListProperties() { 226 names := memberListProperty.getter(s.dynamicMemberTraitListProperties) 227 for _, name := range names { 228 traitListByMember[name] = append(traitListByMember[name], memberListProperty.memberTrait) 229 } 230 } 231 232 traitSetByMember := map[string]android.SdkMemberTraitSet{} 233 for name, list := range traitListByMember { 234 traitSetByMember[name] = android.NewSdkMemberTraitSet(list) 235 } 236 237 return traitSetByMember 238} 239 240// newDependencyContext creates a new SdkDependencyContext for this sdk. 241func (s *sdk) newDependencyContext(mctx android.BottomUpMutatorContext) android.SdkDependencyContext { 242 traits := s.gatherTraits() 243 244 return &dependencyContext{ 245 BottomUpMutatorContext: mctx, 246 requiredTraits: traits, 247 } 248} 249 250type dependencyContext struct { 251 android.BottomUpMutatorContext 252 253 // Map from member name to the set of traits that the sdk requires the member provides. 254 requiredTraits map[string]android.SdkMemberTraitSet 255} 256 257func (d *dependencyContext) RequiredTraits(name string) android.SdkMemberTraitSet { 258 if s, ok := d.requiredTraits[name]; ok { 259 return s 260 } else { 261 return android.EmptySdkMemberTraitSet() 262 } 263} 264 265func (d *dependencyContext) RequiresTrait(name string, trait android.SdkMemberTrait) bool { 266 return d.RequiredTraits(name).Contains(trait) 267} 268 269var _ android.SdkDependencyContext = (*dependencyContext)(nil) 270 271// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware 272// interface and the sdk module type. This function has been made public to be called by tests 273// outside of the sdk package 274func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { 275 ctx.BottomUp("SdkMember", memberMutator).Parallel() 276 ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel() 277 ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel() 278} 279 280type dependencyTag struct { 281 blueprint.BaseDependencyTag 282} 283 284// Mark this tag so dependencies that use it are excluded from APEX contents. 285func (t dependencyTag) ExcludeFromApexContents() {} 286 287var _ android.ExcludeFromApexContentsTag = dependencyTag{} 288 289// For dependencies from an in-development version of an SDK member to frozen versions of the same member 290// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12 291// 292// The dependency represented by this tag requires that for every APEX variant created for the 293// `from` module that an equivalent APEX variant is created for the 'to' module. This is because an 294// APEX that requires a specific version of an sdk (via the `uses_sdks` property will replace 295// dependencies on the unversioned sdk member with a dependency on the appropriate versioned sdk 296// member. In order for that to work the versioned sdk member needs to have a variant for that APEX. 297// As it is not known at the time that the APEX variants are created which specific APEX variants of 298// a versioned sdk members will be required it is necessary for the versioned sdk members to have 299// variants for any APEX that it could be used within. 300// 301// If the APEX selects a versioned sdk member then it will not have a dependency on the `from` 302// module at all so any dependencies of that module will not affect the APEX. However, if the APEX 303// selects the unversioned sdk member then it must exclude all the versioned sdk members. In no 304// situation would this dependency cause the `to` module to be added to the APEX hence why this tag 305// also excludes the `to` module from being added to the APEX contents. 306type sdkMemberVersionedDepTag struct { 307 dependencyTag 308 member string 309 version string 310} 311 312func (t sdkMemberVersionedDepTag) AlwaysRequireApexVariant() bool { 313 return true 314} 315 316// Mark this tag so dependencies that use it are excluded from visibility enforcement. 317func (t sdkMemberVersionedDepTag) ExcludeFromVisibilityEnforcement() {} 318 319var _ android.AlwaysRequireApexVariantTag = sdkMemberVersionedDepTag{} 320 321// Step 1: create dependencies from an SDK module to its members. 322func memberMutator(mctx android.BottomUpMutatorContext) { 323 if s, ok := mctx.Module().(*sdk); ok { 324 // Add dependencies from enabled and non CommonOS variants to the sdk member variants. 325 if s.Enabled() && !s.IsCommonOSVariant() { 326 ctx := s.newDependencyContext(mctx) 327 for _, memberListProperty := range s.memberTypeListProperties() { 328 if memberListProperty.getter == nil { 329 continue 330 } 331 names := memberListProperty.getter(s.dynamicMemberTypeListProperties) 332 if len(names) > 0 { 333 memberType := memberListProperty.memberType 334 335 // Verify that the member type supports the specified traits. 336 supportedTraits := memberType.SupportedTraits() 337 for _, name := range names { 338 requiredTraits := ctx.RequiredTraits(name) 339 unsupportedTraits := requiredTraits.Subtract(supportedTraits) 340 if !unsupportedTraits.Empty() { 341 ctx.ModuleErrorf("sdk member %q has traits %s that are unsupported by its member type %q", name, unsupportedTraits, memberType.SdkPropertyName()) 342 } 343 } 344 345 // Add dependencies using the appropriate tag. 346 tag := memberListProperty.dependencyTag 347 memberType.AddDependencies(ctx, tag, names) 348 } 349 } 350 } 351 } 352} 353 354// Step 2: record that dependencies of SDK modules are members of the SDK modules 355func memberDepsMutator(mctx android.TopDownMutatorContext) { 356 if s, ok := mctx.Module().(*sdk); ok { 357 mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name") 358 if s.snapshot() && mySdkRef.Unversioned() { 359 mctx.PropertyErrorf("name", "sdk_snapshot should be named as <name>@<version>. "+ 360 "Did you manually modify Android.bp?") 361 } 362 if !s.snapshot() && !mySdkRef.Unversioned() { 363 mctx.PropertyErrorf("name", "sdk shouldn't be named as <name>@<version>.") 364 } 365 if mySdkRef.Version != "" && mySdkRef.Version != "current" { 366 if _, err := strconv.Atoi(mySdkRef.Version); err != nil { 367 mctx.PropertyErrorf("name", "version %q is neither a number nor \"current\"", mySdkRef.Version) 368 } 369 } 370 371 mctx.VisitDirectDeps(func(child android.Module) { 372 if member, ok := child.(android.SdkAware); ok { 373 member.MakeMemberOf(mySdkRef) 374 } 375 }) 376 } 377} 378 379// Step 3: create dependencies from the unversioned SDK member to snapshot versions 380// of the same member. By having these dependencies, they are mutated for multiple Mainline modules 381// (apex and apk), each of which might want different sdks to be built with. For example, if both 382// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be 383// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are 384// using. 385func memberInterVersionMutator(mctx android.BottomUpMutatorContext) { 386 if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() && m.IsVersioned() { 387 if !m.ContainingSdk().Unversioned() { 388 memberName := m.MemberName() 389 tag := sdkMemberVersionedDepTag{member: memberName, version: m.ContainingSdk().Version} 390 mctx.AddReverseDependency(mctx.Module(), tag, memberName) 391 } 392 } 393} 394 395// An interface that encapsulates all the functionality needed to manage the sdk dependencies. 396// 397// It is a mixture of apex and sdk module functionality. 398type sdkAndApexModule interface { 399 android.Module 400 android.DepIsInSameApex 401} 402