Merge "Generate empty classpaths.proto for bootclasspath_fragment.go."
diff --git a/android/sdk.go b/android/sdk.go
index 0adfd89..36c576d 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -284,11 +284,20 @@
 	// Add a property set with the specified name and return so that additional
 	// properties can be added.
 	AddPropertySet(name string) BpPropertySet
+
+	// Add comment for property (or property set).
+	AddCommentForProperty(name, text string)
 }
 
 // A .bp module definition.
 type BpModule interface {
 	BpPropertySet
+
+	// ModuleType returns the module type of the module
+	ModuleType() string
+
+	// Name returns the name of the module or "" if no name has been specified.
+	Name() string
 }
 
 // An individual member of the SDK, includes all of the variants that the SDK
@@ -380,6 +389,10 @@
 	// The name of the member type property on an sdk module.
 	SdkPropertyName() string
 
+	// RequiresBpProperty returns true if this member type requires its property to be usable within
+	// an Android.bp file.
+	RequiresBpProperty() bool
+
 	// True if the member type supports the sdk/sdk_snapshot, false otherwise.
 	UsableWithSdkAndSdkSnapshot() bool
 
@@ -405,6 +418,10 @@
 	// the module is not allowed in whichever sdk property it was added.
 	IsInstance(module Module) bool
 
+	// UsesSourceModuleTypeInSnapshot returns true when the AddPrebuiltModule() method returns a
+	// source module type.
+	UsesSourceModuleTypeInSnapshot() bool
+
 	// Add a prebuilt module that the sdk will populate.
 	//
 	// The sdk module code generates the snapshot as follows:
@@ -448,15 +465,29 @@
 
 // Base type for SdkMemberType implementations.
 type SdkMemberTypeBase struct {
-	PropertyName    string
+	PropertyName string
+
+	// When set to true BpPropertyNotRequired indicates that the member type does not require the
+	// property to be specifiable in an Android.bp file.
+	BpPropertyNotRequired bool
+
 	SupportsSdk     bool
 	HostOsDependent bool
+
+	// When set to true UseSourceModuleTypeInSnapshot indicates that the member type creates a source
+	// module type in its SdkMemberType.AddPrebuiltModule() method. That prevents the sdk snapshot
+	// code from automatically adding a prefer: true flag.
+	UseSourceModuleTypeInSnapshot bool
 }
 
 func (b *SdkMemberTypeBase) SdkPropertyName() string {
 	return b.PropertyName
 }
 
+func (b *SdkMemberTypeBase) RequiresBpProperty() bool {
+	return !b.BpPropertyNotRequired
+}
+
 func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
 	return b.SupportsSdk
 }
@@ -465,6 +496,10 @@
 	return b.HostOsDependent
 }
 
+func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool {
+	return b.UseSourceModuleTypeInSnapshot
+}
+
 // Encapsulates the information about registered SdkMemberTypes.
 type SdkMemberTypesRegistry struct {
 	// The list of types sorted by property name.
diff --git a/apex/apex.go b/apex/apex.go
index 7ceb00b..2c0df27 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -50,10 +50,15 @@
 	ctx.RegisterModuleType("override_apex", overrideApexFactory)
 	ctx.RegisterModuleType("apex_set", apexSetFactory)
 
+	ctx.PreArchMutators(registerPreArchMutators)
 	ctx.PreDepsMutators(RegisterPreDepsMutators)
 	ctx.PostDepsMutators(RegisterPostDepsMutators)
 }
 
+func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
+	ctx.TopDown("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel()
+}
+
 func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
 	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 9bc5720..c7cdbfa 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -40,17 +40,29 @@
 // This is intentionally not registered by name as it is not intended to be used from within an
 // `Android.bp` file.
 
-// Properties that are specific to `deapexer` but which need to be provided on the `prebuilt_apex`
-// module.`
-type DeapexerProperties struct {
-	// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
-	// APEX bundle will create an APEX variant and provide dex implementation jars for use by
-	// dexpreopt and boot jars package check.
-	Exported_java_libs []string
+// DeapexerExportedFile defines the properties needed to expose a file from the deapexer module.
+type DeapexerExportedFile struct {
+	// The tag parameter which must be passed to android.OutputFileProducer OutputFiles(tag) method
+	// to retrieve the path to the unpacked file.
+	Tag string
 
-	// List of bootclasspath fragments inside this prebuiltd APEX bundle and for which this APEX
-	// bundle will create an APEX variant.
-	Exported_bootclasspath_fragments []string
+	// The path within the APEX that needs to be exported.
+	Path string `android:"path"`
+}
+
+// DeapexerProperties specifies the properties supported by the deapexer module.
+//
+// As these are never intended to be supplied in a .bp file they use a different naming convention
+// to make it clear that they are different.
+type DeapexerProperties struct {
+	// List of common modules that may need access to files exported by this module.
+	//
+	// A common module in this sense is one that is not arch specific but uses a common variant for
+	// all architectures, e.g. java.
+	CommonModules []string
+
+	// List of files exported from the .apex file by this module
+	ExportedFiles []DeapexerExportedFile
 }
 
 type SelectedApexProperties struct {
@@ -81,7 +93,7 @@
 func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies from the java modules to which this exports files from the `.apex` file onto
 	// this module so that they can access the `DeapexerInfo` object that this provides.
-	for _, lib := range p.properties.Exported_java_libs {
+	for _, lib := range p.properties.CommonModules {
 		dep := prebuiltApexExportedModuleName(ctx, lib)
 		ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
 	}
@@ -96,10 +108,12 @@
 	exports := make(map[string]android.Path)
 
 	// Create mappings from name+tag to all the required exported paths.
-	for _, l := range p.properties.Exported_java_libs {
-		// Populate the exports that this makes available. The path here must match the path of the
-		// file in the APEX created by apexFileForJavaModule(...).
-		exports[l+"{.dexjar}"] = deapexerOutput.Join(ctx, "javalib", l+".jar")
+	for _, e := range p.properties.ExportedFiles {
+		tag := e.Tag
+		path := e.Path
+
+		// Populate the exports that this makes available.
+		exports[tag] = deapexerOutput.Join(ctx, path)
 	}
 
 	// If the prebuilt_apex exports any files then create a build rule that unpacks the apex using
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 8996352..9d632a9 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"strconv"
 	"strings"
 
@@ -46,11 +47,10 @@
 }
 
 type prebuiltCommon struct {
-	prebuilt   android.Prebuilt
-	properties prebuiltCommonProperties
+	prebuilt android.Prebuilt
 
-	deapexerProperties     DeapexerProperties
-	selectedApexProperties SelectedApexProperties
+	// Properties common to both prebuilt_apex and apex_set.
+	prebuiltCommonProperties prebuiltCommonProperties
 }
 
 type sanitizedPrebuilt interface {
@@ -58,7 +58,18 @@
 }
 
 type prebuiltCommonProperties struct {
+	SelectedApexProperties
+
 	ForceDisable bool `blueprint:"mutated"`
+
+	// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
+	// APEX bundle will create an APEX variant and provide dex implementation jars for use by
+	// dexpreopt and boot jars package check.
+	Exported_java_libs []string
+
+	// List of bootclasspath fragments inside this prebuilt APEX bundle and for which this APEX
+	// bundle will create an APEX variant.
+	Exported_bootclasspath_fragments []string
 }
 
 func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
@@ -66,7 +77,7 @@
 }
 
 func (p *prebuiltCommon) isForceDisabled() bool {
-	return p.properties.ForceDisable
+	return p.prebuiltCommonProperties.ForceDisable
 }
 
 func (p *prebuiltCommon) checkForceDisable(ctx android.ModuleContext) bool {
@@ -88,25 +99,47 @@
 	forceDisable = forceDisable || (android.InList("hwaddress", ctx.Config().SanitizeDevice()) && !sanitized.hasSanitizedSource("hwaddress"))
 
 	if forceDisable && p.prebuilt.SourceExists() {
-		p.properties.ForceDisable = true
+		p.prebuiltCommonProperties.ForceDisable = true
 		return true
 	}
 	return false
 }
 
-func (p *prebuiltCommon) deapexerDeps(ctx android.BottomUpMutatorContext) {
+// prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and
+// apex_set in order to create the modules needed to provide access to the prebuilt .apex file.
+type prebuiltApexModuleCreator interface {
+	createPrebuiltApexModules(ctx android.TopDownMutatorContext)
+}
+
+// prebuiltApexModuleCreatorMutator is the mutator responsible for invoking the
+// prebuiltApexModuleCreator's createPrebuiltApexModules method.
+//
+// It is registered as a pre-arch mutator as it must run after the ComponentDepsMutator because it
+// will need to access dependencies added by that (exported modules) but must run before the
+// DepsMutator so that the deapexer module it creates can add dependencies onto itself from the
+// exported modules.
+func prebuiltApexModuleCreatorMutator(ctx android.TopDownMutatorContext) {
+	module := ctx.Module()
+	if creator, ok := module.(prebuiltApexModuleCreator); ok {
+		creator.createPrebuiltApexModules(ctx)
+	}
+}
+
+// prebuiltApexContentsDeps adds dependencies onto the prebuilt apex module's contents.
+func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorContext) {
+	module := ctx.Module()
 	// Add dependencies onto the java modules that represent the java libraries that are provided by
 	// and exported from this prebuilt apex.
-	for _, exported := range p.deapexerProperties.Exported_java_libs {
-		dep := prebuiltApexExportedModuleName(ctx, exported)
-		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
+	for _, exported := range p.prebuiltCommonProperties.Exported_java_libs {
+		dep := android.PrebuiltNameFromSource(exported)
+		ctx.AddDependency(module, exportedJavaLibTag, dep)
 	}
 
 	// Add dependencies onto the bootclasspath fragment modules that are exported from this prebuilt
 	// apex.
-	for _, exported := range p.deapexerProperties.Exported_bootclasspath_fragments {
-		dep := prebuiltApexExportedModuleName(ctx, exported)
-		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedBootclasspathFragmentTag, dep)
+	for _, exported := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments {
+		dep := android.PrebuiltNameFromSource(exported)
+		ctx.AddDependency(module, exportedBootclasspathFragmentTag, dep)
 	}
 }
 
@@ -240,8 +273,7 @@
 	android.ModuleBase
 	prebuiltCommon
 
-	properties             PrebuiltProperties
-	selectedApexProperties SelectedApexProperties
+	properties PrebuiltProperties
 
 	inputApex       android.Path
 	installDir      android.InstallPath
@@ -354,58 +386,16 @@
 }
 
 // prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
-//
-// If this needs to make files from within a `.apex` file available for use by other Soong modules,
-// e.g. make dex implementation jars available for java_import modules isted in exported_java_libs,
-// it does so as follows:
-//
-// 1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
-//    makes them available for use by other modules, at both Soong and ninja levels.
-//
-// 2. It adds a dependency onto those modules and creates an apex specific variant similar to what
-//    an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
-//    dexpreopt, will work the same way from source and prebuilt.
-//
-// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
-//    itself so that they can retrieve the file paths to those files.
-//
-// It also creates a child module `selector` that is responsible for selecting the appropriate
-// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
-// 1. To dedup the selection logic so it only runs in one module.
-// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
-//    `apex_set`.
-//
-//                     prebuilt_apex
-//                    /      |      \
-//                 /         |         \
-//              V            |            V
-//       selector  <---  deapexer  <---  exported java lib
-//
 func PrebuiltFactory() android.Module {
 	module := &Prebuilt{}
-	module.AddProperties(&module.properties, &module.deapexerProperties, &module.selectedApexProperties)
-	android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+	module.AddProperties(&module.properties, &module.prebuiltCommonProperties)
+	android.InitSingleSourcePrebuiltModule(module, &module.prebuiltCommonProperties, "Selected_apex")
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		baseModuleName := module.BaseModuleName()
-
-		apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
-		createApexSelectorModule(ctx, apexSelectorModuleName, &module.properties.ApexFileProperties)
-
-		apexFileSource := ":" + apexSelectorModuleName
-		if len(module.deapexerProperties.Exported_java_libs) != 0 {
-			createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
-		}
-
-		// Add a source reference to retrieve the selected apex from the selector module.
-		module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
-	})
-
 	return module
 }
 
-func createApexSelectorModule(ctx android.LoadHookContext, name string, apexFileProperties *ApexFileProperties) {
+func createApexSelectorModule(ctx android.TopDownMutatorContext, name string, apexFileProperties *ApexFileProperties) {
 	props := struct {
 		Name *string
 	}{
@@ -418,7 +408,54 @@
 	)
 }
 
-func createDeapexerModule(ctx android.LoadHookContext, deapexerName string, apexFileSource string, deapexerProperties *DeapexerProperties) {
+// createDeapexerModuleIfNeeded will create a deapexer module if it is needed.
+//
+// A deapexer module is only needed when the prebuilt apex specifies one or more modules in either
+// the `exported_java_libs` or `exported_bootclasspath_fragments` properties as that indicates that
+// the listed modules need access to files from within the prebuilt .apex file.
+func createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string, properties *prebuiltCommonProperties) {
+	// Only create the deapexer module if it is needed.
+	if len(properties.Exported_java_libs)+len(properties.Exported_bootclasspath_fragments) == 0 {
+		return
+	}
+
+	// Compute the deapexer properties from the transitive dependencies of this module.
+	javaModules := []string{}
+	exportedFiles := map[string]string{}
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		tag := ctx.OtherModuleDependencyTag(child)
+
+		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
+		if java.IsBootclasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
+			javaModules = append(javaModules, name)
+
+			// Add the dex implementation jar to the set of exported files. The path here must match the
+			// path of the file in the APEX created by apexFileForJavaModule(...).
+			exportedFiles[name+"{.dexjar}"] = filepath.Join("javalib", name+".jar")
+
+		} else if tag == exportedBootclasspathFragmentTag {
+			// Only visit the children of the bootclasspath_fragment for now.
+			return true
+		}
+
+		return false
+	})
+
+	// Create properties for deapexer module.
+	deapexerProperties := &DeapexerProperties{
+		// Remove any duplicates from the java modules lists as a module may be included via a direct
+		// dependency as well as transitive ones.
+		CommonModules: android.SortedUniqueStrings(javaModules),
+	}
+
+	// Populate the exported files property in a fixed order.
+	for _, tag := range android.SortedStringKeys(exportedFiles) {
+		deapexerProperties.ExportedFiles = append(deapexerProperties.ExportedFiles, DeapexerExportedFile{
+			Tag:  tag,
+			Path: exportedFiles[tag],
+		})
+	}
+
 	props := struct {
 		Name          *string
 		Selected_apex *string
@@ -479,8 +516,52 @@
 	exportedBootclasspathFragmentTag = exportedDependencyTag{name: "exported_bootclasspath_fragments"}
 )
 
-func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
-	p.deapexerDeps(ctx)
+var _ prebuiltApexModuleCreator = (*Prebuilt)(nil)
+
+// createPrebuiltApexModules creates modules necessary to export files from the prebuilt apex to the
+// build.
+//
+// If this needs to make files from within a `.apex` file available for use by other Soong modules,
+// e.g. make dex implementation jars available for java_import modules listed in exported_java_libs,
+// it does so as follows:
+//
+// 1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
+//    makes them available for use by other modules, at both Soong and ninja levels.
+//
+// 2. It adds a dependency onto those modules and creates an apex specific variant similar to what
+//    an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
+//    dexpreopt, will work the same way from source and prebuilt.
+//
+// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
+//    itself so that they can retrieve the file paths to those files.
+//
+// It also creates a child module `selector` that is responsible for selecting the appropriate
+// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
+// 1. To dedup the selection logic so it only runs in one module.
+// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
+//    `apex_set`.
+//
+//                     prebuilt_apex
+//                    /      |      \
+//                 /         |         \
+//              V            V            V
+//       selector  <---  deapexer  <---  exported java lib
+//
+func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
+	baseModuleName := p.BaseModuleName()
+
+	apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
+	createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
+
+	apexFileSource := ":" + apexSelectorModuleName
+	createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, &p.prebuiltCommonProperties)
+
+	// Add a source reference to retrieve the selected apex from the selector module.
+	p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+}
+
+func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+	p.prebuiltApexContentsDeps(ctx)
 }
 
 var _ ApexInfoMutator = (*Prebuilt)(nil)
@@ -491,7 +572,7 @@
 
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// TODO(jungjw): Check the key validity.
-	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
+	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
 	p.installFilename = p.InstallFilename()
 	if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
@@ -693,30 +774,15 @@
 // prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
 func apexSetFactory() android.Module {
 	module := &ApexSet{}
-	module.AddProperties(&module.properties, &module.selectedApexProperties, &module.deapexerProperties)
+	module.AddProperties(&module.properties, &module.prebuiltCommonProperties)
 
-	android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+	android.InitSingleSourcePrebuiltModule(module, &module.prebuiltCommonProperties, "Selected_apex")
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		baseModuleName := module.BaseModuleName()
-
-		apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
-		createApexExtractorModule(ctx, apexExtractorModuleName, &module.properties.ApexExtractorProperties)
-
-		apexFileSource := ":" + apexExtractorModuleName
-		if len(module.deapexerProperties.Exported_java_libs) != 0 {
-			createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
-		}
-
-		// After passing the arch specific src properties to the creating the apex selector module
-		module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
-	})
-
 	return module
 }
 
-func createApexExtractorModule(ctx android.LoadHookContext, name string, apexExtractorProperties *ApexExtractorProperties) {
+func createApexExtractorModule(ctx android.TopDownMutatorContext, name string, apexExtractorProperties *ApexExtractorProperties) {
 	props := struct {
 		Name *string
 	}{
@@ -733,8 +799,30 @@
 	return baseModuleName + ".apex.extractor"
 }
 
-func (a *ApexSet) DepsMutator(ctx android.BottomUpMutatorContext) {
-	a.deapexerDeps(ctx)
+var _ prebuiltApexModuleCreator = (*ApexSet)(nil)
+
+// createPrebuiltApexModules creates modules necessary to export files from the apex set to other
+// modules.
+//
+// This effectively does for apex_set what Prebuilt.createPrebuiltApexModules does for a
+// prebuilt_apex except that instead of creating a selector module which selects one .apex file
+// from those provided this creates an extractor module which extracts the appropriate .apex file
+// from the zip file containing them.
+func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
+	baseModuleName := a.BaseModuleName()
+
+	apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
+	createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
+
+	apexFileSource := ":" + apexExtractorModuleName
+	createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, &a.prebuiltCommonProperties)
+
+	// After passing the arch specific src properties to the creating the apex selector module
+	a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+}
+
+func (a *ApexSet) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+	a.prebuiltApexContentsDeps(ctx)
 }
 
 var _ ApexInfoMutator = (*ApexSet)(nil)
@@ -749,7 +837,7 @@
 		ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix)
 	}
 
-	inputApex := android.OptionalPathForModuleSrc(ctx, a.selectedApexProperties.Selected_apex).Path()
+	inputApex := android.OptionalPathForModuleSrc(ctx, a.prebuiltCommonProperties.Selected_apex).Path()
 	a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.Cp,
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c543ef8..407073a 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -257,24 +257,74 @@
 			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
 			dir:                                "foo/bar",
 			filesystem: map[string]string{
-				"foo/bar/a.cpp": "",
+				"foo/bar/both.cpp":       "",
+				"foo/bar/sharedonly.cpp": "",
+				"foo/bar/staticonly.cpp": "",
 				"foo/bar/Android.bp": `
 cc_library {
     name: "a",
-    shared: { whole_static_libs: ["b"] },
-    static: { srcs: ["a.cpp"] },
+    srcs: ["both.cpp"],
+    cflags: ["bothflag"],
+    shared_libs: ["shared_dep_for_both"],
+    static_libs: ["static_dep_for_both"],
+    whole_static_libs: ["whole_static_lib_for_both"],
+    static: {
+        srcs: ["staticonly.cpp"],
+        cflags: ["staticflag"],
+        shared_libs: ["shared_dep_for_static"],
+        static_libs: ["static_dep_for_static"],
+        whole_static_libs: ["whole_static_lib_for_static"],
+    },
+    shared: {
+        srcs: ["sharedonly.cpp"],
+        cflags: ["sharedflag"],
+        shared_libs: ["shared_dep_for_shared"],
+        static_libs: ["static_dep_for_shared"],
+        whole_static_libs: ["whole_static_lib_for_shared"],
+    },
     bazel_module: { bp2build_available: true },
 }
 
-cc_library_static { name: "b" }
+cc_library_static { name: "static_dep_for_shared" }
+
+cc_library_static { name: "static_dep_for_static" }
+
+cc_library_static { name: "static_dep_for_both" }
+
+cc_library_static { name: "whole_static_lib_for_shared" }
+
+cc_library_static { name: "whole_static_lib_for_static" }
+
+cc_library_static { name: "whole_static_lib_for_both" }
+
+cc_library { name: "shared_dep_for_shared" }
+
+cc_library { name: "shared_dep_for_static" }
+
+cc_library { name: "shared_dep_for_both" }
 `,
 			},
 			bp: soongCcLibraryPreamble,
 			expectedBazelTargets: []string{`cc_library(
     name = "a",
-    copts = ["-Ifoo/bar"],
-    srcs = ["a.cpp"],
-    static_deps_for_shared = [":b"],
+    copts = [
+        "bothflag",
+        "-Ifoo/bar",
+    ],
+    deps = [":static_dep_for_both"],
+    dynamic_deps = [":shared_dep_for_both"],
+    dynamic_deps_for_shared = [":shared_dep_for_shared"],
+    dynamic_deps_for_static = [":shared_dep_for_static"],
+    shared_copts = ["sharedflag"],
+    shared_srcs = ["sharedonly.cpp"],
+    srcs = ["both.cpp"],
+    static_copts = ["staticflag"],
+    static_deps_for_shared = [":static_dep_for_shared"],
+    static_deps_for_static = [":static_dep_for_static"],
+    static_srcs = ["staticonly.cpp"],
+    whole_archive_deps = [":whole_static_lib_for_both"],
+    whole_archive_deps_for_shared = [":whole_static_lib_for_shared"],
+    whole_archive_deps_for_static = [":whole_static_lib_for_static"],
 )`},
 		},
 		{
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index bff9b07..d082db1 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -189,8 +189,6 @@
         ":header_lib_2",
         ":static_lib_1",
         ":static_lib_2",
-        ":whole_static_lib_1",
-        ":whole_static_lib_2",
     ],
     includes = [
         "export_include_dir_1",
@@ -201,6 +199,10 @@
         "foo_static1.cc",
         "foo_static2.cc",
     ],
+    whole_archive_deps = [
+        ":whole_static_lib_1",
+        ":whole_static_lib_2",
+    ],
 )`, `cc_library_static(
     name = "static_lib_1",
     copts = ["-I."],
@@ -423,13 +425,14 @@
     name = "foo_static",
     copts = ["-I."],
     deps = select({
-        "//build/bazel/platforms/arch:arm64": [
-            ":static_dep",
-            ":static_dep2",
-        ],
+        "//build/bazel/platforms/arch:arm64": [":static_dep"],
         "//conditions:default": [],
     }),
     linkstatic = True,
+    whole_archive_deps = select({
+        "//build/bazel/platforms/arch:arm64": [":static_dep2"],
+        "//conditions:default": [],
+    }),
 )`, `cc_library_static(
     name = "static_dep",
     copts = ["-I."],
@@ -458,13 +461,14 @@
     name = "foo_static",
     copts = ["-I."],
     deps = select({
-        "//build/bazel/platforms/os:android": [
-            ":static_dep",
-            ":static_dep2",
-        ],
+        "//build/bazel/platforms/os:android": [":static_dep"],
         "//conditions:default": [],
     }),
     linkstatic = True,
+    whole_archive_deps = select({
+        "//build/bazel/platforms/os:android": [":static_dep2"],
+        "//conditions:default": [],
+    }),
 )`, `cc_library_static(
     name = "static_dep",
     copts = ["-I."],
@@ -497,10 +501,7 @@
 			expectedBazelTargets: []string{`cc_library_static(
     name = "foo_static",
     copts = ["-I."],
-    deps = [
-        ":static_dep",
-        ":static_dep2",
-    ] + select({
+    deps = [":static_dep"] + select({
         "//build/bazel/platforms/arch:arm64": [":static_dep4"],
         "//conditions:default": [],
     }) + select({
@@ -508,6 +509,7 @@
         "//conditions:default": [],
     }),
     linkstatic = True,
+    whole_archive_deps = [":static_dep2"],
 )`, `cc_library_static(
     name = "static_dep",
     copts = ["-I."],
@@ -732,8 +734,7 @@
 cc_library_static { name: "static_dep" }
 cc_library_static {
     name: "foo_static",
-    static_libs: ["static_dep"],
-    whole_static_libs: ["static_dep"],
+    static_libs: ["static_dep", "static_dep"],
 }`,
 			expectedBazelTargets: []string{`cc_library_static(
     name = "foo_static",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 67f88e2..7d01986 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -85,7 +85,11 @@
 }
 
 type sharedAttributes struct {
-	staticDeps bazel.LabelListAttribute
+	copts            bazel.StringListAttribute
+	srcs             bazel.LabelListAttribute
+	staticDeps       bazel.LabelListAttribute
+	dynamicDeps      bazel.LabelListAttribute
+	wholeArchiveDeps bazel.LabelListAttribute
 }
 
 // bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
@@ -95,17 +99,35 @@
 		return sharedAttributes{}
 	}
 
-	var staticDeps bazel.LabelListAttribute
+	copts := bazel.StringListAttribute{Value: lib.SharedProperties.Shared.Cflags}
 
-	staticDeps.Value = android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)
+	srcs := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleSrc(ctx, lib.SharedProperties.Shared.Srcs)}
+
+	staticDeps := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Static_libs)}
+
+	dynamicDeps := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Shared_libs)}
+
+	wholeArchiveDeps := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)}
 
 	return sharedAttributes{
-		staticDeps: staticDeps,
+		copts:            copts,
+		srcs:             srcs,
+		staticDeps:       staticDeps,
+		dynamicDeps:      dynamicDeps,
+		wholeArchiveDeps: wholeArchiveDeps,
 	}
 }
 
 type staticAttributes struct {
-	srcs bazel.LabelListAttribute
+	copts            bazel.StringListAttribute
+	srcs             bazel.LabelListAttribute
+	staticDeps       bazel.LabelListAttribute
+	dynamicDeps      bazel.LabelListAttribute
+	wholeArchiveDeps bazel.LabelListAttribute
 }
 
 // bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
@@ -115,11 +137,26 @@
 		return staticAttributes{}
 	}
 
-	var srcs bazel.LabelListAttribute
-	srcs.Value = android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)
+	copts := bazel.StringListAttribute{Value: lib.StaticProperties.Static.Cflags}
+
+	srcs := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)}
+
+	staticDeps := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Static_libs)}
+
+	dynamicDeps := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Shared_libs)}
+
+	wholeArchiveDeps := bazel.LabelListAttribute{
+		Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Whole_static_libs)}
 
 	return staticAttributes{
-		srcs: srcs,
+		copts:            copts,
+		srcs:             srcs,
+		staticDeps:       staticDeps,
+		dynamicDeps:      dynamicDeps,
+		wholeArchiveDeps: wholeArchiveDeps,
 	}
 }
 
@@ -246,10 +283,11 @@
 
 // Convenience struct to hold all attributes parsed from linker properties.
 type linkerAttributes struct {
-	deps          bazel.LabelListAttribute
-	dynamicDeps   bazel.LabelListAttribute
-	linkopts      bazel.StringListAttribute
-	versionScript bazel.LabelAttribute
+	deps             bazel.LabelListAttribute
+	dynamicDeps      bazel.LabelListAttribute
+	wholeArchiveDeps bazel.LabelListAttribute
+	linkopts         bazel.StringListAttribute
+	versionScript    bazel.LabelAttribute
 }
 
 // FIXME(b/187655838): Use the existing linkerFlags() function instead of duplicating logic here
@@ -266,6 +304,7 @@
 func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
 	var deps bazel.LabelListAttribute
 	var dynamicDeps bazel.LabelListAttribute
+	var wholeArchiveDeps bazel.LabelListAttribute
 	var linkopts bazel.StringListAttribute
 	var versionScript bazel.LabelAttribute
 
@@ -274,11 +313,11 @@
 			libs := baseLinkerProps.Header_libs
 			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
 			libs = append(libs, baseLinkerProps.Static_libs...)
-			libs = append(libs, baseLinkerProps.Whole_static_libs...)
+			wholeArchiveLibs := baseLinkerProps.Whole_static_libs
 			libs = android.SortedUniqueStrings(libs)
 			deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs))
-
 			linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
+			wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
 
 			if baseLinkerProps.Version_script != nil {
 				versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
@@ -296,19 +335,19 @@
 			libs := baseLinkerProps.Header_libs
 			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
 			libs = append(libs, baseLinkerProps.Static_libs...)
-			libs = append(libs, baseLinkerProps.Whole_static_libs...)
+			wholeArchiveLibs := baseLinkerProps.Whole_static_libs
 			libs = android.SortedUniqueStrings(libs)
 			deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
-
 			linkopts.SetValueForArch(arch.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+			wholeArchiveDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
 
 			if baseLinkerProps.Version_script != nil {
 				versionScript.SetValueForArch(arch.Name,
 					android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
-
-				sharedLibs := baseLinkerProps.Shared_libs
-				dynamicDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
 			}
+
+			sharedLibs := baseLinkerProps.Shared_libs
+			dynamicDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
 		}
 	}
 
@@ -317,8 +356,9 @@
 			libs := baseLinkerProps.Header_libs
 			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
 			libs = append(libs, baseLinkerProps.Static_libs...)
-			libs = append(libs, baseLinkerProps.Whole_static_libs...)
+			wholeArchiveLibs := baseLinkerProps.Whole_static_libs
 			libs = android.SortedUniqueStrings(libs)
+			wholeArchiveDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
 			deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
 
 			linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps))
@@ -329,10 +369,11 @@
 	}
 
 	return linkerAttributes{
-		deps:          deps,
-		dynamicDeps:   dynamicDeps,
-		linkopts:      linkopts,
-		versionScript: versionScript,
+		deps:             deps,
+		dynamicDeps:      dynamicDeps,
+		wholeArchiveDeps: wholeArchiveDeps,
+		linkopts:         linkopts,
+		versionScript:    versionScript,
 	}
 }
 
diff --git a/cc/library.go b/cc/library.go
index 7e960a7..c5ff9b1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -220,16 +220,29 @@
 
 // For bp2build conversion.
 type bazelCcLibraryAttributes struct {
-	Srcs                   bazel.LabelListAttribute
-	Hdrs                   bazel.LabelListAttribute
-	Copts                  bazel.StringListAttribute
-	Linkopts               bazel.StringListAttribute
-	Deps                   bazel.LabelListAttribute
-	Dynamic_deps           bazel.LabelListAttribute
-	User_link_flags        bazel.StringListAttribute
-	Includes               bazel.StringListAttribute
-	Static_deps_for_shared bazel.LabelListAttribute
-	Version_script         bazel.LabelAttribute
+	// Attributes pertaining to both static and shared variants.
+	Srcs               bazel.LabelListAttribute
+	Hdrs               bazel.LabelListAttribute
+	Deps               bazel.LabelListAttribute
+	Dynamic_deps       bazel.LabelListAttribute
+	Whole_archive_deps bazel.LabelListAttribute
+	Copts              bazel.StringListAttribute
+	Includes           bazel.StringListAttribute
+	Linkopts           bazel.StringListAttribute
+	// Attributes pertaining to shared variant.
+	Shared_copts                  bazel.StringListAttribute
+	Shared_srcs                   bazel.LabelListAttribute
+	Static_deps_for_shared        bazel.LabelListAttribute
+	Dynamic_deps_for_shared       bazel.LabelListAttribute
+	Whole_archive_deps_for_shared bazel.LabelListAttribute
+	User_link_flags               bazel.StringListAttribute
+	Version_script                bazel.LabelAttribute
+	// Attributes pertaining to static variant.
+	Static_copts                  bazel.StringListAttribute
+	Static_srcs                   bazel.LabelListAttribute
+	Static_deps_for_static        bazel.LabelListAttribute
+	Dynamic_deps_for_static       bazel.LabelListAttribute
+	Whole_archive_deps_for_static bazel.LabelListAttribute
 }
 
 type bazelCcLibrary struct {
@@ -276,17 +289,26 @@
 
 	var srcs bazel.LabelListAttribute
 	srcs.Append(compilerAttrs.srcs)
-	srcs.Append(staticAttrs.srcs)
 
 	attrs := &bazelCcLibraryAttributes{
-		Srcs:                   srcs,
-		Copts:                  compilerAttrs.copts,
-		Linkopts:               linkerAttrs.linkopts,
-		Deps:                   linkerAttrs.deps,
-		Dynamic_deps:           linkerAttrs.dynamicDeps,
-		Version_script:         linkerAttrs.versionScript,
-		Static_deps_for_shared: sharedAttrs.staticDeps,
-		Includes:               exportedIncludes,
+		Srcs:                          srcs,
+		Deps:                          linkerAttrs.deps,
+		Dynamic_deps:                  linkerAttrs.dynamicDeps,
+		Whole_archive_deps:            linkerAttrs.wholeArchiveDeps,
+		Copts:                         compilerAttrs.copts,
+		Includes:                      exportedIncludes,
+		Linkopts:                      linkerAttrs.linkopts,
+		Shared_copts:                  sharedAttrs.copts,
+		Shared_srcs:                   sharedAttrs.srcs,
+		Static_deps_for_shared:        sharedAttrs.staticDeps,
+		Whole_archive_deps_for_shared: sharedAttrs.wholeArchiveDeps,
+		Dynamic_deps_for_shared:       sharedAttrs.dynamicDeps,
+		Version_script:                linkerAttrs.versionScript,
+		Static_copts:                  staticAttrs.copts,
+		Static_srcs:                   staticAttrs.srcs,
+		Static_deps_for_static:        staticAttrs.staticDeps,
+		Whole_archive_deps_for_static: staticAttrs.wholeArchiveDeps,
+		Dynamic_deps_for_static:       staticAttrs.dynamicDeps,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
@@ -2194,13 +2216,14 @@
 }
 
 type bazelCcLibraryStaticAttributes struct {
-	Copts      bazel.StringListAttribute
-	Srcs       bazel.LabelListAttribute
-	Deps       bazel.LabelListAttribute
-	Linkopts   bazel.StringListAttribute
-	Linkstatic bool
-	Includes   bazel.StringListAttribute
-	Hdrs       bazel.LabelListAttribute
+	Copts              bazel.StringListAttribute
+	Srcs               bazel.LabelListAttribute
+	Deps               bazel.LabelListAttribute
+	Whole_archive_deps bazel.LabelListAttribute
+	Linkopts           bazel.StringListAttribute
+	Linkstatic         bool
+	Includes           bazel.StringListAttribute
+	Hdrs               bazel.LabelListAttribute
 }
 
 type bazelCcLibraryStatic struct {
@@ -2221,9 +2244,11 @@
 	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
 
 	attrs := &bazelCcLibraryStaticAttributes{
-		Copts:      compilerAttrs.copts,
-		Srcs:       compilerAttrs.srcs,
-		Deps:       linkerAttrs.deps,
+		Copts:              compilerAttrs.copts,
+		Srcs:               compilerAttrs.srcs,
+		Deps:               linkerAttrs.deps,
+		Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+
 		Linkopts:   linkerAttrs.linkopts,
 		Linkstatic: true,
 		Includes:   exportedIncludes,
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 0f2fd54..e91546e 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -95,9 +95,6 @@
 				prebuilt_apex {
 					name: "com.android.art",
 					src: "art.apex",
-					exported_java_libs: [
-						"mybootlib",
-					],
 					exported_bootclasspath_fragments: [
 						"mybootclasspathfragment",
 					],
diff --git a/sdk/bp.go b/sdk/bp.go
index 11ec8c6..e2dace8 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -25,6 +25,7 @@
 type bpPropertySet struct {
 	properties map[string]interface{}
 	tags       map[string]android.BpPropertyTag
+	comments   map[string]string
 	order      []string
 }
 
@@ -133,10 +134,22 @@
 	return s.properties[name]
 }
 
+func (s *bpPropertySet) getOptionalValue(name string) (interface{}, bool) {
+	value, ok := s.properties[name]
+	return value, ok
+}
+
 func (s *bpPropertySet) getTag(name string) interface{} {
 	return s.tags[name]
 }
 
+func (s *bpPropertySet) AddCommentForProperty(name, text string) {
+	if s.comments == nil {
+		s.comments = map[string]string{}
+	}
+	s.comments[name] = strings.TrimSpace(text)
+}
+
 func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
 	var newOrder []string
 	for _, name := range s.order {
@@ -188,6 +201,12 @@
 	}
 }
 
+func (s *bpPropertySet) removeProperty(name string) {
+	delete(s.properties, name)
+	delete(s.tags, name)
+	_, s.order = android.RemoveFromList(name, s.order)
+}
+
 func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
 	if s.properties[name] != nil {
 		panic("Property %q already exists in property set")
@@ -216,6 +235,19 @@
 	moduleType string
 }
 
+func (m *bpModule) ModuleType() string {
+	return m.moduleType
+}
+
+func (m *bpModule) Name() string {
+	name, hasName := m.getOptionalValue("name")
+	if hasName {
+		return name.(string)
+	} else {
+		return ""
+	}
+}
+
 var _ android.BpModule = (*bpModule)(nil)
 
 type bpPropertyTransformer interface {
@@ -346,16 +378,26 @@
 // is unique within this file.
 func (f *bpFile) AddModule(module android.BpModule) {
 	m := module.(*bpModule)
-	if name, ok := m.getValue("name").(string); ok {
-		if f.modules[name] != nil {
-			panic(fmt.Sprintf("Module %q already exists in bp file", name))
-		}
-
-		f.modules[name] = m
-		f.order = append(f.order, m)
-	} else {
-		panic("Module does not have a name property, or it is not a string")
+	moduleType := module.ModuleType()
+	name := m.Name()
+	hasName := true
+	if name == "" {
+		// Use a prefixed module type as the name instead just in case this is something like a package
+		// of namespace module which does not require a name.
+		name = "#" + moduleType
+		hasName = false
 	}
+
+	if f.modules[name] != nil {
+		if hasName {
+			panic(fmt.Sprintf("Module %q already exists in bp file", name))
+		} else {
+			panic(fmt.Sprintf("Unnamed module type %q already exists in bp file", moduleType))
+		}
+	}
+
+	f.modules[name] = m
+	f.order = append(f.order, m)
 }
 
 func (f *bpFile) newModule(moduleType string) *bpModule {
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 624c0fa..b1c8aeb 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -169,23 +169,27 @@
 	var fields []reflect.StructField
 
 	// Iterate over the member types creating StructField and sdkMemberListProperty objects.
-	for f, memberType := range sdkMemberTypes {
+	nextFieldIndex := 0
+	for _, memberType := range sdkMemberTypes {
+
 		p := memberType.SdkPropertyName()
 
-		// Create a dynamic exported field for the member type's property.
-		fields = append(fields, reflect.StructField{
-			Name: proptools.FieldNameForProperty(p),
-			Type: reflect.TypeOf([]string{}),
-			Tag:  `android:"arch_variant"`,
-		})
+		var getter func(properties interface{}) []string
+		var setter func(properties interface{}, list []string)
+		if memberType.RequiresBpProperty() {
+			// Create a dynamic exported field for the member type's property.
+			fields = append(fields, reflect.StructField{
+				Name: proptools.FieldNameForProperty(p),
+				Type: reflect.TypeOf([]string{}),
+				Tag:  `android:"arch_variant"`,
+			})
 
-		// 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 := f
+			// 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
 
-		// Create an sdkMemberListProperty for the member type.
-		memberListProperty := &sdkMemberListProperty{
-			getter: func(properties interface{}) []string {
+			getter = func(properties interface{}) []string {
 				// The properties is expected to be of the following form (where
 				// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
 				//     properties *struct {<Module_types> []string, ....}
@@ -195,9 +199,9 @@
 				//
 				list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
 				return list
-			},
+			}
 
-			setter: func(properties interface{}, list []string) {
+			setter = func(properties interface{}, list []string) {
 				// The properties is expected to be of the following form (where
 				// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
 				//     properties *struct {<Module_types> []string, ....}
@@ -206,8 +210,13 @@
 				//    *properties.<Module_types> = list
 				//
 				reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list))
-			},
+			}
+		}
 
+		// Create an sdkMemberListProperty for the member type.
+		memberListProperty := &sdkMemberListProperty{
+			getter:     getter,
+			setter:     setter,
 			memberType: memberType,
 
 			// Dependencies added directly from member properties are always exported.
@@ -402,6 +411,9 @@
 		// Add dependencies from enabled and non CommonOS variants to the sdk member variants.
 		if s.Enabled() && !s.IsCommonOSVariant() {
 			for _, memberListProperty := range s.memberListProperties() {
+				if memberListProperty.getter == nil {
+					continue
+				}
 				names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
 				if len(names) > 0 {
 					tag := memberListProperty.dependencyTag
diff --git a/sdk/update.go b/sdk/update.go
index 853f6b0..a265676 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -266,8 +266,11 @@
 	}
 	s.builderForTests = builder
 
-	// Create the prebuilt modules for each of the member modules.
+	// Group the variants for each member module together and then group the members of each member
+	// type together.
 	members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
+
+	// Create the prebuilt modules for each of the member modules.
 	for _, member := range members {
 		memberType := member.memberType
 
@@ -284,11 +287,6 @@
 	// to internal members with a unique module name and setting prefer: false.
 	unversionedTransformer := unversionedTransformation{
 		builder: builder,
-		// Set the prefer based on the environment variable. This is a temporary work around to allow a
-		// snapshot to be created that sets prefer: true.
-		// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
-		//  dynamically at build time not at snapshot generation time.
-		prefer: ctx.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER"),
 	}
 
 	for _, unversioned := range builder.prebuiltOrder {
@@ -518,15 +516,19 @@
 		}
 
 		combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
-		memberTypeProperty := s.memberListProperty(memberVariantDep.memberType)
+		memberListProperty := s.memberListProperty(memberVariantDep.memberType)
 		memberName := ctx.OtherModuleName(memberVariantDep.variant)
 
+		if memberListProperty.getter == nil {
+			continue
+		}
+
 		// Append the member to the appropriate list, if it is not already present in the list.
-		memberList := memberTypeProperty.getter(combined.dynamicProperties)
+		memberList := memberListProperty.getter(combined.dynamicProperties)
 		if !android.InList(memberName, memberList) {
 			memberList = append(memberList, memberName)
 		}
-		memberTypeProperty.setter(combined.dynamicProperties, memberList)
+		memberListProperty.setter(combined.dynamicProperties, memberList)
 	}
 
 	return list
@@ -578,6 +580,9 @@
 
 	dynamicMemberTypeListProperties := combined.dynamicProperties
 	for _, memberListProperty := range s.memberListProperties() {
+		if memberListProperty.getter == nil {
+			continue
+		}
 		names := memberListProperty.getter(dynamicMemberTypeListProperties)
 		if len(names) > 0 {
 			propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
@@ -611,9 +616,11 @@
 func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
 	// Use a versioned name for the module but remember the original name for the
 	// snapshot.
-	name := module.getValue("name").(string)
+	name := module.Name()
 	module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
 	module.insertAfter("name", "sdk_member_name", name)
+	// Remove the prefer property if present as versioned modules never need marking with prefer.
+	module.removeProperty("prefer")
 	return module
 }
 
@@ -629,20 +636,12 @@
 type unversionedTransformation struct {
 	identityTransformation
 	builder *snapshotBuilder
-	prefer  bool
 }
 
 func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
 	// If the module is an internal member then use a unique name for it.
-	name := module.getValue("name").(string)
+	name := module.Name()
 	module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
-
-	// Set prefer. Setting this to false is not strictly required as that is the default but it does
-	// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to check
-	// the behavior when a prebuilt is preferred. It also makes it explicit what the default behavior
-	// is for the module.
-	module.insertAfter("name", "prefer", t.prefer)
-
 	return module
 }
 
@@ -693,12 +692,26 @@
 func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
 	contents.Indent()
 
+	addComment := func(name string) {
+		if text, ok := set.comments[name]; ok {
+			for _, line := range strings.Split(text, "\n") {
+				contents.Printfln("// %s", line)
+			}
+		}
+	}
+
 	// Output the properties first, followed by the nested sets. This ensures a
 	// consistent output irrespective of whether property sets are created before
 	// or after the properties. This simplifies the creation of the module.
 	for _, name := range set.order {
 		value := set.getValue(name)
 
+		// Do not write property sets in the properties phase.
+		if _, ok := value.(*bpPropertySet); ok {
+			continue
+		}
+
+		addComment(name)
 		switch v := value.(type) {
 		case []string:
 			length := len(v)
@@ -719,9 +732,6 @@
 		case bool:
 			contents.Printfln("%s: %t,", name, v)
 
-		case *bpPropertySet:
-			// Do not write property sets in the properties phase.
-
 		default:
 			contents.Printfln("%s: %q,", name, value)
 		}
@@ -733,6 +743,7 @@
 		// Only write property sets in the sets phase.
 		switch v := value.(type) {
 		case *bpPropertySet:
+			addComment(name)
 			contents.Printfln("%s: {", name)
 			outputPropertySet(contents, v)
 			contents.Printfln("},")
@@ -751,7 +762,9 @@
 func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
 	contents := &generatedContents{}
 	generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
-		return !strings.Contains(module.properties["name"].(string), "@")
+		name := module.Name()
+		// Include modules that are either unversioned or have no name.
+		return !strings.Contains(name, "@")
 	})
 	return contents.content.String()
 }
@@ -759,7 +772,9 @@
 func (s *sdk) GetVersionedAndroidBpContentsForTests() string {
 	contents := &generatedContents{}
 	generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
-		return strings.Contains(module.properties["name"].(string), "@")
+		name := module.Name()
+		// Include modules that are either versioned or have no name.
+		return name == "" || strings.Contains(name, "@")
 	})
 	return contents.content.String()
 }
@@ -1381,6 +1396,21 @@
 
 	memberType := member.memberType
 
+	// Do not add the prefer property if the member snapshot module is a source module type.
+	if !memberType.UsesSourceModuleTypeInSnapshot() {
+		// Set the prefer based on the environment variable. This is a temporary work around to allow a
+		// snapshot to be created that sets prefer: true.
+		// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
+		//  dynamically at build time not at snapshot generation time.
+		prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
+
+		// Set prefer. Setting this to false is not strictly required as that is the default but it does
+		// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
+		// check the behavior when a prebuilt is preferred. It also makes it explicit what the default
+		// behavior is for the module.
+		bpModule.insertAfter("name", "prefer", prefer)
+	}
+
 	// Group the variants by os type.
 	variantsByOsType := make(map[android.OsType][]android.Module)
 	variants := member.Variants()
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go
index 9932c1b..46588d4 100644
--- a/third_party/zip/android_test.go
+++ b/third_party/zip/android_test.go
@@ -140,3 +140,83 @@
 		t.Errorf("Expected UnompressedSize64 %d, got %d", w, g)
 	}
 }
+
+// Test for b/187485108: zip64 output can't be read by p7zip 16.02.
+func TestZip64P7ZipRecords(t *testing.T) {
+	if testing.Short() {
+		t.Skip("slow test; skipping")
+	}
+
+	const size = uint32max + 1
+	zipBytes := &bytes.Buffer{}
+	zip := NewWriter(zipBytes)
+	f, err := zip.CreateHeaderAndroid(&FileHeader{
+		Name:               "large",
+		Method:             Store,
+		UncompressedSize64: size,
+		CompressedSize64:   size,
+	})
+	if err != nil {
+		t.Fatalf("Create: %v", err)
+	}
+	_, err = f.Write(make([]byte, size))
+	if err != nil {
+		t.Fatalf("Write: %v", err)
+	}
+	err = zip.Close()
+	if err != nil {
+		t.Fatalf("Close: %v", err)
+	}
+
+	buf := zipBytes.Bytes()
+	p := findSignatureInBlock(buf)
+	if p < 0 {
+		t.Fatalf("Missing signature")
+	}
+
+	b := readBuf(buf[p+4:]) // skip signature
+	d := &directoryEnd{
+		diskNbr:            uint32(b.uint16()),
+		dirDiskNbr:         uint32(b.uint16()),
+		dirRecordsThisDisk: uint64(b.uint16()),
+		directoryRecords:   uint64(b.uint16()),
+		directorySize:      uint64(b.uint32()),
+		directoryOffset:    uint64(b.uint32()),
+		commentLen:         b.uint16(),
+	}
+
+	// p7zip 16.02 wants regular end record directoryRecords to be accurate.
+	if g, w := d.directoryRecords, uint64(1); g != w {
+		t.Errorf("wanted directoryRecords %d, got %d", w, g)
+	}
+
+	if g, w := d.directorySize, uint64(uint32max); g != w {
+		t.Errorf("wanted directorySize %d, got %d", w, g)
+	}
+
+	if g, w := d.directoryOffset, uint64(uint32max); g != w {
+		t.Errorf("wanted directoryOffset %d, got %d", w, g)
+	}
+
+	r := bytes.NewReader(buf)
+
+	p64, err := findDirectory64End(r, int64(p))
+	if err != nil {
+		t.Fatalf("findDirectory64End: %v", err)
+	}
+	if p < 0 {
+		t.Fatalf("findDirectory64End: not found")
+	}
+	err = readDirectory64End(r, p64, d)
+	if err != nil {
+		t.Fatalf("readDirectory64End: %v", err)
+	}
+
+	if g, w := d.directoryRecords, uint64(1); g != w {
+		t.Errorf("wanted directoryRecords %d, got %d", w, g)
+	}
+
+	if g, w := d.directoryOffset, uint64(uint32max); g <= w {
+		t.Errorf("wanted directoryOffset > %d, got %d", w, g)
+	}
+}
diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go
index 8dd986e..f526838 100644
--- a/third_party/zip/writer.go
+++ b/third_party/zip/writer.go
@@ -155,7 +155,14 @@
 
 		// store max values in the regular end record to signal that
 		// that the zip64 values should be used instead
-		records = uint16max
+		// BEGIN ANDROID CHANGE: only store uintmax for the number of entries in the regular
+		// end record if it doesn't fit.  p7zip 16.02 rejects zip files where the number of
+		// entries in the regular end record is larger than the number of entries counted
+		// in the central directory.
+		if records > uint16max {
+			records = uint16max
+		}
+		// END ANDROID CHANGE
 		size = uint32max
 		offset = uint32max
 	}