Merge "Make @soong_injection usable in standalone builds."
diff --git a/android/config.go b/android/config.go
index 3db7980..79917ad 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1564,6 +1564,15 @@
 	return false
 }
 
+// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
+// an empty string if not found.
+func (l *ConfiguredJarList) ApexOfJar(jar string) string {
+	if idx := IndexList(jar, l.jars); idx != -1 {
+		return l.Apex(IndexList(jar, l.jars))
+	}
+	return ""
+}
+
 // IndexOfJar returns the first pair with the given jar name on the list, or -1
 // if not found.
 func (l *ConfiguredJarList) IndexOfJar(jar string) int {
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/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index f0f51bf..5316d7b 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -216,6 +216,8 @@
 			"LOCAL_JETIFIER_ENABLED":      "jetifier",
 
 			"LOCAL_IS_UNIT_TEST": "unit_test",
+
+			"LOCAL_ENFORCE_USES_LIBRARIES": "enforce_uses_libs",
 		})
 }
 
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index f32ff2a..439f45d 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1446,6 +1446,23 @@
 }
 `,
 	},
+	{
+		desc: "LOCAL_ENFORCE_USES_LIBRARIES",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_ENFORCE_USES_LIBRARIES := false
+LOCAL_ENFORCE_USES_LIBRARIES := true
+include $(BUILD_PACKAGE)
+`,
+		expected: `
+android_app {
+    name: "foo",
+    enforce_uses_libs: false,
+    enforce_uses_libs: true,
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index 949d80e..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()
@@ -2097,6 +2102,11 @@
 		}
 	}
 
+	// Add classpaths.proto config.
+	classpathProtoOutput := bootclasspathFragmentInfo.ClasspathFragmentProtoOutput
+	classpathProto := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), bootclasspathFragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
+	filesToAdd = append(filesToAdd, classpathProto)
+
 	return filesToAdd
 }
 
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index e2b320c..7bb3ff6 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -279,6 +279,7 @@
 		).RunTest(t)
 
 		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+			"etc/classpaths/mybootclasspathfragment.pb",
 			"javalib/arm/boot.art",
 			"javalib/arm/boot.oat",
 			"javalib/arm/boot.vdex",
@@ -481,6 +482,7 @@
 	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
 		// This does not include art, oat or vdex files as they are only included for the art boot
 		// image.
+		"etc/classpaths/mybootclasspathfragment.pb",
 		"javalib/bar.jar",
 		"javalib/foo.jar",
 	})
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 0551a18..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"],
 )`},
 		},
 		{
@@ -302,6 +352,99 @@
     version_script = "v.map",
 )`},
 		},
+		{
+			description:                        "cc_library shared_libs",
+			moduleTypeUnderTest:                "cc_library",
+			moduleTypeUnderTestFactory:         cc.LibraryFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			dir:                                "foo/bar",
+			filesystem: map[string]string{
+				"foo/bar/Android.bp": `
+cc_library {
+    name: "mylib",
+    bazel_module: { bp2build_available: true },
+}
+
+cc_library {
+    name: "a",
+    shared_libs: ["mylib",],
+    bazel_module: { bp2build_available: true },
+}
+`,
+			},
+			bp: soongCcLibraryPreamble,
+			expectedBazelTargets: []string{`cc_library(
+    name = "a",
+    copts = ["-Ifoo/bar"],
+    dynamic_deps = [":mylib"],
+)`, `cc_library(
+    name = "mylib",
+    copts = ["-Ifoo/bar"],
+)`},
+		},
+		{
+			description:                        "cc_library pack_relocations test",
+			moduleTypeUnderTest:                "cc_library",
+			moduleTypeUnderTestFactory:         cc.LibraryFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			dir:                                "foo/bar",
+			filesystem: map[string]string{
+				"foo/bar/Android.bp": `
+cc_library {
+    name: "a",
+    srcs: ["a.cpp"],
+    pack_relocations: false,
+    bazel_module: { bp2build_available: true },
+}
+
+cc_library {
+    name: "b",
+    srcs: ["b.cpp"],
+    arch: {
+        x86_64: {
+		pack_relocations: false,
+	},
+    },
+    bazel_module: { bp2build_available: true },
+}
+
+cc_library {
+    name: "c",
+    srcs: ["c.cpp"],
+    target: {
+        darwin: {
+		pack_relocations: false,
+	},
+    },
+    bazel_module: { bp2build_available: true },
+}`,
+			},
+			bp: soongCcLibraryPreamble,
+			expectedBazelTargets: []string{`cc_library(
+    name = "a",
+    copts = ["-Ifoo/bar"],
+    linkopts = ["-Wl,--pack-dyn-relocs=none"],
+    srcs = ["a.cpp"],
+)`, `cc_library(
+    name = "b",
+    copts = ["-Ifoo/bar"],
+    linkopts = select({
+        "//build/bazel/platforms/arch:x86_64": ["-Wl,--pack-dyn-relocs=none"],
+        "//conditions:default": [],
+    }),
+    srcs = ["b.cpp"],
+)`, `cc_library(
+    name = "c",
+    copts = ["-Ifoo/bar"],
+    linkopts = select({
+        "//build/bazel/platforms/os:darwin": ["-Wl,--pack-dyn-relocs=none"],
+        "//conditions:default": [],
+    }),
+    srcs = ["c.cpp"],
+)`},
+		},
 	}
 
 	dir := "."
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 1433f6f..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,15 +283,28 @@
 
 // Convenience struct to hold all attributes parsed from linker properties.
 type linkerAttributes struct {
-	deps          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
+func getBp2BuildLinkerFlags(linkerProperties *BaseLinkerProperties) []string {
+	flags := linkerProperties.Ldflags
+	if !BoolDefault(linkerProperties.Pack_relocations, true) {
+		flags = append(flags, "-Wl,--pack-dyn-relocs=none")
+	}
+	return flags
 }
 
 // bp2BuildParseLinkerProps parses the linker properties of a module, including
 // configurable attribute values.
 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
 
@@ -263,14 +313,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 = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs))
-			linkopts.Value = baseLinkerProps.Ldflags
+			linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
+			wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
 
 			if baseLinkerProps.Version_script != nil {
 				versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
 			}
+
+			sharedLibs := baseLinkerProps.Shared_libs
+			dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, sharedLibs))
+
 			break
 		}
 	}
@@ -280,14 +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, baseLinkerProps.Ldflags)
+			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))
 		}
 	}
 
@@ -296,17 +356,24 @@
 			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, baseLinkerProps.Ldflags)
+
+			linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+
+			sharedLibs := baseLinkerProps.Shared_libs
+			dynamicDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
 		}
 	}
 
 	return linkerAttributes{
-		deps:          deps,
-		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 7b631fa..c5ff9b1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -220,15 +220,29 @@
 
 // For bp2build conversion.
 type bazelCcLibraryAttributes struct {
-	Srcs                   bazel.LabelListAttribute
-	Hdrs                   bazel.LabelListAttribute
-	Copts                  bazel.StringListAttribute
-	Linkopts               bazel.StringListAttribute
-	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 {
@@ -275,16 +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,
-		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{
@@ -2192,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 {
@@ -2219,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/cc/linker.go b/cc/linker.go
index 73fc4f0..a9930ad 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -421,9 +421,13 @@
 		if !BoolDefault(linker.Properties.Pack_relocations, true) {
 			flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none")
 		} else if ctx.Device() {
-			// The SHT_RELR relocations is only supported by API level >= 28.
-			// Do not turn this on if older version NDK is used.
-			if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, 28) {
+			// SHT_RELR relocations are only supported at API level >= 30.
+			// ANDROID_RELR relocations were supported at API level >= 28.
+			// Relocation packer was supported at API level >= 23.
+			// Do the best we can...
+			if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, 30) {
+				flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr")
+			} else if CheckSdkVersionAtLeast(ctx, 28) {
 				flags.Global.LdFlags = append(flags.Global.LdFlags,
 					"-Wl,--pack-dyn-relocs=android+relr",
 					"-Wl,--use-android-relr-tags")
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index a69de6a..b7c260c 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -114,7 +114,10 @@
 		err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
 	}
 
-	// Now, produce per-package module lists with detailed information.
+	// Now, produce per-package module lists with detailed information, and a list
+	// of keywords.
+	keywordsTmpl := template.Must(template.New("file").Parse(keywordsTemplate))
+	keywordsBuf := &bytes.Buffer{}
 	for _, pkg := range packages {
 		// We need a module name getter/setter function because I couldn't
 		// find a way to keep it in a variable defined within the template.
@@ -141,7 +144,17 @@
 		if err != nil {
 			return err
 		}
+		err = keywordsTmpl.Execute(keywordsBuf, data)
+		if err != nil {
+			return err
+		}
 	}
+
+	// Write out list of keywords. This includes all module and property names, which is useful for
+	// building syntax highlighters.
+	keywordsFilename := filepath.Join(filepath.Dir(filename), "keywords.txt")
+	err = ioutil.WriteFile(keywordsFilename, keywordsBuf.Bytes(), 0666)
+
 	return err
 }
 
@@ -413,4 +426,9 @@
 </script>
 {{end}}
 `
+
+	keywordsTemplate = `
+{{range $moduleType := .Modules}}{{$moduleType.Name}}:{{range $property := $moduleType.Properties}}{{$property.Name}},{{end}}
+{{end}}
+`
 )
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 6270b5b..bed629d 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -109,6 +109,8 @@
 	android.ModuleBase
 	android.ApexModuleBase
 	android.SdkBase
+	ClasspathFragmentBase
+
 	properties bootclasspathFragmentProperties
 }
 
@@ -117,6 +119,7 @@
 	m.AddProperties(&m.properties)
 	android.InitApexModule(m)
 	android.InitSdkAwareModule(m)
+	initClasspathFragment(m, BOOTCLASSPATH)
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
 
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
@@ -242,6 +245,22 @@
 // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
 // apex contents.
 type BootclasspathFragmentApexContentInfo struct {
+	// ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
+	//
+	// The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
+	// for more details.
+	ClasspathFragmentProtoOutput android.OutputPath
+
+	// ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
+	//
+	// The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
+	// for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
+	// use android.InstallPath#Rel().
+	//
+	// This is only relevant for APEX modules as they perform their own installation; while regular
+	// system files are installed via ClasspathFragmentBase#androidMkEntries().
+	ClasspathFragmentProtoInstallDir android.InstallPath
+
 	// The image config, internal to this module (and the dex_bootjars singleton).
 	//
 	// Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
@@ -339,30 +358,47 @@
 		b.bootclasspathImageNameContentsConsistencyCheck(ctx)
 	}
 
+	// Generate classpaths.proto config
+	b.generateClasspathProtoBuildActions(ctx)
+
 	// Perform hidden API processing.
 	b.generateHiddenAPIBuildActions(ctx)
 
-	// Nothing to do if skipping the dexpreopt of boot image jars.
-	if SkipDexpreoptBootJars(ctx) {
-		return
-	}
-
-	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
-	// GenerateSingletonBuildActions method as it cannot create it for itself.
-	dexpreopt.GetGlobalSoongConfig(ctx)
-
-	imageConfig := b.getImageConfig(ctx)
-	if imageConfig == nil {
-		return
-	}
-
 	// Construct the boot image info from the config.
-	info := BootclasspathFragmentApexContentInfo{imageConfig: imageConfig}
+	info := BootclasspathFragmentApexContentInfo{
+		ClasspathFragmentProtoInstallDir: b.classpathFragmentBase().installDirPath,
+		ClasspathFragmentProtoOutput:     b.classpathFragmentBase().outputFilepath,
+		imageConfig:                      nil,
+	}
+
+	if !SkipDexpreoptBootJars(ctx) {
+		// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+		// GenerateSingletonBuildActions method as it cannot create it for itself.
+		dexpreopt.GetGlobalSoongConfig(ctx)
+		info.imageConfig = b.getImageConfig(ctx)
+	}
 
 	// Make it available for other modules.
 	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
 }
 
+// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
+func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
+	var classpathJars []classpathJar
+	if "art" == proptools.String(b.properties.Image_name) {
+		// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
+		classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+	} else {
+		classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
+	}
+	b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+}
+
+func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+	// TODO(satayev): populate with actual content
+	return android.EmptyConfiguredJarList()
+}
+
 func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
 	// Get a map of the image configs that are supported.
 	imageConfigs := genBootImageConfigs(ctx)
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 2e05823..7422fa2 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -143,6 +143,8 @@
 	android.WriteFileRule(ctx, output, content.String())
 }
 
+// Returns AndroidMkEntries objects to install generated classpath.proto.
+// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes.
 func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
 	return []android.AndroidMkEntries{{
 		Class:      "ETC",
diff --git a/java/java.go b/java/java.go
index d74bf68..9a5fbfc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1222,6 +1222,13 @@
 	return LintDepSets{}
 }
 
+func (j *Import) getStrictUpdatabilityLinting() bool {
+	return false
+}
+
+func (j *Import) setStrictUpdatabilityLinting(bool) {
+}
+
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 
@@ -1545,6 +1552,13 @@
 	return true
 }
 
+func (j *DexImport) getStrictUpdatabilityLinting() bool {
+	return false
+}
+
+func (j *DexImport) setStrictUpdatabilityLinting(bool) {
+}
+
 func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(j.properties.Jars) != 1 {
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
diff --git a/java/lint.go b/java/lint.go
index 5e39274..9f769df 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -103,6 +103,10 @@
 
 type lintDepSetsIntf interface {
 	LintDepSets() LintDepSets
+
+	// Methods used to propagate strict_updatability_linting values.
+	getStrictUpdatabilityLinting() bool
+	setStrictUpdatabilityLinting(bool)
 }
 
 type LintDepSets struct {
@@ -153,6 +157,14 @@
 	return l.outputs.depSets
 }
 
+func (l *linter) getStrictUpdatabilityLinting() bool {
+	return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
+}
+
+func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) {
+	l.properties.Lint.Strict_updatability_linting = &strictLinting
+}
+
 var _ lintDepSetsIntf = (*linter)(nil)
 
 var _ lintOutputsIntf = (*linter)(nil)
@@ -260,7 +272,7 @@
 	cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
 	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
 
-	if BoolDefault(l.properties.Lint.Strict_updatability_linting, false) {
+	if l.getStrictUpdatabilityLinting() {
 		// Verify the module does not baseline issues that endanger safe updatability.
 		if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
 			cmd.FlagWithInput("--baseline ", baselinePath.Path())
@@ -586,6 +598,14 @@
 func init() {
 	android.RegisterSingletonType("lint",
 		func() android.Singleton { return &lintSingleton{} })
+
+	registerLintBuildComponents(android.InitRegistrationContext)
+}
+
+func registerLintBuildComponents(ctx android.RegistrationContext) {
+	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
+	})
 }
 
 func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
@@ -604,3 +624,15 @@
 
 	rule.Build(outputPath.Base(), outputPath.Base())
 }
+
+// Enforce the strict updatability linting to all applicable transitive dependencies.
+func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
+	m := ctx.Module()
+	if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() {
+		ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
+			if a, ok := d.(lintDepSetsIntf); ok {
+				a.setStrictUpdatabilityLinting(true)
+			}
+		})
+	}
+}
diff --git a/java/lint_test.go b/java/lint_test.go
index a253df9..6d64de7 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -181,12 +181,22 @@
 			srcs: [
 				"a.java",
 			],
+			static_libs: ["bar"],
 			min_sdk_version: "29",
 			sdk_version: "current",
 			lint: {
 				strict_updatability_linting: true,
 			},
 		}
+
+		java_library {
+			name: "bar",
+			srcs: [
+				"a.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "current",
+		}
 	`
 	fs := android.MockFS{
 		"lint-baseline.xml": nil,
@@ -201,4 +211,11 @@
 		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
 		t.Error("did not restrict baselining NewApi")
 	}
+
+	bar := result.ModuleForTests("bar", "android_common")
+	sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
+	if !strings.Contains(*sboxProto.Commands[0].Command,
+		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
+		t.Error("did not restrict baselining NewApi")
+	}
 }
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 1caffe4..c787e47 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -203,6 +203,7 @@
 func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
 	// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
 	classpathJars := configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+
 	// TODO(satayev): remove updatable boot jars once each apex has its own fragment
 	global := dexpreopt.GetGlobalConfig(ctx)
 	classpathJars = append(classpathJars, configuredJarListToClasspathJars(ctx, global.UpdatableBootJars, BOOTCLASSPATH)...)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index aff4539..800e93b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2195,6 +2195,20 @@
 	}
 }
 
+func (module *SdkLibraryImport) getStrictUpdatabilityLinting() bool {
+	if module.implLibraryModule == nil {
+		return false
+	} else {
+		return module.implLibraryModule.getStrictUpdatabilityLinting()
+	}
+}
+
+func (module *SdkLibraryImport) setStrictUpdatabilityLinting(strictLinting bool) {
+	if module.implLibraryModule != nil {
+		module.implLibraryModule.setStrictUpdatabilityLinting(strictLinting)
+	}
+}
+
 // to satisfy apex.javaDependency interface
 func (module *SdkLibraryImport) Stem() string {
 	return module.BaseModuleName()
diff --git a/java/testing.go b/java/testing.go
index 37e63f5..387d595 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -245,6 +245,7 @@
 	RegisterStubsBuildComponents(ctx)
 	RegisterSystemModulesBuildComponents(ctx)
 	registerSystemserverClasspathBuildComponents(ctx)
+	registerLintBuildComponents(ctx)
 }
 
 // gatherRequiredDepsForTest gathers the module definitions used by
diff --git a/scripts/Android.bp b/scripts/Android.bp
index b0a8669..1c02bd0 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -265,22 +265,3 @@
         "linker_config_proto",
     ],
 }
-
-python_binary_host {
-    name: "conv_classpaths_proto",
-    srcs: [
-        "conv_classpaths_proto.py",
-    ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
-    libs: [
-        "classpaths_proto_python",
-    ],
-}
diff --git a/scripts/conv_classpaths_proto.py b/scripts/conv_classpaths_proto.py
deleted file mode 100644
index f49fbbb..0000000
--- a/scripts/conv_classpaths_proto.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#  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.
-
-import argparse
-
-import classpaths_pb2
-
-import google.protobuf.json_format as json_format
-import google.protobuf.text_format as text_format
-
-
-def encode(args):
-    pb = classpaths_pb2.ExportedClasspathsJars()
-    if args.format == 'json':
-        json_format.Parse(args.input.read(), pb)
-    else:
-        text_format.Parse(args.input.read(), pb)
-    args.output.write(pb.SerializeToString())
-    args.input.close()
-    args.output.close()
-
-
-def decode(args):
-    pb = classpaths_pb2.ExportedClasspathsJars()
-    pb.ParseFromString(args.input.read())
-    if args.format == 'json':
-        args.output.write(json_format.MessageToJson(pb))
-    else:
-        args.output.write(text_format.MessageToString(pb).encode('utf_8'))
-    args.input.close()
-    args.output.close()
-
-
-def main():
-    parser = argparse.ArgumentParser('Convert classpaths.proto messages between binary and '
-                                     'human-readable formats.')
-    parser.add_argument('-f', '--format', default='textproto',
-                        help='human-readable format, either json or text(proto), '
-                             'defaults to textproto')
-    parser.add_argument('-i', '--input',
-                        nargs='?', type=argparse.FileType('rb'), default=sys.stdin.buffer)
-    parser.add_argument('-o', '--output',
-                        nargs='?', type=argparse.FileType('wb'),
-                        default=sys.stdout.buffer)
-
-    subparsers = parser.add_subparsers()
-
-    parser_encode = subparsers.add_parser('encode',
-                                          help='convert classpaths protobuf message from '
-                                               'JSON to binary format',
-                                          parents=[parser], add_help=False)
-
-    parser_encode.set_defaults(func=encode)
-
-    parser_decode = subparsers.add_parser('decode',
-                                          help='print classpaths config in JSON format',
-                                          parents=[parser], add_help=False)
-    parser_decode.set_defaults(func=decode)
-
-    args = parser.parse_args()
-    args.func(args)
-
-
-if __name__ == '__main__':
-    main()
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/sdk_test.go b/sdk/sdk_test.go
index e9129e0..12545d6 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -525,4 +525,43 @@
 			`),
 		)
 	})
+
+	t.Run("SOONG_SDK_SNAPSHOT_PREFER=true", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			preparer,
+			android.FixtureMergeEnv(map[string]string{
+				"SOONG_SDK_SNAPSHOT_PREFER": "true",
+			}),
+		).RunTest(t)
+
+		checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
+
+		CheckSnapshot(t, result, "mysdk", "",
+			checkAndroidBpContents(`
+// 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: ["java/myjavalib.jar"],
+}
+
+java_import {
+    name: "myjavalib",
+    prefer: true,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    visibility: ["//visibility:public"],
+    java_header_libs: ["mysdk_myjavalib@current"],
+}
+			`),
+		)
+	})
 }
diff --git a/sdk/update.go b/sdk/update.go
index 457cbd9..a265676 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -29,6 +29,14 @@
 	"android/soong/android"
 )
 
+// Environment variables that affect the generated snapshot
+// ========================================================
+//
+// SOONG_SDK_SNAPSHOT_PREFER
+//     By default every unversioned module in the generated snapshot has prefer: false. Building it
+//     with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
+//
+
 var pctx = android.NewPackageContext("android/soong/sdk")
 
 var (
@@ -258,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
 
@@ -274,7 +285,9 @@
 
 	// Create a transformer that will transform an unversioned module by replacing any references
 	// to internal members with a unique module name and setting prefer: false.
-	unversionedTransformer := unversionedTransformation{builder: builder}
+	unversionedTransformer := unversionedTransformation{
+		builder: builder,
+	}
 
 	for _, unversioned := range builder.prebuiltOrder {
 		// Prune any empty property sets.
@@ -503,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
@@ -563,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))
@@ -596,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
 }
 
@@ -618,12 +640,8 @@
 
 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: false - this is not strictly required as that is the default.
-	module.insertAfter("name", "prefer", false)
-
 	return module
 }
 
@@ -674,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)
@@ -700,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)
 		}
@@ -714,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("},")
@@ -732,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()
 }
@@ -740,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()
 }
@@ -1362,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
 	}