Merge "Include static lib information for the snapshot modules"
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 57f75ea..8ede226 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -46,6 +46,7 @@
 		blueprint: `cc_object {
     name: "foo",
     local_include_dirs: ["include"],
+    default_shared_libs: [],
     cflags: [
         "-Wno-gcc-compat",
         "-Wall",
@@ -83,6 +84,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     local_include_dirs: ["include"],
     srcs: [
         "a/b/*.h",
@@ -135,12 +137,14 @@
 		},
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     srcs: ["a/b/c.c"],
     objs: ["bar"],
 }
 
 cc_object {
     name: "bar",
+    default_shared_libs: [],
     srcs: ["x/y/z.c"],
 }
 `,
@@ -178,6 +182,7 @@
 		},
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     srcs: ["a/b/c.c"],
     include_build_directory: false,
 }
@@ -199,6 +204,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     include_build_directory: false,
     product_variables: {
         platform_sdk_version: {
@@ -227,6 +233,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     srcs: ["a.cpp"],
     arch: {
         x86: {
@@ -266,6 +273,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     srcs: ["base.cpp"],
     arch: {
         x86: {
@@ -321,6 +329,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
 		blueprint: `cc_object {
     name: "foo",
+    default_shared_libs: [],
     srcs: ["base.cpp"],
     target: {
         android: {
diff --git a/cc/cc.go b/cc/cc.go
index ffd2863..1f73149 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -526,8 +526,6 @@
 // feature represents additional (optional) steps to building cc-related modules, such as invocation
 // of clang-tidy.
 type feature interface {
-	begin(ctx BaseModuleContext)
-	deps(ctx DepsContext, deps Deps) Deps
 	flags(ctx ModuleContext, flags Flags) Flags
 	props() []interface{}
 }
@@ -1899,21 +1897,12 @@
 	if c.coverage != nil {
 		c.coverage.begin(ctx)
 	}
-	if c.sabi != nil {
-		c.sabi.begin(ctx)
-	}
-	if c.vndkdep != nil {
-		c.vndkdep.begin(ctx)
-	}
 	if c.lto != nil {
 		c.lto.begin(ctx)
 	}
 	if c.pgo != nil {
 		c.pgo.begin(ctx)
 	}
-	for _, feature := range c.features {
-		feature.begin(ctx)
-	}
 	if ctx.useSdk() && c.IsSdkVariant() {
 		version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
 		if err != nil {
@@ -1937,24 +1926,9 @@
 	if c.stl != nil {
 		deps = c.stl.deps(ctx, deps)
 	}
-	if c.sanitize != nil {
-		deps = c.sanitize.deps(ctx, deps)
-	}
 	if c.coverage != nil {
 		deps = c.coverage.deps(ctx, deps)
 	}
-	if c.sabi != nil {
-		deps = c.sabi.deps(ctx, deps)
-	}
-	if c.vndkdep != nil {
-		deps = c.vndkdep.deps(ctx, deps)
-	}
-	if c.lto != nil {
-		deps = c.lto.deps(ctx, deps)
-	}
-	for _, feature := range c.features {
-		deps = feature.deps(ctx, deps)
-	}
 
 	deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
 	deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
diff --git a/cc/lto.go b/cc/lto.go
index a3b28d9..fccb597 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -80,10 +80,6 @@
 	}
 }
 
-func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
-	return deps
-}
-
 func (lto *lto) useClangLld(ctx BaseModuleContext) bool {
 	if lto.Properties.Use_clang_lld != nil {
 		return Bool(lto.Properties.Use_clang_lld)
diff --git a/cc/object.go b/cc/object.go
index 39fc43d..9f2db2e 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -67,9 +67,19 @@
 }
 
 type ObjectLinkerProperties struct {
+	// list of static library modules that should only provide headers for this module.
+	Static_libs []string `android:"arch_variant,variant_prepend"`
+
+	// list of shared library modules should only provide headers for this module.
+	Shared_libs []string `android:"arch_variant"`
+
 	// list of modules that should only provide headers for this module.
 	Header_libs []string `android:"arch_variant,variant_prepend"`
 
+	// list of default libraries that will provide headers for this module.  If unset, generally
+	// defaults to libc, libm, and libdl.  Set to [] to prevent using headers from the defaults.
+	Default_shared_libs []string `android:"arch_variant"`
+
 	// names of other cc_object modules to link into this module using partial linking
 	Objs []string `android:"arch_variant"`
 
@@ -84,8 +94,8 @@
 	Crt *bool
 }
 
-func newObject() *Module {
-	module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
+func newObject(hod android.HostOrDeviceSupported) *Module {
+	module := newBaseModule(hod, android.MultilibBoth)
 	module.sanitize = &sanitize{}
 	module.stl = &stl{}
 	return module
@@ -95,7 +105,7 @@
 // necessary, but sometimes used to generate .s files from .c files to use as
 // input to a cc_genrule module.
 func ObjectFactory() android.Module {
-	module := newObject()
+	module := newObject(android.HostAndDeviceSupported)
 	module.linker = &objectLinker{
 		baseLinker: NewBaseLinker(module.sanitize),
 	}
@@ -198,7 +208,18 @@
 
 func (object *objectLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
 	deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs...)
+	deps.SharedLibs = append(deps.SharedLibs, object.Properties.Shared_libs...)
+	deps.StaticLibs = append(deps.StaticLibs, object.Properties.Static_libs...)
 	deps.ObjFiles = append(deps.ObjFiles, object.Properties.Objs...)
+
+	deps.SystemSharedLibs = object.Properties.Default_shared_libs
+	if deps.SystemSharedLibs == nil {
+		// Provide a default set of shared libraries if default_shared_libs is unspecified.
+		// Note: If an empty list [] is specified, it implies that the module declines the
+		// default shared libraries.
+		deps.SystemSharedLibs = append(deps.SystemSharedLibs, ctx.toolchain().DefaultSharedLibraries()...)
+	}
+	deps.LateSharedLibs = append(deps.LateSharedLibs, deps.SystemSharedLibs...)
 	return deps
 }
 
@@ -247,6 +268,20 @@
 	return outputFile
 }
 
+func (object *objectLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, object.Properties.Shared_libs...)
+
+	// Must distinguish nil and [] in default_shared_libs - ensure that [] in
+	// either input list doesn't come out as nil.
+	if specifiedDeps.defaultSharedLibs == nil {
+		specifiedDeps.defaultSharedLibs = object.Properties.Default_shared_libs
+	} else {
+		specifiedDeps.defaultSharedLibs = append(specifiedDeps.defaultSharedLibs, object.Properties.Default_shared_libs...)
+	}
+
+	return specifiedDeps
+}
+
 func (object *objectLinker) unstrippedOutputFilePath() android.Path {
 	return nil
 }
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index fd310a2..f7154ec 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -388,8 +388,8 @@
 	return true
 }
 
-func newPrebuiltObject() *Module {
-	module := newObject()
+func NewPrebuiltObject(hod android.HostOrDeviceSupported) *Module {
+	module := newObject(hod)
 	prebuilt := &prebuiltObjectLinker{
 		objectLinker: objectLinker{
 			baseLinker: NewBaseLinker(nil),
@@ -403,7 +403,7 @@
 }
 
 func prebuiltObjectFactory() android.Module {
-	module := newPrebuiltObject()
+	module := NewPrebuiltObject(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
diff --git a/cc/sabi.go b/cc/sabi.go
index 1f331cb..5fd6f5d 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -45,12 +45,6 @@
 	return []interface{}{&sabi.Properties}
 }
 
-func (sabi *sabi) begin(ctx BaseModuleContext) {}
-
-func (sabi *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
-	return deps
-}
-
 func (sabi *sabi) flags(ctx ModuleContext, flags Flags) Flags {
 	// Filter out flags which libTooling don't understand.
 	// This is here for legacy reasons and future-proof, in case the version of libTooling and clang
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b0eb0c6..cdd7dfb 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -499,14 +499,6 @@
 	}
 }
 
-func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps {
-	if !sanitize.Properties.SanitizerEnabled { // || c.static() {
-		return deps
-	}
-
-	return deps
-}
-
 func toDisableImplicitIntegerChange(flags []string) bool {
 	// Returns true if any flag is fsanitize*integer, and there is
 	// no explicit flag about sanitize=implicit-integer-sign-change.
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 3a382a1..fb89224 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -931,7 +931,7 @@
 // development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_object
 // overrides the vendor variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
 func VendorSnapshotObjectFactory() android.Module {
-	module := newObject()
+	module := newObject(android.DeviceSupported)
 
 	prebuilt := &snapshotObjectLinker{
 		objectLinker: objectLinker{
@@ -949,7 +949,7 @@
 // development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_object
 // overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
 func RecoverySnapshotObjectFactory() android.Module {
-	module := newObject()
+	module := newObject(android.DeviceSupported)
 
 	prebuilt := &snapshotObjectLinker{
 		objectLinker: objectLinker{
diff --git a/cc/testing.go b/cc/testing.go
index 80cc0ef..b9d84f6 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -367,6 +367,7 @@
 			stl: "none",
 			min_sdk_version: "16",
 			crt: true,
+			default_shared_libs: [],
 			apex_available: [
 				"//apex_available:platform",
 				"//apex_available:anyapex",
diff --git a/cc/tidy.go b/cc/tidy.go
index 616cf8a..b2382e8 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -61,13 +61,6 @@
 	return []interface{}{&tidy.Properties}
 }
 
-func (tidy *tidyFeature) begin(ctx BaseModuleContext) {
-}
-
-func (tidy *tidyFeature) deps(ctx DepsContext, deps Deps) Deps {
-	return deps
-}
-
 func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
 	CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
 	CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
diff --git a/cc/vndk.go b/cc/vndk.go
index 0b40076..499d428 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -100,12 +100,6 @@
 	return []interface{}{&vndk.Properties}
 }
 
-func (vndk *vndkdep) begin(ctx BaseModuleContext) {}
-
-func (vndk *vndkdep) deps(ctx BaseModuleContext, deps Deps) Deps {
-	return deps
-}
-
 func (vndk *vndkdep) isVndk() bool {
 	return Bool(vndk.Properties.Vndk.Enabled)
 }
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index b469886..3d0e155 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -197,7 +197,7 @@
 				],
 			},
 			core_platform_api: {
-				stub_libs: ["mycoreplatform"],
+				stub_libs: ["mycoreplatform.stubs"],
 			},
 		}
 
diff --git a/java/droidstubs.go b/java/droidstubs.go
index d348b55..ec1b04a 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -128,12 +128,15 @@
 	// whicih can be used for scheduling purposes
 	High_mem *bool
 
-	// is set to true, Metalava will allow framework SDK to contain API levels annotations.
+	// if set to true, Metalava will allow framework SDK to contain API levels annotations.
 	Api_levels_annotations_enabled *bool
 
 	// the dirs which Metalava extracts API levels annotations from.
 	Api_levels_annotations_dirs []string
 
+	// the sdk kind which Metalava extracts API levels annotations from. Supports 'public' and 'system' for now; defaults to public.
+	Api_levels_sdk_type *string
+
 	// the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
 	Api_levels_jar_filename *string
 
@@ -367,6 +370,7 @@
 
 	filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
 
+	var dirs []string
 	ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
 		if t, ok := m.(*ExportedDroiddocDir); ok {
 			for _, dep := range t.deps {
@@ -383,12 +387,32 @@
 					cmd.Implicit(dep)
 				}
 			}
-			cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/"+filename)
+
+			dirs = append(dirs, t.dir.String())
 		} else {
 			ctx.PropertyErrorf("api_levels_annotations_dirs",
 				"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
 		}
 	})
+
+	// Add all relevant --android-jar-pattern patterns for Metalava.
+	// When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
+	// an actual file present on disk (in the order the patterns were passed). For system APIs for
+	// privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
+	// for older releases.
+	if sdkType := proptools.StringDefault(d.properties.Api_levels_sdk_type, "public"); sdkType != "public" {
+		if sdkType != "system" {
+			ctx.PropertyErrorf("api_levels_sdk_type", "only 'public' and 'system' are supported")
+		}
+		// If building non public stubs, add all sdkType patterns first...
+		for _, dir := range dirs {
+			cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkType, filename))
+		}
+	}
+	for _, dir := range dirs {
+		// ... and fallback to public ones, for Metalava to use if needed.
+		cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, "public", filename))
+	}
 }
 
 func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index db664c1..60d0bea 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"reflect"
+	"regexp"
 	"strings"
 	"testing"
 
@@ -81,6 +82,46 @@
 	}
 }
 
+func TestSystemDroidstubs(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		droiddoc_exported_dir {
+			name: "some-exported-dir",
+			path: "somedir",
+		}
+
+		droiddoc_exported_dir {
+			name: "some-other-exported-dir",
+			path: "someotherdir",
+		}
+
+		droidstubs {
+			name: "foo-stubs",
+			srcs: ["foo-doc/a.java"],
+			api_levels_annotations_dirs: [
+				"some-exported-dir",
+				"some-other-exported-dir",
+			],
+			api_levels_annotations_enabled: true,
+            api_levels_sdk_type: "system",
+		}
+		`,
+		map[string][]byte{
+			"foo-doc/a.java": nil,
+		})
+
+	m := ctx.ModuleForTests("foo-stubs", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	cmd := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+	r := regexp.MustCompile(`--android-jar-pattern [^ ]+/android.jar`)
+	matches := r.FindAllString(cmd, -1)
+	android.AssertArrayString(t, "order of patterns", []string{
+		"--android-jar-pattern somedir/%/system/android.jar",
+		"--android-jar-pattern someotherdir/%/system/android.jar",
+		"--android-jar-pattern somedir/%/public/android.jar",
+		"--android-jar-pattern someotherdir/%/public/android.jar",
+	}, matches)
+}
+
 func TestDroidstubsSandbox(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		genrule {
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 0895951..c4832d2 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -586,6 +586,13 @@
 // addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope.
 func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) {
 	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
+
+	// Each named module provides one dex jar for each scope. However, in some cases different API
+	// versions of a single classes are provided by separate modules. e.g. the core platform
+	// version of java.lang.Object is provided by the legacy.art.module.platform.api module but the
+	// public version is provided by the art.module.public.api module. In those cases it is necessary
+	// to treat all those modules as they were the same name, otherwise it will result in multiple
+	// definitions of a single class being passed to hidden API processing which will cause an error.
 	if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule {
 		// Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
 		// java_sdk_library.
@@ -606,6 +613,14 @@
 		// conscrypt.module.public.api java_sdk_library which will be the case once the former has been
 		// migrated to a module_lib API.
 		name = "conscrypt.module.public.api"
+	} else if d, ok := module.(SdkLibraryComponentDependency); ok {
+		sdkLibraryName := d.SdkLibraryName()
+		if sdkLibraryName != nil {
+			// The module is a component of a java_sdk_library so use the name of the java_sdk_library.
+			// e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then
+			// use `foo` as the name.
+			name = *sdkLibraryName
+		}
 	}
 	stubDexJarsByScope := s[name]
 	if stubDexJarsByScope == nil {
@@ -1146,6 +1161,14 @@
 		return true
 	}
 
+	// A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
+	// is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
+	// versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
+	// failures missing boot dex jars need to be deferred.
+	if android.IsModuleInVersionedSdk(ctx.Module()) {
+		return true
+	}
+
 	// This is called for both platform_bootclasspath and bootclasspath_fragment modules.
 	//
 	// A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
@@ -1182,6 +1205,14 @@
 	//
 	// TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
 	if android.IsModulePrebuilt(module) {
+		// An inactive source module can still contribute to the APEX but an inactive prebuilt module
+		// should not contribute to anything. So, rather than have a missing dex jar cause a Soong
+		// failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly
+		// built Ninja should never use the dex jar file.
+		if !isActiveModule(module) {
+			return true
+		}
+
 		if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
 			apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
 			if apexInfo.IsForPlatform() {
@@ -1190,14 +1221,6 @@
 		}
 	}
 
-	// A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
-	// is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
-	// versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
-	// failures missing boot dex jars need to be deferred.
-	if android.IsModuleInVersionedSdk(ctx.Module()) {
-		return true
-	}
-
 	return false
 }
 
diff --git a/java/sdk.go b/java/sdk.go
index cbd873d..d1b899e 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -175,10 +175,24 @@
 		}
 	case android.SdkModule:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx))
+		return sdkDep{
+			useModule:          true,
+			bootclasspath:      []string{"android_module_lib_stubs_current", config.DefaultLambdaStubsLibrary},
+			systemModules:      "core-module-lib-stubs-system-modules",
+			java9Classpath:     []string{"android_module_lib_stubs_current"},
+			frameworkResModule: "framework-res",
+			aidl:               android.OptionalPathForPath(nonUpdatableFrameworkAidlPath(ctx)),
+		}
 	case android.SdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+		return sdkDep{
+			useModule:          true,
+			bootclasspath:      []string{"android_system_server_stubs_current", config.DefaultLambdaStubsLibrary},
+			systemModules:      "core-module-lib-stubs-system-modules",
+			java9Classpath:     []string{"android_system_server_stubs_current"},
+			frameworkResModule: "framework-res",
+			aidl:               android.OptionalPathForPath(sdkFrameworkAidlPath(ctx)),
+		}
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 567e292..ed9aeff 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -675,10 +675,13 @@
 		return false
 	}
 
+	namePtr := proptools.StringPtr(c.module.BaseModuleName())
+	c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
+
 	// Only track this sdk library if this can be used as a shared library.
 	if c.sharedLibrary() {
 		// Use the name specified in the module definition as the owner.
-		c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.module.BaseModuleName())
+		c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = namePtr
 	}
 
 	return true
@@ -922,15 +925,19 @@
 
 func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
 	componentProps := &struct {
+		SdkLibraryName              *string
 		SdkLibraryToImplicitlyTrack *string
 	}{}
 
+	namePtr := proptools.StringPtr(c.module.BaseModuleName())
+	componentProps.SdkLibraryName = namePtr
+
 	if c.sharedLibrary() {
 		// Mark the stubs library as being components of this java_sdk_library so that
 		// any app that includes code which depends (directly or indirectly) on the stubs
 		// library will have the appropriate <uses-library> invocation inserted into its
 		// manifest if necessary.
-		componentProps.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.module.BaseModuleName())
+		componentProps.SdkLibraryToImplicitlyTrack = namePtr
 	}
 
 	return componentProps
@@ -949,6 +956,8 @@
 
 // Properties related to the use of a module as an component of a java_sdk_library.
 type SdkLibraryComponentProperties struct {
+	// The name of the java_sdk_library/_import module.
+	SdkLibraryName *string `blueprint:"mutated"`
 
 	// The name of the java_sdk_library/_import to add to a <uses-library> entry
 	// in the AndroidManifest.xml of any Android app that includes code that references
@@ -967,6 +976,11 @@
 }
 
 // to satisfy SdkLibraryComponentDependency
+func (e *EmbeddableSdkLibraryComponent) SdkLibraryName() *string {
+	return e.sdkLibraryComponentProperties.SdkLibraryName
+}
+
+// to satisfy SdkLibraryComponentDependency
 func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string {
 	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
 }
@@ -982,6 +996,9 @@
 type SdkLibraryComponentDependency interface {
 	UsesLibraryDependency
 
+	// SdkLibraryName returns the name of the java_sdk_library/_import module.
+	SdkLibraryName() *string
+
 	// The optional name of the sdk library that should be implicitly added to the
 	// AndroidManifest of an app that contains code which references the sdk library.
 	//
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 2b18465..bb595a5 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -219,7 +219,7 @@
 			name:           "module_current",
 			properties:     `sdk_version: "module_current",`,
 			bootclasspath:  []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
-			system:         "core-current-stubs-system-modules",
+			system:         "core-module-lib-stubs-system-modules",
 			java9classpath: []string{"android_module_lib_stubs_current"},
 			aidl:           "-pout/soong/framework_non_updatable.aidl",
 		},
@@ -227,7 +227,7 @@
 			name:           "system_server_current",
 			properties:     `sdk_version: "system_server_current",`,
 			bootclasspath:  []string{"android_system_server_stubs_current", "core-lambda-stubs"},
-			system:         "core-current-stubs-system-modules",
+			system:         "core-module-lib-stubs-system-modules",
 			java9classpath: []string{"android_system_server_stubs_current"},
 			aidl:           "-pout/soong/framework.aidl",
 		},
diff --git a/java/testing.go b/java/testing.go
index c3803c8..e2ff5cd 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -312,6 +312,7 @@
 
 	systemModules := []string{
 		"core-current-stubs-system-modules",
+		"core-module-lib-stubs-system-modules",
 		"legacy-core-platform-api-stubs-system-modules",
 		"stable-core-platform-api-stubs-system-modules",
 	}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 98697dc..60fbccf 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -347,6 +347,7 @@
 		cc_object {
 			name: "crtobj",
 			stl: "none",
+			default_shared_libs: [],
 			sanitize: {
 				never: true,
 			},
@@ -364,6 +365,7 @@
     apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
+    default_shared_libs: [],
     sanitize: {
         never: true,
     },
@@ -388,6 +390,7 @@
     apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
+    default_shared_libs: [],
     sanitize: {
         never: true,
     },
diff --git a/sdk/sdk.go b/sdk/sdk.go
index b1c8aeb..afc6aa4 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -93,6 +93,10 @@
 	//   dropped. Adding a rule to members that have //visibility:private will
 	//   cause the //visibility:private to be discarded.
 	Prebuilt_visibility []string
+
+	// Specifying whether the generated prebuilt SDK build rule should have the
+	// prefer flag set or not.
+	Prebuilts_prefer *bool // default: false
 }
 
 // Contains information about the sdk properties that list sdk members, e.g.
@@ -292,6 +296,10 @@
 	return s.properties.Snapshot
 }
 
+func (s *sdk) PreferPrebuilts() bool {
+	return proptools.BoolDefault(s.properties.Prebuilts_prefer, false)
+}
+
 func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if s.snapshot() {
 		// We don't need to create a snapshot out of sdk_snapshot.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index a13b0d7..0933db2 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -662,3 +662,68 @@
 		)
 	})
 }
+
+// Ensure that sdk prebuilt_prefer works correctly.
+func TestSnapshot_PrebuiltPreferTrue(t *testing.T) {
+	bp := `
+		sdk {
+			name: "mysdk",
+			java_header_libs: ["myjavalib"],
+			prebuilts_prefer: true,
+		}
+
+		java_library {
+			name: "myjavalib",
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+			host_supported: true,
+		}
+	`
+	preparer := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		android.FixtureWithRootAndroidBp(bp),
+	)
+
+	checkZipFile := func(t *testing.T, result *android.TestResult, expected string) {
+		zipRule := result.ModuleForTests("mysdk", "common_os").Rule("SnapshotZipFiles")
+		android.AssertStringEquals(t, "snapshot zip file", expected, zipRule.Output.String())
+	}
+
+	t.Run("prefer=true", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			preparer,
+		).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 b146b62..2ab45d7 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -32,8 +32,9 @@
 // ========================================================
 //
 // 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.
+//     By default every unversioned module in the generated snapshot has prefer set by the
+//     sdk.prebuilts_prefer property. Building it with SOONG_SDK_SNAPSHOT_PREFER=true will force
+//     them to use prefer: true.
 //
 // SOONG_SDK_SNAPSHOT_VERSION
 //     This provides control over the version of the generated snapshot.
@@ -1623,11 +1624,11 @@
 
 	// 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.
+		// Set the prefer based on the environment variable if present, else the sdk.prefer_prebuilts
+		// value.
 		// 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")
+		prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER") || s.PreferPrebuilts()
 
 		// 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