Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f7f7e8a authored by Justin Yun's avatar Justin Yun
Browse files

Create product variant for product partition

When PRODUCT_PRODUCT_VNDK_VERSION is set to 'current', product
modules are enforced to use only VNDK libs from the system partition
as BOARD_VNDK_VERSION does to vendor partition.

Modules with 'vendor_available: true' create product variant as well
as core and vendor variants. The product variant as an image variant
is used for the modules in /product or /system/product.

It must not affect the current build behavior without
PRODUCT_PRODUCT_VNDK_VERSION set.

Bug: 134099726
Bug: 138966004
Bug: 144534640
Test: build without PRODUCT_PRODUCT_VNDK_VERSION set
Change-Id: I4d3585c110d84493e45bf76d550dc240bb26137f
parent 120d73fe
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -946,6 +946,10 @@ func (c *deviceConfig) PlatformVndkVersion() string {
	return String(c.config.productVariables.Platform_vndk_version)
}

func (c *deviceConfig) ProductVndkVersion() string {
	return String(c.config.productVariables.ProductVndkVersion)
}

func (c *deviceConfig) ExtraVndkVersions() []string {
	return c.config.productVariables.ExtraVndkVersions
}
+2 −0
Original line number Diff line number Diff line
@@ -306,6 +306,8 @@ type productVariables struct {
	ProductPrivateSepolicyDirs []string `json:",omitempty"`
	ProductCompatibleProperty  *bool    `json:",omitempty"`

	ProductVndkVersion *string `json:",omitempty"`

	TargetFSConfigGen []string `json:",omitempty"`

	MissingUsesLibraries []string `json:",omitempty"`
+3 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import (

var (
	nativeBridgeSuffix = ".native_bridge"
	productSuffix      = ".product"
	vendorSuffix       = ".vendor"
	recoverySuffix     = ".recovery"
)
@@ -37,7 +38,7 @@ type AndroidMkContext interface {
	Os() android.OsType
	Host() bool
	UseVndk() bool
	vndkVersion() string
	VndkVersion() string
	static() bool
	InRecovery() bool
}
@@ -92,7 +93,7 @@ func (c *Module) AndroidMk() android.AndroidMkData {
				if c.UseVndk() {
					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
					if c.IsVndk() && !c.static() {
						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.VndkVersion())
						// VNDK libraries available to vendor are not installed because
						// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
						if !c.isVndkExt() {
+148 −64
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ type BaseProperties struct {
	PreventInstall            bool     `blueprint:"mutated"`
	ApexesProvidingSharedLibs []string `blueprint:"mutated"`

	ImageVariationPrefix string `blueprint:"mutated"`
	VndkVersion          string `blueprint:"mutated"`
	SubName              string `blueprint:"mutated"`

@@ -228,7 +229,7 @@ type BaseProperties struct {
	// Set by imageMutator
	CoreVariantNeeded     bool     `blueprint:"mutated"`
	RecoveryVariantNeeded bool     `blueprint:"mutated"`
	VendorVariants        []string `blueprint:"mutated"`
	ExtraVariants         []string `blueprint:"mutated"`

	// Allows this module to use non-APEX version of libraries. Useful
	// for building binaries that are started before APEXes are activated.
@@ -242,20 +243,24 @@ type BaseProperties struct {
type VendorProperties struct {
	// whether this module should be allowed to be directly depended by other
	// modules with `vendor: true`, `proprietary: true`, or `vendor_available:true`.
	// If set to true, two variants will be built separately, one like
	// normal, and the other limited to the set of libraries and headers
	// that are exposed to /vendor modules.
	// In addition, this module should be allowed to be directly depended by
	// product modules with `product_specific: true`.
	// If set to true, three variants will be built separately, one like
	// normal, another limited to the set of libraries and headers
	// that are exposed to /vendor modules, and the other to /product modules.
	//
	// The vendor variant may be used with a different (newer) /system,
	// The vendor and product variants may be used with a different (newer) /system,
	// so it shouldn't have any unversioned runtime dependencies, or
	// make assumptions about the system that may not be true in the
	// future.
	//
	// If set to false, this module becomes inaccessible from /vendor modules.
	// If set to false, this module becomes inaccessible from /vendor or /product
	// modules.
	//
	// Default value is true when vndk: {enabled: true} or vendor: true.
	//
	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
	// If PRODUCT_PRODUCT_VNDK_VERSION isn't set, product variant will not be used.
	Vendor_available *bool

	// whether this module is capable of being loaded with other instance
@@ -283,6 +288,8 @@ type ModuleContextIntf interface {
	isVndk() bool
	isVndkSp() bool
	isVndkExt() bool
	inProduct() bool
	inVendor() bool
	inRecovery() bool
	shouldCreateSourceAbiDump() bool
	selectedStl() string
@@ -680,7 +687,7 @@ func (c *Module) RelativeInstallPath() string {
}

func (c *Module) VndkVersion() string {
	return c.vndkVersion()
	return c.Properties.VndkVersion
}

func (c *Module) Init() android.Module {
@@ -752,6 +759,12 @@ func (c *Module) isDependencyRoot() bool {
	return false
}

// Returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
// "product" and "vendor" variant modules return true for this function.
// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
// "soc_specific: true" and more vendor installed modules are included here.
// When PRODUCT_PRODUCT_VNDK_VERSION is set, product variants of "vendor_available: true" or
// "product_specific: true" modules are included here.
func (c *Module) UseVndk() bool {
	return c.Properties.VndkVersion != ""
}
@@ -787,10 +800,6 @@ func (c *Module) IsVndk() bool {
	return false
}

func (c *Module) vndkVersion() string {
	return c.Properties.VndkVersion
}

func (c *Module) isPgoCompile() bool {
	if pgo := c.pgo; pgo != nil {
		return pgo.Properties.PgoCompile
@@ -830,12 +839,32 @@ func (c *Module) getVndkExtendsModuleName() string {
	return ""
}

// Returns true only when this module is configured to have core and vendor
// 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)
}

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."
)

// 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) InRecovery() bool {
	return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery()
}
@@ -944,9 +973,14 @@ type moduleContext struct {
	moduleContextImpl
}

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.UseVndk() && !ctx.mod.IsVndk())
		(ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk())
}

type moduleContextImpl struct {
@@ -980,15 +1014,11 @@ func (ctx *moduleContextImpl) useSdk() bool {
func (ctx *moduleContextImpl) sdkVersion() string {
	if ctx.ctx.Device() {
		if ctx.useVndk() {
			vndk_ver := ctx.ctx.DeviceConfig().VndkVersion()
			if vndk_ver == "current" {
				platform_vndk_ver := ctx.ctx.DeviceConfig().PlatformVndkVersion()
				if inList(platform_vndk_ver, ctx.ctx.Config().PlatformVersionCombinedCodenames()) {
			vndkVer := ctx.mod.VndkVersion()
			if inList(vndkVer, ctx.ctx.Config().PlatformVersionCombinedCodenames()) {
				return "current"
			}
				return platform_vndk_ver
			}
			return vndk_ver
			return vndkVer
		}
		return String(ctx.mod.Properties.Sdk_version)
	}
@@ -1039,6 +1069,14 @@ func (ctx *moduleContextImpl) mustUseVendorVariant() bool {
	return ctx.mod.MustUseVendorVariant()
}

func (ctx *moduleContextImpl) inProduct() bool {
	return ctx.mod.inProduct()
}

func (ctx *moduleContextImpl) inVendor() bool {
	return ctx.mod.inVendor()
}

func (ctx *moduleContextImpl) inRecovery() bool {
	return ctx.mod.InRecovery()
}
@@ -1222,6 +1260,29 @@ func (c *Module) IsTestPerSrcAllTestsVariation() bool {
	return ok && test.isAllTestsVariation()
}

func (c *Module) getNameSuffixWithVndkVersion(ctx android.ModuleContext) string {
	// Returns the name suffix for product and vendor variants. If the VNDK version is not
	// "current", it will append the VNDK version to the name suffix.
	var vndkVersion string
	var nameSuffix string
	if c.inProduct() {
		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
		nameSuffix = productSuffix
	} else {
		vndkVersion = ctx.DeviceConfig().VndkVersion()
		nameSuffix = vendorSuffix
	}
	if vndkVersion == "current" {
		vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
	}
	if c.Properties.VndkVersion != vndkVersion {
		// add version suffix only if the module is using different vndk version than the
		// version in product or vendor partition.
		nameSuffix += "." + c.Properties.VndkVersion
	}
	return nameSuffix
}

func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
	// Handle the case of a test module split by `test_per_src` mutator.
	//
@@ -1241,21 +1302,17 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
		c.Properties.SubName += nativeBridgeSuffix
	}

	if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
	_, llndk := c.linker.(*llndkStubDecorator)
	_, llndkHeader := c.linker.(*llndkHeadersDecorator)
	if llndk || llndkHeader || (c.UseVndk() && c.HasVendorVariant()) {
		// .vendor.{version} suffix is added for vendor variant or .product.{version} suffix is
		// added for product variant only when we have vendor and product variants with core
		// variant. The suffix is not added for vendor-only or product-only module.
		c.Properties.SubName += c.getNameSuffixWithVndkVersion(actx)
	} else if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
		// .vendor suffix is added for backward compatibility with VNDK snapshot whose names with
		// such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp.
		c.Properties.SubName += vendorSuffix
	} else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.UseVndk() && c.HasVendorVariant()) {
		// .vendor.{version} suffix is added only when we will have two variants: core and vendor.
		// The suffix is not added for vendor-only module.
		c.Properties.SubName += vendorSuffix
		vendorVersion := actx.DeviceConfig().VndkVersion()
		if vendorVersion == "current" {
			vendorVersion = actx.DeviceConfig().PlatformVndkVersion()
		}
		if c.Properties.VndkVersion != vendorVersion {
			c.Properties.SubName += "." + c.Properties.VndkVersion
		}
	} else if c.InRecovery() && !c.OnlyInRecovery() {
		c.Properties.SubName += recoverySuffix
	}
@@ -2203,15 +2260,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
			} else if c.UseVndk() && bothVendorAndCoreVariantsExist {
				// The vendor module in Make will have been renamed to not conflict with the core
				// module, so update the dependency name here accordingly.
				ret := libName + vendorSuffix
				vendorVersion := ctx.DeviceConfig().VndkVersion()
				if vendorVersion == "current" {
					vendorVersion = ctx.DeviceConfig().PlatformVndkVersion()
				}
				if c.Properties.VndkVersion != vendorVersion {
					ret += "." + c.Properties.VndkVersion
				}
				return ret
				return libName + c.getNameSuffixWithVndkVersion(ctx)
			} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
				return libName + vendorPublicLibrarySuffix
			} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
@@ -2364,6 +2413,9 @@ func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
			}
			return "native:vndk_private"
		}
		if c.inProduct() {
			return "native:product"
		}
		return "native:vendor"
	} else if c.InRecovery() {
		return "native:recovery"
@@ -2489,12 +2541,6 @@ func DefaultsFactory(props ...interface{}) android.Module {
	return module
}

const (
	// VendorVariationPrefix is the variant prefix used for /vendor code that compiles
	// against the VNDK.
	VendorVariationPrefix = "vendor."
)

func squashVendorSrcs(m *Module) {
	if lib, ok := m.compiler.(*libraryDecorator); ok {
		lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs,
@@ -2566,49 +2612,65 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
	var recoveryVariantNeeded bool = false

	var vendorVariants []string
	var productVariants []string

	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
	deviceVndkVersion := mctx.DeviceConfig().VndkVersion()
	if deviceVndkVersion == "current" {
		deviceVndkVersion = platformVndkVersion
	boardVndkVersion := mctx.DeviceConfig().VndkVersion()
	productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
	if boardVndkVersion == "current" {
		boardVndkVersion = platformVndkVersion
	}
	if productVndkVersion == "current" {
		productVndkVersion = platformVndkVersion
	}

	if mctx.DeviceConfig().VndkVersion() == "" {
	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 variant, since the
		// real libraries will be used in the core variant.
		// 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,
			deviceVndkVersion,
			boardVndkVersion,
		)
		productVariants = append(productVariants,
			platformVndkVersion,
			productVndkVersion,
		)
	} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
		// ... and LL-NDK headers as well
		vendorVariants = append(vendorVariants,
			platformVndkVersion,
			deviceVndkVersion,
			boardVndkVersion,
		)
		productVariants = append(productVariants,
			platformVndkVersion,
			productVndkVersion,
		)
	} else if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
		// PRODUCT_EXTRA_VNDK_VERSIONS.
		vendorVariants = append(vendorVariants, lib.version())
	} else if m.HasVendorVariant() && !vendorSpecific {
		// This will be available in both /system and /vendor
		// or a /system directory that is available to vendor.
		// This will be available in /system, /vendor and /product
		// or a /system directory that is available to vendor and product.
		coreVariantNeeded = true
		vendorVariants = append(vendorVariants, platformVndkVersion)
		productVariants = append(productVariants, platformVndkVersion)
		// VNDK modules must not create BOARD_VNDK_VERSION variant because its
		// code is PLATFORM_VNDK_VERSION.
		// On the other hand, vendor_available modules which are not VNDK should
		// also build BOARD_VNDK_VERSION because it's installed in /vendor.
		// vendor_available modules are also available to /product.
		if !m.IsVndk() {
			vendorVariants = append(vendorVariants, deviceVndkVersion)
			vendorVariants = append(vendorVariants, boardVndkVersion)
			productVariants = append(productVariants, productVndkVersion)
		}
	} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
		// This will be available in /vendor (or /odm) only
		vendorVariants = append(vendorVariants, deviceVndkVersion)
		vendorVariants = append(vendorVariants, boardVndkVersion)
	} else {
		// This is either in /system (or similar: /data), or is a
		// modules built with the NDK. Modules built with the NDK
@@ -2616,6 +2678,19 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
		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.Recovery_available) {
		recoveryVariantNeeded = true
	}
@@ -2626,7 +2701,11 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
	}

	for _, variant := range android.FirstUniqueStrings(vendorVariants) {
		m.Properties.VendorVariants = append(m.Properties.VendorVariants, VendorVariationPrefix+variant)
		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.RecoveryVariantNeeded = recoveryVariantNeeded
@@ -2642,7 +2721,7 @@ func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
}

func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string {
	return c.Properties.VendorVariants
	return c.Properties.ExtraVariants
}

func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
@@ -2651,8 +2730,13 @@ func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string
		m.MakeAsPlatform()
		squashRecoverySrcs(m)
	} else if strings.HasPrefix(variant, VendorVariationPrefix) {
		m.Properties.ImageVariationPrefix = VendorVariationPrefix
		m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
		squashVendorSrcs(m)
	} else if strings.HasPrefix(variant, ProductVariationPrefix) {
		m.Properties.ImageVariationPrefix = ProductVariationPrefix
		m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
		squashVendorSrcs(m)
	}
}

+173 −4
Original line number Diff line number Diff line
@@ -82,11 +82,8 @@ func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
	return testCcWithConfig(t, config)
}

func testCcError(t *testing.T, pattern string, bp string) {
func testCcErrorWithConfig(t *testing.T, pattern string, config android.Config) {
	t.Helper()
	config := TestConfig(buildDir, android.Android, nil, bp, nil)
	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")

	ctx := CreateTestContext()
	ctx.Register(config)
@@ -106,9 +103,27 @@ func testCcError(t *testing.T, pattern string, bp string) {
	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
}

func testCcError(t *testing.T, pattern string, bp string) {
	config := TestConfig(buildDir, android.Android, nil, bp, nil)
	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
	testCcErrorWithConfig(t, pattern, config)
	return
}

func testCcErrorProductVndk(t *testing.T, pattern string, bp string) {
	config := TestConfig(buildDir, android.Android, nil, bp, nil)
	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
	testCcErrorWithConfig(t, pattern, config)
	return
}

const (
	coreVariant     = "android_arm64_armv8-a_shared"
	vendorVariant   = "android_vendor.VER_arm64_armv8-a_shared"
	productVariant  = "android_product.VER_arm64_armv8-a_shared"
	recoveryVariant = "android_recovery_arm64_armv8-a_shared"
)

@@ -1445,6 +1460,160 @@ func TestVndkUseVndkExtError(t *testing.T) {
	`)
}

func TestEnforceProductVndkVersion(t *testing.T) {
	bp := `
		cc_library {
			name: "libllndk",
		}
		llndk_library {
			name: "libllndk",
			symbol_file: "",
		}
		cc_library {
			name: "libvndk",
			vendor_available: true,
			vndk: {
				enabled: true,
			},
			nocrt: true,
		}
		cc_library {
			name: "libvndk_sp",
			vendor_available: true,
			vndk: {
				enabled: true,
				support_system_process: true,
			},
			nocrt: true,
		}
		cc_library {
			name: "libva",
			vendor_available: true,
			nocrt: true,
		}
		cc_library {
			name: "libproduct_va",
			product_specific: true,
			vendor_available: true,
			nocrt: true,
		}
		cc_library {
			name: "libprod",
			product_specific: true,
			shared_libs: [
				"libllndk",
				"libvndk",
				"libvndk_sp",
				"libva",
				"libproduct_va",
			],
			nocrt: true,
		}
		cc_library {
			name: "libvendor",
			vendor: true,
			shared_libs: [
				"libllndk",
				"libvndk",
				"libvndk_sp",
				"libva",
				"libproduct_va",
			],
			nocrt: true,
		}
	`

	config := TestConfig(buildDir, android.Android, nil, bp, nil)
	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")

	ctx := testCcWithConfig(t, config)

	checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
	checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
}

func TestEnforceProductVndkVersionErrors(t *testing.T) {
	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
		cc_library {
			name: "libprod",
			product_specific: true,
			shared_libs: [
				"libvendor",
			],
			nocrt: true,
		}
		cc_library {
			name: "libvendor",
			vendor: true,
			nocrt: true,
		}
	`)
	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
		cc_library {
			name: "libprod",
			product_specific: true,
			shared_libs: [
				"libsystem",
			],
			nocrt: true,
		}
		cc_library {
			name: "libsystem",
			nocrt: true,
		}
	`)
	testCcErrorProductVndk(t, "Vendor module that is not VNDK should not link to \".*\" which is marked as `vendor_available: false`", `
		cc_library {
			name: "libprod",
			product_specific: true,
			shared_libs: [
				"libvndk_private",
			],
			nocrt: true,
		}
		cc_library {
			name: "libvndk_private",
			vendor_available: false,
			vndk: {
				enabled: true,
			},
			nocrt: true,
		}
	`)
	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
		cc_library {
			name: "libprod",
			product_specific: true,
			shared_libs: [
				"libsystem_ext",
			],
			nocrt: true,
		}
		cc_library {
			name: "libsystem_ext",
			system_ext_specific: true,
			nocrt: true,
		}
	`)
	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:", `
		cc_library {
			name: "libsystem",
			shared_libs: [
				"libproduct_va",
			],
			nocrt: true,
		}
		cc_library {
			name: "libproduct_va",
			product_specific: true,
			vendor_available: true,
			nocrt: true,
		}
	`)
}

func TestMakeLinkType(t *testing.T) {
	bp := `
		cc_library {
Loading