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