Home | History | Annotate | Download | only in android
      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