Define odm_available property to install a vendor variant to odm

'vendor_available: true' creates a vendor variant from a system
module. The vendor variant of the module is installed to /vendor.
However, we may want to install the vendor variant to /odm, instead.

'device_specific: true' does not work for this purpose because
'vendor_available: true' is allowed only for the system or product
modules to create a vendor variant. But 'device_specific: true'
itself creates a vendor variant that may not work with
'vendor_available: true'.

To install the vendor variant to /odm, we define a new property
'odm_available'. 'odm_available' is exactly the same as the
'vendor_available' except the install path of the vendor variant.
By defining 'odm_available: true', the vendor variant of the module
will be installed to /odm or /vendor/odm instead of /vendor.

Bug: 176147321
Bug: 176079978
Test: check if a module with 'odm_available: true' is installed to
      /vendor/odm
Change-Id: I2d16bd2c515796597b2fbd1eb66f7c2736434697
diff --git a/cc/cc.go b/cc/cc.go
index 8755efe..afa6bf9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -390,6 +390,17 @@
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
 
+	// This is the same as the "vendor_available" except that the install path
+	// of the vendor variant is /odm or /vendor/odm.
+	// By replacing "vendor_available: true" with "odm_available: true", the
+	// module will install its vendor variant to the /odm partition or /vendor/odm.
+	// As the modules with "odm_available: true" still create the vendor variants,
+	// they can link to the other vendor modules as the vendor_available modules do.
+	// Also, the vendor modules can link to odm_available modules.
+	//
+	// It may not be used for VNDK modules.
+	Odm_available *bool
+
 	// whether this module should be allowed to be directly depended by other
 	// modules with `product_specific: true` or `product_available: true`.
 	// If set to true, an additional product variant will be built separately
diff --git a/cc/genrule.go b/cc/genrule.go
index 1ce2169..ca4fda7 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -25,6 +25,7 @@
 
 type GenruleExtraProperties struct {
 	Vendor_available         *bool
+	Odm_available            *bool
 	Product_available        *bool
 	Ramdisk_available        *bool
 	Vendor_ramdisk_available *bool
@@ -63,7 +64,7 @@
 		return false
 	}
 
-	return Bool(g.Vendor_available) || Bool(g.Product_available) || !(ctx.SocSpecific() || ctx.DeviceSpecific())
+	return !(ctx.SocSpecific() || ctx.DeviceSpecific())
 }
 
 func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -92,7 +93,7 @@
 	}
 
 	var variants []string
-	if Bool(g.Vendor_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
+	if Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
 		vndkVersion := ctx.DeviceConfig().VndkVersion()
 		// If vndkVersion is current, we can always use PlatformVndkVersion.
 		// If not, we assume modules under proprietary paths are compatible for
diff --git a/cc/image.go b/cc/image.go
index f89194f..231da7e 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -56,8 +56,14 @@
 
 func (ctx *moduleContext) SocSpecific() bool {
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
-	// module. As well as SoC specific modules, vendor variants must be installed to /vendor.
-	return ctx.ModuleContext.SocSpecific() || ctx.mod.InVendor()
+	// module. As well as SoC specific modules, vendor variants must be installed to /vendor
+	// unless they have "odm_available: true".
+	return ctx.ModuleContext.SocSpecific() || (ctx.mod.InVendor() && !ctx.mod.VendorVariantToOdm())
+}
+
+func (ctx *moduleContext) DeviceSpecific() bool {
+	// Some vendor variants want to be installed to /odm by setting "odm_available: true".
+	return ctx.ModuleContext.DeviceSpecific() || (ctx.mod.InVendor() && ctx.mod.VendorVariantToOdm())
 }
 
 func (ctx *moduleContextImpl) inProduct() bool {
@@ -82,7 +88,13 @@
 
 // Returns true when this module is configured to have core and vendor variants.
 func (c *Module) HasVendorVariant() bool {
-	return Bool(c.VendorProperties.Vendor_available)
+	return Bool(c.VendorProperties.Vendor_available) || Bool(c.VendorProperties.Odm_available)
+}
+
+// Returns true when this module creates a vendor variant and wants to install the vendor variant
+// to the odm partition.
+func (c *Module) VendorVariantToOdm() bool {
+	return Bool(c.VendorProperties.Odm_available)
 }
 
 // Returns true when this module is configured to have core and product variants.
@@ -183,7 +195,18 @@
 	if Bool(m.VendorProperties.Vendor_available) {
 		if vendorSpecific {
 			mctx.PropertyErrorf("vendor_available",
-				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
+				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
+		}
+		if Bool(m.VendorProperties.Odm_available) {
+			mctx.PropertyErrorf("vendor_available",
+				"doesn't make sense at the same time as `odm_available: true`")
+		}
+	}
+
+	if Bool(m.VendorProperties.Odm_available) {
+		if vendorSpecific {
+			mctx.PropertyErrorf("odm_available",
+				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
 		}
 	}
 
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 3f2cf49..1402991 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -130,6 +130,10 @@
 		pbm.AddProperty("vendor_available", true)
 	}
 
+	if proptools.Bool(ccModule.VendorProperties.Odm_available) {
+		pbm.AddProperty("odm_available", true)
+	}
+
 	if proptools.Bool(ccModule.VendorProperties.Product_available) {
 		pbm.AddProperty("product_available", true)
 	}