| // Copyright 2020 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package cc |
| |
| // This file contains image variant related things, including image mutator functions, utility |
| // functions to determine where a module is installed, etc. |
| |
| import ( |
| "strings" |
| |
| "android/soong/android" |
| ) |
| |
| var _ android.ImageInterface = (*Module)(nil) |
| |
| type imageVariantType string |
| |
| const ( |
| coreImageVariant imageVariantType = "core" |
| vendorImageVariant imageVariantType = "vendor" |
| productImageVariant imageVariantType = "product" |
| ramdiskImageVariant imageVariantType = "ramdisk" |
| recoveryImageVariant imageVariantType = "recovery" |
| hostImageVariant imageVariantType = "host" |
| ) |
| |
| func (c *Module) getImageVariantType() imageVariantType { |
| if c.Host() { |
| return hostImageVariant |
| } else if c.inVendor() { |
| return vendorImageVariant |
| } else if c.inProduct() { |
| return productImageVariant |
| } else if c.InRamdisk() { |
| return ramdiskImageVariant |
| } else if c.InRecovery() { |
| return recoveryImageVariant |
| } else { |
| return coreImageVariant |
| } |
| } |
| |
| const ( |
| // VendorVariationPrefix is the variant prefix used for /vendor code that compiles |
| // against the VNDK. |
| VendorVariationPrefix = "vendor." |
| |
| // ProductVariationPrefix is the variant prefix used for /product code that compiles |
| // against the VNDK. |
| ProductVariationPrefix = "product." |
| ) |
| |
| func (ctx *moduleContext) ProductSpecific() bool { |
| return ctx.ModuleContext.ProductSpecific() || |
| (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk()) |
| } |
| |
| func (ctx *moduleContext) SocSpecific() bool { |
| return ctx.ModuleContext.SocSpecific() || |
| (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk()) |
| } |
| |
| func (ctx *moduleContextImpl) inProduct() bool { |
| return ctx.mod.inProduct() |
| } |
| |
| func (ctx *moduleContextImpl) inVendor() bool { |
| return ctx.mod.inVendor() |
| } |
| |
| func (ctx *moduleContextImpl) inRamdisk() bool { |
| return ctx.mod.InRamdisk() |
| } |
| |
| func (ctx *moduleContextImpl) inRecovery() bool { |
| return ctx.mod.InRecovery() |
| } |
| |
| // Returns true only when this module is configured to have core, product and vendor |
| // variants. |
| func (c *Module) HasVendorVariant() bool { |
| return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) |
| } |
| |
| // Returns true if the module is "product" variant. Usually these modules are installed in /product |
| func (c *Module) inProduct() bool { |
| return c.Properties.ImageVariationPrefix == ProductVariationPrefix |
| } |
| |
| // Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor |
| func (c *Module) inVendor() bool { |
| return c.Properties.ImageVariationPrefix == VendorVariationPrefix |
| } |
| |
| func (c *Module) InRamdisk() bool { |
| return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk() |
| } |
| |
| func (c *Module) InRecovery() bool { |
| return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery() |
| } |
| |
| func (c *Module) OnlyInRamdisk() bool { |
| return c.ModuleBase.InstallInRamdisk() |
| } |
| |
| func (c *Module) OnlyInRecovery() bool { |
| return c.ModuleBase.InstallInRecovery() |
| } |
| |
| func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { |
| // Validation check |
| vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() |
| productSpecific := mctx.ProductSpecific() |
| |
| if m.VendorProperties.Vendor_available != nil && vendorSpecific { |
| mctx.PropertyErrorf("vendor_available", |
| "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") |
| } |
| |
| if vndkdep := m.vndkdep; vndkdep != nil { |
| if vndkdep.isVndk() { |
| if vendorSpecific || productSpecific { |
| if !vndkdep.isVndkExt() { |
| mctx.PropertyErrorf("vndk", |
| "must set `extends: \"...\"` to vndk extension") |
| } else if m.VendorProperties.Vendor_available != nil { |
| mctx.PropertyErrorf("vendor_available", |
| "must not set at the same time as `vndk: {extends: \"...\"}`") |
| } |
| } else { |
| if vndkdep.isVndkExt() { |
| mctx.PropertyErrorf("vndk", |
| "must set `vendor: true` or `product_specific: true` to set `extends: %q`", |
| m.getVndkExtendsModuleName()) |
| } |
| if m.VendorProperties.Vendor_available == nil { |
| mctx.PropertyErrorf("vndk", |
| "vendor_available must be set to either true or false when `vndk: {enabled: true}`") |
| } |
| } |
| } else { |
| if vndkdep.isVndkSp() { |
| mctx.PropertyErrorf("vndk", |
| "must set `enabled: true` to set `support_system_process: true`") |
| } |
| if vndkdep.isVndkExt() { |
| mctx.PropertyErrorf("vndk", |
| "must set `enabled: true` to set `extends: %q`", |
| m.getVndkExtendsModuleName()) |
| } |
| } |
| } |
| |
| var coreVariantNeeded bool = false |
| var ramdiskVariantNeeded bool = false |
| var recoveryVariantNeeded bool = false |
| |
| var vendorVariants []string |
| var productVariants []string |
| |
| platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() |
| boardVndkVersion := mctx.DeviceConfig().VndkVersion() |
| productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() |
| if boardVndkVersion == "current" { |
| boardVndkVersion = platformVndkVersion |
| } |
| if productVndkVersion == "current" { |
| productVndkVersion = platformVndkVersion |
| } |
| |
| if boardVndkVersion == "" { |
| // If the device isn't compiling against the VNDK, we always |
| // use the core mode. |
| coreVariantNeeded = true |
| } else if _, ok := m.linker.(*llndkStubDecorator); ok { |
| // LL-NDK stubs only exist in the vendor and product variants, |
| // since the real libraries will be used in the core variant. |
| vendorVariants = append(vendorVariants, |
| platformVndkVersion, |
| boardVndkVersion, |
| ) |
| productVariants = append(productVariants, |
| platformVndkVersion, |
| productVndkVersion, |
| ) |
| } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { |
| // ... and LL-NDK headers as well |
| vendorVariants = append(vendorVariants, |
| platformVndkVersion, |
| boardVndkVersion, |
| ) |
| productVariants = append(productVariants, |
| platformVndkVersion, |
| productVndkVersion, |
| ) |
| } else if m.isSnapshotPrebuilt() { |
| // Make vendor variants only for the versions in BOARD_VNDK_VERSION and |
| // PRODUCT_EXTRA_VNDK_VERSIONS. |
| if snapshot, ok := m.linker.(interface { |
| version() string |
| }); ok { |
| vendorVariants = append(vendorVariants, snapshot.version()) |
| } else { |
| mctx.ModuleErrorf("version is unknown for snapshot prebuilt") |
| } |
| } else if m.HasVendorVariant() && !m.isVndkExt() { |
| // This will be available in /system, /vendor and /product |
| // or a /system directory that is available to vendor and product. |
| coreVariantNeeded = true |
| |
| // We assume that modules under proprietary paths are compatible for |
| // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or |
| // PLATFORM_VNDK_VERSION. |
| if isVendorProprietaryModule(mctx) { |
| vendorVariants = append(vendorVariants, boardVndkVersion) |
| } else { |
| vendorVariants = append(vendorVariants, platformVndkVersion) |
| } |
| |
| // vendor_available modules are also available to /product. |
| productVariants = append(productVariants, platformVndkVersion) |
| // VNDK is always PLATFORM_VNDK_VERSION |
| if !m.IsVndk() { |
| productVariants = append(productVariants, productVndkVersion) |
| } |
| } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { |
| // This will be available in /vendor (or /odm) only |
| |
| // kernel_headers is a special module type whose exported headers |
| // are coming from DeviceKernelHeaders() which is always vendor |
| // dependent. They'll always have both vendor variants. |
| // For other modules, we assume that modules under proprietary |
| // paths are compatible for BOARD_VNDK_VERSION. The other modules |
| // are regarded as AOSP, which is PLATFORM_VNDK_VERSION. |
| if _, ok := m.linker.(*kernelHeadersDecorator); ok { |
| vendorVariants = append(vendorVariants, |
| platformVndkVersion, |
| boardVndkVersion, |
| ) |
| } else if isVendorProprietaryModule(mctx) { |
| vendorVariants = append(vendorVariants, boardVndkVersion) |
| } else { |
| vendorVariants = append(vendorVariants, platformVndkVersion) |
| } |
| } else { |
| // This is either in /system (or similar: /data), or is a |
| // modules built with the NDK. Modules built with the NDK |
| // will be restricted using the existing link type checks. |
| coreVariantNeeded = true |
| } |
| |
| if boardVndkVersion != "" && productVndkVersion != "" { |
| if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" { |
| // The module has "product_specific: true" that does not create core variant. |
| coreVariantNeeded = false |
| productVariants = append(productVariants, productVndkVersion) |
| } |
| } else { |
| // Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no |
| // restriction to use system libs. |
| // No product variants defined in this case. |
| productVariants = []string{} |
| } |
| |
| if Bool(m.Properties.Ramdisk_available) { |
| ramdiskVariantNeeded = true |
| } |
| |
| if m.ModuleBase.InstallInRamdisk() { |
| ramdiskVariantNeeded = true |
| coreVariantNeeded = false |
| } |
| |
| if Bool(m.Properties.Recovery_available) { |
| recoveryVariantNeeded = true |
| } |
| |
| if m.ModuleBase.InstallInRecovery() { |
| recoveryVariantNeeded = true |
| coreVariantNeeded = false |
| } |
| |
| for _, variant := range android.FirstUniqueStrings(vendorVariants) { |
| m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) |
| } |
| |
| for _, variant := range android.FirstUniqueStrings(productVariants) { |
| m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant) |
| } |
| |
| m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded |
| m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded |
| m.Properties.CoreVariantNeeded = coreVariantNeeded |
| } |
| |
| func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { |
| return c.Properties.CoreVariantNeeded |
| } |
| |
| func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { |
| return c.Properties.RamdiskVariantNeeded |
| } |
| |
| func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { |
| return c.Properties.RecoveryVariantNeeded |
| } |
| |
| func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string { |
| return c.Properties.ExtraVariants |
| } |
| |
| func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { |
| m := module.(*Module) |
| if variant == android.RamdiskVariation { |
| m.MakeAsPlatform() |
| } else if variant == android.RecoveryVariation { |
| m.MakeAsPlatform() |
| squashRecoverySrcs(m) |
| } else if strings.HasPrefix(variant, VendorVariationPrefix) { |
| m.Properties.ImageVariationPrefix = VendorVariationPrefix |
| m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix) |
| squashVendorSrcs(m) |
| |
| // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION. |
| // Hide other vendor variants to avoid collision. |
| vndkVersion := ctx.DeviceConfig().VndkVersion() |
| if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion { |
| m.Properties.HideFromMake = true |
| m.SkipInstall() |
| } |
| } else if strings.HasPrefix(variant, ProductVariationPrefix) { |
| m.Properties.ImageVariationPrefix = ProductVariationPrefix |
| m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) |
| squashVendorSrcs(m) |
| } |
| } |