Merge "Add bp2build converter for cc_genrule."
diff --git a/android/Android.bp b/android/Android.bp
index f3a3850..6450a06 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -110,6 +110,7 @@
         "paths_test.go",
         "prebuilt_test.go",
         "rule_builder_test.go",
+        "sdk_test.go",
         "singleton_module_test.go",
         "soong_config_modules_test.go",
         "util_test.go",
diff --git a/android/arch.go b/android/arch.go
index ddc082b..6add1b1 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -934,6 +934,8 @@
 		if len(values) > 0 && values[0] != "path" {
 			panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
 		} else if len(values) == 1 {
+			// FIXME(b/200678898): This assumes that the only tag type when there's
+			// `android:"arch_variant"` is `android` itself and thus clobbers others
 			field.Tag = reflect.StructTag(`android:"` + strings.Join(values, ",") + `"`)
 		} else {
 			field.Tag = ``
diff --git a/android/neverallow.go b/android/neverallow.go
index 19b58a7..a91d523 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -152,7 +152,7 @@
 	javaDeviceForHostProjectsAllowedList := []string{
 		"external/guava",
 		"external/robolectric-shadows",
-		"framework/layoutlib",
+		"frameworks/layoutlib",
 	}
 
 	return []Rule{
diff --git a/android/sdk.go b/android/sdk.go
index 100f63b..1d63d7a 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"fmt"
 	"sort"
 	"strings"
 
@@ -376,6 +377,224 @@
 
 var _ BpPrintable = BpPrintableBase{}
 
+// sdkRegisterable defines the interface that must be implemented by objects that can be registered
+// in an sdkRegistry.
+type sdkRegisterable interface {
+	// SdkPropertyName returns the name of the corresponding property on an sdk module.
+	SdkPropertyName() string
+}
+
+// sdkRegistry provides support for registering and retrieving objects that define properties for
+// use by sdk and module_exports module types.
+type sdkRegistry struct {
+	// The list of registered objects sorted by property name.
+	list []sdkRegisterable
+}
+
+// copyAndAppend creates a new sdkRegistry that includes all the traits registered in
+// this registry plus the supplied trait.
+func (r *sdkRegistry) copyAndAppend(registerable sdkRegisterable) *sdkRegistry {
+	oldList := r.list
+
+	// Make sure that list does not already contain the property. Uses a simple linear search instead
+	// of a binary search even though the list is sorted. That is because the number of items in the
+	// list is small and so not worth the overhead of a binary search.
+	found := false
+	newPropertyName := registerable.SdkPropertyName()
+	for _, r := range oldList {
+		if r.SdkPropertyName() == newPropertyName {
+			found = true
+			break
+		}
+	}
+	if found {
+		names := []string{}
+		for _, r := range oldList {
+			names = append(names, r.SdkPropertyName())
+		}
+		panic(fmt.Errorf("duplicate properties found, %q already exists in %q", newPropertyName, names))
+	}
+
+	// Copy the slice just in case this is being read while being modified, e.g. when testing.
+	list := make([]sdkRegisterable, 0, len(oldList)+1)
+	list = append(list, oldList...)
+	list = append(list, registerable)
+
+	// Sort the registered objects by their property name to ensure that registry order has no effect
+	// on behavior.
+	sort.Slice(list, func(i1, i2 int) bool {
+		t1 := list[i1]
+		t2 := list[i2]
+
+		return t1.SdkPropertyName() < t2.SdkPropertyName()
+	})
+
+	// Create a new registry so the pointer uniquely identifies the set of registered types.
+	return &sdkRegistry{
+		list: list,
+	}
+}
+
+// registeredObjects returns the list of registered instances.
+func (r *sdkRegistry) registeredObjects() []sdkRegisterable {
+	return r.list
+}
+
+// uniqueOnceKey returns a key that uniquely identifies this instance and can be used with
+// OncePer.Once
+func (r *sdkRegistry) uniqueOnceKey() OnceKey {
+	// Use the pointer to the registry as the unique key. The pointer is used because it is guaranteed
+	// to uniquely identify the contained list. The list itself cannot be used as slices are not
+	// comparable. Using the pointer does mean that two separate registries with identical lists would
+	// have different keys and so cause whatever information is cached to be created multiple times.
+	// However, that is not an issue in practice as it should not occur outside tests. Constructing a
+	// string representation of the list to use instead would avoid that but is an unnecessary
+	// complication that provides no significant benefit.
+	return NewCustomOnceKey(r)
+}
+
+// SdkMemberTrait represents a trait that members of an sdk module can contribute to the sdk
+// snapshot.
+//
+// A trait is simply a characteristic of sdk member that is not required by default which may be
+// required for some members but not others. Traits can cause additional information to be output
+// to the sdk snapshot or replace the default information exported for a member with something else.
+// e.g.
+// * By default cc libraries only export the default image variants to the SDK. However, for some
+//   members it may be necessary to export specific image variants, e.g. vendor, or recovery.
+// * By default cc libraries export all the configured architecture variants except for the native
+//   bridge architecture variants. However, for some members it may be necessary to export the
+//   native bridge architecture variants as well.
+// * By default cc libraries export the platform variant (i.e. sdk:). However, for some members it
+//   may be necessary to export the sdk variant (i.e. sdk:sdk).
+//
+// A sdk can request a module to provide no traits, one trait or a collection of traits. The exact
+// behavior of a trait is determined by how SdkMemberType implementations handle the traits. A trait
+// could be specific to one SdkMemberType or many. Some trait combinations could be incompatible.
+//
+// The sdk module type will create a special traits structure that contains a property for each
+// trait registered with RegisterSdkMemberTrait(). The property names are those returned from
+// SdkPropertyName(). Each property contains a list of modules that are required to have that trait.
+// e.g. something like this:
+//
+//   sdk {
+//     name: "sdk",
+//     ...
+//     traits: {
+//       recovery_image: ["module1", "module4", "module5"],
+//       native_bridge: ["module1", "module2"],
+//       native_sdk: ["module1", "module3"],
+//       ...
+//     },
+//     ...
+//   }
+type SdkMemberTrait interface {
+	// SdkPropertyName returns the name of the traits property on an sdk module.
+	SdkPropertyName() string
+}
+
+var _ sdkRegisterable = (SdkMemberTrait)(nil)
+
+// SdkMemberTraitBase is the base struct that must be embedded within any type that implements
+// SdkMemberTrait.
+type SdkMemberTraitBase struct {
+	// PropertyName is the name of the property
+	PropertyName string
+}
+
+func (b *SdkMemberTraitBase) SdkPropertyName() string {
+	return b.PropertyName
+}
+
+// SdkMemberTraitSet is a set of SdkMemberTrait instances.
+type SdkMemberTraitSet interface {
+	// Empty returns true if this set is empty.
+	Empty() bool
+
+	// Contains returns true if this set contains the specified trait.
+	Contains(trait SdkMemberTrait) bool
+
+	// Subtract returns a new set containing all elements of this set except for those in the
+	// other set.
+	Subtract(other SdkMemberTraitSet) SdkMemberTraitSet
+
+	// String returns a string representation of the set and its contents.
+	String() string
+}
+
+func NewSdkMemberTraitSet(traits []SdkMemberTrait) SdkMemberTraitSet {
+	if len(traits) == 0 {
+		return EmptySdkMemberTraitSet()
+	}
+
+	m := sdkMemberTraitSet{}
+	for _, trait := range traits {
+		m[trait] = true
+	}
+	return m
+}
+
+func EmptySdkMemberTraitSet() SdkMemberTraitSet {
+	return (sdkMemberTraitSet)(nil)
+}
+
+type sdkMemberTraitSet map[SdkMemberTrait]bool
+
+var _ SdkMemberTraitSet = (sdkMemberTraitSet{})
+
+func (s sdkMemberTraitSet) Empty() bool {
+	return len(s) == 0
+}
+
+func (s sdkMemberTraitSet) Contains(trait SdkMemberTrait) bool {
+	return s[trait]
+}
+
+func (s sdkMemberTraitSet) Subtract(other SdkMemberTraitSet) SdkMemberTraitSet {
+	if other.Empty() {
+		return s
+	}
+
+	var remainder []SdkMemberTrait
+	for trait, _ := range s {
+		if !other.Contains(trait) {
+			remainder = append(remainder, trait)
+		}
+	}
+
+	return NewSdkMemberTraitSet(remainder)
+}
+
+func (s sdkMemberTraitSet) String() string {
+	list := []string{}
+	for trait, _ := range s {
+		list = append(list, trait.SdkPropertyName())
+	}
+	sort.Strings(list)
+	return fmt.Sprintf("[%s]", strings.Join(list, ","))
+}
+
+var registeredSdkMemberTraits = &sdkRegistry{}
+
+// RegisteredSdkMemberTraits returns a OnceKey and a sorted list of registered traits.
+//
+// The key uniquely identifies the array of traits and can be used with OncePer.Once() to cache
+// information derived from the array of traits.
+func RegisteredSdkMemberTraits() (OnceKey, []SdkMemberTrait) {
+	registerables := registeredSdkMemberTraits.registeredObjects()
+	traits := make([]SdkMemberTrait, len(registerables))
+	for i, registerable := range registerables {
+		traits[i] = registerable.(SdkMemberTrait)
+	}
+	return registeredSdkMemberTraits.uniqueOnceKey(), traits
+}
+
+// RegisterSdkMemberTrait registers an SdkMemberTrait object to allow them to be used in the
+// module_exports, module_exports_snapshot, sdk and sdk_snapshot module types.
+func RegisterSdkMemberTrait(trait SdkMemberTrait) {
+	registeredSdkMemberTraits = registeredSdkMemberTraits.copyAndAppend(trait)
+}
+
 // SdkMember is an individual member of the SDK.
 //
 // It includes all of the variants that the SDK depends upon.
@@ -541,12 +760,25 @@
 	// CreateVariantPropertiesStruct creates a structure into which variant specific properties can be
 	// added.
 	CreateVariantPropertiesStruct() SdkMemberProperties
+
+	// SupportedTraits returns the set of traits supported by this member type.
+	SupportedTraits() SdkMemberTraitSet
 }
 
+var _ sdkRegisterable = (SdkMemberType)(nil)
+
 // SdkDependencyContext provides access to information needed by the SdkMemberType.AddDependencies()
 // implementations.
 type SdkDependencyContext interface {
 	BottomUpMutatorContext
+
+	// RequiredTraits returns the set of SdkMemberTrait instances that the sdk requires the named
+	// member to provide.
+	RequiredTraits(name string) SdkMemberTraitSet
+
+	// RequiresTrait returns true if the sdk requires the member with the supplied name to provide the
+	// supplied trait.
+	RequiresTrait(name string, trait SdkMemberTrait) bool
 }
 
 // SdkMemberTypeBase is the base type for SdkMemberType implementations and must be embedded in any
@@ -565,6 +797,9 @@
 	// module type in its SdkMemberType.AddPrebuiltModule() method. That prevents the sdk snapshot
 	// code from automatically adding a prefer: true flag.
 	UseSourceModuleTypeInSnapshot bool
+
+	// The list of supported traits.
+	Traits []SdkMemberTrait
 }
 
 func (b *SdkMemberTypeBase) SdkPropertyName() string {
@@ -587,60 +822,52 @@
 	return b.UseSourceModuleTypeInSnapshot
 }
 
-// SdkMemberTypesRegistry encapsulates the information about registered SdkMemberTypes.
-type SdkMemberTypesRegistry struct {
-	// The list of types sorted by property name.
-	list []SdkMemberType
+func (b *SdkMemberTypeBase) SupportedTraits() SdkMemberTraitSet {
+	return NewSdkMemberTraitSet(b.Traits)
 }
 
-func (r *SdkMemberTypesRegistry) copyAndAppend(memberType SdkMemberType) *SdkMemberTypesRegistry {
-	oldList := r.list
+// registeredModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports
+// modules.
+var registeredModuleExportsMemberTypes = &sdkRegistry{}
 
-	// Copy the slice just in case this is being read while being modified, e.g. when testing.
-	list := make([]SdkMemberType, 0, len(oldList)+1)
-	list = append(list, oldList...)
-	list = append(list, memberType)
+// registeredSdkMemberTypes is the set of registered registeredSdkMemberTypes for sdk modules.
+var registeredSdkMemberTypes = &sdkRegistry{}
 
-	// Sort the member types by their property name to ensure that registry order has no effect
-	// on behavior.
-	sort.Slice(list, func(i1, i2 int) bool {
-		t1 := list[i1]
-		t2 := list[i2]
-
-		return t1.SdkPropertyName() < t2.SdkPropertyName()
-	})
-
-	// Create a new registry so the pointer uniquely identifies the set of registered types.
-	return &SdkMemberTypesRegistry{
-		list: list,
+// RegisteredSdkMemberTypes returns a OnceKey and a sorted list of registered types.
+//
+// If moduleExports is true then the slice of types includes all registered types that can be used
+// with the module_exports and module_exports_snapshot module types. Otherwise, the slice of types
+// only includes those registered types that can be used with the sdk and sdk_snapshot module
+// types.
+//
+// The key uniquely identifies the array of types and can be used with OncePer.Once() to cache
+// information derived from the array of types.
+func RegisteredSdkMemberTypes(moduleExports bool) (OnceKey, []SdkMemberType) {
+	var registry *sdkRegistry
+	if moduleExports {
+		registry = registeredModuleExportsMemberTypes
+	} else {
+		registry = registeredSdkMemberTypes
 	}
+
+	registerables := registry.registeredObjects()
+	types := make([]SdkMemberType, len(registerables))
+	for i, registerable := range registerables {
+		types[i] = registerable.(SdkMemberType)
+	}
+	return registry.uniqueOnceKey(), types
 }
 
-func (r *SdkMemberTypesRegistry) RegisteredTypes() []SdkMemberType {
-	return r.list
-}
-
-func (r *SdkMemberTypesRegistry) UniqueOnceKey() OnceKey {
-	// Use the pointer to the registry as the unique key.
-	return NewCustomOnceKey(r)
-}
-
-// ModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports modules.
-var ModuleExportsMemberTypes = &SdkMemberTypesRegistry{}
-
-// SdkMemberTypes is the set of registered SdkMemberTypes for sdk modules.
-var SdkMemberTypes = &SdkMemberTypesRegistry{}
-
 // RegisterSdkMemberType registers an SdkMemberType object to allow them to be used in the
 // module_exports, module_exports_snapshot and (depending on the value returned from
 // SdkMemberType.UsableWithSdkAndSdkSnapshot) the sdk and sdk_snapshot module types.
 func RegisterSdkMemberType(memberType SdkMemberType) {
 	// All member types are usable with module_exports.
-	ModuleExportsMemberTypes = ModuleExportsMemberTypes.copyAndAppend(memberType)
+	registeredModuleExportsMemberTypes = registeredModuleExportsMemberTypes.copyAndAppend(memberType)
 
 	// Only those that explicitly indicate it are usable with sdk.
 	if memberType.UsableWithSdkAndSdkSnapshot() {
-		SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
+		registeredSdkMemberTypes = registeredSdkMemberTypes.copyAndAppend(memberType)
 	}
 }
 
@@ -733,6 +960,9 @@
 	// Provided for use by sdk members to create a member specific location within the snapshot
 	// into which to copy the prebuilt files.
 	Name() string
+
+	// RequiresTrait returns true if this member is expected to provide the specified trait.
+	RequiresTrait(trait SdkMemberTrait) bool
 }
 
 // ExportedComponentsInfo contains information about the components that this module exports to an
diff --git a/android/sdk_test.go b/android/sdk_test.go
new file mode 100644
index 0000000..51aeb31
--- /dev/null
+++ b/android/sdk_test.go
@@ -0,0 +1,53 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 "testing"
+
+type testSdkRegisterable struct {
+	name string
+}
+
+func (t *testSdkRegisterable) SdkPropertyName() string {
+	return t.name
+}
+
+var _ sdkRegisterable = &testSdkRegisterable{}
+
+func TestSdkRegistry(t *testing.T) {
+	alpha := &testSdkRegisterable{"alpha"}
+	beta := &testSdkRegisterable{"beta"}
+	betaDup := &testSdkRegisterable{"beta"}
+
+	// Make sure that an empty registry is empty.
+	emptyRegistry := &sdkRegistry{}
+	AssertDeepEquals(t, "emptyRegistry should be empty", ([]sdkRegisterable)(nil), emptyRegistry.registeredObjects())
+
+	// Add beta to the empty registry to create another registry, check that it contains beta and make
+	// sure that it does not affect the creating registry.
+	registry1 := emptyRegistry.copyAndAppend(beta)
+	AssertDeepEquals(t, "emptyRegistry should still be empty", ([]sdkRegisterable)(nil), emptyRegistry.registeredObjects())
+	AssertDeepEquals(t, "registry1 should contain beta", []sdkRegisterable{beta}, registry1.registeredObjects())
+
+	// Add alpha to the registry containing beta to create another registry, check that it contains
+	// alpha,beta (in order) and make sure that it does not affect the creating registry.
+	registry2 := registry1.copyAndAppend(alpha)
+	AssertDeepEquals(t, "registry1 should still contain beta", []sdkRegisterable{beta}, registry1.registeredObjects())
+	AssertDeepEquals(t, "registry2 should contain alpha,beta", []sdkRegisterable{alpha, beta}, registry2.registeredObjects())
+
+	AssertPanicMessageContains(t, "duplicate beta should be detected", `"beta" already exists in ["alpha" "beta"]`, func() {
+		registry2.copyAndAppend(betaDup)
+	})
+}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index d731f3e..0bd71c6 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -111,14 +111,20 @@
 rootStaticArchives = []
 linker_inputs = cc_info.linking_context.linker_inputs.to_list()
 
-for linker_input in linker_inputs:
-  for library in linker_input.libraries:
-    for object in library.objects:
-      ccObjectFiles += [object.path]
-    if library.static_library:
-      staticLibraries.append(library.static_library.path)
-      if linker_input.owner == target.label:
-        rootStaticArchives.append(library.static_library.path)
+static_info_tag = "//build/bazel/rules:cc_library_static.bzl%CcStaticLibraryInfo"
+if static_info_tag in providers(target):
+  static_info = providers(target)[static_info_tag]
+  ccObjectFiles = [f.path for f in static_info.objects]
+  rootStaticArchives = [static_info.root_static_archive.path]
+else:
+  for linker_input in linker_inputs:
+    for library in linker_input.libraries:
+      for object in library.objects:
+        ccObjectFiles += [object.path]
+      if library.static_library:
+        staticLibraries.append(library.static_library.path)
+        if linker_input.owner == target.label:
+          rootStaticArchives.append(library.static_library.path)
 
 rootDynamicLibraries = []
 
@@ -141,9 +147,10 @@
   system_includes,
   rootStaticArchives,
   rootDynamicLibraries,
+  [toc_file]
 ]
 
-return "|".join([", ".join(r) for r in returns] + [toc_file])`
+return "|".join([", ".join(r) for r in returns])`
 }
 
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
diff --git a/cc/Android.bp b/cc/Android.bp
index bff2761..190d55e 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -63,6 +63,7 @@
         "library.go",
         "library_headers.go",
         "library_sdk_member.go",
+        "native_bridge_sdk_trait.go",
         "object.go",
         "test.go",
         "toolchain_library.go",
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index d4fcf7c..e72efae 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -47,17 +47,29 @@
 	"android.hardware.power-V1-ndk",
 	"android.hardware.power-V1-ndk_platform",
 	"android.hardware.power-ndk_platform",
-	"android.hardware.rebootescrow-V1-ndk",
-	"android.hardware.rebootescrow-V1-ndk_platform",
 	"android.hardware.power.stats-V1-ndk",
 	"android.hardware.power.stats-V1-ndk_platform",
 	"android.hardware.power.stats-ndk_platform",
 	"android.hardware.power.stats-unstable-ndk_platform",
+	"android.hardware.rebootescrow-V1-ndk",
+	"android.hardware.rebootescrow-V1-ndk_platform",
+	"android.hardware.rebootescrow-ndk_platform",
 	"android.hardware.radio-V1-ndk",
 	"android.hardware.radio-V1-ndk_platform",
 	"android.hardware.radio.config-V1-ndk",
 	"android.hardware.radio.config-V1-ndk_platform",
-	"android.hardware.rebootescrow-ndk_platform",
+	"android.hardware.radio.data-V1-ndk",
+	"android.hardware.radio.data-V1-ndk_platform",
+	"android.hardware.radio.messaging-V1-ndk",
+	"android.hardware.radio.messaging-V1-ndk_platform",
+	"android.hardware.radio.modem-V1-ndk",
+	"android.hardware.radio.modem-V1-ndk_platform",
+	"android.hardware.radio.network-V1-ndk",
+	"android.hardware.radio.network-V1-ndk_platform",
+	"android.hardware.radio.sim-V1-ndk",
+	"android.hardware.radio.sim-V1-ndk_platform",
+	"android.hardware.radio.voice-V1-ndk",
+	"android.hardware.radio.voice-V1-ndk_platform",
 	"android.hardware.security.keymint-V1-ndk",
 	"android.hardware.security.keymint-V1-ndk_platform",
 	"android.hardware.security.keymint-ndk_platform",
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 14b90c1..b335035 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -33,6 +33,9 @@
 		PropertyName:    "native_header_libs",
 		SupportsSdk:     true,
 		HostOsDependent: true,
+		Traits: []android.SdkMemberTrait{
+			nativeBridgeSdkTrait,
+		},
 	},
 	prebuiltModuleType: "cc_prebuilt_library_headers",
 	noOutputFiles:      true,
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 559e940..bed7954 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -75,8 +75,33 @@
 }
 
 func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
-	targets := ctx.MultiTargets()
+	// The base set of targets which does not include native bridge targets.
+	defaultTargets := ctx.MultiTargets()
+
+	// The lazily created list of native bridge targets.
+	var includeNativeBridgeTargets []android.Target
+
 	for _, lib := range names {
+		targets := defaultTargets
+
+		// If native bridge support is required in the sdk snapshot then add native bridge targets to
+		// the basic list of targets that are required.
+		nativeBridgeSupport := ctx.RequiresTrait(lib, nativeBridgeSdkTrait)
+		if nativeBridgeSupport && ctx.Device() {
+			// If not already computed then compute the list of native bridge targets.
+			if includeNativeBridgeTargets == nil {
+				includeNativeBridgeTargets = append([]android.Target{}, defaultTargets...)
+				allAndroidTargets := ctx.Config().Targets[android.Android]
+				for _, possibleNativeBridgeTarget := range allAndroidTargets {
+					if possibleNativeBridgeTarget.NativeBridge == android.NativeBridgeEnabled {
+						includeNativeBridgeTargets = append(includeNativeBridgeTargets, possibleNativeBridgeTarget)
+					}
+				}
+			}
+
+			// Include the native bridge targets as well.
+			targets = includeNativeBridgeTargets
+		}
 		for _, target := range targets {
 			name, version := StubsLibNameAndVersion(lib)
 			if version == "" {
@@ -122,6 +147,10 @@
 
 	ccModule := member.Variants()[0].(*Module)
 
+	if ctx.RequiresTrait(nativeBridgeSdkTrait) {
+		pbm.AddProperty("native_bridge_supported", true)
+	}
+
 	if proptools.Bool(ccModule.Properties.Recovery_available) {
 		pbm.AddProperty("recovery_available", true)
 	}
@@ -436,7 +465,11 @@
 	exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
 		exportedInfo.IncludeDirs, isGeneratedHeaderDirectory)
 
-	p.archSubDir = ccModule.Target().Arch.ArchType.String()
+	target := ccModule.Target()
+	p.archSubDir = target.Arch.ArchType.String()
+	if target.NativeBridge == android.NativeBridgeEnabled {
+		p.archSubDir += "_native_bridge"
+	}
 
 	// Make sure that the include directories are unique.
 	p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
diff --git a/cc/native_bridge_sdk_trait.go b/cc/native_bridge_sdk_trait.go
new file mode 100644
index 0000000..1326d57
--- /dev/null
+++ b/cc/native_bridge_sdk_trait.go
@@ -0,0 +1,33 @@
+// Copyright 2021 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 cc
+
+import "android/soong/android"
+
+// This file contains support for the native bridge sdk trait.
+
+func init() {
+	android.RegisterSdkMemberTrait(nativeBridgeSdkTrait)
+}
+
+type nativeBridgeSdkTraitStruct struct {
+	android.SdkMemberTraitBase
+}
+
+var nativeBridgeSdkTrait android.SdkMemberTrait = &nativeBridgeSdkTraitStruct{
+	SdkMemberTraitBase: android.SdkMemberTraitBase{
+		PropertyName: "native_bridge_support",
+	},
+}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 7733c1b..965b755 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -261,10 +261,18 @@
 			clcTarget = append(clcTarget, GetSystemServerDexLocation(global, lib))
 		}
 
-		// Copy the system server jar to a predefined location where dex2oat will find it.
-		dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
-		rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
-		rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
+		if DexpreoptRunningInSoong {
+			// Copy the system server jar to a predefined location where dex2oat will find it.
+			dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
+			rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
+			rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
+		} else {
+			// For Make modules the copy rule is generated in the makefiles, not in dexpreopt.sh.
+			// This is necessary to expose the rule to Ninja, otherwise it has rules that depend on
+			// the jar (namely, dexpreopt commands for all subsequent system server jars that have
+			// this one in their class loader context), but no rule that creates it (because Ninja
+			// cannot see the rule in the generated dexpreopt.sh script).
+		}
 
 		checkSystemServerOrder(ctx, jarIndex)
 
diff --git a/java/droidstubs.go b/java/droidstubs.go
index ec1b04a..7fd88fc 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -156,6 +156,7 @@
 
 // Provider of information about API stubs, used by java_sdk_library.
 type ApiStubsProvider interface {
+	AnnotationsZip() android.Path
 	ApiFilePath
 	RemovedApiFilePath() android.Path
 
@@ -210,6 +211,10 @@
 	}
 }
 
+func (d *Droidstubs) AnnotationsZip() android.Path {
+	return d.annotationsZip
+}
+
 func (d *Droidstubs) ApiFilePath() android.Path {
 	return d.apiFilePath
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 2d8aef7..d469522 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -550,6 +550,9 @@
 
 	// The stubs source jar.
 	stubsSrcJar android.OptionalPath
+
+	// Extracted annotations.
+	annotationsZip android.OptionalPath
 }
 
 func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
@@ -585,6 +588,7 @@
 }
 
 func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
+	paths.annotationsZip = android.OptionalPathForPath(provider.AnnotationsZip())
 	paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
 	paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
 }
@@ -739,6 +743,8 @@
 	apiTxtComponentName = "api.txt"
 
 	removedApiTxtComponentName = "removed-api.txt"
+
+	annotationsComponentName = "annotations.zip"
 )
 
 // A regular expression to match tags that reference a specific stubs component.
@@ -757,7 +763,7 @@
 	scopesRegexp := choice(allScopeNames...)
 
 	// Regular expression to match one of the components.
-	componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName)
+	componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName, annotationsComponentName)
 
 	// Regular expression to match any combination of one scope and one component.
 	return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
@@ -765,9 +771,7 @@
 
 // For OutputFileProducer interface
 //
-// .<scope>.stubs.source
-// .<scope>.api.txt
-// .<scope>.removed-api.txt
+// .<scope>.<component name>, for all ComponentNames (for example: .public.removed-api.txt)
 func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
 	if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
 		scopeName := groups[1]
@@ -794,6 +798,11 @@
 				if paths.removedApiFilePath.Valid() {
 					return android.Paths{paths.removedApiFilePath.Path()}, nil
 				}
+
+			case annotationsComponentName:
+				if paths.annotationsZip.Valid() {
+					return android.Paths{paths.annotationsZip.Path()}, nil
+				}
 			}
 
 			return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
@@ -1888,6 +1897,9 @@
 
 	// The removed.txt
 	Removed_api *string `android:"path"`
+
+	// Annotation zip
+	Annotations *string `android:"path"`
 }
 
 type sdkLibraryImportProperties struct {
@@ -2201,6 +2213,7 @@
 		}
 
 		paths := module.getScopePathsCreateIfNeeded(apiScope)
+		paths.annotationsZip = android.OptionalPathForModuleSrc(ctx, scopeProperties.Annotations)
 		paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api)
 		paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api)
 	}
@@ -2551,6 +2564,7 @@
 	StubsSrcJar    android.Path
 	CurrentApiFile android.Path
 	RemovedApiFile android.Path
+	AnnotationsZip android.Path
 	SdkVersion     string
 }
 
@@ -2576,6 +2590,10 @@
 			if paths.removedApiFilePath.Valid() {
 				properties.RemovedApiFile = paths.removedApiFilePath.Path()
 			}
+			// The annotations zip is only available for modules that set annotations_enabled: true.
+			if paths.annotationsZip.Valid() {
+				properties.AnnotationsZip = paths.annotationsZip.Path()
+			}
 			s.Scopes[apiScope] = properties
 		}
 	}
@@ -2640,6 +2658,12 @@
 				scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
 			}
 
+			if properties.AnnotationsZip != nil {
+				annotationsSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"_annotations.zip")
+				ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath)
+				scopeSet.AddProperty("annotations", annotationsSnapshotPath)
+			}
+
 			if properties.SdkVersion != "" {
 				scopeSet.AddProperty("sdk_version", properties.SdkVersion)
 			}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index d6c0946..be23536 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -248,7 +248,7 @@
 	}
 }
 
-func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
+func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) {
 	android.GroupFixturePreparers(
 		prepareForJavaTest,
 		PrepareForTestWithJavaSdkLibraryFiles,
@@ -258,6 +258,31 @@
 			name: "foo",
 			srcs: ["a.java"],
 			api_packages: ["foo"],
+			annotations_enabled: true,
+			public: {
+				enabled: true,
+			},
+		}
+		java_library {
+			name: "bar",
+			srcs: ["b.java", ":foo{.public.stubs.source}"],
+			java_resources: [":foo{.public.annotations.zip}"],
+		}
+		`)
+}
+
+func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+	).
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": path dependency ":foo{.public.annotations.zip}": annotations.zip not available for api scope public`)).
+		RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			api_packages: ["foo"],
 			public: {
 				enabled: true,
 			},
@@ -266,6 +291,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["b.java", ":foo{.public.stubs.source}"],
+			java_resources: [":foo{.public.annotations.zip}"],
 		}
 		`)
 }
@@ -329,6 +355,7 @@
 				stub_srcs: ["a.java"],
 				current_api: "api/current.txt",
 				removed_api: "api/removed.txt",
+				annotations: "x/annotations.zip",
 			},
 		}
 
@@ -338,6 +365,7 @@
 			java_resources: [
 				":foo{.public.api.txt}",
 				":foo{.public.removed-api.txt}",
+				":foo{.public.annotations.zip}",
 			],
 		}
 		`)
diff --git a/java/testing.go b/java/testing.go
index a642753..99d55a0 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -300,6 +300,7 @@
 		"kotlin-stdlib-jdk7",
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
+		"stub-annotations",
 	}
 
 	for _, extra := range extraModules {
diff --git a/sdk/Android.bp b/sdk/Android.bp
index 0c9bf27..c6544d6 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -16,6 +16,7 @@
     srcs: [
         "bp.go",
         "exports.go",
+        "member_trait.go",
         "member_type.go",
         "sdk.go",
         "update.go",
@@ -28,6 +29,7 @@
         "exports_test.go",
         "java_sdk_test.go",
         "license_sdk_test.go",
+        "member_trait_test.go",
         "sdk_test.go",
         "testing.go",
     ],
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 25e35fc..da90c6d 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -32,6 +32,23 @@
 	"some/where/stubslib.map.txt":     nil,
 }
 
+// Adds a native bridge target to the configured list of targets.
+var prepareForTestWithNativeBridgeTarget = android.FixtureModifyConfig(func(config android.Config) {
+	config.Targets[android.Android] = append(config.Targets[android.Android], android.Target{
+		Os: android.Android,
+		Arch: android.Arch{
+			ArchType:     android.Arm64,
+			ArchVariant:  "armv8-a",
+			CpuVariant:   "cpu",
+			Abi:          nil,
+			ArchFeatures: nil,
+		},
+		NativeBridge:             android.NativeBridgeEnabled,
+		NativeBridgeHostArchName: "x86_64",
+		NativeBridgeRelativePath: "native_bridge",
+	})
+})
+
 func testSdkWithCc(t *testing.T, bp string) *android.TestResult {
 	t.Helper()
 	return testSdkWithFs(t, bp, ccTestFs)
@@ -1979,6 +1996,91 @@
 	)
 }
 
+func TestSnapshotWithCcHeadersLibraryAndNativeBridgeSupport(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		cc.PrepareForTestWithCcDefaultModules,
+		PrepareForTestWithSdkBuildComponents,
+		ccTestFs.AddToFixture(),
+		prepareForTestWithNativeBridgeTarget,
+	).RunTestWithBp(t, `
+		sdk {
+			name: "mysdk",
+			native_header_libs: ["mynativeheaders"],
+			traits: {
+				native_bridge_support: ["mynativeheaders"],
+			},
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			export_include_dirs: ["myinclude"],
+			stl: "none",
+			system_shared_libs: [],
+			native_bridge_supported: true,
+		}
+	`)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    native_bridge_supported: true,
+    stl: "none",
+    compile_multilib: "both",
+    system_shared_libs: [],
+    export_include_dirs: ["include/myinclude"],
+}
+`),
+		checkAllCopyRules(`
+myinclude/Test.h -> include/myinclude/Test.h
+`),
+	)
+}
+
+// TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties verifies that when a
+// module that has different output files for a native bridge target requests the native bridge
+// variants are copied into the sdk snapshot that it reports an error.
+func TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties(t *testing.T) {
+	android.GroupFixturePreparers(
+		cc.PrepareForTestWithCcDefaultModules,
+		PrepareForTestWithSdkBuildComponents,
+		ccTestFs.AddToFixture(),
+		prepareForTestWithNativeBridgeTarget,
+	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+		`\QArchitecture variant "arm64_native_bridge" of sdk member "mynativeheaders" has properties distinct from other variants; this is not yet supported. The properties are:
+        export_include_dirs: [
+            "arm64_native_bridge/include/myinclude_nativebridge",
+            "arm64_native_bridge/include/myinclude",
+        ],\E`)).
+		RunTestWithBp(t, `
+		sdk {
+			name: "mysdk",
+			native_header_libs: ["mynativeheaders"],
+			traits: {
+				native_bridge_support: ["mynativeheaders"],
+			},
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			export_include_dirs: ["myinclude"],
+			stl: "none",
+			system_shared_libs: [],
+			native_bridge_supported: true,
+			target: {
+				native_bridge: {
+					export_include_dirs: ["myinclude_nativebridge"],
+				},
+			},
+		}
+	`)
+}
+
 func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 9efb3a4..43542cb 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1205,6 +1205,55 @@
 	)
 }
 
+func TestSnapshotWithJavaSdkLibrary_AnnotationsZip(t *testing.T) {
+	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
+		sdk {
+			name: "mysdk",
+			java_sdk_libs: ["myjavalib"],
+		}
+
+		java_sdk_library {
+			name: "myjavalib",
+			srcs: ["Test.java"],
+			sdk_version: "current",
+			shared_library: false,
+			annotations_enabled: true,
+			public: {
+				enabled: true,
+			},
+		}
+	`)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "myjavalib",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        annotations: "sdk_library/public/myjavalib_annotations.zip",
+        sdk_version: "current",
+    },
+}
+		`),
+		checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_annotations.zip -> sdk_library/public/myjavalib_annotations.zip
+		`),
+		checkMergeZips(".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip"),
+	)
+}
+
 func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) {
 	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
 		sdk {
diff --git a/sdk/member_trait.go b/sdk/member_trait.go
new file mode 100644
index 0000000..4229ca8
--- /dev/null
+++ b/sdk/member_trait.go
@@ -0,0 +1,126 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 sdk
+
+import (
+	"reflect"
+
+	"android/soong/android"
+	"github.com/google/blueprint/proptools"
+)
+
+// Contains information about the sdk properties that list sdk members by trait, e.g.
+// native_bridge.
+type sdkMemberTraitListProperty struct {
+	// getter for the list of member names
+	getter func(properties interface{}) []string
+
+	// the trait of member referenced in the list
+	memberTrait android.SdkMemberTrait
+}
+
+// Cache of dynamically generated dynamicSdkMemberTraits objects. The key is the pointer
+// to a slice of SdkMemberTrait instances returned by android.RegisteredSdkMemberTraits().
+var dynamicSdkMemberTraitsMap android.OncePer
+
+// A dynamically generated set of member list properties and associated structure type.
+//
+// Instances of this are created by createDynamicSdkMemberTraits.
+type dynamicSdkMemberTraits struct {
+	// The dynamically generated structure type.
+	//
+	// Contains one []string exported field for each SdkMemberTrait returned by android.RegisteredSdkMemberTraits(). The name of
+	// the field is the exported form of the value returned by SdkMemberTrait.SdkPropertyName().
+	propertiesStructType reflect.Type
+
+	// Information about each of the member trait specific list properties.
+	memberTraitListProperties []*sdkMemberTraitListProperty
+}
+
+func (d *dynamicSdkMemberTraits) createMemberTraitListProperties() interface{} {
+	return reflect.New(d.propertiesStructType).Interface()
+}
+
+func getDynamicSdkMemberTraits(key android.OnceKey, registeredTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits {
+	// Get the cached value, creating new instance if necessary.
+	return dynamicSdkMemberTraitsMap.Once(key, func() interface{} {
+		return createDynamicSdkMemberTraits(registeredTraits)
+	}).(*dynamicSdkMemberTraits)
+}
+
+// Create the dynamicSdkMemberTraits from the list of registered member traits.
+//
+// A struct is created which contains one exported field per member trait corresponding to
+// the SdkMemberTrait.SdkPropertyName() value.
+//
+// A list of sdkMemberTraitListProperty instances is created, one per member trait that provides:
+// * a reference to the member trait.
+// * a getter for the corresponding field in the properties struct.
+//
+func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits {
+
+	var listProperties []*sdkMemberTraitListProperty
+	memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{}
+	var fields []reflect.StructField
+
+	// Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects.
+	nextFieldIndex := 0
+	for _, memberTrait := range sdkMemberTraits {
+
+		p := memberTrait.SdkPropertyName()
+
+		var getter func(properties interface{}) []string
+
+		// Create a dynamic exported field for the member trait's property.
+		fields = append(fields, reflect.StructField{
+			Name: proptools.FieldNameForProperty(p),
+			Type: reflect.TypeOf([]string{}),
+		})
+
+		// Copy the field index for use in the getter func as using the loop variable directly will
+		// cause all funcs to use the last value.
+		fieldIndex := nextFieldIndex
+		nextFieldIndex += 1
+
+		getter = func(properties interface{}) []string {
+			// The properties is expected to be of the following form (where
+			// <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName().
+			//     properties *struct {<Module_traits> []string, ....}
+			//
+			// Although it accesses the field by index the following reflection code is equivalent to:
+			//    *properties.<Module_traits>
+			//
+			list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
+			return list
+		}
+
+		// Create an sdkMemberTraitListProperty for the member trait.
+		memberListProperty := &sdkMemberTraitListProperty{
+			getter:      getter,
+			memberTrait: memberTrait,
+		}
+
+		memberTraitToProperty[memberTrait] = memberListProperty
+		listProperties = append(listProperties, memberListProperty)
+	}
+
+	// Create a dynamic struct from the collated fields.
+	propertiesStructType := reflect.StructOf(fields)
+
+	return &dynamicSdkMemberTraits{
+		memberTraitListProperties: listProperties,
+		propertiesStructType:      propertiesStructType,
+	}
+}
diff --git a/sdk/member_trait_test.go b/sdk/member_trait_test.go
new file mode 100644
index 0000000..a3db189
--- /dev/null
+++ b/sdk/member_trait_test.go
@@ -0,0 +1,287 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 sdk
+
+import (
+	"fmt"
+	"path/filepath"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/java"
+	"github.com/google/blueprint"
+)
+
+type fakeMemberTrait struct {
+	android.SdkMemberTraitBase
+}
+
+type fakeMemberType struct {
+	android.SdkMemberTypeBase
+}
+
+func (t *fakeMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+	for _, name := range names {
+		ctx.AddVariationDependencies(nil, dependencyTag, name)
+
+		if ctx.RequiresTrait(name, extraTrait) {
+			ctx.AddVariationDependencies(nil, dependencyTag, name+"_extra")
+		}
+		if ctx.RequiresTrait(name, specialTrait) {
+			ctx.AddVariationDependencies(nil, dependencyTag, name+"_special")
+		}
+	}
+}
+
+func (t *fakeMemberType) IsInstance(module android.Module) bool {
+	return true
+}
+
+func (t *fakeMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	moduleType := "java_import"
+	if ctx.RequiresTrait(extraTrait) {
+		moduleType = "java_test_import"
+	}
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, moduleType)
+}
+
+func (t *fakeMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &fakeMemberTypeProperties{}
+}
+
+type fakeMemberTypeProperties struct {
+	android.SdkMemberPropertiesBase
+
+	path android.Path
+}
+
+func (t *fakeMemberTypeProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	headerJars := variant.(java.ApexDependency).HeaderJars()
+	if len(headerJars) != 1 {
+		panic(fmt.Errorf("there must be only one header jar from %q", variant.Name()))
+	}
+
+	t.path = headerJars[0]
+}
+
+func (t *fakeMemberTypeProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if t.path != nil {
+		relative := filepath.Join("javalibs", t.path.Base())
+		ctx.SnapshotBuilder().CopyToSnapshot(t.path, relative)
+		propertySet.AddProperty("jars", []string{relative})
+	}
+}
+
+var (
+	extraTrait = &fakeMemberTrait{
+		SdkMemberTraitBase: android.SdkMemberTraitBase{
+			PropertyName: "extra",
+		},
+	}
+
+	specialTrait = &fakeMemberTrait{
+		SdkMemberTraitBase: android.SdkMemberTraitBase{
+			PropertyName: "special",
+		},
+	}
+
+	fakeType = &fakeMemberType{
+		SdkMemberTypeBase: android.SdkMemberTypeBase{
+			PropertyName: "fake_members",
+			SupportsSdk:  true,
+			Traits: []android.SdkMemberTrait{
+				extraTrait,
+				specialTrait,
+			},
+		},
+	}
+)
+
+func init() {
+	android.RegisterSdkMemberTrait(extraTrait)
+	android.RegisterSdkMemberTrait(specialTrait)
+	android.RegisterSdkMemberType(fakeType)
+}
+
+func TestBasicTrait_WithoutTrait(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				fake_members: ["myjavalib"],
+			}
+
+			java_library {
+				name: "myjavalib",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+		`),
+	).RunTest(t)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "myjavalib",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/myjavalib.jar"],
+}
+`),
+		checkVersionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/myjavalib.jar"],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    visibility: ["//visibility:public"],
+    fake_members: ["mysdk_myjavalib@current"],
+}
+`),
+	)
+}
+
+func TestBasicTrait_MultipleTraits(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				fake_members: ["myjavalib", "anotherjavalib"],
+				traits: {
+					extra: ["myjavalib"],
+					special: ["myjavalib", "anotherjavalib"],
+				},
+			}
+
+			java_library {
+				name: "myjavalib",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+
+			java_library {
+				name: "myjavalib_extra",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+
+			java_library {
+				name: "myjavalib_special",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+
+			java_library {
+				name: "anotherjavalib",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+
+			java_library {
+				name: "anotherjavalib_special",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+		`),
+	).RunTest(t)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_test_import {
+    name: "myjavalib",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/myjavalib.jar"],
+}
+
+java_import {
+    name: "myjavalib_extra",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/myjavalib_extra.jar"],
+}
+
+java_import {
+    name: "myjavalib_special",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/myjavalib_special.jar"],
+}
+
+java_import {
+    name: "anotherjavalib",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/anotherjavalib.jar"],
+}
+
+java_import {
+    name: "anotherjavalib_special",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["javalibs/anotherjavalib_special.jar"],
+}
+`),
+	)
+}
+
+func TestTraitUnsupportedByMemberType(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				java_header_libs: ["myjavalib"],
+				traits: {
+					extra: ["myjavalib"],
+				},
+			}
+
+			java_library {
+				name: "myjavalib",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+			}
+		`),
+	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+		`\Qsdk member "myjavalib" has traits [extra] that are unsupported by its member type "java_header_libs"\E`)).
+		RunTest(t)
+}
diff --git a/sdk/member_type.go b/sdk/member_type.go
index 9aab61d..10669fe 100644
--- a/sdk/member_type.go
+++ b/sdk/member_type.go
@@ -64,14 +64,7 @@
 	return reflect.New(d.propertiesStructType).Interface()
 }
 
-func getDynamicSdkMemberTypes(registry *android.SdkMemberTypesRegistry) *dynamicSdkMemberTypes {
-
-	// Get a key that uniquely identifies the registry contents.
-	key := registry.UniqueOnceKey()
-
-	// Get the registered types.
-	registeredTypes := registry.RegisteredTypes()
-
+func getDynamicSdkMemberTypes(key android.OnceKey, registeredTypes []android.SdkMemberType) *dynamicSdkMemberTypes {
 	// Get the cached value, creating new instance if necessary.
 	return dynamicSdkMemberTypesMap.Once(key, func() interface{} {
 		return createDynamicSdkMemberTypes(registeredTypes)
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 6dea752..84c9a96 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -53,6 +53,13 @@
 	// list properties, e.g. java_libs.
 	dynamicMemberTypeListProperties interface{}
 
+	// The dynamically generated information about the registered SdkMemberTrait
+	dynamicSdkMemberTraits *dynamicSdkMemberTraits
+
+	// The dynamically created instance of the properties struct containing the sdk member trait
+	// list properties.
+	dynamicMemberTraitListProperties interface{}
+
 	// Information about the OsType specific member variants depended upon by this variant.
 	//
 	// Set by OsType specific variants in the collectMembers() method and used by the
@@ -104,17 +111,25 @@
 	s := &sdk{}
 	s.properties.Module_exports = moduleExports
 	// Get the dynamic sdk member type data for the currently registered sdk member types.
-	var typeRegistry *android.SdkMemberTypesRegistry
-	if moduleExports {
-		typeRegistry = android.ModuleExportsMemberTypes
-	} else {
-		typeRegistry = android.SdkMemberTypes
-	}
-	s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(typeRegistry)
+	sdkMemberTypeKey, sdkMemberTypes := android.RegisteredSdkMemberTypes(moduleExports)
+	s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(sdkMemberTypeKey, sdkMemberTypes)
 	// Create an instance of the dynamically created struct that contains all the
 	// properties for the member type specific list properties.
 	s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberTypeListProperties()
-	s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties)
+
+	sdkMemberTraitsKey, sdkMemberTraits := android.RegisteredSdkMemberTraits()
+	s.dynamicSdkMemberTraits = getDynamicSdkMemberTraits(sdkMemberTraitsKey, sdkMemberTraits)
+	// Create an instance of the dynamically created struct that contains all the properties for the
+	// member trait specific list properties.
+	s.dynamicMemberTraitListProperties = s.dynamicSdkMemberTraits.createMemberTraitListProperties()
+
+	// Create a wrapper around the dynamic trait specific properties so that they have to be
+	// specified within a traits:{} section in the .bp file.
+	traitsWrapper := struct {
+		Traits interface{}
+	}{s.dynamicMemberTraitListProperties}
+
+	s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties, &traitsWrapper)
 
 	// Make sure that the prebuilt visibility property is verified for errors.
 	android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility)
@@ -145,6 +160,11 @@
 	return s.dynamicSdkMemberTypes.memberTypeToProperty[memberType]
 }
 
+// memberTraitListProperties returns the list of *sdkMemberTraitListProperty instances for this sdk.
+func (s *sdk) memberTraitListProperties() []*sdkMemberTraitListProperty {
+	return s.dynamicSdkMemberTraits.memberTraitListProperties
+}
+
 func (s *sdk) snapshot() bool {
 	return s.properties.Snapshot
 }
@@ -198,15 +218,53 @@
 	}}
 }
 
+// gatherTraits gathers the traits from the dynamically generated trait specific properties.
+//
+// Returns a map from member name to the set of required traits.
+func (s *sdk) gatherTraits() map[string]android.SdkMemberTraitSet {
+	traitListByMember := map[string][]android.SdkMemberTrait{}
+	for _, memberListProperty := range s.memberTraitListProperties() {
+		names := memberListProperty.getter(s.dynamicMemberTraitListProperties)
+		for _, name := range names {
+			traitListByMember[name] = append(traitListByMember[name], memberListProperty.memberTrait)
+		}
+	}
+
+	traitSetByMember := map[string]android.SdkMemberTraitSet{}
+	for name, list := range traitListByMember {
+		traitSetByMember[name] = android.NewSdkMemberTraitSet(list)
+	}
+
+	return traitSetByMember
+}
+
 // newDependencyContext creates a new SdkDependencyContext for this sdk.
 func (s *sdk) newDependencyContext(mctx android.BottomUpMutatorContext) android.SdkDependencyContext {
+	traits := s.gatherTraits()
+
 	return &dependencyContext{
 		BottomUpMutatorContext: mctx,
+		requiredTraits:         traits,
 	}
 }
 
 type dependencyContext struct {
 	android.BottomUpMutatorContext
+
+	// Map from member name to the set of traits that the sdk requires the member provides.
+	requiredTraits map[string]android.SdkMemberTraitSet
+}
+
+func (d *dependencyContext) RequiredTraits(name string) android.SdkMemberTraitSet {
+	if s, ok := d.requiredTraits[name]; ok {
+		return s
+	} else {
+		return android.EmptySdkMemberTraitSet()
+	}
+}
+
+func (d *dependencyContext) RequiresTrait(name string, trait android.SdkMemberTrait) bool {
+	return d.RequiredTraits(name).Contains(trait)
 }
 
 var _ android.SdkDependencyContext = (*dependencyContext)(nil)
@@ -287,8 +345,21 @@
 				}
 				names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
 				if len(names) > 0 {
+					memberType := memberListProperty.memberType
+
+					// Verify that the member type supports the specified traits.
+					supportedTraits := memberType.SupportedTraits()
+					for _, name := range names {
+						requiredTraits := ctx.RequiredTraits(name)
+						unsupportedTraits := requiredTraits.Subtract(supportedTraits)
+						if !unsupportedTraits.Empty() {
+							ctx.ModuleErrorf("sdk member %q has traits %s that are unsupported by its member type %q", name, unsupportedTraits, memberType.SdkPropertyName())
+						}
+					}
+
+					// Add dependencies using the appropriate tag.
 					tag := memberListProperty.dependencyTag
-					memberListProperty.memberType.AddDependencies(ctx, tag, names)
+					memberType.AddDependencies(ctx, tag, names)
 				}
 			}
 		}
diff --git a/sdk/update.go b/sdk/update.go
index 89a5c92..02e61fb 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -393,10 +393,18 @@
 	members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
 
 	// Create the prebuilt modules for each of the member modules.
+	traits := s.gatherTraits()
 	for _, member := range members {
 		memberType := member.memberType
 
-		memberCtx := &memberContext{ctx, builder, memberType, member.name}
+		name := member.name
+		requiredTraits := traits[name]
+		if requiredTraits == nil {
+			requiredTraits = android.EmptySdkMemberTraitSet()
+		}
+
+		// Create the snapshot for the member.
+		memberCtx := &memberContext{ctx, builder, memberType, name, requiredTraits}
 
 		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
 		s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
@@ -1385,19 +1393,19 @@
 	osInfo.Properties = osSpecificVariantPropertiesFactory()
 
 	// Group the variants by arch type.
-	var variantsByArchName = make(map[string][]android.Module)
-	var archTypes []android.ArchType
+	var variantsByArchId = make(map[archId][]android.Module)
+	var archIds []archId
 	for _, variant := range osTypeVariants {
-		archType := variant.Target().Arch.ArchType
-		archTypeName := archType.Name
-		if _, ok := variantsByArchName[archTypeName]; !ok {
-			archTypes = append(archTypes, archType)
+		target := variant.Target()
+		id := archIdFromTarget(target)
+		if _, ok := variantsByArchId[id]; !ok {
+			archIds = append(archIds, id)
 		}
 
-		variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
+		variantsByArchId[id] = append(variantsByArchId[id], variant)
 	}
 
-	if commonVariants, ok := variantsByArchName["common"]; ok {
+	if commonVariants, ok := variantsByArchId[commonArchId]; ok {
 		if len(osTypeVariants) != 1 {
 			panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
 		}
@@ -1407,11 +1415,9 @@
 		osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
 	} else {
 		// Create an arch specific info for each supported architecture type.
-		for _, archType := range archTypes {
-			archTypeName := archType.Name
-
-			archVariants := variantsByArchName[archTypeName]
-			archInfo := newArchSpecificInfo(ctx, archType, osType, osSpecificVariantPropertiesFactory, archVariants)
+		for _, id := range archIds {
+			archVariants := variantsByArchId[id]
+			archInfo := newArchSpecificInfo(ctx, id, osType, osSpecificVariantPropertiesFactory, archVariants)
 
 			osInfo.archInfos = append(osInfo.archInfos, archInfo)
 		}
@@ -1430,7 +1436,7 @@
 
 	multilib := multilibNone
 	for _, archInfo := range osInfo.archInfos {
-		multilib = multilib.addArchType(archInfo.archType)
+		multilib = multilib.addArchType(archInfo.archId.archType)
 
 		// Optimize the arch properties first.
 		archInfo.optimizeProperties(ctx, commonValueExtractor)
@@ -1523,11 +1529,55 @@
 	return fmt.Sprintf("OsType{%s}", osInfo.osType)
 }
 
+// archId encapsulates the information needed to identify a combination of arch type and native
+// bridge support.
+//
+// Conceptually, native bridge support is a facet of an android.Target, not an android.Arch as it is
+// essentially using one android.Arch to implement another. However, in terms of the handling of
+// the variants native bridge is treated as part of the arch variation. See the ArchVariation method
+// on android.Target.
+//
+// So, it makes sense when optimizing the variants to combine native bridge with the arch type.
+type archId struct {
+	// The arch type of the variant's target.
+	archType android.ArchType
+
+	// True if the variants is for the native bridge, false otherwise.
+	nativeBridge bool
+}
+
+// propertyName returns the name of the property corresponding to use for this arch id.
+func (i *archId) propertyName() string {
+	name := i.archType.Name
+	if i.nativeBridge {
+		// Note: This does not result in a valid property because there is no architecture specific
+		// native bridge property, only a generic "native_bridge" property. However, this will be used
+		// in error messages if there is an attempt to use this in a generated bp file.
+		name += "_native_bridge"
+	}
+	return name
+}
+
+func (i *archId) String() string {
+	return fmt.Sprintf("ArchType{%s}, NativeBridge{%t}", i.archType, i.nativeBridge)
+}
+
+// archIdFromTarget returns an archId initialized from information in the supplied target.
+func archIdFromTarget(target android.Target) archId {
+	return archId{
+		archType:     target.Arch.ArchType,
+		nativeBridge: target.NativeBridge == android.NativeBridgeEnabled,
+	}
+}
+
+// commonArchId is the archId for the common architecture.
+var commonArchId = archId{archType: android.Common}
+
 type archTypeSpecificInfo struct {
 	baseInfo
 
-	archType android.ArchType
-	osType   android.OsType
+	archId archId
+	osType android.OsType
 
 	linkInfos []*linkTypeSpecificInfo
 }
@@ -1536,10 +1586,10 @@
 
 // Create a new archTypeSpecificInfo for the specified arch type and its properties
 // structures populated with information from the variants.
-func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
+func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
 
 	// Create an arch specific info into which the variant properties can be copied.
-	archInfo := &archTypeSpecificInfo{archType: archType, osType: osType}
+	archInfo := &archTypeSpecificInfo{archId: archId, osType: osType}
 
 	// Create the properties into which the arch type specific properties will be
 	// added.
@@ -1597,8 +1647,9 @@
 
 // Add the properties for an arch type to a property set.
 func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
-	archTypeName := archInfo.archType.Name
-	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
+	archPropertySuffix := archInfo.archId.propertyName()
+	propertySetName := archOsPrefix + archPropertySuffix
+	archTypePropertySet := archPropertySet.AddPropertySet(propertySetName)
 	// Enable the <os>_<arch> variant explicitly when we've disabled it by default on host.
 	if ctx.memberType.IsHostOsDependent() && archInfo.osType.Class == android.Host {
 		archTypePropertySet.AddProperty("enabled", true)
@@ -1608,10 +1659,36 @@
 	for _, linkInfo := range archInfo.linkInfos {
 		linkInfo.addToPropertySet(ctx, archTypePropertySet)
 	}
+
+	// If this is for a native bridge architecture then make sure that the property set does not
+	// contain any properties as providing native bridge specific properties is not currently
+	// supported.
+	if archInfo.archId.nativeBridge {
+		propertySetContents := getPropertySetContents(archTypePropertySet)
+		if propertySetContents != "" {
+			ctx.SdkModuleContext().ModuleErrorf("Architecture variant %q of sdk member %q has properties distinct from other variants; this is not yet supported. The properties are:\n%s",
+				propertySetName, ctx.name, propertySetContents)
+		}
+	}
+}
+
+// getPropertySetContents returns the string representation of the contents of a property set, after
+// recursively pruning any empty nested property sets.
+func getPropertySetContents(propertySet android.BpPropertySet) string {
+	set := propertySet.(*bpPropertySet)
+	set.transformContents(pruneEmptySetTransformer{})
+	if len(set.properties) != 0 {
+		contents := &generatedContents{}
+		contents.Indent()
+		outputPropertySet(contents, set)
+		setAsString := contents.content.String()
+		return setAsString
+	}
+	return ""
 }
 
 func (archInfo *archTypeSpecificInfo) String() string {
-	return fmt.Sprintf("ArchType{%s}", archInfo.archType)
+	return archInfo.archId.String()
 }
 
 type linkTypeSpecificInfo struct {
@@ -1651,6 +1728,9 @@
 	builder          *snapshotBuilder
 	memberType       android.SdkMemberType
 	name             string
+
+	// The set of traits required of this member.
+	requiredTraits android.SdkMemberTraitSet
 }
 
 func (m *memberContext) SdkModuleContext() android.ModuleContext {
@@ -1669,6 +1749,10 @@
 	return m.name
 }
 
+func (m *memberContext) RequiresTrait(trait android.SdkMemberTrait) bool {
+	return m.requiredTraits.Contains(trait)
+}
+
 func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
 
 	memberType := member.memberType