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 15package android 16 17import ( 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. 39type 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 79type 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(). 86type ApexModuleBase struct { 87 ApexProperties ApexProperties 88 89 canHaveApexVariants bool 90 91 apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator 92 apexVariations []string 93} 94 95func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase { 96 return m 97} 98 99func (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 107func (m *ApexModuleBase) ApexName() string { 108 return m.ApexProperties.ApexName 109} 110 111func (m *ApexModuleBase) IsForPlatform() bool { 112 return m.ApexProperties.ApexName == "" 113} 114 115func (m *ApexModuleBase) setApexName(apexName string) { 116 m.ApexProperties.ApexName = apexName 117} 118 119func (m *ApexModuleBase) CanHaveApexVariants() bool { 120 return m.canHaveApexVariants 121} 122 123func (m *ApexModuleBase) IsInstallableToApex() bool { 124 // should be overriden if needed 125 return false 126} 127 128func (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 146var apexData OncePer 147var apexNamesMapMutex sync.Mutex 148var 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 156func 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. 166func 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. 179func 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 188type hostContext interface { 189 Host() bool 190} 191 192// Tests whether a module named moduleName is directly depended on by any APEX. 193func 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. 212func InAnyApex(moduleName string) bool { 213 apexNamesMapMutex.Lock() 214 defer apexNamesMapMutex.Unlock() 215 apexNames, ok := apexNamesMap()[moduleName] 216 return ok && len(apexNames) > 0 217} 218 219func 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 231func InitApexModule(m ApexModule) { 232 base := m.apexModuleBase() 233 base.canHaveApexVariants = true 234 235 m.AddProperties(&base.ApexProperties) 236} 237