Merge "Fix profileCommand to remove the profile first."
diff --git a/android/bazel.go b/android/bazel.go
index 11fc2b6..e330681 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -205,7 +205,6 @@
 
 		// Linker error
 		"libc_malloc_hooks", // jingwen@, cc_library, undefined symbol: __malloc_hook, etc.
-		"libdl",             // jingwen@, cc_library, clang failed
 		"libstdc++",         // jingwen@, cc_library, undefined symbol: free
 
 		// Includes not found
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index d9cd22d..aa8200b 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -50,6 +50,7 @@
 		expectedBazelTargets               []string
 		filesystem                         map[string]string
 		dir                                string
+		depsMutators                       []android.RegisterMutatorFunc
 	}{
 		{
 			description:                        "cc_library - simple example",
@@ -248,6 +249,34 @@
     srcs = ["math/cosf.c"],
 )`},
 		},
+		{
+			description:                        "cc_library shared/static props",
+			moduleTypeUnderTest:                "cc_library",
+			moduleTypeUnderTestFactory:         cc.LibraryFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			dir:                                "foo/bar",
+			filesystem: map[string]string{
+				"foo/bar/a.cpp": "",
+				"foo/bar/Android.bp": `
+cc_library {
+    name: "a",
+    shared: { whole_static_libs: ["b"] },
+    static: { srcs: ["a.cpp"] },
+    bazel_module: { bp2build_available: true },
+}
+
+cc_library_static { name: "b" }
+`,
+			},
+			bp: soongCcLibraryPreamble,
+			expectedBazelTargets: []string{`cc_library(
+    name = "a",
+    copts = ["-Ifoo/bar"],
+    srcs = ["a.cpp"],
+    static_deps_for_shared = [":b"],
+)`},
+		},
 	}
 
 	dir := "."
@@ -266,11 +295,15 @@
 		ctx := android.NewTestContext(config)
 
 		cc.RegisterCCBuildComponents(ctx)
+		ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
 		ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
 		ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
 		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
 		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
 		ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests
+		for _, m := range testCase.depsMutators {
+			ctx.DepsBp2BuildMutators(m)
+		}
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 9c4bf6e5..a4db79f 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -68,9 +68,61 @@
 		}
 	}
 
+	// Deps in the static: { .. } and shared: { .. } props of a cc_library.
+	if lib, ok := module.compiler.(*libraryDecorator); ok {
+		allDeps = append(allDeps, lib.SharedProperties.Shared.Static_libs...)
+		allDeps = append(allDeps, lib.SharedProperties.Shared.Whole_static_libs...)
+		allDeps = append(allDeps, lib.SharedProperties.Shared.Shared_libs...)
+		allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
+
+		allDeps = append(allDeps, lib.StaticProperties.Static.Static_libs...)
+		allDeps = append(allDeps, lib.StaticProperties.Static.Whole_static_libs...)
+		allDeps = append(allDeps, lib.StaticProperties.Static.Shared_libs...)
+		allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+	}
+
 	ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
 }
 
+type sharedAttributes struct {
+	staticDeps bazel.LabelListAttribute
+}
+
+// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
+func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) sharedAttributes {
+	lib, ok := module.compiler.(*libraryDecorator)
+	if !ok {
+		return sharedAttributes{}
+	}
+
+	var staticDeps bazel.LabelListAttribute
+
+	staticDeps.Value = android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)
+
+	return sharedAttributes{
+		staticDeps: staticDeps,
+	}
+}
+
+type staticAttributes struct {
+	srcs bazel.LabelListAttribute
+}
+
+// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
+func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticAttributes {
+	lib, ok := module.compiler.(*libraryDecorator)
+	if !ok {
+		return staticAttributes{}
+	}
+
+	var srcs bazel.LabelListAttribute
+	srcs.Value = android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)
+
+	return staticAttributes{
+		srcs: srcs,
+	}
+}
+
 // Convenience struct to hold all attributes parsed from compiler properties.
 type compilerAttributes struct {
 	copts    bazel.StringListAttribute
diff --git a/cc/library.go b/cc/library.go
index 3a70765..4cd1b09 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -217,13 +217,14 @@
 
 // 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
+	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
 }
 
 type bazelCcLibrary struct {
@@ -254,16 +255,23 @@
 		return
 	}
 
+	sharedAttrs := bp2BuildParseSharedProps(ctx, m)
+	staticAttrs := bp2BuildParseStaticProps(ctx, m)
 	compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
 	linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
 	exportedIncludes := bp2BuildParseExportedIncludes(ctx, m)
 
+	var srcs bazel.LabelListAttribute
+	srcs.Append(compilerAttrs.srcs)
+	srcs.Append(staticAttrs.srcs)
+
 	attrs := &bazelCcLibraryAttributes{
-		Srcs:     compilerAttrs.srcs,
-		Copts:    compilerAttrs.copts,
-		Linkopts: linkerAttrs.linkopts,
-		Deps:     linkerAttrs.deps,
-		Includes: exportedIncludes,
+		Srcs:                   srcs,
+		Copts:                  compilerAttrs.copts,
+		Linkopts:               linkerAttrs.linkopts,
+		Deps:                   linkerAttrs.deps,
+		Static_deps_for_shared: sharedAttrs.staticDeps,
+		Includes:               exportedIncludes,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index c16193d..02833ab 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -69,13 +69,15 @@
 // addDependencyOntoApexModulePair adds a dependency onto the specified APEX specific variant or the
 // specified module.
 //
-// If apex="platform" then this adds a dependency onto the platform variant of the module. This adds
-// dependencies onto the prebuilt and source modules with the specified name, depending on which
-// ones are available. Visiting must use isActiveModule to select the preferred module when both
-// source and prebuilt modules are available.
+// If apex="platform" or "system_ext" then this adds a dependency onto the platform variant of the
+// module. This adds dependencies onto the prebuilt and source modules with the specified name,
+// depending on which ones are available. Visiting must use isActiveModule to select the preferred
+// module when both source and prebuilt modules are available.
+//
+// Use gatherApexModulePairDepsWithTag to retrieve the dependencies.
 func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
 	var variations []blueprint.Variation
-	if apex != "platform" {
+	if apex != "platform" && apex != "system_ext" {
 		// Pick the correct apex variant.
 		variations = []blueprint.Variation{
 			{Mutator: "apex", Variation: apex},
@@ -118,12 +120,28 @@
 	ctx.AddFarVariationDependencies(variations, nil, name)
 }
 
+// gatherApexModulePairDepsWithTag returns the list of dependencies with the supplied tag that was
+// added by addDependencyOntoApexModulePair.
+func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tag blueprint.DependencyTag) []android.Module {
+	var modules []android.Module
+	ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
+		t := ctx.OtherModuleDependencyTag(module)
+		if t == tag {
+			modules = append(modules, module)
+		}
+	})
+	return modules
+}
+
 // ApexVariantReference specifies a particular apex variant of a module.
 type ApexVariantReference struct {
 	// The name of the module apex variant, i.e. the apex containing the module variant.
 	//
 	// If this is not specified then it defaults to "platform" which will cause a dependency to be
 	// added to the module's platform variant.
+	//
+	// A value of system_ext should be used for any module that will be part of the system_ext
+	// partition.
 	Apex *string
 
 	// The name of the module.
@@ -161,3 +179,59 @@
 
 // The tag used for dependencies onto bootclasspath_fragments.
 var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"}
+
+// BootclasspathNestedAPIProperties defines properties related to the API provided by parts of the
+// bootclasspath that are nested within the main BootclasspathAPIProperties.
+type BootclasspathNestedAPIProperties struct {
+	// java_library or preferably, java_sdk_library modules providing stub classes that define the
+	// APIs provided by this bootclasspath_fragment.
+	Stub_libs []string
+}
+
+// BootclasspathAPIProperties defines properties for defining the API provided by parts of the
+// bootclasspath.
+type BootclasspathAPIProperties struct {
+	// Api properties provide information about the APIs provided by the bootclasspath_fragment.
+	// Properties in this section apply to public, system and test api scopes. They DO NOT apply to
+	// core_platform as that is a special, ART specific scope, that does not follow the pattern and so
+	// has its own section. It is in the process of being deprecated and replaced by the system scope
+	// but this will remain for the foreseeable future to maintain backwards compatibility.
+	//
+	// Every bootclasspath_fragment must specify at least one stubs_lib in this section and must
+	// specify stubs for all the APIs provided by its contents. Failure to do so will lead to those
+	// methods being inaccessible to other parts of Android, including but not limited to
+	// applications.
+	Api BootclasspathNestedAPIProperties
+
+	// Properties related to the core platform API surface.
+	//
+	// This must only be used by the following modules:
+	// * ART
+	// * Conscrypt
+	// * I18N
+	//
+	// The bootclasspath_fragments for each of the above modules must specify at least one stubs_lib
+	// and must specify stubs for all the APIs provided by its contents. Failure to do so will lead to
+	// those methods being inaccessible to the other modules in the list.
+	Core_platform_api BootclasspathNestedAPIProperties
+}
+
+// sdkKindToStubLibs calculates the stub library modules for each relevant android.SdkKind from the
+// Stub_libs properties.
+func (p BootclasspathAPIProperties) sdkKindToStubLibs() map[android.SdkKind][]string {
+	m := map[android.SdkKind][]string{}
+	for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
+		m[kind] = p.Api.Stub_libs
+	}
+	m[android.SdkCorePlatform] = p.Core_platform_api.Stub_libs
+	return m
+}
+
+// bootclasspathApiInfo contains paths resolved from BootclasspathAPIProperties
+type bootclasspathApiInfo struct {
+	// stubJarsByKind maps from the android.SdkKind to the paths containing dex stub jars for each
+	// kind.
+	stubJarsByKind map[android.SdkKind]android.Paths
+}
+
+var bootclasspathApiInfoProvider = blueprint.NewProvider(bootclasspathApiInfo{})
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 5c1c5f0..d7525ec 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -88,6 +88,9 @@
 	//
 	// The order of this list matters as it is the order that is used in the bootclasspath.
 	Contents []string
+
+	// The properties for specifying the API stubs provided by this fragment.
+	BootclasspathAPIProperties
 }
 
 type bootclasspathFragmentProperties struct {
@@ -316,6 +319,9 @@
 }
 
 func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Add dependencies onto all the modules that provide the API stubs for classes on this
+	// bootclasspath fragment.
+	hiddenAPIAddStubLibDependencies(ctx, b.properties.sdkKindToStubLibs())
 
 	if SkipDexpreoptBootJars(ctx) {
 		return
@@ -384,6 +390,13 @@
 
 	// Store the information for use by platform_bootclasspath.
 	ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
+
+	// Convert the kind specific lists of modules into kind specific lists of jars.
+	stubJarsByKind := hiddenAPIGatherStubLibDexJarPaths(ctx)
+
+	// Store the information for use by other modules.
+	bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: stubJarsByKind}
+	ctx.SetProvider(bootclasspathApiInfoProvider, bootclasspathApiInfo)
 }
 
 type bootclasspathFragmentMemberType struct {
@@ -420,6 +433,10 @@
 	// Contents of the bootclasspath fragment
 	Contents []string
 
+	// Stub_libs properties.
+	Stub_libs               []string
+	Core_platform_stub_libs []string
+
 	// Flag files by *hiddenAPIFlagFileCategory
 	Flag_files_by_category map[*hiddenAPIFlagFileCategory]android.Paths
 }
@@ -434,6 +451,10 @@
 	mctx := ctx.SdkModuleContext()
 	flagFileInfo := mctx.OtherModuleProvider(module, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
 	b.Flag_files_by_category = flagFileInfo.categoryToPaths
+
+	// Copy stub_libs properties.
+	b.Stub_libs = module.properties.Api.Stub_libs
+	b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs
 }
 
 func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -441,11 +462,22 @@
 		propertySet.AddProperty("image_name", *b.Image_name)
 	}
 
+	builder := ctx.SnapshotBuilder()
+	requiredMemberDependency := builder.SdkMemberReferencePropertyTag(true)
+
 	if len(b.Contents) > 0 {
-		propertySet.AddPropertyWithTag("contents", b.Contents, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
+		propertySet.AddPropertyWithTag("contents", b.Contents, requiredMemberDependency)
 	}
 
-	builder := ctx.SnapshotBuilder()
+	if len(b.Stub_libs) > 0 {
+		apiPropertySet := propertySet.AddPropertySet("api")
+		apiPropertySet.AddPropertyWithTag("stub_libs", b.Stub_libs, requiredMemberDependency)
+	}
+	if len(b.Core_platform_stub_libs) > 0 {
+		corePlatformApiPropertySet := propertySet.AddPropertySet("core_platform_api")
+		corePlatformApiPropertySet.AddPropertyWithTag("stub_libs", b.Core_platform_stub_libs, requiredMemberDependency)
+	}
+
 	if b.Flag_files_by_category != nil {
 		hiddenAPISet := propertySet.AddPropertySet("hidden_api")
 		for _, category := range hiddenAPIFlagFileCategories {
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 0419a46..32ed7ea 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -125,10 +125,20 @@
 			contents: [
 				"mybootlib",
 			],
+			api: {
+				stub_libs: [
+					"mysdklibrary",
+				],
+			},
 			coverage: {
 				contents: [
 					"coveragelib",
 				],
+				api: {
+					stub_libs: [
+						"mycoveragestubs",
+					],
+				},
 			},
 		}
 
@@ -147,6 +157,21 @@
 			sdk_version: "none",
 			compile_dex: true,
 		}
+
+		java_sdk_library {
+			name: "mysdklibrary",
+			srcs: ["Test.java"],
+			compile_dex: true,
+			public: {enabled: true},
+			system: {enabled: true},
+		}
+
+		java_sdk_library {
+			name: "mycoveragestubs",
+			srcs: ["Test.java"],
+			compile_dex: true,
+			public: {enabled: true},
+		}
 	`)
 
 	checkContents := func(t *testing.T, result *android.TestResult, expected ...string) {
@@ -154,20 +179,88 @@
 		android.AssertArrayString(t, "contents property", expected, module.properties.Contents)
 	}
 
+	preparer := android.GroupFixturePreparers(
+		prepareForTestWithBootclasspathFragment,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
+		prepareWithBp,
+	)
+
 	t.Run("without coverage", func(t *testing.T) {
-		result := android.GroupFixturePreparers(
-			prepareForTestWithBootclasspathFragment,
-			prepareWithBp,
-		).RunTest(t)
+		result := preparer.RunTest(t)
 		checkContents(t, result, "mybootlib")
 	})
 
 	t.Run("with coverage", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
-			prepareForTestWithBootclasspathFragment,
 			prepareForTestWithFrameworkCoverage,
-			prepareWithBp,
+			preparer,
 		).RunTest(t)
 		checkContents(t, result, "mybootlib", "coveragelib")
 	})
 }
+
+func TestBootclasspathFragment_StubLibs(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithBootclasspathFragment,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("mysdklibrary", "mycoreplatform"),
+	).RunTestWithBp(t, `
+		bootclasspath_fragment {
+			name: "myfragment",
+			contents: ["mysdklibrary"],
+			api: {
+				stub_libs: [
+					"mystublib",
+					"mysdklibrary",
+				],
+			},
+			core_platform_api: {
+				stub_libs: ["mycoreplatform"],
+			},
+		}
+
+		java_library {
+			name: "mystublib",
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+		}
+
+		java_sdk_library {
+			name: "mysdklibrary",
+			srcs: ["a.java"],
+			compile_dex: true,
+			public: {enabled: true},
+			system: {enabled: true},
+		}
+
+		java_sdk_library {
+			name: "mycoreplatform",
+			srcs: ["a.java"],
+			compile_dex: true,
+			public: {enabled: true},
+		}
+	`)
+
+	fragment := result.Module("myfragment", "android_common")
+	info := result.ModuleProvider(fragment, bootclasspathApiInfoProvider).(bootclasspathApiInfo)
+
+	stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
+
+	// Check that SdkPublic uses public stubs.
+	publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar"
+	android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{stubsJar, publicStubsJar}, info.stubJarsByKind[android.SdkPublic])
+
+	// Check that SdkSystem uses system stubs.
+	systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.system/android_common/dex/mysdklibrary.stubs.system.jar"
+	android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{stubsJar, systemStubsJar}, info.stubJarsByKind[android.SdkSystem])
+
+	// Check that SdkTest also uses system stubs as the mysdklibrary does not provide test stubs.
+	android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{stubsJar, systemStubsJar}, info.stubJarsByKind[android.SdkTest])
+
+	// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
+	corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
+	android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.stubJarsByKind[android.SdkCorePlatform])
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 8a6f3d1..8c6c9e3 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -431,9 +431,6 @@
 	defaultImageConfig := defaultBootImageConfig(ctx)
 	profile := bootImageProfileRule(ctx, defaultImageConfig)
 
-	// Generate the updatable bootclasspath packages rule.
-	updatableBcpPackagesRule(ctx, defaultImageConfig)
-
 	// Create the default boot image.
 	d.defaultBootImage = buildBootImage(ctx, defaultImageConfig, profile)
 
@@ -441,8 +438,6 @@
 	d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx), profile))
 
 	copyUpdatableBootJars(ctx)
-
-	dumpOatRules(ctx, d.defaultBootImage)
 }
 
 // shouldBuildBootImages determines whether boot images should be built.
@@ -887,32 +882,9 @@
 	return profile
 }
 
-func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig) android.WritablePath {
-	if ctx.Config().UnbundledBuild() {
-		return nil
-	}
-
-	global := dexpreopt.GetGlobalConfig(ctx)
-	var modules []android.Module
-	updatableModules := global.UpdatableBootJars.CopyOfJars()
-	ctx.VisitAllModules(func(module android.Module) {
-		if !isActiveModule(module) {
-			return
-		}
-		name := ctx.ModuleName(module)
-		if i := android.IndexList(name, updatableModules); i != -1 {
-			modules = append(modules, module)
-			// Do not match the same library repeatedly.
-			updatableModules = append(updatableModules[:i], updatableModules[i+1:]...)
-		}
-	})
-
-	return generateUpdatableBcpPackagesRule(ctx, image, modules)
-}
-
 // generateUpdatableBcpPackagesRule generates the rule to create the updatable-bcp-packages.txt file
 // and returns a path to the generated file.
-func generateUpdatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, updatableModules []android.Module) android.WritablePath {
+func generateUpdatableBcpPackagesRule(ctx android.ModuleContext, image *bootImageConfig, updatableModules []android.Module) android.WritablePath {
 	// Collect `permitted_packages` for updatable boot jars.
 	var updatablePackages []string
 	for _, module := range updatableModules {
@@ -921,7 +893,7 @@
 			if len(pp) > 0 {
 				updatablePackages = append(updatablePackages, pp...)
 			} else {
-				ctx.Errorf("Missing permitted_packages for %s", ctx.ModuleName(module))
+				ctx.ModuleErrorf("Missing permitted_packages")
 			}
 		}
 	}
@@ -944,7 +916,7 @@
 	return updatableBcpPackages
 }
 
-func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
+func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
 	var allPhonies android.Paths
 	for _, image := range image.variants {
 		arch := image.target.Arch.ArchType
@@ -985,7 +957,6 @@
 		Inputs:      allPhonies,
 		Description: "dump-oat-boot",
 	})
-
 }
 
 func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 793d63a..335f5b8 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -127,7 +127,7 @@
 		tag := ctx.OtherModuleDependencyTag(module)
 		if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
 			kind := hiddenAPIStubsTag.sdkKind
-			dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module)
+			dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
 			if dexJar != nil {
 				m[kind] = append(m[kind], dexJar)
 			}
@@ -138,17 +138,21 @@
 
 // hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
 // available, or reports an error.
-func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module) android.Path {
-	if j, ok := module.(UsesLibraryDependency); ok {
-		dexJar := j.DexJarBuildPath()
-		if dexJar != nil {
-			return dexJar
-		}
-		ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
+func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
+	var dexJar android.Path
+	if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
+		dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
+	} else if j, ok := module.(UsesLibraryDependency); ok {
+		dexJar = j.DexJarBuildPath()
 	} else {
 		ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module))
+		return nil
 	}
-	return nil
+
+	if dexJar == nil {
+		ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
+	}
+	return dexJar
 }
 
 var sdkKindToHiddenapiListOption = map[android.SdkKind]string{
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 3cc88e6..9826baf 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -186,7 +186,7 @@
 
 	// Now match the apex part of the boot image configuration.
 	requiredApex := configuredBootJars.Apex(index)
-	if requiredApex == "platform" {
+	if requiredApex == "platform" || requiredApex == "system_ext" {
 		if len(apexInfo.InApexes) != 0 {
 			// A platform variant is required but this is for an apex so ignore it.
 			return false
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 6503eca..6bf9ea0 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -29,8 +29,13 @@
 	ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
 }
 
-// The tag used for the dependency between the platform bootclasspath and any configured boot jars.
-var platformBootclasspathModuleDepTag = bootclasspathDependencyTag{name: "module"}
+// The tags used for the dependencies between the platform bootclasspath and any configured boot
+// jars.
+var (
+	platformBootclasspathArtBootJarDepTag          = bootclasspathDependencyTag{name: "art-boot-jar"}
+	platformBootclasspathNonUpdatableBootJarDepTag = bootclasspathDependencyTag{name: "non-updatable-boot-jar"}
+	platformBootclasspathUpdatableBootJarDepTag    = bootclasspathDependencyTag{name: "updatable-boot-jar"}
+)
 
 type platformBootclasspathModule struct {
 	android.ModuleBase
@@ -125,41 +130,47 @@
 func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies on all the modules configured in the "art" boot image.
 	artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
-	addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
+	addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag)
 
-	// Add dependencies on all the modules configured in the "boot" boot image. That does not
-	// include modules configured in the "art" boot image.
+	// Add dependencies on all the non-updatable module configured in the "boot" boot image. That does
+	// not include modules configured in the "art" boot image.
 	bootImageConfig := b.getImageConfig(ctx)
-	addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
+	addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathNonUpdatableBootJarDepTag)
 
 	// Add dependencies on all the updatable modules.
 	updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
-	addDependenciesOntoBootImageModules(ctx, updatableModules)
+	addDependenciesOntoBootImageModules(ctx, updatableModules, platformBootclasspathUpdatableBootJarDepTag)
 
 	// Add dependencies on all the fragments.
 	b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
 }
 
-func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
+func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) {
 	for i := 0; i < modules.Len(); i++ {
 		apex := modules.Apex(i)
 		name := modules.Jar(i)
 
-		addDependencyOntoApexModulePair(ctx, apex, name, platformBootclasspathModuleDepTag)
+		addDependencyOntoApexModulePair(ctx, apex, name, tag)
 	}
 }
 
 func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	b.classpathFragmentBase().generateAndroidBuildActions(ctx)
 
-	ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
-		tag := ctx.OtherModuleDependencyTag(module)
-		if tag == platformBootclasspathModuleDepTag {
-			b.configuredModules = append(b.configuredModules, module)
-		} else if tag == bootclasspathFragmentDepTag {
-			b.fragments = append(b.fragments, module)
-		}
-	})
+	// Gather all the dependencies from the art, updatable and non-updatable boot jars.
+	artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag)
+	nonUpdatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathNonUpdatableBootJarDepTag)
+	updatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathUpdatableBootJarDepTag)
+
+	// Concatenate them all, in order as they would appear on the bootclasspath.
+	var allModules []android.Module
+	allModules = append(allModules, artModules...)
+	allModules = append(allModules, nonUpdatableModules...)
+	allModules = append(allModules, updatableModules...)
+	b.configuredModules = allModules
+
+	// Gather all the fragments dependencies.
+	b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
 
 	b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
 
@@ -168,7 +179,7 @@
 		return
 	}
 
-	b.generateBootImageBuildActions(ctx)
+	b.generateBootImageBuildActions(ctx, updatableModules)
 }
 
 func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
@@ -297,7 +308,7 @@
 }
 
 // generateBootImageBuildActions generates ninja rules related to the boot image creation.
-func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) {
+func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, updatableModules []android.Module) {
 	// 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)
@@ -314,4 +325,9 @@
 
 	// Generate the framework profile rule
 	bootFrameworkProfileRule(ctx, imageConfig)
+
+	// Generate the updatable bootclasspath packages rule.
+	generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
+
+	dumpOatRules(ctx, imageConfig)
 }
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 955e387..2216b11 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -33,7 +33,7 @@
 func TestPlatformBootclasspath(t *testing.T) {
 	preparer := android.GroupFixturePreparers(
 		prepareForTestWithPlatformBootclasspath,
-		FixtureConfigureBootJars("platform:foo", "platform:bar"),
+		FixtureConfigureBootJars("platform:foo", "system_ext:bar"),
 		android.FixtureWithRootAndroidBp(`
 			platform_bootclasspath {
 				name: "platform-bootclasspath",
@@ -45,6 +45,7 @@
 				system_modules: "none",
 				sdk_version: "none",
 				compile_dex: true,
+				system_ext_specific: true,
 			}
 		`),
 	)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 5658f16..2827567 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -165,15 +165,25 @@
 func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mycoreplatform"),
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
 				bootclasspath_fragments: ["mybootclasspathfragment"],
+				java_sdk_libs: ["mysdklibrary", "mycoreplatform"],
 			}
 
 			bootclasspath_fragment {
 				name: "mybootclasspathfragment",
 				contents: ["mybootlib"],
+				api: {
+					stub_libs: ["mysdklibrary"],
+				},
+				core_platform_api: {
+					stub_libs: ["mycoreplatform"],
+				},
 			}
 
 			java_library {
@@ -183,6 +193,20 @@
 				sdk_version: "none",
 				compile_dex: true,
 			}
+
+			java_sdk_library {
+				name: "mysdklibrary",
+				srcs: ["Test.java"],
+				compile_dex: true,
+				public: {enabled: true},
+			}
+
+			java_sdk_library {
+				name: "mycoreplatform",
+				srcs: ["Test.java"],
+				compile_dex: true,
+				public: {enabled: true},
+			}
 		`),
 	).RunTest(t)
 
@@ -196,6 +220,12 @@
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     contents: ["mybootlib"],
+    api: {
+        stub_libs: ["mysdklibrary"],
+    },
+    core_platform_api: {
+        stub_libs: ["mycoreplatform"],
+    },
 }
 
 java_import {
@@ -205,6 +235,38 @@
     apex_available: ["//apex_available:platform"],
     jars: ["java/mybootlib.jar"],
 }
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: true,
+    compile_dex: true,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+java_sdk_library_import {
+    name: "mycoreplatform",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: true,
+    compile_dex: true,
+    public: {
+        jars: ["sdk_library/public/mycoreplatform-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mycoreplatform_stub_sources"],
+        current_api: "sdk_library/public/mycoreplatform.txt",
+        removed_api: "sdk_library/public/mycoreplatform-removed.txt",
+        sdk_version: "current",
+    },
+}
 `),
 		checkVersionedAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
@@ -215,6 +277,12 @@
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     contents: ["mysdk_mybootlib@current"],
+    api: {
+        stub_libs: ["mysdk_mysdklibrary@current"],
+    },
+    core_platform_api: {
+        stub_libs: ["mysdk_mycoreplatform@current"],
+    },
 }
 
 java_import {
@@ -225,15 +293,57 @@
     jars: ["java/mybootlib.jar"],
 }
 
+java_sdk_library_import {
+    name: "mysdk_mysdklibrary@current",
+    sdk_member_name: "mysdklibrary",
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: true,
+    compile_dex: true,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+java_sdk_library_import {
+    name: "mysdk_mycoreplatform@current",
+    sdk_member_name: "mycoreplatform",
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: true,
+    compile_dex: true,
+    public: {
+        jars: ["sdk_library/public/mycoreplatform-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mycoreplatform_stub_sources"],
+        current_api: "sdk_library/public/mycoreplatform.txt",
+        removed_api: "sdk_library/public/mycoreplatform-removed.txt",
+        sdk_version: "current",
+    },
+}
+
 sdk_snapshot {
     name: "mysdk@current",
     visibility: ["//visibility:public"],
     bootclasspath_fragments: ["mysdk_mybootclasspathfragment@current"],
     java_boot_libs: ["mysdk_mybootlib@current"],
+    java_sdk_libs: [
+        "mysdk_mysdklibrary@current",
+        "mysdk_mycoreplatform@current",
+    ],
 }
 `),
 		checkAllCopyRules(`
 .intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
 `))
 }