Merge "Support LOCAL_ENFORCE_USES_LIBRARIES in androidmk"
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/apex/apex.go b/apex/apex.go
index d26c06d..2c0df27 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2102,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/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/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/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
 	}