blob: 99b13ab7259a1ed862f60a6412ed31b289df0657 [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"
Jiyong Park4f7dd9b2019-08-12 10:37:49 +090022 "github.com/google/blueprint/proptools"
Jiyong Park0ddfcd12018-12-11 01:35:25 +090023)
Jiyong Park25fc6a92018-11-18 18:02:45 +090024
Jiyong Park9d452992018-10-03 00:38:19 +090025// ApexModule is the interface that a module type is expected to implement if
26// the module has to be built differently depending on whether the module
27// is destined for an apex or not (installed to one of the regular partitions).
28//
29// Native shared libraries are one such module type; when it is built for an
30// APEX, it should depend only on stable interfaces such as NDK, stable AIDL,
31// or C APIs from other APEXs.
32//
33// A module implementing this interface will be mutated into multiple
Jiyong Park0ddfcd12018-12-11 01:35:25 +090034// variations by apex.apexMutator if it is directly or indirectly included
Jiyong Park9d452992018-10-03 00:38:19 +090035// in one or more APEXs. Specifically, if a module is included in apex.foo and
36// apex.bar then three apex variants are created: platform, apex.foo and
37// apex.bar. The platform variant is for the regular partitions
38// (e.g., /system or /vendor, etc.) while the other two are for the APEXs,
39// respectively.
40type ApexModule interface {
41 Module
42 apexModuleBase() *ApexModuleBase
43
Jiyong Park0ddfcd12018-12-11 01:35:25 +090044 // Marks that this module should be built for the APEX of the specified name.
45 // Call this before apex.apexMutator is run.
Jiyong Park9d452992018-10-03 00:38:19 +090046 BuildForApex(apexName string)
47
Jiyong Park9d452992018-10-03 00:38:19 +090048 // Returns the name of APEX that this module will be built for. Empty string
49 // is returned when 'IsForPlatform() == true'. Note that a module can be
Jiyong Park0ddfcd12018-12-11 01:35:25 +090050 // included in multiple APEXes, in which case, the module is mutated into
Jiyong Park9d452992018-10-03 00:38:19 +090051 // multiple modules each of which for an APEX. This method returns the
52 // name of the APEX that a variant module is for.
Jiyong Park0ddfcd12018-12-11 01:35:25 +090053 // Call this after apex.apexMutator is run.
Jiyong Park9d452992018-10-03 00:38:19 +090054 ApexName() string
55
Jiyong Park0ddfcd12018-12-11 01:35:25 +090056 // Tests whether this module will be built for the platform or not.
57 // This is a shortcut for ApexName() == ""
58 IsForPlatform() bool
59
60 // Tests if this module could have APEX variants. APEX variants are
Jiyong Park9d452992018-10-03 00:38:19 +090061 // created only for the modules that returns true here. This is useful
Jiyong Park0ddfcd12018-12-11 01:35:25 +090062 // for not creating APEX variants for certain types of shared libraries
63 // such as NDK stubs.
Jiyong Park9d452992018-10-03 00:38:19 +090064 CanHaveApexVariants() bool
65
66 // Tests if this module can be installed to APEX as a file. For example,
67 // this would return true for shared libs while return false for static
68 // libs.
69 IsInstallableToApex() bool
Jiyong Park0ddfcd12018-12-11 01:35:25 +090070
71 // Mutate this module into one or more variants each of which is built
72 // for an APEX marked via BuildForApex().
73 CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module
74
75 // Sets the name of the apex variant of this module. Called inside
76 // CreateApexVariations.
77 setApexName(apexName string)
Jiyong Park4f7dd9b2019-08-12 10:37:49 +090078
79 // Return the no_apex property
80 NoApex() bool
Jiyong Park9d452992018-10-03 00:38:19 +090081}
82
83type ApexProperties struct {
Jiyong Park4f7dd9b2019-08-12 10:37:49 +090084 // Whether this module should not be part of any APEX. Default is false.
85 No_apex *bool
86
Jiyong Park0ddfcd12018-12-11 01:35:25 +090087 // Name of the apex variant that this module is mutated into
Jiyong Park9d452992018-10-03 00:38:19 +090088 ApexName string `blueprint:"mutated"`
89}
90
91// Provides default implementation for the ApexModule interface. APEX-aware
92// modules are expected to include this struct and call InitApexModule().
93type ApexModuleBase struct {
94 ApexProperties ApexProperties
95
96 canHaveApexVariants bool
Colin Crosscefa94bd2019-06-03 15:07:03 -070097
98 apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
99 apexVariations []string
Jiyong Park9d452992018-10-03 00:38:19 +0900100}
101
102func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
103 return m
104}
105
106func (m *ApexModuleBase) BuildForApex(apexName string) {
Colin Crosscefa94bd2019-06-03 15:07:03 -0700107 m.apexVariationsLock.Lock()
108 defer m.apexVariationsLock.Unlock()
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900109 if !InList(apexName, m.apexVariations) {
110 m.apexVariations = append(m.apexVariations, apexName)
111 }
112}
113
114func (m *ApexModuleBase) ApexName() string {
115 return m.ApexProperties.ApexName
Jiyong Park9d452992018-10-03 00:38:19 +0900116}
117
118func (m *ApexModuleBase) IsForPlatform() bool {
119 return m.ApexProperties.ApexName == ""
120}
121
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900122func (m *ApexModuleBase) setApexName(apexName string) {
123 m.ApexProperties.ApexName = apexName
Jiyong Park9d452992018-10-03 00:38:19 +0900124}
125
126func (m *ApexModuleBase) CanHaveApexVariants() bool {
127 return m.canHaveApexVariants
128}
129
130func (m *ApexModuleBase) IsInstallableToApex() bool {
131 // should be overriden if needed
132 return false
133}
134
Jiyong Park4f7dd9b2019-08-12 10:37:49 +0900135func (m *ApexModuleBase) NoApex() bool {
136 return proptools.Bool(m.ApexProperties.No_apex)
137}
138
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900139func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
140 if len(m.apexVariations) > 0 {
Colin Crosscefa94bd2019-06-03 15:07:03 -0700141 sort.Strings(m.apexVariations)
Logan Chien3aeedc92018-12-26 15:32:21 +0800142 variations := []string{""} // Original variation for platform
143 variations = append(variations, m.apexVariations...)
144
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900145 modules := mctx.CreateVariations(variations...)
146 for i, m := range modules {
147 if i == 0 {
Logan Chien3aeedc92018-12-26 15:32:21 +0800148 continue
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900149 }
150 m.(ApexModule).setApexName(variations[i])
151 }
152 return modules
153 }
154 return nil
155}
156
157var apexData OncePer
158var apexNamesMapMutex sync.Mutex
Colin Cross571cccf2019-02-04 11:22:08 -0800159var apexNamesKey = NewOnceKey("apexNames")
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900160
161// This structure maintains the global mapping in between modules and APEXes.
162// Examples:
Jiyong Park25fc6a92018-11-18 18:02:45 +0900163//
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900164// apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar
165// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
166// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar
167func apexNamesMap() map[string]map[string]bool {
Colin Cross571cccf2019-02-04 11:22:08 -0800168 return apexData.Once(apexNamesKey, func() interface{} {
Jiyong Park25fc6a92018-11-18 18:02:45 +0900169 return make(map[string]map[string]bool)
170 }).(map[string]map[string]bool)
171}
172
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900173// Update the map to mark that a module named moduleName is directly or indirectly
174// depended on by an APEX named apexName. Directly depending means that a module
175// is explicitly listed in the build definition of the APEX via properties like
176// native_shared_libs, java_libs, etc.
177func UpdateApexDependency(apexName string, moduleName string, directDep bool) {
178 apexNamesMapMutex.Lock()
179 defer apexNamesMapMutex.Unlock()
180 apexNames, ok := apexNamesMap()[moduleName]
Jiyong Park25fc6a92018-11-18 18:02:45 +0900181 if !ok {
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900182 apexNames = make(map[string]bool)
183 apexNamesMap()[moduleName] = apexNames
Jiyong Park25fc6a92018-11-18 18:02:45 +0900184 }
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900185 apexNames[apexName] = apexNames[apexName] || directDep
Jiyong Park25fc6a92018-11-18 18:02:45 +0900186}
187
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900188// Tests whether a module named moduleName is directly depended on by an APEX
189// named apexName.
190func DirectlyInApex(apexName string, moduleName string) bool {
191 apexNamesMapMutex.Lock()
192 defer apexNamesMapMutex.Unlock()
193 if apexNames, ok := apexNamesMap()[moduleName]; ok {
194 return apexNames[apexName]
Jiyong Park25fc6a92018-11-18 18:02:45 +0900195 }
196 return false
197}
198
Nicolas Geoffrayc22c1bf2019-01-15 19:53:23 +0000199type hostContext interface {
200 Host() bool
201}
202
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900203// Tests whether a module named moduleName is directly depended on by any APEX.
Nicolas Geoffrayc22c1bf2019-01-15 19:53:23 +0000204func DirectlyInAnyApex(ctx hostContext, moduleName string) bool {
205 if ctx.Host() {
206 // Host has no APEX.
207 return false
208 }
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900209 apexNamesMapMutex.Lock()
210 defer apexNamesMapMutex.Unlock()
211 if apexNames, ok := apexNamesMap()[moduleName]; ok {
212 for an := range apexNames {
213 if apexNames[an] {
Jiyong Park25fc6a92018-11-18 18:02:45 +0900214 return true
215 }
216 }
217 }
218 return false
219}
220
Jiyong Park0ddfcd12018-12-11 01:35:25 +0900221// Tests whether a module named module is depended on (including both
222// direct and indirect dependencies) by any APEX.
223func InAnyApex(moduleName string) bool {
224 apexNamesMapMutex.Lock()
225 defer apexNamesMapMutex.Unlock()
226 apexNames, ok := apexNamesMap()[moduleName]
227 return ok && len(apexNames) > 0
228}
229
230func GetApexesForModule(moduleName string) []string {
231 ret := []string{}
232 apexNamesMapMutex.Lock()
233 defer apexNamesMapMutex.Unlock()
234 if apexNames, ok := apexNamesMap()[moduleName]; ok {
235 for an := range apexNames {
236 ret = append(ret, an)
237 }
238 }
239 return ret
Jiyong Parkde866cb2018-12-07 23:08:36 +0900240}
241
Jiyong Park9d452992018-10-03 00:38:19 +0900242func InitApexModule(m ApexModule) {
243 base := m.apexModuleBase()
244 base.canHaveApexVariants = true
245
246 m.AddProperties(&base.ApexProperties)
247}