Merge "Retry: Adds support for 'ignored-on-host'"
diff --git a/android/sdk.go b/android/sdk.go
index 36afc3d..e823106 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -351,6 +351,15 @@
 	//   values that differ by arch, fields not tagged as such must have common values across
 	//   all variants.
 	//
+	// * Additional field tags can be specified on a field that will ignore certain values
+	//   for the purpose of common value optimization. A value that is ignored must have the
+	//   default value for the property type. This is to ensure that significant value are not
+	//   ignored by accident. The purpose of this is to allow the snapshot generation to reflect
+	//   the behavior of the runtime. e.g. if a property is ignored on the host then a property
+	//   that is common for android can be treated as if it was common for android and host as
+	//   the setting for host is ignored anyway.
+	//   * `sdk:"ignored-on-host" - this indicates the property is ignored on the host variant.
+	//
 	// * The sdk module type populates the BpModule structure, creating the arch specific
 	//   structure and calls AddToPropertySet(...) on the properties struct to add the member
 	//   specific properties in the correct place in the structure.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 898ecea..ae1a492 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -289,9 +289,12 @@
 	}
 
 	extractor := newCommonValueExtractor(common)
-	extractor.extractCommonProperties(common, structs)
 
 	h := TestHelper{t}
+
+	err := extractor.extractCommonProperties(common, structs)
+	h.AssertDeepEquals("unexpected error", nil, err)
+
 	h.AssertDeepEquals("common properties not correct",
 		&testPropertiesStruct{
 			name:        "common",
diff --git a/sdk/update.go b/sdk/update.go
index bcc2c77..991428e 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -1215,11 +1215,26 @@
 // struct (or one of its embedded structs).
 type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
 
+// Checks the metadata to determine whether the property should be ignored for the
+// purposes of common value extraction or not.
+type extractorMetadataPredicate func(metadata propertiesContainer) bool
+
+// Indicates whether optimizable properties are provided by a host variant or
+// not.
+type isHostVariant interface {
+	isHostVariant() bool
+}
+
 // A property that can be optimized by the commonValueExtractor.
 type extractorProperty struct {
 	// The name of the field for this property.
 	name string
 
+	// Filter that can use metadata associated with the properties being optimized
+	// to determine whether the field should be ignored during common value
+	// optimization.
+	filter extractorMetadataPredicate
+
 	// Retrieves the value on which common value optimization will be performed.
 	getter fieldAccessorFunc
 
@@ -1273,6 +1288,20 @@
 			continue
 		}
 
+		var filter extractorMetadataPredicate
+
+		// Add a filter
+		if proptools.HasTag(field, "sdk", "ignored-on-host") {
+			filter = func(metadata propertiesContainer) bool {
+				if m, ok := metadata.(isHostVariant); ok {
+					if m.isHostVariant() {
+						return false
+					}
+				}
+				return true
+			}
+		}
+
 		// Save a copy of the field index for use in the function.
 		fieldIndex := f
 
@@ -1304,6 +1333,7 @@
 		} else {
 			property := extractorProperty{
 				name,
+				filter,
 				fieldGetter,
 				reflect.Zero(field.Type),
 				proptools.HasTag(field, "android", "arch_variant"),
@@ -1372,6 +1402,12 @@
 
 	for _, property := range e.properties {
 		fieldGetter := property.getter
+		filter := property.filter
+		if filter == nil {
+			filter = func(metadata propertiesContainer) bool {
+				return true
+			}
+		}
 
 		// Check to see if all the structures have the same value for the field. The commonValue
 		// is nil on entry to the loop and if it is nil on exit then there is no common value or
@@ -1389,6 +1425,15 @@
 			itemValue := reflect.ValueOf(container.optimizableProperties())
 			fieldValue := fieldGetter(itemValue)
 
+			if !filter(container) {
+				expectedValue := property.emptyValue.Interface()
+				actualValue := fieldValue.Interface()
+				if !reflect.DeepEqual(expectedValue, actualValue) {
+					return fmt.Errorf("field %q is supposed to be ignored for %q but is set to %#v instead of %#v", property, container, actualValue, expectedValue)
+				}
+				continue
+			}
+
 			if commonValue == nil {
 				// Use the first value as the commonProperties value.
 				commonValue = &fieldValue