1 // Copyright 2018 Google Inc. All rights reserved. 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 15 package android 16 17 import ( 18 "sort" 19 "sync" 20 21 "github.com/google/blueprint" 22 ) 23 24 // ApexModule is the interface that a module type is expected to implement if 25 // the module has to be built differently depending on whether the module 26 // is destined for an apex or not (installed to one of the regular partitions). 27 // 28 // Native shared libraries are one such module type; when it is built for an 29 // APEX, it should depend only on stable interfaces such as NDK, stable AIDL, 30 // or C APIs from other APEXs. 31 // 32 // A module implementing this interface will be mutated into multiple 33 // variations by apex.apexMutator if it is directly or indirectly included 34 // in one or more APEXs. Specifically, if a module is included in apex.foo and 35 // apex.bar then three apex variants are created: platform, apex.foo and 36 // apex.bar. The platform variant is for the regular partitions 37 // (e.g., /system or /vendor, etc.) while the other two are for the APEXs, 38 // respectively. 39 type ApexModule interface { 40 Module 41 apexModuleBase() *ApexModuleBase 42 43 // Marks that this module should be built for the APEX of the specified name. 44 // Call this before apex.apexMutator is run. 45 BuildForApex(apexName string) 46 47 // Returns the name of APEX that this module will be built for. Empty string 48 // is returned when 'IsForPlatform() == true'. Note that a module can be 49 // included in multiple APEXes, in which case, the module is mutated into 50 // multiple modules each of which for an APEX. This method returns the 51 // name of the APEX that a variant module is for. 52 // Call this after apex.apexMutator is run. 53 ApexName() string 54 55 // Tests whether this module will be built for the platform or not. 56 // This is a shortcut for ApexName() == "" 57 IsForPlatform() bool 58 59 // Tests if this module could have APEX variants. APEX variants are 60 // created only for the modules that returns true here. This is useful 61 // for not creating APEX variants for certain types of shared libraries 62 // such as NDK stubs. 63 CanHaveApexVariants() bool 64 65 // Tests if this module can be installed to APEX as a file. For example, 66 // this would return true for shared libs while return false for static 67 // libs. 68 IsInstallableToApex() bool 69 70 // Mutate this module into one or more variants each of which is built 71 // for an APEX marked via BuildForApex(). 72 CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module 73 74 // Sets the name of the apex variant of this module. Called inside 75 // CreateApexVariations. 76 setApexName(apexName string) 77 } 78 79 type ApexProperties struct { 80 // Name of the apex variant that this module is mutated into 81 ApexName string `blueprint:"mutated"` 82 } 83 84 // Provides default implementation for the ApexModule interface. APEX-aware 85 // modules are expected to include this struct and call InitApexModule(). 86 type ApexModuleBase struct { 87 ApexProperties ApexProperties 88 89 canHaveApexVariants bool 90 91 apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator 92 apexVariations []string 93 } 94 95 func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase { 96 return m 97 } 98 99 func (m *ApexModuleBase) BuildForApex(apexName string) { 100 m.apexVariationsLock.Lock() 101 defer m.apexVariationsLock.Unlock() 102 if !InList(apexName, m.apexVariations) { 103 m.apexVariations = append(m.apexVariations, apexName) 104 } 105 } 106 107 func (m *ApexModuleBase) ApexName() string { 108 return m.ApexProperties.ApexName 109 } 110 111 func (m *ApexModuleBase) IsForPlatform() bool { 112 return m.ApexProperties.ApexName == "" 113 } 114 115 func (m *ApexModuleBase) setApexName(apexName string) { 116 m.ApexProperties.ApexName = apexName 117 } 118 119 func (m *ApexModuleBase) CanHaveApexVariants() bool { 120 return m.canHaveApexVariants 121 } 122 123 func (m *ApexModuleBase) IsInstallableToApex() bool { 124 // should be overriden if needed 125 return false 126 } 127 128 func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module { 129 if len(m.apexVariations) > 0 { 130 sort.Strings(m.apexVariations) 131 variations := []string{""} // Original variation for platform 132 variations = append(variations, m.apexVariations...) 133 134 modules := mctx.CreateVariations(variations...) 135 for i, m := range modules { 136 if i == 0 { 137 continue 138 } 139 m.(ApexModule).setApexName(variations[i]) 140 } 141 return modules 142 } 143 return nil 144 } 145 146 var apexData OncePer 147 var apexNamesMapMutex sync.Mutex 148 var apexNamesKey = NewOnceKey("apexNames") 149 150 // This structure maintains the global mapping in between modules and APEXes. 151 // Examples: 152 // 153 // apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar 154 // apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar 155 // apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar 156 func apexNamesMap() map[string]map[string]bool { 157 return apexData.Once(apexNamesKey, func() interface{} { 158 return make(map[string]map[string]bool) 159 }).(map[string]map[string]bool) 160 } 161 162 // Update the map to mark that a module named moduleName is directly or indirectly 163 // depended on by an APEX named apexName. Directly depending means that a module 164 // is explicitly listed in the build definition of the APEX via properties like 165 // native_shared_libs, java_libs, etc. 166 func UpdateApexDependency(apexName string, moduleName string, directDep bool) { 167 apexNamesMapMutex.Lock() 168 defer apexNamesMapMutex.Unlock() 169 apexNames, ok := apexNamesMap()[moduleName] 170 if !ok { 171 apexNames = make(map[string]bool) 172 apexNamesMap()[moduleName] = apexNames 173 } 174 apexNames[apexName] = apexNames[apexName] || directDep 175 } 176 177 // Tests whether a module named moduleName is directly depended on by an APEX 178 // named apexName. 179 func DirectlyInApex(apexName string, moduleName string) bool { 180 apexNamesMapMutex.Lock() 181 defer apexNamesMapMutex.Unlock() 182 if apexNames, ok := apexNamesMap()[moduleName]; ok { 183 return apexNames[apexName] 184 } 185 return false 186 } 187 188 type hostContext interface { 189 Host() bool 190 } 191 192 // Tests whether a module named moduleName is directly depended on by any APEX. 193 func DirectlyInAnyApex(ctx hostContext, moduleName string) bool { 194 if ctx.Host() { 195 // Host has no APEX. 196 return false 197 } 198 apexNamesMapMutex.Lock() 199 defer apexNamesMapMutex.Unlock() 200 if apexNames, ok := apexNamesMap()[moduleName]; ok { 201 for an := range apexNames { 202 if apexNames[an] { 203 return true 204 } 205 } 206 } 207 return false 208 } 209 210 // Tests whether a module named module is depended on (including both 211 // direct and indirect dependencies) by any APEX. 212 func InAnyApex(moduleName string) bool { 213 apexNamesMapMutex.Lock() 214 defer apexNamesMapMutex.Unlock() 215 apexNames, ok := apexNamesMap()[moduleName] 216 return ok && len(apexNames) > 0 217 } 218 219 func GetApexesForModule(moduleName string) []string { 220 ret := []string{} 221 apexNamesMapMutex.Lock() 222 defer apexNamesMapMutex.Unlock() 223 if apexNames, ok := apexNamesMap()[moduleName]; ok { 224 for an := range apexNames { 225 ret = append(ret, an) 226 } 227 } 228 return ret 229 } 230 231 func InitApexModule(m ApexModule) { 232 base := m.apexModuleBase() 233 base.canHaveApexVariants = true 234 235 m.AddProperties(&base.ApexProperties) 236 } 237