1// Copyright (C) 2021 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 "reflect" 19 20 "android/soong/android" 21 "github.com/google/blueprint/proptools" 22) 23 24// Contains information about the sdk properties that list sdk members by type, e.g. 25// Java_header_libs. 26type sdkMemberTypeListProperty struct { 27 // getter for the list of member names 28 getter func(properties interface{}) []string 29 30 // setter for the list of member names 31 setter func(properties interface{}, list []string) 32 33 // the type of member referenced in the list 34 memberType android.SdkMemberType 35 36 // the dependency tag used for items in this list that can be used to determine the memberType 37 // for a resolved dependency. 38 dependencyTag android.SdkMemberDependencyTag 39} 40 41func (p *sdkMemberTypeListProperty) propertyName() string { 42 return p.memberType.SdkPropertyName() 43} 44 45// Cache of dynamically generated dynamicSdkMemberTypes objects. The key is the pointer 46// to a slice of SdkMemberType instances held in android.SdkMemberTypes. 47var dynamicSdkMemberTypesMap android.OncePer 48 49// A dynamically generated set of member list properties and associated structure type. 50type dynamicSdkMemberTypes struct { 51 // The dynamically generated structure type. 52 // 53 // Contains one []string exported field for each android.SdkMemberTypes. The name of the field 54 // is the exported form of the value returned by SdkMemberType.SdkPropertyName(). 55 propertiesStructType reflect.Type 56 57 // Information about each of the member type specific list properties. 58 memberTypeListProperties []*sdkMemberTypeListProperty 59 60 memberTypeToProperty map[android.SdkMemberType]*sdkMemberTypeListProperty 61} 62 63func (d *dynamicSdkMemberTypes) createMemberTypeListProperties() interface{} { 64 return reflect.New(d.propertiesStructType).Interface() 65} 66 67func getDynamicSdkMemberTypes(key android.OnceKey, registeredTypes []android.SdkMemberType) *dynamicSdkMemberTypes { 68 // Get the cached value, creating new instance if necessary. 69 return dynamicSdkMemberTypesMap.Once(key, func() interface{} { 70 return createDynamicSdkMemberTypes(registeredTypes) 71 }).(*dynamicSdkMemberTypes) 72} 73 74// Create the dynamicSdkMemberTypes from the list of registered member types. 75// 76// A struct is created which contains one exported field per member type corresponding to 77// the SdkMemberType.SdkPropertyName() value. 78// 79// A list of sdkMemberTypeListProperty instances is created, one per member type that provides: 80// * a reference to the member type. 81// * a getter for the corresponding field in the properties struct. 82// * a dependency tag that identifies the member type of a resolved dependency. 83func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynamicSdkMemberTypes { 84 85 var listProperties []*sdkMemberTypeListProperty 86 memberTypeToProperty := map[android.SdkMemberType]*sdkMemberTypeListProperty{} 87 var fields []reflect.StructField 88 89 // Iterate over the member types creating StructField and sdkMemberTypeListProperty objects. 90 nextFieldIndex := 0 91 for _, memberType := range sdkMemberTypes { 92 93 p := memberType.SdkPropertyName() 94 95 var getter func(properties interface{}) []string 96 var setter func(properties interface{}, list []string) 97 if memberType.RequiresBpProperty() { 98 // Create a dynamic exported field for the member type's property. 99 fields = append(fields, reflect.StructField{ 100 Name: proptools.FieldNameForProperty(p), 101 Type: reflect.TypeOf([]string{}), 102 Tag: `android:"arch_variant"`, 103 }) 104 105 // Copy the field index for use in the getter func as using the loop variable directly will 106 // cause all funcs to use the last value. 107 fieldIndex := nextFieldIndex 108 nextFieldIndex += 1 109 110 getter = func(properties interface{}) []string { 111 // The properties is expected to be of the following form (where 112 // <Module_types> is the name of an SdkMemberType.SdkPropertyName(). 113 // properties *struct {<Module_types> []string, ....} 114 // 115 // Although it accesses the field by index the following reflection code is equivalent to: 116 // *properties.<Module_types> 117 // 118 list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string) 119 return list 120 } 121 122 setter = func(properties interface{}, list []string) { 123 // The properties is expected to be of the following form (where 124 // <Module_types> is the name of an SdkMemberType.SdkPropertyName(). 125 // properties *struct {<Module_types> []string, ....} 126 // 127 // Although it accesses the field by index the following reflection code is equivalent to: 128 // *properties.<Module_types> = list 129 // 130 reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list)) 131 } 132 } 133 134 // Create an sdkMemberTypeListProperty for the member type. 135 memberListProperty := &sdkMemberTypeListProperty{ 136 getter: getter, 137 setter: setter, 138 memberType: memberType, 139 140 // Dependencies added directly from member properties are always exported. 141 dependencyTag: android.DependencyTagForSdkMemberType(memberType, true), 142 } 143 144 memberTypeToProperty[memberType] = memberListProperty 145 listProperties = append(listProperties, memberListProperty) 146 } 147 148 // Create a dynamic struct from the collated fields. 149 propertiesStructType := reflect.StructOf(fields) 150 151 return &dynamicSdkMemberTypes{ 152 memberTypeListProperties: listProperties, 153 memberTypeToProperty: memberTypeToProperty, 154 propertiesStructType: propertiesStructType, 155 } 156} 157