blob: 17df7624039d94bdc44d3a30820a613054a0f46f [file] [log] [blame]
Jiyong Park9d452992018-10-03 00:38:19 +09001// 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
Jiyong Park0ddfcd12018-12-11 01:35:25 +090017import (
Colin Crosscefa94bd2019-06-03 15:07:03 -070018 "sort"
Jiyong Park0ddfcd12018-12-11 01:35:25 +090019 "sync"
20
21 "github.com/google/blueprint"
22)
Jiyong Park25fc6a92018-11-18 18:02:45 +090023
Jiyong Park9d452992018-10-03 00:38:19 +090024// 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
Jiyong Park0ddfcd12018-12-11 01:35:25 +090033// variations by apex.apexMutator if it is directly or indirectly included
Jiyong Park9d452992018-10-03 00:38:19 +090034// 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
Jiyong Park0ddfcd12018-12-11 01:35:25 +090043 // Marks that this module should be built for the APEX of the specified name.
44 // Call this before apex.apexMutator is run.
Jiyong Park9d452992018-10-03 00:38:19 +090045 BuildForApex(apexName string)
46
Jiyong Park9d452992018-10-03 00:38:19 +090047 // 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
Jiyong Park0ddfcd12018-12-11 01:35:25 +090049 // included in multiple APEXes, in which case, the module is mutated into
Jiyong Park9d452992018-10-03 00:38:19 +090050 // multiple modules each of which for an APEX. This method returns the
51 // name of the APEX that a variant module is for.
Jiyong Park0ddfcd12018-12-11 01:35:25 +090052 // Call this after apex.apexMutator is run.
Jiyong Park9d452992018-10-03 00:38:19 +090053 ApexName() string
54
Jiyong Park0ddfcd12018-12-11 01:35:25 +090055 // 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
Jiyong Park9d452992018-10-03 00:38:19 +090060 // created only for the modules that returns true here. This is useful
Jiyong Park0ddfcd12018-12-11 01:35:25 +090061 // for not creating APEX variants for certain types of shared libraries
62 // such as NDK stubs.
Jiyong Park9d452992018-10-03 00:38:19 +090063 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
Jiyong Park0ddfcd12018-12-11 01:35:25 +090069
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)
Jiyong Park9d452992018-10-03 00:38:19 +090077}
78
79type ApexProperties struct {
Jiyong Park0ddfcd12018-12-11 01:35:25 +090080 // Name of the apex variant that this module is mutated into
Jiyong Park9d452992018-10-03 00:38:19 +090081 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
Colin Crosscefa94bd2019-06-03 15:07:03 -070090
91 apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
92 apexVariations []string
Jiyong Park9d452992018-10-03 00:38:19 +090093}
94
95func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
96 return m
97}
98
99func (m *ApexModuleBase) BuildForApex(apexName string) {
Colin Crosscefa94bd2019-06-03 15:07:03 -0700100 m.apexVariationsLock.Lock()
101 defer m.apexVariationsLock.Unlock()
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900102 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
Jiyong Park9d452992018-10-03 00:38:19 +0900109}
110
111func (m *ApexModuleBase) IsForPlatform() bool {
112 return m.ApexProperties.ApexName == ""
113}
114
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900115func (m *ApexModuleBase) setApexName(apexName string) {
116 m.ApexProperties.ApexName = apexName
Jiyong Park9d452992018-10-03 00:38:19 +0900117}
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
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900128func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
129 if len(m.apexVariations) > 0 {
Colin Crosscefa94bd2019-06-03 15:07:03 -0700130 sort.Strings(m.apexVariations)
Logan Chien3aeedc92018-12-26 15:32:21 +0800131 variations := []string{""} // Original variation for platform
132 variations = append(variations, m.apexVariations...)
133
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900134 modules := mctx.CreateVariations(variations...)
135 for i, m := range modules {
136 if i == 0 {
Logan Chien3aeedc92018-12-26 15:32:21 +0800137 continue
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900138 }
139 m.(ApexModule).setApexName(variations[i])
140 }
141 return modules
142 }
143 return nil
144}
145
146var apexData OncePer
147var apexNamesMapMutex sync.Mutex
Colin Cross571cccf2019-02-04 11:22:08 -0800148var apexNamesKey = NewOnceKey("apexNames")
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900149
150// This structure maintains the global mapping in between modules and APEXes.
151// Examples:
Jiyong Park25fc6a92018-11-18 18:02:45 +0900152//
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900153// 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 {
Colin Cross571cccf2019-02-04 11:22:08 -0800157 return apexData.Once(apexNamesKey, func() interface{} {
Jiyong Park25fc6a92018-11-18 18:02:45 +0900158 return make(map[string]map[string]bool)
159 }).(map[string]map[string]bool)
160}
161
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900162// 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]
Jiyong Park25fc6a92018-11-18 18:02:45 +0900170 if !ok {
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900171 apexNames = make(map[string]bool)
172 apexNamesMap()[moduleName] = apexNames
Jiyong Park25fc6a92018-11-18 18:02:45 +0900173 }
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900174 apexNames[apexName] = apexNames[apexName] || directDep
Jiyong Park25fc6a92018-11-18 18:02:45 +0900175}
176
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900177// 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]
Jiyong Park25fc6a92018-11-18 18:02:45 +0900184 }
185 return false
186}
187
Nicolas Geoffrayc22c1bf2019-01-15 19:53:23 +0000188type hostContext interface {
189 Host() bool
190}
191
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900192// Tests whether a module named moduleName is directly depended on by any APEX.
Nicolas Geoffrayc22c1bf2019-01-15 19:53:23 +0000193func DirectlyInAnyApex(ctx hostContext, moduleName string) bool {
194 if ctx.Host() {
195 // Host has no APEX.
196 return false
197 }
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900198 apexNamesMapMutex.Lock()
199 defer apexNamesMapMutex.Unlock()
200 if apexNames, ok := apexNamesMap()[moduleName]; ok {
201 for an := range apexNames {
202 if apexNames[an] {
Jiyong Park25fc6a92018-11-18 18:02:45 +0900203 return true
204 }
205 }
206 }
207 return false
208}
209
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900210// 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
Jiyong Parkde866cb2018-12-07 23:08:36 +0900229}
230
Jiyong Park9d452992018-10-03 00:38:19 +0900231func InitApexModule(m ApexModule) {
232 base := m.apexModuleBase()
233 base.canHaveApexVariants = true
234
235 m.AddProperties(&base.ApexProperties)
236}