Merge "bp2build: fix BUILD file generation incrementality bug."
diff --git a/android/apex.go b/android/apex.go
index b87ff09..6bb0751 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -749,74 +749,69 @@
 	}
 	return list
 }(map[string]int{
-	"adbd":                  30,
-	"android.net.ipsec.ike": 30,
-	"androidx-constraintlayout_constraintlayout-solver": 30,
-	"androidx.annotation_annotation":                    28,
-	"androidx.arch.core_core-common":                    28,
-	"androidx.collection_collection":                    28,
-	"androidx.lifecycle_lifecycle-common":               28,
-	"apache-commons-compress":                           29,
-	"bouncycastle_ike_digests":                          30,
-	"brotli-java":                                       29,
-	"captiveportal-lib":                                 28,
-	"flatbuffer_headers":                                30,
-	"framework-permission":                              30,
-	"framework-statsd":                                  30,
-	"gemmlowp_headers":                                  30,
-	"ike-internals":                                     30,
-	"kotlinx-coroutines-android":                        28,
-	"kotlinx-coroutines-core":                           28,
-	"libadb_crypto":                                     30,
-	"libadb_pairing_auth":                               30,
-	"libadb_pairing_connection":                         30,
-	"libadb_pairing_server":                             30,
-	"libadb_protos":                                     30,
-	"libadb_tls_connection":                             30,
-	"libadbconnection_client":                           30,
-	"libadbconnection_server":                           30,
-	"libadbd_core":                                      30,
-	"libadbd_services":                                  30,
-	"libadbd":                                           30,
-	"libapp_processes_protos_lite":                      30,
-	"libasyncio":                                        30,
-	"libbrotli":                                         30,
-	"libbuildversion":                                   30,
-	"libcrypto_static":                                  30,
-	"libcrypto_utils":                                   30,
-	"libdiagnose_usb":                                   30,
-	"libeigen":                                          30,
-	"liblz4":                                            30,
-	"libmdnssd":                                         30,
-	"libneuralnetworks_common":                          30,
-	"libneuralnetworks_headers":                         30,
-	"libneuralnetworks":                                 30,
-	"libprocpartition":                                  30,
-	"libprotobuf-java-lite":                             30,
-	"libprotoutil":                                      30,
-	"libqemu_pipe":                                      30,
-	"libstats_jni":                                      30,
-	"libstatslog_statsd":                                30,
-	"libstatsmetadata":                                  30,
-	"libstatspull":                                      30,
-	"libstatssocket":                                    30,
-	"libsync":                                           30,
-	"libtextclassifier_hash_headers":                    30,
-	"libtextclassifier_hash_static":                     30,
-	"libtflite_kernel_utils":                            30,
-	"libwatchdog":                                       29,
-	"libzstd":                                           30,
-	"metrics-constants-protos":                          28,
-	"net-utils-framework-common":                        29,
-	"permissioncontroller-statsd":                       28,
-	"philox_random_headers":                             30,
-	"philox_random":                                     30,
-	"service-permission":                                30,
-	"service-statsd":                                    30,
-	"statsd-aidl-ndk_platform":                          30,
-	"statsd":                                            30,
-	"tensorflow_headers":                                30,
-	"xz-java":                                           29,
+	"adbd":                           30,
+	"android.net.ipsec.ike":          30,
+	"apache-commons-compress":        29,
+	"bouncycastle_ike_digests":       30,
+	"brotli-java":                    29,
+	"captiveportal-lib":              28,
+	"flatbuffer_headers":             30,
+	"framework-permission":           30,
+	"framework-statsd":               30,
+	"gemmlowp_headers":               30,
+	"ike-internals":                  30,
+	"kotlinx-coroutines-android":     28,
+	"kotlinx-coroutines-core":        28,
+	"libadb_crypto":                  30,
+	"libadb_pairing_auth":            30,
+	"libadb_pairing_connection":      30,
+	"libadb_pairing_server":          30,
+	"libadb_protos":                  30,
+	"libadb_tls_connection":          30,
+	"libadbconnection_client":        30,
+	"libadbconnection_server":        30,
+	"libadbd_core":                   30,
+	"libadbd_services":               30,
+	"libadbd":                        30,
+	"libapp_processes_protos_lite":   30,
+	"libasyncio":                     30,
+	"libbrotli":                      30,
+	"libbuildversion":                30,
+	"libcrypto_static":               30,
+	"libcrypto_utils":                30,
+	"libdiagnose_usb":                30,
+	"libeigen":                       30,
+	"liblz4":                         30,
+	"libmdnssd":                      30,
+	"libneuralnetworks_common":       30,
+	"libneuralnetworks_headers":      30,
+	"libneuralnetworks":              30,
+	"libprocpartition":               30,
+	"libprotobuf-java-lite":          30,
+	"libprotoutil":                   30,
+	"libqemu_pipe":                   30,
+	"libstats_jni":                   30,
+	"libstatslog_statsd":             30,
+	"libstatsmetadata":               30,
+	"libstatspull":                   30,
+	"libstatssocket":                 30,
+	"libsync":                        30,
+	"libtextclassifier_hash_headers": 30,
+	"libtextclassifier_hash_static":  30,
+	"libtflite_kernel_utils":         30,
+	"libwatchdog":                    29,
+	"libzstd":                        30,
+	"metrics-constants-protos":       28,
+	"net-utils-framework-common":     29,
+	"permissioncontroller-statsd":    28,
+	"philox_random_headers":          30,
+	"philox_random":                  30,
+	"service-permission":             30,
+	"service-statsd":                 30,
+	"statsd-aidl-ndk_platform":       30,
+	"statsd":                         30,
+	"tensorflow_headers":             30,
+	"xz-java":                        29,
 })
 
 // Function called while walking an APEX's payload dependencies.
diff --git a/android/config.go b/android/config.go
index 8090889..e0f3a91 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1624,21 +1624,33 @@
 func splitConfiguredJarPair(str string) (string, string, error) {
 	pair := strings.SplitN(str, ":", 2)
 	if len(pair) == 2 {
-		return pair[0], pair[1], nil
+		apex := pair[0]
+		jar := pair[1]
+		if apex == "" {
+			return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
+		}
+		return apex, jar, nil
 	} else {
 		return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
 	}
 }
 
-// CreateTestConfiguredJarList is a function to create ConfiguredJarList for
-// tests.
+// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
 func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
-	apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
+	// Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
+	// a json list of strings and then unmarshalling into a ConfiguredJarList instance.
+	b, err := json.Marshal(list)
 	if err != nil {
 		panic(err)
 	}
 
-	return ConfiguredJarList{apexes, jars}
+	var jarList ConfiguredJarList
+	err = json.Unmarshal(b, &jarList)
+	if err != nil {
+		panic(err)
+	}
+
+	return jarList
 }
 
 // EmptyConfiguredJarList returns an empty jar list.
diff --git a/android/config_test.go b/android/config_test.go
index 7bfc800..a11115d 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -100,6 +100,22 @@
 		assertStringEquals(t, "apex1:jarA", list1.String())
 	})
 
+	t.Run("create invalid - missing apex", func(t *testing.T) {
+		defer func() {
+			err := recover().(error)
+			assertStringEquals(t, "malformed (apex, jar) pair: 'jarA', expected format: <apex>:<jar>", err.Error())
+		}()
+		CreateTestConfiguredJarList([]string{"jarA"})
+	})
+
+	t.Run("create invalid - empty apex", func(t *testing.T) {
+		defer func() {
+			err := recover().(error)
+			assertStringEquals(t, "invalid apex '' in <apex>:<jar> pair ':jarA', expected format: <apex>:<jar>", err.Error())
+		}()
+		CreateTestConfiguredJarList([]string{":jarA"})
+	})
+
 	list2 := list1.Append("apex2", "jarB")
 	t.Run("append", func(t *testing.T) {
 		assertStringEquals(t, "apex1:jarA,apex2:jarB", list2.String())
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index fb84df8..5d00e06 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -52,6 +52,7 @@
 android.hidl.safe_union@1.0(minSdkVersion:29)
 android.hidl.token@1.0(minSdkVersion:29)
 android.hidl.token@1.0-utils(minSdkVersion:29)
+android.net.ipsec.ike(minSdkVersion:30)
 android.net.ipsec.ike(minSdkVersion:current)
 android.net.ipsec.ike.xml(minSdkVersion:(no version))
 androidx-constraintlayout_constraintlayout(minSdkVersion:14)
@@ -238,6 +239,7 @@
 libbase(minSdkVersion:29)
 libbase_headers(minSdkVersion:29)
 libbinder_headers(minSdkVersion:29)
+libbinder_headers_platform_shared(minSdkVersion:29)
 libbinderthreadstateutils(minSdkVersion:29)
 libbluetooth-types-header(minSdkVersion:29)
 libbrotli(minSdkVersion:(no version))
diff --git a/cc/cc.go b/cc/cc.go
index d282b6e..431e9e7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1535,6 +1535,11 @@
 	var vndkVersion string
 	var nameSuffix string
 	if c.InProduct() {
+		if c.ProductSpecific() {
+			// If the module is product specific with 'product_specific: true',
+			// do not add a name suffix because it is a base module.
+			return ""
+		}
 		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
 		nameSuffix = productSuffix
 	} else {
@@ -2891,12 +2896,12 @@
 	ccDepModule, _ := ccDep.(*Module)
 	isLLndk := ccDepModule != nil && ccDepModule.IsLlndk()
 	isVendorPublicLib := inList(libName, *vendorPublicLibraries)
-	bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
+	nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
 
-	if c, ok := ccDep.(*Module); ok {
+	if ccDepModule != nil {
 		// Use base module name for snapshots when exporting to Makefile.
-		if snapshotPrebuilt, ok := c.linker.(snapshotInterface); ok {
-			baseName := c.BaseModuleName()
+		if snapshotPrebuilt, ok := ccDepModule.linker.(snapshotInterface); ok {
+			baseName := ccDepModule.BaseModuleName()
 
 			return baseName + snapshotPrebuilt.snapshotAndroidMkSuffix()
 		}
@@ -2907,10 +2912,10 @@
 		// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 		// core module instead.
 		return libName
-	} 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.
-		return libName + c.getNameSuffixWithVndkVersion(ctx)
+	} else if ccDep.UseVndk() && nonSystemVariantsExist && ccDepModule != nil {
+		// The vendor and product modules in Make will have been renamed to not conflict with the
+		// core module, so update the dependency name here accordingly.
+		return libName + ccDepModule.Properties.SubName
 	} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
 		return libName + vendorPublicLibrarySuffix
 	} else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7288cc4..6403547 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2712,6 +2712,14 @@
 		system_shared_libs : [],
 	}
 	cc_library {
+		name: "libproduct_vendor",
+		product_specific: true,
+		vendor_available: true,
+		no_libcrt : true,
+		nocrt : true,
+		system_shared_libs : [],
+	}
+	cc_library {
 		name: "libcore",
 		runtime_libs: ["liball_available"],
 		no_libcrt : true,
@@ -2728,7 +2736,7 @@
 	cc_library {
 		name: "libvendor2",
 		vendor: true,
-		runtime_libs: ["liball_available", "libvendor1"],
+		runtime_libs: ["liball_available", "libvendor1", "libproduct_vendor"],
 		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
@@ -2751,7 +2759,7 @@
 	cc_library {
 		name: "libproduct2",
 		product_specific: true,
-		runtime_libs: ["liball_available", "libproduct1"],
+		runtime_libs: ["liball_available", "libproduct1", "libproduct_vendor"],
 		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
@@ -2781,7 +2789,7 @@
 	checkRuntimeLibs(t, []string{"liball_available.vendor"}, module)
 
 	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available.vendor", "libvendor1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available.vendor", "libvendor1", "libproduct_vendor.vendor"}, module)
 
 	// runtime_libs for product variants have '.product' suffixes if the modules have both core
 	// and product variants.
@@ -2791,7 +2799,7 @@
 	checkRuntimeLibs(t, []string{"liball_available.product"}, module)
 
 	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available.product", "libproduct1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available.product", "libproduct1", "libproduct_vendor"}, module)
 }
 
 func TestExcludeRuntimeLibs(t *testing.T) {
@@ -2817,10 +2825,10 @@
 	checkRuntimeLibs(t, []string{"liball_available"}, module)
 
 	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libvendor1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available", "libvendor1", "libproduct_vendor"}, module)
 
 	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libproduct1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available", "libproduct1", "libproduct_vendor"}, module)
 }
 
 func checkStaticLibs(t *testing.T, expected []string, module *Module) {
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 35dd10f..71c7626 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -142,6 +142,9 @@
 		// Nested and array designated initialization is nice to have.
 		"-Wno-c99-designator",
 
+		// Warnings from clang-12
+		"-Wno-gnu-folding-constant",
+
 		// Calls to the APIs that are newer than the min sdk version of the caller should be
 		// guarded with __builtin_available.
 		"-Wunguarded-availability",
diff --git a/cc/linkable.go b/cc/linkable.go
index ab5a552..58919a0 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -106,6 +106,8 @@
 	IsVndkExt() bool
 	IsVndkPrivate() bool
 	HasVendorVariant() bool
+	HasProductVariant() bool
+	HasNonSystemVariants() bool
 	InProduct() bool
 
 	SdkVersion() string
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 5092ad0..c06fd4f 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -51,6 +51,9 @@
 	// Type of the filesystem. Currently, ext4 and compressed_cpio are supported. Default is
 	// ext4.
 	Type *string
+
+	// file_contexts file to make image. Currently, only ext4 is supported.
+	File_contexts *string `android:"path"`
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -142,6 +145,16 @@
 	return output
 }
 
+func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
+	builder := android.NewRuleBuilder(pctx, ctx)
+	fcBin := android.PathForModuleOut(ctx, "file_contexts.bin")
+	builder.Command().BuiltTool("sefcontext_compile").
+		FlagWithOutput("-o ", fcBin).
+		Input(android.PathForModuleSrc(ctx, proptools.String(f.properties.File_contexts)))
+	builder.Build("build_filesystem_file_contexts", fmt.Sprintf("Creating filesystem file contexts for %s", f.BaseModuleName()))
+	return fcBin.OutputPath
+}
+
 func (f *filesystem) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
 	type prop struct {
 		name  string
@@ -188,6 +201,10 @@
 		addStr("partition_name", f.Name())
 	}
 
+	if proptools.String(f.properties.File_contexts) != "" {
+		addPath("selinux_fc", f.buildFileContexts(ctx))
+	}
+
 	propFile = android.PathForModuleOut(ctx, "prop").OutputPath
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().Text("rm").Flag("-rf").Output(propFile)
@@ -207,6 +224,10 @@
 			"Consider adding this to bootimg module and signing the entire boot image.")
 	}
 
+	if proptools.String(f.properties.File_contexts) != "" {
+		ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.")
+	}
+
 	zipFile := android.PathForModuleOut(ctx, "temp.zip").OutputPath
 	f.CopyDepsToZip(ctx, zipFile)
 
@@ -250,6 +271,16 @@
 	}}
 }
 
+var _ android.OutputFileProducer = (*filesystem)(nil)
+
+// Implements android.OutputFileProducer
+func (f *filesystem) OutputFiles(tag string) (android.Paths, error) {
+	if tag == "" {
+		return []android.Path{f.output}, nil
+	}
+	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+}
+
 // Filesystem is the public interface for the filesystem struct. Currently, it's only for the apex
 // package to have access to the output file.
 type Filesystem interface {
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index da62100..29c73c1 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -129,8 +129,6 @@
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
 
-	buildPath := android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath
-
 	providesUsesLib := ctx.ModuleName()
 	if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
 		name := ulib.ProvidesUsesLib()
@@ -146,7 +144,6 @@
 		slimDexpreoptConfig := &dexpreopt.ModuleConfig{
 			Name:                 ctx.ModuleName(),
 			DexLocation:          dexLocation,
-			BuildPath:            buildPath,
 			EnforceUsesLibraries: d.enforceUsesLibs,
 			ProvidesUsesLibrary:  providesUsesLib,
 			ClassLoaderContexts:  d.classLoaderContexts,
@@ -218,7 +215,7 @@
 	dexpreoptConfig := &dexpreopt.ModuleConfig{
 		Name:            ctx.ModuleName(),
 		DexLocation:     dexLocation,
-		BuildPath:       buildPath,
+		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
 		DexPath:         dexJarFile,
 		ManifestPath:    d.manifestFile,
 		UncompressedDex: d.uncompressedDex,
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 0f9ef58..27f363e 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -65,7 +65,7 @@
 			srcs: ["a.java"],
 			compile_dex: true,
 	}
-	`, []string{":foo"}, nil)
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -82,7 +82,7 @@
 			jars: ["a.jar"],
 			compile_dex: true,
 	}
-	`, []string{":foo"}, nil)
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -106,7 +106,7 @@
 			compile_dex: true,
 			prefer: false,
 	}
-	`, []string{":foo"}, nil)
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -135,7 +135,7 @@
 			compile_dex: true,
 			prefer: true,
 	}
-	`, []string{":foo"}, nil)
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -236,7 +236,7 @@
 			jars: ["a.jar"],
 			compile_dex: true,
 	}
-	`, []string{":foo"}, &prebuiltHiddenApiDir)
+	`, []string{"platform:foo"}, &prebuiltHiddenApiDir)
 
 	expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv"
 	expectedCpOutput := buildDir + "/hiddenapi/hiddenapi-flags.csv"
diff --git a/java/java.go b/java/java.go
index d49b64f..78d974b 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2383,7 +2383,7 @@
 
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test
-	Data []string `android:"path"`
+	Data []string `android:"path,arch_variant"`
 
 	// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go
index 94e04cb..14ac021 100644
--- a/kernel/prebuilt_kernel_modules.go
+++ b/kernel/prebuilt_kernel_modules.go
@@ -72,7 +72,7 @@
 	depmodOut := runDepmod(ctx, modules)
 	strippedModules := stripDebugSymbols(ctx, modules)
 
-	installDir := android.PathForModuleInstall(ctx, "lib", "module")
+	installDir := android.PathForModuleInstall(ctx, "lib", "modules")
 	if pkm.KernelVersion() != "" {
 		installDir = installDir.Join(ctx, pkm.KernelVersion())
 	}
diff --git a/kernel/prebuilt_kernel_modules_test.go b/kernel/prebuilt_kernel_modules_test.go
index b49e167..433548b 100644
--- a/kernel/prebuilt_kernel_modules_test.go
+++ b/kernel/prebuilt_kernel_modules_test.go
@@ -84,12 +84,12 @@
 		})
 
 	expected := []string{
-		"lib/module/5.10/mod1.ko",
-		"lib/module/5.10/mod2.ko",
-		"lib/module/5.10/modules.load",
-		"lib/module/5.10/modules.dep",
-		"lib/module/5.10/modules.softdep",
-		"lib/module/5.10/modules.alias",
+		"lib/modules/5.10/mod1.ko",
+		"lib/modules/5.10/mod2.ko",
+		"lib/modules/5.10/modules.load",
+		"lib/modules/5.10/modules.dep",
+		"lib/modules/5.10/modules.softdep",
+		"lib/modules/5.10/modules.alias",
 	}
 
 	var actual []string
diff --git a/rust/image.go b/rust/image.go
index 5ff10ae..ac8c1b3 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -71,6 +71,15 @@
 	return Bool(mod.VendorProperties.Vendor_available) || Bool(mod.VendorProperties.Odm_available)
 }
 
+// Always returns false because rust modules do not support product variant.
+func (mod *Module) HasProductVariant() bool {
+	return Bool(mod.VendorProperties.Product_available)
+}
+
+func (mod *Module) HasNonSystemVariants() bool {
+	return mod.HasVendorVariant() || mod.HasProductVariant()
+}
+
 func (c *Module) InProduct() bool {
 	return false
 }