Merge "Add a prod var to override package names."
diff --git a/Android.bp b/Android.bp
index 62e276a..3215fa2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -71,6 +71,7 @@
         "android/env.go",
     ],
     testSrcs: [
+        "android/arch_test.go",
         "android/config_test.go",
         "android/expand_test.go",
         "android/namespace_test.go",
diff --git a/android/arch.go b/android/arch.go
index de19dbe..6aeccb0 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -616,10 +616,10 @@
 	}
 }
 
-func filterArchStructFields(fields []reflect.StructField) []reflect.StructField {
-	var ret []reflect.StructField
+func filterArchStructFields(fields []reflect.StructField) (filteredFields []reflect.StructField, filtered bool) {
 	for _, field := range fields {
 		if !proptools.HasTag(field, "android", "arch_variant") {
+			filtered = true
 			continue
 		}
 
@@ -637,15 +637,17 @@
 		// Recurse into structs
 		switch field.Type.Kind() {
 		case reflect.Struct:
-			var ok bool
-			field.Type, ok = filterArchStruct(field.Type)
-			if !ok {
+			var subFiltered bool
+			field.Type, subFiltered = filterArchStruct(field.Type)
+			filtered = filtered || subFiltered
+			if field.Type == nil {
 				continue
 			}
 		case reflect.Ptr:
 			if field.Type.Elem().Kind() == reflect.Struct {
-				nestedType, ok := filterArchStruct(field.Type.Elem())
-				if !ok {
+				nestedType, subFiltered := filterArchStruct(field.Type.Elem())
+				filtered = filtered || subFiltered
+				if nestedType == nil {
 					continue
 				}
 				field.Type = reflect.PtrTo(nestedType)
@@ -654,13 +656,17 @@
 			panic("Interfaces are not supported in arch_variant properties")
 		}
 
-		ret = append(ret, field)
+		filteredFields = append(filteredFields, field)
 	}
 
-	return ret
+	return filteredFields, filtered
 }
 
-func filterArchStruct(prop reflect.Type) (reflect.Type, bool) {
+// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a reflect.Type
+// that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, and a bool
+// that is true if the new struct type has fewer fields than the original type.  If there are no fields in the
+// original type with the struct tag it returns nil and true.
+func filterArchStruct(prop reflect.Type) (filteredProp reflect.Type, filtered bool) {
 	var fields []reflect.StructField
 
 	ptr := prop.Kind() == reflect.Ptr
@@ -672,13 +678,20 @@
 		fields = append(fields, prop.Field(i))
 	}
 
-	fields = filterArchStructFields(fields)
+	filteredFields, filtered := filterArchStructFields(fields)
 
-	if len(fields) == 0 {
-		return nil, false
+	if len(filteredFields) == 0 {
+		return nil, true
 	}
 
-	ret := reflect.StructOf(fields)
+	if !filtered {
+		if ptr {
+			return reflect.PtrTo(prop), false
+		}
+		return prop, false
+	}
+
+	ret := reflect.StructOf(filteredFields)
 	if ptr {
 		ret = reflect.PtrTo(ret)
 	}
@@ -686,7 +699,13 @@
 	return ret, true
 }
 
-func filterArchStructSharded(prop reflect.Type) ([]reflect.Type, bool) {
+// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a list of
+// reflect.Type that only contains the fields in the original type that have an `android:"arch_variant"` struct tag,
+// and a bool that is true if the new struct type has fewer fields than the original type.  If there are no fields in
+// the original type with the struct tag it returns nil and true.  Each returned struct type will have a maximum of
+// 10 top level fields in it to attempt to avoid hitting the reflect.StructOf name length limit, although the limit
+// can still be reached with a single struct field with many fields in it.
+func filterArchStructSharded(prop reflect.Type) (filteredProp []reflect.Type, filtered bool) {
 	var fields []reflect.StructField
 
 	ptr := prop.Kind() == reflect.Ptr
@@ -698,24 +717,29 @@
 		fields = append(fields, prop.Field(i))
 	}
 
-	fields = filterArchStructFields(fields)
+	fields, filtered = filterArchStructFields(fields)
+	if !filtered {
+		if ptr {
+			return []reflect.Type{reflect.PtrTo(prop)}, false
+		}
+		return []reflect.Type{prop}, false
+	}
 
 	if len(fields) == 0 {
-		return nil, false
+		return nil, true
 	}
 
 	shards := shardFields(fields, 10)
 
-	var ret []reflect.Type
 	for _, shard := range shards {
 		s := reflect.StructOf(shard)
 		if ptr {
 			s = reflect.PtrTo(s)
 		}
-		ret = append(ret, s)
+		filteredProp = append(filteredProp, s)
 	}
 
-	return ret, true
+	return filteredProp, true
 }
 
 func shardFields(fields []reflect.StructField, shardSize int) [][]reflect.StructField {
@@ -730,9 +754,12 @@
 	return ret
 }
 
+// createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of
+// reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib,
+// etc.
 func createArchType(props reflect.Type) []reflect.Type {
-	propShards, ok := filterArchStructSharded(props)
-	if !ok {
+	propShards, _ := filterArchStructSharded(props)
+	if len(propShards) == 0 {
 		return nil
 	}
 
diff --git a/android/arch_test.go b/android/arch_test.go
new file mode 100644
index 0000000..0589e6c
--- /dev/null
+++ b/android/arch_test.go
@@ -0,0 +1,232 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"reflect"
+	"testing"
+)
+
+type Named struct {
+	A *string `android:"arch_variant"`
+	B *string
+}
+
+type NamedAllFiltered struct {
+	A *string
+}
+
+type NamedNoneFiltered struct {
+	A *string `android:"arch_variant"`
+}
+
+func TestFilterArchStruct(t *testing.T) {
+	tests := []struct {
+		name     string
+		in       interface{}
+		out      interface{}
+		filtered bool
+	}{
+		// Property tests
+		{
+			name: "basic",
+			in: &struct {
+				A *string `android:"arch_variant"`
+				B *string
+			}{},
+			out: &struct {
+				A *string
+			}{},
+			filtered: true,
+		},
+		{
+			name: "all filtered",
+			in: &struct {
+				A *string
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "none filtered",
+			in: &struct {
+				A *string `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A *string `android:"arch_variant"`
+			}{},
+			filtered: false,
+		},
+
+		// Sub-struct tests
+		{
+			name: "substruct",
+			in: &struct {
+				A struct {
+					A *string `android:"arch_variant"`
+					B *string
+				} `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "substruct all filtered",
+			in: &struct {
+				A struct {
+					A *string
+				} `android:"arch_variant"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "substruct none filtered",
+			in: &struct {
+				A struct {
+					A *string `android:"arch_variant"`
+				} `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A struct {
+					A *string `android:"arch_variant"`
+				} `android:"arch_variant"`
+			}{},
+			filtered: false,
+		},
+
+		// Named sub-struct tests
+		{
+			name: "named substruct",
+			in: &struct {
+				A Named `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "substruct all filtered",
+			in: &struct {
+				A NamedAllFiltered `android:"arch_variant"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "substruct none filtered",
+			in: &struct {
+				A NamedNoneFiltered `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A NamedNoneFiltered `android:"arch_variant"`
+			}{},
+			filtered: false,
+		},
+
+		// Pointer to sub-struct tests
+		{
+			name: "pointer substruct",
+			in: &struct {
+				A *struct {
+					A *string `android:"arch_variant"`
+					B *string
+				} `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A *struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "pointer substruct all filtered",
+			in: &struct {
+				A *struct {
+					A *string
+				} `android:"arch_variant"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "pointer substruct none filtered",
+			in: &struct {
+				A *struct {
+					A *string `android:"arch_variant"`
+				} `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A *struct {
+					A *string `android:"arch_variant"`
+				} `android:"arch_variant"`
+			}{},
+			filtered: false,
+		},
+
+		// Pointer to named sub-struct tests
+		{
+			name: "pointer named substruct",
+			in: &struct {
+				A *Named `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A *struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "pointer substruct all filtered",
+			in: &struct {
+				A *NamedAllFiltered `android:"arch_variant"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "pointer substruct none filtered",
+			in: &struct {
+				A *NamedNoneFiltered `android:"arch_variant"`
+			}{},
+			out: &struct {
+				A *NamedNoneFiltered `android:"arch_variant"`
+			}{},
+			filtered: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			out, filtered := filterArchStruct(reflect.TypeOf(test.in))
+			if filtered != test.filtered {
+				t.Errorf("expected filtered %v, got %v", test.filtered, filtered)
+			}
+			expected := reflect.TypeOf(test.out)
+			if out != expected {
+				t.Errorf("expected type %v, got %v", expected, out)
+			}
+		})
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index 09e5b50..ad07db4 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -29,27 +29,23 @@
 	"android/soong/genrule"
 )
 
+type StaticSharedLibraryProperties struct {
+	Srcs   []string `android:"arch_variant"`
+	Cflags []string `android:"arch_variant"`
+
+	Enabled            *bool    `android:"arch_variant"`
+	Whole_static_libs  []string `android:"arch_variant"`
+	Static_libs        []string `android:"arch_variant"`
+	Shared_libs        []string `android:"arch_variant"`
+	System_shared_libs []string `android:"arch_variant"`
+
+	Export_shared_lib_headers []string `android:"arch_variant"`
+	Export_static_lib_headers []string `android:"arch_variant"`
+}
+
 type LibraryProperties struct {
-	Static struct {
-		Srcs   []string `android:"arch_variant"`
-		Cflags []string `android:"arch_variant"`
-
-		Enabled            *bool    `android:"arch_variant"`
-		Whole_static_libs  []string `android:"arch_variant"`
-		Static_libs        []string `android:"arch_variant"`
-		Shared_libs        []string `android:"arch_variant"`
-		System_shared_libs []string `android:"arch_variant"`
-	} `android:"arch_variant"`
-	Shared struct {
-		Srcs   []string `android:"arch_variant"`
-		Cflags []string `android:"arch_variant"`
-
-		Enabled            *bool    `android:"arch_variant"`
-		Whole_static_libs  []string `android:"arch_variant"`
-		Static_libs        []string `android:"arch_variant"`
-		Shared_libs        []string `android:"arch_variant"`
-		System_shared_libs []string `android:"arch_variant"`
-	} `android:"arch_variant"`
+	Static StaticSharedLibraryProperties `android:"arch_variant"`
+	Shared StaticSharedLibraryProperties `android:"arch_variant"`
 
 	// local file name to pass to the linker as -unexported_symbols_list
 	Unexported_symbols_list *string `android:"arch_variant"`
@@ -539,6 +535,9 @@
 			library.Properties.Static.Whole_static_libs...)
 		deps.StaticLibs = append(deps.StaticLibs, library.Properties.Static.Static_libs...)
 		deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...)
+
+		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.Properties.Static.Export_shared_lib_headers...)
+		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.Properties.Static.Export_static_lib_headers...)
 	} else if library.shared() {
 		if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
 			if !ctx.useSdk() {
@@ -560,6 +559,9 @@
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.Properties.Shared.Whole_static_libs...)
 		deps.StaticLibs = append(deps.StaticLibs, library.Properties.Shared.Static_libs...)
 		deps.SharedLibs = append(deps.SharedLibs, library.Properties.Shared.Shared_libs...)
+
+		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.Properties.Shared.Export_shared_lib_headers...)
+		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.Properties.Shared.Export_static_lib_headers...)
 	}
 	if ctx.useVndk() {
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)