'vendor_available: *' will not create product variant

With this patch, `vendor_available: true` will no longer creates
product variant. Instead, modules need to set `product_available:
true` if they have to be available to product vanriant.
If both properties are defined for VNDKs, they must have the same
values.

Bug: 150902910
Test: m nothing
Change-Id: I28fb6886e6114583227a31151136627c8516ac9c
diff --git a/cc/cc.go b/cc/cc.go
index a023f3f..26250a7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -360,7 +360,11 @@
 	//
 	// If set to false, this module becomes inaccessible from /vendor modules.
 	//
-	// Default value is true when vndk: {enabled: true} or vendor: true.
+	// The modules with vndk: {enabled: true} must define 'vendor_available'
+	// to either 'true' or 'false'. In this case, 'vendor_available: false' has
+	// a different meaning than that of non-VNDK modules.
+	// 'vendor_available: false' for a VNDK module means 'VNDK-private' that
+	// can only be depended on by VNDK libraries, not by non-VNDK vendor modules.
 	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
@@ -376,7 +380,19 @@
 	// make assumptions about the system that may not be true in the
 	// future.
 	//
-	// It must be set to true by default for vndk: {enabled: true} modules.
+	// If set to false, this module becomes inaccessible from /product modules.
+	//
+	// Different from the 'vendor_available' property, the modules with
+	// vndk: {enabled: true} don't have to define 'product_available'. The VNDK
+	// library without 'product_available' may not be depended on by any other
+	// modules that has product variants including the product available VNDKs.
+	// However, for the modules with vndk: {enabled: true},
+	// 'product_available: false' creates the product variant that is available
+	// only for the other product available VNDK modules but not by non-VNDK
+	// product modules.
+	// In the case of the modules with vndk: {enabled: true}, if
+	// 'product_available' is defined, it must have the same value with the
+	// 'vendor_available'.
 	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	// and PRODUCT_PRODUCT_VNDK_VERSION isn't set.
diff --git a/cc/cc_test.go b/cc/cc_test.go
index fe9db37..071e813 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -326,7 +326,6 @@
 		cc_library {
 			name: "libvndk",
 			vendor_available: true,
-			product_available: true,
 			vndk: {
 				enabled: true,
 			},
@@ -336,7 +335,6 @@
 		cc_library {
 			name: "libvndk_private",
 			vendor_available: false,
-			product_available: false,
 			vndk: {
 				enabled: true,
 			},
@@ -345,11 +343,28 @@
 		}
 
 		cc_library {
-			name: "libvndk_sp",
+			name: "libvndk_product",
 			vendor_available: true,
 			product_available: true,
 			vndk: {
 				enabled: true,
+			},
+			nocrt: true,
+			target: {
+				vendor: {
+					cflags: ["-DTEST"],
+				},
+				product: {
+					cflags: ["-DTEST"],
+				},
+			},
+		}
+
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
 				support_system_process: true,
 			},
 			nocrt: true,
@@ -359,7 +374,6 @@
 		cc_library {
 			name: "libvndk_sp_private",
 			vendor_available: false,
-			product_available: false,
 			vndk: {
 				enabled: true,
 				support_system_process: true,
@@ -371,6 +385,26 @@
 				},
 			},
 		}
+
+		cc_library {
+			name: "libvndk_sp_product_private",
+			vendor_available: false,
+			product_available: false,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+			target: {
+				vendor: {
+					suffix: "-x",
+				},
+				product: {
+					suffix: "-x",
+				},
+			},
+		}
+
 		vndk_libraries_txt {
 			name: "llndk.libraries.txt",
 		}
@@ -399,13 +433,13 @@
 	// They are installed as part of VNDK APEX instead.
 	checkVndkModule(t, ctx, "libvndk", "", false, "", vendorVariant)
 	checkVndkModule(t, ctx, "libvndk_private", "", false, "", vendorVariant)
+	checkVndkModule(t, ctx, "libvndk_product", "", false, "", vendorVariant)
 	checkVndkModule(t, ctx, "libvndk_sp", "", true, "", vendorVariant)
 	checkVndkModule(t, ctx, "libvndk_sp_private", "", true, "", vendorVariant)
+	checkVndkModule(t, ctx, "libvndk_sp_product_private", "", true, "", vendorVariant)
 
-	checkVndkModule(t, ctx, "libvndk", "", false, "", productVariant)
-	checkVndkModule(t, ctx, "libvndk_private", "", false, "", productVariant)
-	checkVndkModule(t, ctx, "libvndk_sp", "", true, "", productVariant)
-	checkVndkModule(t, ctx, "libvndk_sp_private", "", true, "", productVariant)
+	checkVndkModule(t, ctx, "libvndk_product", "", false, "", productVariant)
+	checkVndkModule(t, ctx, "libvndk_sp_product_private", "", true, "", productVariant)
 
 	// Check VNDK snapshot output.
 
@@ -429,6 +463,8 @@
 
 	checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLibPath, variant)
 	checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
+	checkSnapshot(t, ctx, snapshotSingleton, "libvndk_product", "libvndk_product.so", vndkCoreLibPath, variant)
+	checkSnapshot(t, ctx, snapshotSingleton, "libvndk_product", "libvndk_product.so", vndkCoreLib2ndPath, variant2nd)
 	checkSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
 	checkSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
 
@@ -446,16 +482,19 @@
 		"VNDK-SP: libc++.so",
 		"VNDK-SP: libvndk_sp-x.so",
 		"VNDK-SP: libvndk_sp_private-x.so",
+		"VNDK-SP: libvndk_sp_product_private-x.so",
 		"VNDK-core: libvndk-private.so",
 		"VNDK-core: libvndk.so",
+		"VNDK-core: libvndk_product.so",
 		"VNDK-private: libft2.so",
 		"VNDK-private: libvndk-private.so",
 		"VNDK-private: libvndk_sp_private-x.so",
+		"VNDK-private: libvndk_sp_product_private-x.so",
 	})
 	checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libm.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so", "libvndk_product.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
 	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil)
 }
 
@@ -683,7 +722,28 @@
 
 func TestVndkModuleError(t *testing.T) {
 	// Check the error message for vendor_available and product_available properties.
-	testCcError(t, "product_available: may not have different value than `vendor_available`", `
+	testCcErrorProductVndk(t, "vndk: vendor_available must be set to either true or false when `vndk: {enabled: true}`", `
+		cc_library {
+			name: "libvndk",
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+	`)
+
+	testCcErrorProductVndk(t, "vndk: vendor_available must be set to either true or false when `vndk: {enabled: true}`", `
+		cc_library {
+			name: "libvndk",
+			product_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+	`)
+
+	testCcErrorProductVndk(t, "product_available: may not have different value than `vendor_available` for a VNDK", `
 		cc_library {
 			name: "libvndk",
 			vendor_available: true,
@@ -694,6 +754,23 @@
 			nocrt: true,
 		}
 	`)
+
+	testCcErrorProductVndk(t, "product properties must have the same values with the vendor properties for VNDK modules", `
+		cc_library {
+			name: "libvndkprop",
+			vendor_available: true,
+			product_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+			target: {
+				vendor: {
+					cflags: ["-DTEST",],
+				},
+			},
+		}
+	`)
 }
 
 func TestVndkDepError(t *testing.T) {
@@ -2208,7 +2285,7 @@
 		}
 	`)
 
-	testCcErrorProductVndk(t, "`extends` refers module \".*\" which does not have `vendor_available: true`", `
+	testCcErrorProductVndk(t, "`extends` refers module \".*\" which does not have `product_available: true`", `
 		cc_library {
 			name: "libvndk",
 			vendor_available: false,
@@ -2562,7 +2639,6 @@
 		cc_library {
 			name: "libvndk2",
 			vendor_available: true,
-			product_available: true,
 			vndk: {
 				enabled: true,
 			},
@@ -2635,7 +2711,6 @@
 		cc_library {
 			name: "libvndk_sp2",
 			vendor_available: true,
-			product_available: true,
 			vndk: {
 				enabled: true,
 			},
@@ -2689,6 +2764,20 @@
 			nocrt: true,
 		}
 		cc_library {
+			name: "libboth_available",
+			vendor_available: true,
+			product_available: true,
+			nocrt: true,
+			target: {
+				vendor: {
+					suffix: "-vendor",
+				},
+				product: {
+					suffix: "-product",
+				},
+			}
+		}
+		cc_library {
 			name: "libproduct_va",
 			product_specific: true,
 			vendor_available: true,
@@ -2702,6 +2791,7 @@
 				"libvndk",
 				"libvndk_sp",
 				"libpa",
+				"libboth_available",
 				"libproduct_va",
 			],
 			nocrt: true,
@@ -2714,6 +2804,7 @@
 				"libvndk",
 				"libvndk_sp",
 				"libva",
+				"libboth_available",
 				"libproduct_va",
 			],
 			nocrt: true,
@@ -2729,6 +2820,12 @@
 
 	checkVndkModule(t, ctx, "libvndk", "", false, "", productVariant)
 	checkVndkModule(t, ctx, "libvndk_sp", "", true, "", productVariant)
+
+	mod_vendor := ctx.ModuleForTests("libboth_available", vendorVariant).Module().(*Module)
+	assertString(t, mod_vendor.outputFile.Path().Base(), "libboth_available-vendor.so")
+
+	mod_product := ctx.ModuleForTests("libboth_available", productVariant).Module().(*Module)
+	assertString(t, mod_product.outputFile.Path().Base(), "libboth_available-product.so")
 }
 
 func TestEnforceProductVndkVersionErrors(t *testing.T) {
@@ -2761,7 +2858,22 @@
 			nocrt: true,
 		}
 	`)
-	testCcErrorProductVndk(t, "Vendor module that is not VNDK should not link to \".*\" which is marked as `vendor_available: false`", `
+	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+		cc_library {
+			name: "libprod",
+			product_specific: true,
+			shared_libs: [
+				"libva",
+			],
+			nocrt: true,
+		}
+		cc_library {
+			name: "libva",
+			vendor_available: true,
+			nocrt: true,
+		}
+	`)
+	testCcErrorProductVndk(t, "product module that is not VNDK should not link to \".*\" which is marked as `product_available: false`", `
 		cc_library {
 			name: "libprod",
 			product_specific: true,
diff --git a/cc/compiler.go b/cc/compiler.go
index b78bb6c..2c05899 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -479,8 +479,7 @@
 	}
 
 	if ctx.inProduct() {
-		// TODO(b/150902910): must use 'compiler.Properties.Target.Product.Cflags'
-		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor.Cflags)...)
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Product.Cflags)...)
 	}
 
 	if ctx.inRecovery() {
diff --git a/cc/genrule.go b/cc/genrule.go
index 3668e2b..9648869 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -101,8 +101,7 @@
 		return variants
 	}
 
-	// TODO(b/150902910): vendor_available will not create product variant. Remove Bool(g.Vendor_available)
-	if Bool(g.Vendor_available) || Bool(g.Product_available) || ctx.ProductSpecific() {
+	if Bool(g.Product_available) || ctx.ProductSpecific() {
 		variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
 		if vndkVersion := ctx.DeviceConfig().ProductVndkVersion(); vndkVersion != "current" {
 			variants = append(variants, ProductVariationPrefix+vndkVersion)
diff --git a/cc/image.go b/cc/image.go
index 380c1db..b55e1f4 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -17,6 +17,8 @@
 // functions to determine where a module is installed, etc.
 
 import (
+	"fmt"
+	"reflect"
 	"strings"
 
 	"android/soong/android"
@@ -97,17 +99,23 @@
 
 // Returns true when this module is configured to have core and vendor variants.
 func (c *Module) HasVendorVariant() bool {
+	// In case of a VNDK, 'vendor_available: false' still creates a vendor variant.
 	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 {
+	if c.VendorProperties.Product_available == nil {
+		// Without 'product_available', product variant will not be created even for VNDKs.
+		return false
+	}
+	// However, 'product_available: false' in a VNDK still creates a product variant.
 	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)
+	return c.HasVendorVariant() || c.HasProductVariant()
 }
 
 // Returns true if the module is "product" variant. Usually these modules are installed in /product
@@ -144,6 +152,52 @@
 	return c.ModuleBase.InstallInRecovery()
 }
 
+func visitPropsAndCompareVendorAndProductProps(v reflect.Value) bool {
+	if v.Kind() != reflect.Struct {
+		return true
+	}
+	for i := 0; i < v.NumField(); i++ {
+		prop := v.Field(i)
+		if prop.Kind() == reflect.Struct && v.Type().Field(i).Name == "Target" {
+			vendor_prop := prop.FieldByName("Vendor")
+			product_prop := prop.FieldByName("Product")
+			if vendor_prop.Kind() != reflect.Struct && product_prop.Kind() != reflect.Struct {
+				// Neither Target.Vendor nor Target.Product is defined
+				continue
+			}
+			if vendor_prop.Kind() != reflect.Struct || product_prop.Kind() != reflect.Struct ||
+				!reflect.DeepEqual(vendor_prop.Interface(), product_prop.Interface()) {
+				// If only one of either Target.Vendor or Target.Product is
+				// defined or they have different values, it fails the build
+				// since VNDK must have the same properties for both vendor
+				// and product variants.
+				return false
+			}
+		} else if !visitPropsAndCompareVendorAndProductProps(prop) {
+			// Visit the substructures to find Target.Vendor and Target.Product
+			return false
+		}
+	}
+	return true
+}
+
+// In the case of VNDK, vendor and product variants must have the same properties.
+// VNDK installs only one file and shares it for both vendor and product modules on
+// runtime. We may not define different versions of a VNDK lib for each partition.
+// This function is used only for the VNDK modules that is available to both vendor
+// and product partitions.
+func (c *Module) compareVendorAndProductProps() bool {
+	if !c.IsVndk() && c.VendorProperties.Product_available != nil {
+		panic(fmt.Errorf("This is only for product available VNDK libs. %q is not a VNDK library or not product available", c.Name()))
+	}
+	for _, properties := range c.GetProperties() {
+		if !visitPropsAndCompareVendorAndProductProps(reflect.ValueOf(properties).Elem()) {
+			return false
+		}
+	}
+	return true
+}
+
 func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
 	// Validation check
 	vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
@@ -154,14 +208,6 @@
 			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 {
@@ -198,6 +244,18 @@
 					mctx.PropertyErrorf("vndk",
 						"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
 				}
+				if m.VendorProperties.Product_available != nil {
+					// If product_available is defined for a VNDK, make sure vendor_available and
+					// product_available has the same value since `false` for these properties
+					// means the module is VNDK-private.
+					if Bool(m.VendorProperties.Vendor_available) != Bool(m.VendorProperties.Product_available) {
+						mctx.PropertyErrorf("product_available", "may not have different value than `vendor_available` for a VNDK")
+					}
+					// Also, both variants must have the same properties since they share a single VNDK library on runtime.
+					if !m.compareVendorAndProductProps() {
+						mctx.ModuleErrorf("product properties must have the same values with the vendor properties for VNDK modules")
+					}
+				}
 			}
 		} else {
 			if vndkdep.isVndkSp() {
@@ -281,13 +339,13 @@
 			}
 		}
 
-		// 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)
+		// product_available modules are available to /product.
+		if m.HasProductVariant() {
+			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
@@ -471,7 +529,6 @@
 	} 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)
+		squashProductSrcs(m)
 	}
 }
diff --git a/cc/library.go b/cc/library.go
index f4400a9..9bd2884 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -275,12 +275,13 @@
 // any module that links against this module. This is obtained from
 // the export_include_dirs property in the appropriate target stanza.
 func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
-	// TODO(b/150902910): product variant must use Target.Product
-	if ctx.useVndk() && f.Properties.Target.Vendor.Override_export_include_dirs != nil {
+	if ctx.inVendor() && f.Properties.Target.Vendor.Override_export_include_dirs != nil {
 		return android.PathsForModuleSrc(ctx, f.Properties.Target.Vendor.Override_export_include_dirs)
-	} else {
-		return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs)
 	}
+	if ctx.inProduct() && f.Properties.Target.Product.Override_export_include_dirs != nil {
+		return android.PathsForModuleSrc(ctx, f.Properties.Target.Product.Override_export_include_dirs)
+	}
+	return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs)
 }
 
 // exportIncludes registers the include directories and system include directories to be exported
@@ -726,7 +727,7 @@
 var _ libraryInterface = (*libraryDecorator)(nil)
 var _ versionedInterface = (*libraryDecorator)(nil)
 
-func (library *libraryDecorator) getLibNameHelper(baseModuleName string, useVndk bool) string {
+func (library *libraryDecorator) getLibNameHelper(baseModuleName string, inVendor bool, inProduct bool) string {
 	name := library.libName
 	if name == "" {
 		name = String(library.Properties.Stem)
@@ -736,9 +737,10 @@
 	}
 
 	suffix := ""
-	if useVndk {
-		// TODO(b/150902910): product variant must use Target.Product
+	if inVendor {
 		suffix = String(library.Properties.Target.Vendor.Suffix)
+	} else if inProduct {
+		suffix = String(library.Properties.Target.Product.Suffix)
 	}
 	if suffix == "" {
 		suffix = String(library.Properties.Suffix)
@@ -750,7 +752,7 @@
 // getLibName returns the actual canonical name of the library (the name which
 // should be passed to the linker via linker flags).
 func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
-	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.useVndk())
+	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.inVendor(), ctx.inProduct())
 
 	if ctx.IsVndkExt() {
 		// vndk-ext lib should have the same name with original lib
@@ -851,14 +853,20 @@
 		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.SharedProperties.Shared.Export_shared_lib_headers...)
 		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.SharedProperties.Shared.Export_static_lib_headers...)
 	}
-	// TODO(b/150902910): product variant must use Target.Product
-	if ctx.useVndk() {
+	if ctx.inVendor() {
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
 		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
 	}
+	if ctx.inProduct() {
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Product.Exclude_static_libs)
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Product.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Product.Exclude_static_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Product.Exclude_shared_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Product.Exclude_static_libs)
+	}
 	if ctx.inRecovery() {
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Recovery.Exclude_shared_libs)
diff --git a/cc/linker.go b/cc/linker.go
index 815cdab..ff07224 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -263,8 +263,7 @@
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion")
 	}
 
-	// TODO(b/150902910): product variant must use Target.Product
-	if ctx.useVndk() {
+	if ctx.inVendor() {
 		deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Vendor.Shared_libs...)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor.Exclude_shared_libs)
@@ -276,6 +275,18 @@
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs)
 	}
 
+	if ctx.inProduct() {
+		deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Product.Shared_libs...)
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Product.Exclude_shared_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Product.Exclude_shared_libs)
+		deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Product.Static_libs...)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Product.Exclude_static_libs)
+		deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Product.Exclude_header_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Product.Exclude_static_libs)
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Product.Exclude_static_libs)
+		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Product.Exclude_runtime_libs)
+	}
+
 	if ctx.inRecovery() {
 		deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Recovery.Shared_libs...)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Recovery.Exclude_shared_libs)
@@ -500,11 +511,14 @@
 		versionScript := ctx.ExpandOptionalSource(
 			linker.Properties.Version_script, "version_script")
 
-		// TODO(b/150902910): product variant must use Target.Product
-		if ctx.useVndk() && linker.Properties.Target.Vendor.Version_script != nil {
+		if ctx.inVendor() && linker.Properties.Target.Vendor.Version_script != nil {
 			versionScript = ctx.ExpandOptionalSource(
 				linker.Properties.Target.Vendor.Version_script,
 				"target.vendor.version_script")
+		} else if ctx.inProduct() && linker.Properties.Target.Product.Version_script != nil {
+			versionScript = ctx.ExpandOptionalSource(
+				linker.Properties.Target.Product.Version_script,
+				"target.product.version_script")
 		}
 
 		if versionScript.Valid() {
diff --git a/cc/vndk.go b/cc/vndk.go
index bfa6b59..1708841 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -140,18 +140,26 @@
 		// or those installed to /product or /system/product can't depend
 		// on modules marked with product_available: false.
 		violation := false
+		variant := "vendor"
 		if lib, ok := to.linker.(*llndkStubDecorator); ok && !Bool(lib.Properties.Vendor_available) {
 			violation = true
-		} else {
-			if _, ok := to.linker.(libraryInterface); ok && to.VendorProperties.Vendor_available != nil && !Bool(to.VendorProperties.Vendor_available) {
-				// Vendor_available == nil && !Bool(Vendor_available) should be okay since
-				// it means a vendor-only, or product-only library which is a valid dependency
-				// for non-VNDK modules.
+			if to.InProduct() {
+				variant = "product"
+			}
+		} else if _, ok := to.linker.(libraryInterface); ok {
+			if to.inVendor() && to.VendorProperties.Vendor_available != nil && !Bool(to.VendorProperties.Vendor_available) {
+				// A vendor module with Vendor_available == nil should be okay since it means a
+				// vendor-only library which is a valid dependency for non-VNDK vendor modules.
 				violation = true
+			} else if to.InProduct() && to.VendorProperties.Product_available != nil && !Bool(to.VendorProperties.Product_available) {
+				// A product module with Product_available == nil should be okay since it means a
+				// product-only library which is a valid dependency for non-VNDK product modules.
+				violation = true
+				variant = "product"
 			}
 		}
 		if violation {
-			ctx.ModuleErrorf("Vendor module that is not VNDK should not link to %q which is marked as `vendor_available: false`", to.Name())
+			ctx.ModuleErrorf("%s module that is not VNDK should not link to %q which is marked as `%s_available: false`", variant, to.Name(), variant)
 		}
 	}
 	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
@@ -183,13 +191,18 @@
 				to.Name())
 			return
 		}
-		// TODO(b/150902910): vndk-ext for product must check product_available.
-		if !Bool(to.VendorProperties.Vendor_available) {
+		if to.inVendor() && !Bool(to.VendorProperties.Vendor_available) {
 			ctx.ModuleErrorf(
 				"`extends` refers module %q which does not have `vendor_available: true`",
 				to.Name())
 			return
 		}
+		if to.InProduct() && !Bool(to.VendorProperties.Product_available) {
+			ctx.ModuleErrorf(
+				"`extends` refers module %q which does not have `product_available: true`",
+				to.Name())
+			return
+		}
 	}
 	if to.vndkdep == nil {
 		return
@@ -324,6 +337,12 @@
 	vndkLibrariesLock.Lock()
 	defer vndkLibrariesLock.Unlock()
 
+	if m.InProduct() {
+		// We may skip the other steps for the product variants because they
+		// are already covered by the vendor variants.
+		return
+	}
+
 	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
 		m.Properties.MustUseVendorVariant = true
 	}
@@ -796,10 +815,10 @@
 
 func getVndkFileName(m *Module) (string, error) {
 	if library, ok := m.linker.(*libraryDecorator); ok {
-		return library.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
+		return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
 	}
 	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
-		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
+		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
 	}
 	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
 }