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 android 16 17import ( 18 "sort" 19 "strings" 20 21 "github.com/google/blueprint" 22 "github.com/google/blueprint/proptools" 23) 24 25// Extracted from SdkAware to make it easier to define custom subsets of the 26// SdkAware interface and improve code navigation within the IDE. 27// 28// In addition to its use in SdkAware this interface must also be implemented by 29// APEX to specify the SDKs required by that module and its contents. e.g. APEX 30// is expected to implement RequiredSdks() by reading its own properties like 31// `uses_sdks`. 32type RequiredSdks interface { 33 // The set of SDKs required by an APEX and its contents. 34 RequiredSdks() SdkRefs 35} 36 37// Provided to improve code navigation with the IDE. 38type sdkAwareWithoutModule interface { 39 RequiredSdks 40 41 sdkBase() *SdkBase 42 MakeMemberOf(sdk SdkRef) 43 IsInAnySdk() bool 44 ContainingSdk() SdkRef 45 MemberName() string 46 BuildWithSdks(sdks SdkRefs) 47} 48 49// SdkAware is the interface that must be supported by any module to become a member of SDK or to be 50// built with SDK 51type SdkAware interface { 52 Module 53 sdkAwareWithoutModule 54} 55 56// SdkRef refers to a version of an SDK 57type SdkRef struct { 58 Name string 59 Version string 60} 61 62// Unversioned determines if the SdkRef is referencing to the unversioned SDK module 63func (s SdkRef) Unversioned() bool { 64 return s.Version == "" 65} 66 67// String returns string representation of this SdkRef for debugging purpose 68func (s SdkRef) String() string { 69 if s.Name == "" { 70 return "(No Sdk)" 71 } 72 if s.Unversioned() { 73 return s.Name 74 } 75 return s.Name + string(SdkVersionSeparator) + s.Version 76} 77 78// SdkVersionSeparator is a character used to separate an sdk name and its version 79const SdkVersionSeparator = '@' 80 81// ParseSdkRef parses a `name@version` style string into a corresponding SdkRef struct 82func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef { 83 tokens := strings.Split(str, string(SdkVersionSeparator)) 84 if len(tokens) < 1 || len(tokens) > 2 { 85 ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str) 86 return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"} 87 } 88 89 name := tokens[0] 90 91 var version string 92 if len(tokens) == 2 { 93 version = tokens[1] 94 } 95 96 return SdkRef{Name: name, Version: version} 97} 98 99type SdkRefs []SdkRef 100 101// Contains tells if the given SdkRef is in this list of SdkRef's 102func (refs SdkRefs) Contains(s SdkRef) bool { 103 for _, r := range refs { 104 if r == s { 105 return true 106 } 107 } 108 return false 109} 110 111type sdkProperties struct { 112 // The SDK that this module is a member of. nil if it is not a member of any SDK 113 ContainingSdk *SdkRef `blueprint:"mutated"` 114 115 // The list of SDK names and versions that are used to build this module 116 RequiredSdks SdkRefs `blueprint:"mutated"` 117 118 // Name of the module that this sdk member is representing 119 Sdk_member_name *string 120} 121 122// SdkBase is a struct that is expected to be included in module types to implement the SdkAware 123// interface. InitSdkAwareModule should be called to initialize this struct. 124type SdkBase struct { 125 properties sdkProperties 126 module SdkAware 127} 128 129func (s *SdkBase) sdkBase() *SdkBase { 130 return s 131} 132 133// MakeMemberOf sets this module to be a member of a specific SDK 134func (s *SdkBase) MakeMemberOf(sdk SdkRef) { 135 s.properties.ContainingSdk = &sdk 136} 137 138// IsInAnySdk returns true if this module is a member of any SDK 139func (s *SdkBase) IsInAnySdk() bool { 140 return s.properties.ContainingSdk != nil 141} 142 143// ContainingSdk returns the SDK that this module is a member of 144func (s *SdkBase) ContainingSdk() SdkRef { 145 if s.properties.ContainingSdk != nil { 146 return *s.properties.ContainingSdk 147 } 148 return SdkRef{Name: "", Version: ""} 149} 150 151// MemberName returns the name of the module that this SDK member is overriding 152func (s *SdkBase) MemberName() string { 153 return proptools.String(s.properties.Sdk_member_name) 154} 155 156// BuildWithSdks is used to mark that this module has to be built with the given SDK(s). 157func (s *SdkBase) BuildWithSdks(sdks SdkRefs) { 158 s.properties.RequiredSdks = sdks 159} 160 161// RequiredSdks returns the SDK(s) that this module has to be built with 162func (s *SdkBase) RequiredSdks() SdkRefs { 163 return s.properties.RequiredSdks 164} 165 166// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including 167// SdkBase. 168func InitSdkAwareModule(m SdkAware) { 169 base := m.sdkBase() 170 base.module = m 171 m.AddProperties(&base.properties) 172} 173 174// Provide support for generating the build rules which will build the snapshot. 175type SnapshotBuilder interface { 176 // Copy src to the dest (which is a snapshot relative path) and add the dest 177 // to the zip 178 CopyToSnapshot(src Path, dest string) 179 180 // Unzip the supplied zip into the snapshot relative directory destDir. 181 UnzipToSnapshot(zipPath Path, destDir string) 182 183 // Add a new prebuilt module to the snapshot. The returned module 184 // must be populated with the module type specific properties. The following 185 // properties will be automatically populated. 186 // 187 // * name 188 // * sdk_member_name 189 // * prefer 190 // 191 // This will result in two Soong modules being generated in the Android. One 192 // that is versioned, coupled to the snapshot version and marked as 193 // prefer=true. And one that is not versioned, not marked as prefer=true and 194 // will only be used if the equivalently named non-prebuilt module is not 195 // present. 196 AddPrebuiltModule(member SdkMember, moduleType string) BpModule 197 198 // The property tag to use when adding a property to a BpModule that contains 199 // references to other sdk members. Using this will ensure that the reference 200 // is correctly output for both versioned and unversioned prebuilts in the 201 // snapshot. 202 // 203 // "required: true" means that the property must only contain references 204 // to other members of the sdk. Passing a reference to a module that is not a 205 // member of the sdk will result in a build error. 206 // 207 // "required: false" means that the property can contain references to modules 208 // that are either members or not members of the sdk. If a reference is to a 209 // module that is a non member then the reference is left unchanged, i.e. it 210 // is not transformed as references to members are. 211 // 212 // The handling of the member names is dependent on whether it is an internal or 213 // exported member. An exported member is one whose name is specified in one of 214 // the member type specific properties. An internal member is one that is added 215 // due to being a part of an exported (or other internal) member and is not itself 216 // an exported member. 217 // 218 // Member names are handled as follows: 219 // * When creating the unversioned form of the module the name is left unchecked 220 // unless the member is internal in which case it is transformed into an sdk 221 // specific name, i.e. by prefixing with the sdk name. 222 // 223 // * When creating the versioned form of the module the name is transformed into 224 // a versioned sdk specific name, i.e. by prefixing with the sdk name and 225 // suffixing with the version. 226 // 227 // e.g. 228 // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true)) 229 SdkMemberReferencePropertyTag(required bool) BpPropertyTag 230} 231 232type BpPropertyTag interface{} 233 234// A set of properties for use in a .bp file. 235type BpPropertySet interface { 236 // Add a property, the value can be one of the following types: 237 // * string 238 // * array of the above 239 // * bool 240 // * BpPropertySet 241 // 242 // It is an error if multiple properties with the same name are added. 243 AddProperty(name string, value interface{}) 244 245 // Add a property with an associated tag 246 AddPropertyWithTag(name string, value interface{}, tag BpPropertyTag) 247 248 // Add a property set with the specified name and return so that additional 249 // properties can be added. 250 AddPropertySet(name string) BpPropertySet 251} 252 253// A .bp module definition. 254type BpModule interface { 255 BpPropertySet 256} 257 258// An individual member of the SDK, includes all of the variants that the SDK 259// requires. 260type SdkMember interface { 261 // The name of the member. 262 Name() string 263 264 // All the variants required by the SDK. 265 Variants() []SdkAware 266} 267 268type SdkMemberTypeDependencyTag interface { 269 blueprint.DependencyTag 270 271 SdkMemberType() SdkMemberType 272} 273 274var _ SdkMemberTypeDependencyTag = (*sdkMemberDependencyTag)(nil) 275var _ ReplaceSourceWithPrebuilt = (*sdkMemberDependencyTag)(nil) 276 277type sdkMemberDependencyTag struct { 278 blueprint.BaseDependencyTag 279 memberType SdkMemberType 280} 281 282func (t *sdkMemberDependencyTag) SdkMemberType() SdkMemberType { 283 return t.memberType 284} 285 286// Prevent dependencies from the sdk/module_exports onto their members from being 287// replaced with a preferred prebuilt. 288func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool { 289 return false 290} 291 292func DependencyTagForSdkMemberType(memberType SdkMemberType) SdkMemberTypeDependencyTag { 293 return &sdkMemberDependencyTag{memberType: memberType} 294} 295 296// Interface that must be implemented for every type that can be a member of an 297// sdk. 298// 299// The basic implementation should look something like this, where ModuleType is 300// the name of the module type being supported. 301// 302// type moduleTypeSdkMemberType struct { 303// android.SdkMemberTypeBase 304// } 305// 306// func init() { 307// android.RegisterSdkMemberType(&moduleTypeSdkMemberType{ 308// SdkMemberTypeBase: android.SdkMemberTypeBase{ 309// PropertyName: "module_types", 310// }, 311// } 312// } 313// 314// ...methods... 315// 316type SdkMemberType interface { 317 // The name of the member type property on an sdk module. 318 SdkPropertyName() string 319 320 // True if the member type supports the sdk/sdk_snapshot, false otherwise. 321 UsableWithSdkAndSdkSnapshot() bool 322 323 // Return true if modules of this type can have dependencies which should be 324 // treated as if they are sdk members. 325 // 326 // Any dependency that is to be treated as a member of the sdk needs to implement 327 // SdkAware and be added with an SdkMemberTypeDependencyTag tag. 328 HasTransitiveSdkMembers() bool 329 330 // Add dependencies from the SDK module to all the module variants the member 331 // type contributes to the SDK. `names` is the list of module names given in 332 // the member type property (as returned by SdkPropertyName()) in the SDK 333 // module. The exact set of variants required is determined by the SDK and its 334 // properties. The dependencies must be added with the supplied tag. 335 // 336 // The BottomUpMutatorContext provided is for the SDK module. 337 AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) 338 339 // Return true if the supplied module is an instance of this member type. 340 // 341 // This is used to check the type of each variant before added to the 342 // SdkMember. Returning false will cause an error to be logged expaining that 343 // the module is not allowed in whichever sdk property it was added. 344 IsInstance(module Module) bool 345 346 // Add a prebuilt module that the sdk will populate. 347 // 348 // The sdk module code generates the snapshot as follows: 349 // 350 // * A properties struct of type SdkMemberProperties is created for each variant and 351 // populated with information from the variant by calling PopulateFromVariant(SdkAware) 352 // on the struct. 353 // 354 // * An additional properties struct is created into which the common properties will be 355 // added. 356 // 357 // * The variant property structs are analysed to find exported (capitalized) fields which 358 // have common values. Those fields are cleared and the common value added to the common 359 // properties. 360 // 361 // A field annotated with a tag of `sdk:"keep"` will be treated as if it 362 // was not capitalized, i.e. not optimized for common values. 363 // 364 // A field annotated with a tag of `android:"arch_variant"` will be allowed to have 365 // values that differ by arch, fields not tagged as such must have common values across 366 // all variants. 367 // 368 // * Additional field tags can be specified on a field that will ignore certain values 369 // for the purpose of common value optimization. A value that is ignored must have the 370 // default value for the property type. This is to ensure that significant value are not 371 // ignored by accident. The purpose of this is to allow the snapshot generation to reflect 372 // the behavior of the runtime. e.g. if a property is ignored on the host then a property 373 // that is common for android can be treated as if it was common for android and host as 374 // the setting for host is ignored anyway. 375 // * `sdk:"ignored-on-host" - this indicates the property is ignored on the host variant. 376 // 377 // * The sdk module type populates the BpModule structure, creating the arch specific 378 // structure and calls AddToPropertySet(...) on the properties struct to add the member 379 // specific properties in the correct place in the structure. 380 // 381 AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule 382 383 // Create a structure into which variant specific properties can be added. 384 CreateVariantPropertiesStruct() SdkMemberProperties 385} 386 387// Base type for SdkMemberType implementations. 388type SdkMemberTypeBase struct { 389 PropertyName string 390 SupportsSdk bool 391 TransitiveSdkMembers bool 392} 393 394func (b *SdkMemberTypeBase) SdkPropertyName() string { 395 return b.PropertyName 396} 397 398func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool { 399 return b.SupportsSdk 400} 401 402func (b *SdkMemberTypeBase) HasTransitiveSdkMembers() bool { 403 return b.TransitiveSdkMembers 404} 405 406// Encapsulates the information about registered SdkMemberTypes. 407type SdkMemberTypesRegistry struct { 408 // The list of types sorted by property name. 409 list []SdkMemberType 410 411 // The key that uniquely identifies this registry instance. 412 key OnceKey 413} 414 415func (r *SdkMemberTypesRegistry) copyAndAppend(memberType SdkMemberType) *SdkMemberTypesRegistry { 416 oldList := r.list 417 418 // Copy the slice just in case this is being read while being modified, e.g. when testing. 419 list := make([]SdkMemberType, 0, len(oldList)+1) 420 list = append(list, oldList...) 421 list = append(list, memberType) 422 423 // Sort the member types by their property name to ensure that registry order has no effect 424 // on behavior. 425 sort.Slice(list, func(i1, i2 int) bool { 426 t1 := list[i1] 427 t2 := list[i2] 428 429 return t1.SdkPropertyName() < t2.SdkPropertyName() 430 }) 431 432 // Generate a key that identifies the slice of SdkMemberTypes by joining the property names 433 // from all the SdkMemberType . 434 var properties []string 435 for _, t := range list { 436 properties = append(properties, t.SdkPropertyName()) 437 } 438 key := NewOnceKey(strings.Join(properties, "|")) 439 440 // Create a new registry so the pointer uniquely identifies the set of registered types. 441 return &SdkMemberTypesRegistry{ 442 list: list, 443 key: key, 444 } 445} 446 447func (r *SdkMemberTypesRegistry) RegisteredTypes() []SdkMemberType { 448 return r.list 449} 450 451func (r *SdkMemberTypesRegistry) UniqueOnceKey() OnceKey { 452 // Use the pointer to the registry as the unique key. 453 return NewCustomOnceKey(r) 454} 455 456// The set of registered SdkMemberTypes, one for sdk module and one for module_exports. 457var ModuleExportsMemberTypes = &SdkMemberTypesRegistry{} 458var SdkMemberTypes = &SdkMemberTypesRegistry{} 459 460// Register an SdkMemberType object to allow them to be used in the sdk and sdk_snapshot module 461// types. 462func RegisterSdkMemberType(memberType SdkMemberType) { 463 // All member types are usable with module_exports. 464 ModuleExportsMemberTypes = ModuleExportsMemberTypes.copyAndAppend(memberType) 465 466 // Only those that explicitly indicate it are usable with sdk. 467 if memberType.UsableWithSdkAndSdkSnapshot() { 468 SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType) 469 } 470} 471 472// Base structure for all implementations of SdkMemberProperties. 473// 474// Contains common properties that apply across many different member types. 475type SdkMemberPropertiesBase struct { 476 // The number of unique os types supported by the member variants. 477 // 478 // If a member has a variant with more than one os type then it will need to differentiate 479 // the locations of any of their prebuilt files in the snapshot by os type to prevent them 480 // from colliding. See OsPrefix(). 481 // 482 // This property is the same for all variants of a member and so would be optimized away 483 // if it was not explicitly kept. 484 Os_count int `sdk:"keep"` 485 486 // The os type for which these properties refer. 487 // 488 // Provided to allow a member to differentiate between os types in the locations of their 489 // prebuilt files when it supports more than one os type. 490 // 491 // This property is the same for all os type specific variants of a member and so would be 492 // optimized away if it was not explicitly kept. 493 Os OsType `sdk:"keep"` 494 495 // The setting to use for the compile_multilib property. 496 Compile_multilib string `android:"arch_variant"` 497} 498 499// The os prefix to use for any file paths in the sdk. 500// 501// Is an empty string if the member only provides variants for a single os type, otherwise 502// is the OsType.Name. 503func (b *SdkMemberPropertiesBase) OsPrefix() string { 504 if b.Os_count == 1 { 505 return "" 506 } else { 507 return b.Os.Name 508 } 509} 510 511func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase { 512 return b 513} 514 515// Interface to be implemented on top of a structure that contains variant specific 516// information. 517// 518// Struct fields that are capitalized are examined for common values to extract. Fields 519// that are not capitalized are assumed to be arch specific. 520type SdkMemberProperties interface { 521 // Access the base structure. 522 Base() *SdkMemberPropertiesBase 523 524 // Populate this structure with information from the variant. 525 PopulateFromVariant(ctx SdkMemberContext, variant Module) 526 527 // Add the information from this structure to the property set. 528 AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet) 529} 530 531// Provides access to information common to a specific member. 532type SdkMemberContext interface { 533 534 // The module context of the sdk common os variant which is creating the snapshot. 535 SdkModuleContext() ModuleContext 536 537 // The builder of the snapshot. 538 SnapshotBuilder() SnapshotBuilder 539 540 // The type of the member. 541 MemberType() SdkMemberType 542 543 // The name of the member. 544 // 545 // Provided for use by sdk members to create a member specific location within the snapshot 546 // into which to copy the prebuilt files. 547 Name() string 548} 549