Merge "Refactoring fuzz packaging code"
diff --git a/OWNERS b/OWNERS
index bbfd011..f15bd32 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,17 +1,22 @@
 # This file is included by several other projects as the list of people
 # approving build related projects.
 
+# AMER
 ahumesky@google.com
 asmundak@google.com
 ccross@android.com
 cparsons@google.com
 dwillemsen@google.com
 eakammer@google.com
-jingwen@google.com
 joeo@google.com
-lberki@google.com
+spandandas@google.com
+yuntaoxu@google.com
+
+# APAC
+jingwen@google.com
 ruperts@google.com
 
-# To expedite LON reviews
+# EMEA
 hansson@google.com
+lberki@google.com
 paulduffin@google.com
diff --git a/android/arch.go b/android/arch.go
index 340f136..cc70eee 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1987,6 +1987,10 @@
 	axisToProps[bazel.OsConfigurationAxis] = osToProp
 	axisToProps[bazel.OsArchConfigurationAxis] = archOsToProp
 
+	axisToProps[bazel.BionicConfigurationAxis] = map[string]interface{}{
+		"bionic": getTargetStruct(ctx, propertySet, archProperties, "Bionic"),
+	}
+
 	return axisToProps
 }
 
diff --git a/android/bazel.go b/android/bazel.go
index 8d13762..46212dc 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -129,7 +129,7 @@
 	// Keep any existing BUILD files (and do not generate new BUILD files) for these directories
 	bp2buildKeepExistingBuildFile = map[string]bool{
 		// This is actually build/bazel/build.BAZEL symlinked to ./BUILD
-		".":/*recrusive = */ false,
+		".":/*recursive = */ false,
 
 		"build/bazel":/* recursive = */ true,
 		"build/pesto":/* recursive = */ true,
@@ -144,9 +144,10 @@
 
 	// Configure modules in these directories to enable bp2build_available: true or false by default.
 	bp2buildDefaultConfig = Bp2BuildConfig{
-		"bionic":                Bp2BuildDefaultTrueRecursively,
-		"external/gwp_asan":     Bp2BuildDefaultTrueRecursively,
-		"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
+		"bionic":                            Bp2BuildDefaultTrueRecursively,
+		"build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
+		"external/gwp_asan":                 Bp2BuildDefaultTrueRecursively,
+		"system/core/libcutils":             Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
 		"system/libbase":                  Bp2BuildDefaultTrueRecursively,
 		"system/logging/liblog":           Bp2BuildDefaultTrueRecursively,
diff --git a/android/sdk.go b/android/sdk.go
index e700031..da740f3 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -239,6 +239,12 @@
 	// to the zip
 	CopyToSnapshot(src Path, dest string)
 
+	// Return the path to an empty file.
+	//
+	// This can be used by sdk member types that need to create an empty file in the snapshot, simply
+	// pass the value returned from this to the CopyToSnapshot() method.
+	EmptyFile() Path
+
 	// Unzip the supplied zip into the snapshot relative directory destDir.
 	UnzipToSnapshot(zipPath Path, destDir string)
 
diff --git a/apex/apex.go b/apex/apex.go
index 11df288..d385ac1 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2240,6 +2240,7 @@
 	android.InitDefaultableModule(module)
 	android.InitSdkAwareModule(module)
 	android.InitOverridableModule(module, &module.overridableProperties.Overrides)
+	android.InitBazelModule(module)
 	return module
 }
 
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 282c606..35f194d 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -91,6 +91,11 @@
 		conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
 	}
 
+	platformBionicMap = map[string]string{
+		"bionic":          "//build/bazel/platforms/os:bionic",
+		conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
+	}
+
 	platformOsArchMap = map[string]string{
 		osArchAndroidArm:        "//build/bazel/platforms/os_arch:android_arm",
 		osArchAndroidArm64:      "//build/bazel/platforms/os_arch:android_arm64",
@@ -117,6 +122,7 @@
 	arch
 	os
 	osArch
+	bionic
 	productVariables
 )
 
@@ -126,6 +132,7 @@
 		arch:             "arch",
 		os:               "os",
 		osArch:           "arch_os",
+		bionic:           "bionic",
 		productVariables: "product_variables",
 	}[ct]
 }
@@ -148,6 +155,10 @@
 		if _, ok := platformOsArchMap[config]; !ok {
 			panic(fmt.Errorf("Unknown os+arch: %s", config))
 		}
+	case bionic:
+		if _, ok := platformBionicMap[config]; !ok {
+			panic(fmt.Errorf("Unknown for %s: %s", ct.String(), config))
+		}
 	case productVariables:
 		// do nothing
 	default:
@@ -167,6 +178,8 @@
 		return platformOsMap[config]
 	case osArch:
 		return platformOsArchMap[config]
+	case bionic:
+		return platformBionicMap[config]
 	case productVariables:
 		if config == conditionsDefault {
 			return ConditionsDefaultSelectKey
@@ -186,6 +199,8 @@
 	OsConfigurationAxis = ConfigurationAxis{configurationType: os}
 	// An axis for arch+os-specific configurations
 	OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
+	// An axis for bionic os-specific configurations
+	BionicConfigurationAxis = ConfigurationAxis{configurationType: bionic}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/properties.go b/bazel/properties.go
index 7ecc92b..2656bad 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -321,7 +321,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		la.Value = &value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if la.ConfigurableValues == nil {
 			la.ConfigurableValues = make(configurableLabels)
 		}
@@ -337,7 +337,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return *la.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		return *la.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -394,7 +394,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		ba.Value = value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if ba.ConfigurableValues == nil {
 			ba.ConfigurableValues = make(configurableBools)
 		}
@@ -410,7 +410,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return ba.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if v, ok := ba.ConfigurableValues[axis][config]; ok {
 			return &v
 		} else {
@@ -509,7 +509,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -525,7 +525,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -682,7 +682,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -698,7 +698,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index fbf6fa2..f4a1016 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -46,3 +46,23 @@
     manifest = "manifest.json",
 )`}})
 }
+
+func TestApexBundleHasBazelModuleProps(t *testing.T) {
+	runApexTestCase(t, bp2buildTestCase{
+		description:                        "apex - has bazel module props",
+		moduleTypeUnderTest:                "apex",
+		moduleTypeUnderTestFactory:         apex.BundleFactory,
+		moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build,
+		filesystem:                         map[string]string{},
+		blueprint: `
+apex {
+	name: "apogee",
+	manifest: "manifest.json",
+	bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{`apex(
+    name = "apogee",
+    manifest = "manifest.json",
+)`}})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 4f720f5..662d9d1 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -118,6 +118,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
 		filesystem: map[string]string{
 			"android.cpp": "",
+			"bionic.cpp":  "",
 			"darwin.cpp":  "",
 			// Refer to cc.headerExts for the supported header extensions in Soong.
 			"header.h":         "",
@@ -164,6 +165,9 @@
         darwin: {
             srcs: ["darwin.cpp"],
         },
+        bionic: {
+          srcs: ["bionic.cpp"]
+        },
     },
 }
 `,
@@ -190,6 +194,9 @@
         "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
         "//build/bazel/platforms/os:linux": ["linux.cpp"],
         "//conditions:default": [],
+    }) + select({
+        "//build/bazel/platforms/os:bionic": ["bionic.cpp"],
+        "//conditions:default": [],
     }),
 )`}})
 }
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bdf0dae..503c31f 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -579,25 +579,9 @@
 	// Create hidden API input structure.
 	input := b.createHiddenAPIFlagInput(ctx, contents, fragments)
 
-	var output *HiddenAPIOutput
-
-	// Hidden API processing is conditional as a temporary workaround as not all
-	// bootclasspath_fragments provide the appropriate information needed for hidden API processing
-	// which leads to breakages of the build.
-	// TODO(b/179354495): Stop hidden API processing being conditional once all bootclasspath_fragment
-	//  modules have been updated to support it.
-	if input.canPerformHiddenAPIProcessing(ctx, b.properties) {
-		// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
-		common := ctx.Module().(commonBootclasspathFragment)
-		output = common.produceHiddenAPIOutput(ctx, contents, input)
-	} else {
-		// As hidden API processing cannot be performed fall back to trying to retrieve the legacy
-		// encoded boot dex files, i.e. those files encoded by the individual libraries and returned
-		// from the DexJarBuildPath() method.
-		output = &HiddenAPIOutput{
-			EncodedBootDexFilesByModule: retrieveLegacyEncodedBootDexFiles(ctx, contents),
-		}
-	}
+	// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
+	common := ctx.Module().(commonBootclasspathFragment)
+	output := common.produceHiddenAPIOutput(ctx, contents, input)
 
 	// Initialize a HiddenAPIInfo structure.
 	hiddenAPIInfo := HiddenAPIInfo{
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c4832d2..654ebb7 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -20,7 +20,6 @@
 
 	"android/soong/android"
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
 )
 
 // Contains support for processing hiddenAPI in a modular fashion.
@@ -712,42 +711,6 @@
 	return input
 }
 
-// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
-//
-// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
-// appropriate information needed for hidden API processing breaking the build.
-// TODO(b/179354495): Remove this workaround.
-func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
-	// Performing hidden API processing without stubs is not supported and it is unlikely to ever be
-	// required as the whole point of adding something to the bootclasspath fragment is to add it to
-	// the bootclasspath in order to be used by something else in the system. Without any stubs it
-	// cannot do that.
-	if len(i.StubDexJarsByScope) == 0 {
-		return false
-	}
-
-	// Hidden API processing is always enabled in tests.
-	if ctx.Config().TestProductVariables != nil {
-		return true
-	}
-
-	// A module that has fragments should have access to the information it needs in order to perform
-	// hidden API processing.
-	if len(properties.Fragments) != 0 {
-		return true
-	}
-
-	// The art bootclasspath fragment does not depend on any other fragments but already supports
-	// hidden API processing.
-	imageName := proptools.String(properties.Image_name)
-	if imageName == "art" {
-		return true
-	}
-
-	// Disable it for everything else.
-	return false
-}
-
 // gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
 // dependencies added in hiddenAPIAddStubLibDependencies.
 //
diff --git a/java/java.go b/java/java.go
index 83e9fe1..e38a714 100644
--- a/java/java.go
+++ b/java/java.go
@@ -130,11 +130,19 @@
 			PropertyName: "java_boot_libs",
 			SupportsSdk:  true,
 		},
-		// Temporarily export implementation classes jar for java_boot_libs as it is required for the
-		// hiddenapi processing.
-		// TODO(b/179354495): Revert once hiddenapi processing has been modularized.
-		exportImplementationClassesJar,
-		sdkSnapshotFilePathForJar,
+		func(ctx android.SdkMemberContext, j *Library) android.Path {
+			// Java boot libs are only provided in the SDK to provide access to their dex implementation
+			// jar for use by dexpreopting and boot jars package check. They do not need to provide an
+			// actual implementation jar but the java_import will need a file that exists so just copy an
+			// empty file. Any attempt to use that file as a jar will cause a build error.
+			return ctx.SnapshotBuilder().EmptyFile()
+		},
+		func(osPrefix, name string) string {
+			// Create a special name for the implementation jar to try and provide some useful information
+			// to a developer that attempts to compile against this.
+			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
+			return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
+		},
 		onlyCopyJarToSnapshot,
 	}
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index d1b4a47..268e797 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -981,13 +981,15 @@
 }
 
 // to satisfy SdkLibraryComponentDependency
-func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string {
-	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
-}
-
-// to satisfy SdkLibraryComponentDependency
 func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string {
-	// Currently implementation library name is the same as the SDK library name.
+	// For shared libraries, this is the same as the SDK library name. If a Java library or app
+	// depends on a component library (e.g. a stub library) it still needs to know the name of the
+	// run-time library and the corresponding module that provides the implementation. This name is
+	// passed to manifest_fixer (to be added to AndroidManifest.xml) and added to CLC (to be used
+	// in dexpreopt).
+	//
+	// For non-shared SDK (component or not) libraries this returns `nil`, as they are not
+	// <uses-library> and should not be added to the manifest or to CLC.
 	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
 }
 
@@ -999,12 +1001,6 @@
 	// 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.
-	//
-	// Returns the name of the optional implicit SDK library or nil, if there isn't one.
-	OptionalImplicitSdkLibrary() *string
-
 	// The name of the implementation library for the optional SDK library or nil, if there isn't one.
 	OptionalSdkLibraryImplementation() *string
 }
diff --git a/rust/library.go b/rust/library.go
index 747a29d..5a36bd1 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -431,6 +431,12 @@
 
 func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
+	if library.dylib() {
+		// We need to add a dependency on std in order to link crates as dylibs.
+		// The hack to add this dependency is guarded by the following cfg so
+		// that we don't force a dependency when it isn't needed.
+		library.baseCompiler.Properties.Cfgs = append(library.baseCompiler.Properties.Cfgs, "android_dylib")
+	}
 	flags = library.baseCompiler.compilerFlags(ctx, flags)
 	if library.shared() || library.static() {
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
diff --git a/rust/library_test.go b/rust/library_test.go
index 54cd2a5..cb4ef7e 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -85,6 +85,22 @@
 	}
 }
 
+// Check that we are passing the android_dylib config flag
+func TestAndroidDylib(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host_dylib {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
+		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+	}
+}
+
 func TestValidateLibraryStem(t *testing.T) {
 	testRustError(t, "crate_name must be defined.", `
 			rust_library_host {
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 1d2ab42..efd2b5b 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -133,6 +133,13 @@
     apex_available: ["com.android.art"],
     image_name: "art",
     contents: ["mybootlib"],
+    hidden_api: {
+        stub_flags: "hiddenapi/stub-flags.csv",
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
 }
 
 java_import {
@@ -140,7 +147,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
 }
 `),
 		checkVersionedAndroidBpContents(`
@@ -153,6 +160,13 @@
     apex_available: ["com.android.art"],
     image_name: "art",
     contents: ["mysdk_mybootlib@current"],
+    hidden_api: {
+        stub_flags: "hiddenapi/stub-flags.csv",
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
 }
 
 java_import {
@@ -160,7 +174,7 @@
     sdk_member_name: "mybootlib",
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
 }
 
 sdk_snapshot {
@@ -171,8 +185,13 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
-`),
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+		`),
 		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
 
 		// Check the behavior of the snapshot without the source.
@@ -326,7 +345,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
     permitted_packages: ["mybootlib"],
 }
 
@@ -410,7 +429,7 @@
     sdk_member_name: "mybootlib",
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
     permitted_packages: ["mybootlib"],
 }
 
@@ -480,7 +499,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
@@ -832,7 +851,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
     permitted_packages: ["mybootlib"],
 }
 
@@ -867,7 +886,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/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
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 813dcfd..9efb3a4 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -453,7 +453,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: ["java/myjavalib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
     permitted_packages: ["pkg.myjavalib"],
 }
 `),
@@ -465,7 +465,7 @@
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: ["java/myjavalib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
     permitted_packages: ["pkg.myjavalib"],
 }
 
@@ -474,9 +474,10 @@
     visibility: ["//visibility:public"],
     java_boot_libs: ["myexports_myjavalib@current"],
 }
+
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib/android_common/withres/myjavalib.jar -> java/myjavalib.jar
+.intermediates/myexports/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
 `),
 	)
 }
diff --git a/sdk/update.go b/sdk/update.go
index 6da3756..3ec1bfa 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -1029,6 +1029,9 @@
 	filesToZip  android.Paths
 	zipsToMerge android.Paths
 
+	// The path to an empty file.
+	emptyFile android.WritablePath
+
 	prebuiltModules map[string]*bpModule
 	prebuiltOrder   []*bpModule
 
@@ -1079,6 +1082,19 @@
 	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
 }
 
+func (s *snapshotBuilder) EmptyFile() android.Path {
+	if s.emptyFile == nil {
+		ctx := s.ctx
+		s.emptyFile = android.PathForModuleOut(ctx, "empty")
+		s.ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Touch,
+			Output: s.emptyFile,
+		})
+	}
+
+	return s.emptyFile
+}
+
 func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
 	name := member.Name()
 	if s.prebuiltModules[name] != nil {