// 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" vendorRamdiskImageVariant imageVariantType = "vendor_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.InVendorRamdisk() { return vendorRamdiskImageVariant } 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 { //TODO(b/150902910): Replace HasNonSystemVariants() with HasProductVariant() return ctx.ModuleContext.ProductSpecific() || (ctx.mod.HasNonSystemVariants() && ctx.mod.inProduct()) } func (ctx *moduleContext) SocSpecific() bool { return ctx.ModuleContext.SocSpecific() || (ctx.mod.HasVendorVariant() && ctx.mod.inVendor()) } 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) inVendorRamdisk() bool { return ctx.mod.InVendorRamdisk() } func (ctx *moduleContextImpl) inRecovery() bool { return ctx.mod.InRecovery() } // Returns true when this module is configured to have core and vendor variants. func (c *Module) HasVendorVariant() bool { return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) } // Returns true when this module is configured to have core and product variants. func (c *Module) HasProductVariant() bool { return c.IsVndk() || Bool(c.VendorProperties.Product_available) } // Returns true when this module is configured to have core and either product or vendor variants. func (c *Module) HasNonSystemVariants() bool { return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) || Bool(c.VendorProperties.Product_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) InVendorRamdisk() bool { return c.ModuleBase.InVendorRamdisk() || c.ModuleBase.InstallInVendorRamdisk() } func (c *Module) InRecovery() bool { return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery() } func (c *Module) OnlyInRamdisk() bool { return c.ModuleBase.InstallInRamdisk() } func (c *Module) OnlyInVendorRamdisk() bool { return c.ModuleBase.InstallInVendorRamdisk() } 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 { if vendorSpecific { mctx.PropertyErrorf("vendor_available", "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") } // If defined, make sure vendor_available and product_available has the // same value since `false` for these properties means the module is // for system only but provides the variant. if m.VendorProperties.Product_available != nil { if Bool(m.VendorProperties.Vendor_available) != Bool(m.VendorProperties.Product_available) { mctx.PropertyErrorf("product_available", "may not have different value than `vendor_available`") } } } if m.VendorProperties.Product_available != nil { if productSpecific { mctx.PropertyErrorf("product_available", "doesn't make sense at the same time as `product_specific: true`") } if vendorSpecific { mctx.PropertyErrorf("product_available", "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: 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 m.VendorProperties.Product_available != nil { mctx.PropertyErrorf("product_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 vendorRamdiskVariantNeeded 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.HasNonSystemVariants() && !m.isVndkExt() { // This will be available to /system unless it is product_specific // which will be handled later. 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 m.HasVendorVariant() { if isVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) } } // vendor_available modules are also available to /product. // TODO(b/150902910): product variant will be created only if // m.HasProductVariant() is true. 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.Vendor_ramdisk_available) { vendorRamdiskVariantNeeded = true } if m.ModuleBase.InstallInVendorRamdisk() { vendorRamdiskVariantNeeded = 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.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded 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) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return c.Properties.VendorRamdiskVariantNeeded } 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 squashVendorSrcs(m *Module) { if lib, ok := m.compiler.(*libraryDecorator); ok { lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs, lib.baseCompiler.Properties.Target.Vendor.Srcs...) lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Vendor.Exclude_srcs...) lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources, lib.baseCompiler.Properties.Target.Vendor.Exclude_generated_sources...) } } func squashProductSrcs(m *Module) { if lib, ok := m.compiler.(*libraryDecorator); ok { lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs, lib.baseCompiler.Properties.Target.Product.Srcs...) lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Product.Exclude_srcs...) lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources, lib.baseCompiler.Properties.Target.Product.Exclude_generated_sources...) } } func squashRecoverySrcs(m *Module) { if lib, ok := m.compiler.(*libraryDecorator); ok { lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs, lib.baseCompiler.Properties.Target.Recovery.Srcs...) lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Recovery.Exclude_srcs...) lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources, lib.baseCompiler.Properties.Target.Recovery.Exclude_generated_sources...) } } func squashVendorRamdiskSrcs(m *Module) { if lib, ok := m.compiler.(*libraryDecorator); ok { lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Vendor_ramdisk.Exclude_srcs...) } } 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.VendorRamdiskVariation { m.MakeAsPlatform() squashVendorRamdiskSrcs(m) } 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) // TODO (b/150902910): This will be replaced with squashProductSrcs(m). squashVendorSrcs(m) } }