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