Merge "Combine hidden API encoding with flag generation"
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 03db524..8b97467 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -6564,6 +6564,7 @@
 				"com.android.art.debug",
 			],
 			hostdex: true,
+			compile_dex: true,
 		}
 
 		apex {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index d77c47d..1971dcd 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -82,6 +82,7 @@
 				"com.android.art",
 			],
 			srcs: ["b.java"],
+			compile_dex: true,
 		}
 
 		java_library {
@@ -90,6 +91,7 @@
 				"com.android.art",
 			],
 			srcs: ["b.java"],
+			compile_dex: true,
 		}
 
 		bootclasspath_fragment {
@@ -318,6 +320,7 @@
 			apex_available: [
 				"com.android.art",
 			],
+			compile_dex: true,
 		}
 
 		java_import {
@@ -326,6 +329,7 @@
 			apex_available: [
 				"com.android.art",
 			],
+			compile_dex: true,
 		}
 	`),
 	)
@@ -489,7 +493,7 @@
 					src: "com.android.art-arm.apex",
 				},
 			},
-			exported_java_libs: ["foo", "bar"],
+			exported_bootclasspath_fragments: ["mybootclasspathfragment"],
 		}
 
 		java_import {
@@ -521,8 +525,7 @@
 
 	java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 		`com.android.art.apex.selector`,
-		`prebuilt_bar`,
-		`prebuilt_foo`,
+		`prebuilt_mybootclasspathfragment`,
 	})
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common", []string{
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index a6f6505..3ceffd2 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -137,10 +137,13 @@
 // commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
 // bootclasspath fragment modules.
 type commonBootclasspathFragment interface {
-	// produceHiddenAPIAllFlagsFile produces the all-flags.csv and intermediate files.
+	// produceHiddenAPIOutput produces the all-flags.csv and intermediate files and encodes the flags
+	// into dex files.
 	//
-	// Updates the supplied hiddenAPIInfo with the paths to the generated files set.
-	produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIFlagOutput
+	// Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the
+	// module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a
+	// versioned sdk.
+	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
 }
 
 var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil)
@@ -292,9 +295,9 @@
 	// Map from arch type to the boot image files.
 	bootImageFilesByArch map[android.ArchType]android.OutputPaths
 
-	// Map from the name of the context module (as returned by Name()) to the hidden API encoded dex
-	// jar path.
-	contentModuleDexJarPaths map[string]android.Path
+	// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
+	// hidden API encoded dex jar path.
+	contentModuleDexJarPaths bootDexJarByModule
 }
 
 func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
@@ -312,6 +315,8 @@
 //
 // The dex boot jar is one which has had hidden API encoding performed on it.
 func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) {
+	// A bootclasspath_fragment cannot use a prebuilt library so Name() will return the base name
+	// without a prebuilt_ prefix so is safe to use as the key for the contentModuleDexJarPaths.
 	name := module.Name()
 	if dexJar, ok := i.contentModuleDexJarPaths[name]; ok {
 		return dexJar, nil
@@ -400,28 +405,34 @@
 
 	fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
 
-	// Perform hidden API processing.
-	hiddenAPIFlagOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
-
 	// Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
 	// prebuilt which will not use the image config.
 	imageConfig := b.getImageConfig(ctx)
 
-	// A prebuilt fragment cannot contribute to the apex.
-	if !android.IsModulePrebuilt(ctx.Module()) {
-		// Provide the apex content info.
-		b.provideApexContentInfo(ctx, imageConfig, contents, hiddenAPIFlagOutput)
+	// A versioned prebuilt_bootclasspath_fragment cannot and does not need to perform hidden API
+	// processing. It cannot do it because it is not part of a prebuilt_apex and so has no access to
+	// the correct dex implementation jar. It does not need to because the platform-bootclasspath
+	// always references the latest bootclasspath_fragments.
+	if !android.IsModuleInVersionedSdk(ctx.Module()) {
+		// Perform hidden API processing.
+		hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
+
+		// A prebuilt fragment cannot contribute to an apex.
+		if !android.IsModulePrebuilt(ctx.Module()) {
+			// Provide the apex content info.
+			b.provideApexContentInfo(ctx, imageConfig, contents, hiddenAPIOutput)
+		}
 	}
 }
 
 // provideApexContentInfo creates, initializes and stores the apex content info for use by other
 // modules.
-func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) {
+func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module, hiddenAPIOutput *HiddenAPIOutput) {
 	// Construct the apex content info from the config.
-	info := BootclasspathFragmentApexContentInfo{}
-
-	// Populate the apex content info with paths to the dex jars.
-	b.populateApexContentInfoDexJars(ctx, &info, contents, hiddenAPIFlagOutput)
+	info := BootclasspathFragmentApexContentInfo{
+		// Populate the apex content info with paths to the dex jars.
+		contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule,
+	}
 
 	if imageConfig != nil {
 		info.modules = imageConfig.modules
@@ -451,38 +462,6 @@
 	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
 }
 
-// populateApexContentInfoDexJars adds paths to the dex jars provided by this fragment to the
-// apex content info.
-func (b *BootclasspathFragmentModule) populateApexContentInfoDexJars(ctx android.ModuleContext, info *BootclasspathFragmentApexContentInfo, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) {
-
-	info.contentModuleDexJarPaths = map[string]android.Path{}
-	if hiddenAPIFlagOutput != nil {
-		// Hidden API encoding has been performed.
-		flags := hiddenAPIFlagOutput.AllFlagsPath
-		for _, m := range contents {
-			h := m.(hiddenAPIModule)
-			unencodedDex := h.bootDexJar()
-			if unencodedDex == nil {
-				// This is an error. Sometimes Soong will report the error directly, other times it will
-				// defer the error reporting to happen only when trying to use the missing file in ninja.
-				// Either way it is handled by extractBootDexJarsFromModules which must have been
-				// called before this as it generates the flags that are used to encode these files.
-				continue
-			}
-
-			outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
-			encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, flags, *h.uncompressDex(), outputDir)
-			info.contentModuleDexJarPaths[m.Name()] = encodedDex
-		}
-	} else {
-		for _, m := range contents {
-			j := m.(UsesLibraryDependency)
-			dexJar := j.DexJarBuildPath()
-			info.contentModuleDexJarPaths[m.Name()] = dexJar
-		}
-	}
-}
-
 // generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
 func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
 	var classpathJars []classpathJar
@@ -548,12 +527,12 @@
 }
 
 // generateHiddenAPIBuildActions generates all the hidden API related build rules.
-func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIFlagOutput {
+func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput {
 
 	// Create hidden API input structure.
 	input := b.createHiddenAPIFlagInput(ctx, contents, fragments)
 
-	var output *HiddenAPIFlagOutput
+	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
@@ -563,7 +542,14 @@
 	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.produceHiddenAPIAllFlagsFile(ctx, contents, input)
+		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),
+		}
 	}
 
 	// Initialize a HiddenAPIInfo structure.
@@ -580,11 +566,9 @@
 		TransitiveStubDexJarsByKind: input.transitiveStubDexJarsByKind(),
 	}
 
-	if output != nil {
-		// The monolithic hidden API processing also needs access to all the output files produced by
-		// hidden API processing of this fragment.
-		hiddenAPIInfo.HiddenAPIFlagOutput = *output
-	}
+	// The monolithic hidden API processing also needs access to all the output files produced by
+	// hidden API processing of this fragment.
+	hiddenAPIInfo.HiddenAPIFlagOutput = (*output).HiddenAPIFlagOutput
 
 	//  Provide it for use by other modules.
 	ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
@@ -592,6 +576,21 @@
 	return output
 }
 
+// retrieveLegacyEncodedBootDexFiles attempts to retrieve the legacy encoded boot dex jar files.
+func retrieveLegacyEncodedBootDexFiles(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
+	// If the current bootclasspath_fragment is the active module or a source module then retrieve the
+	// encoded dex files, otherwise return an empty map.
+	//
+	// An inactive (i.e. not preferred) bootclasspath_fragment needs to retrieve the encoded dex jars
+	// as they are still needed by an apex. An inactive prebuilt_bootclasspath_fragment does not need
+	// to do so and may not yet have access to dex boot jars from a prebuilt_apex/apex_set.
+	if isActiveModule(ctx.Module()) || !android.IsModulePrebuilt(ctx.Module()) {
+		return extractEncodedDexJarsFromModules(ctx, contents)
+	} else {
+		return nil
+	}
+}
+
 // createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
 // from the properties on this module and its dependencies.
 func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
@@ -615,12 +614,12 @@
 	return input
 }
 
-// produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files)
-// for the fragment.
-func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
+// for the fragment as well as encoding the flags in the boot dex jars.
+func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
 	// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
 	// paths to the created files.
-	return hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, input)
+	return hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
 }
 
 // generateBootImageBuildActions generates ninja rules to create the boot image if required for this
@@ -836,9 +835,8 @@
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
-// produceHiddenAPIAllFlagsFile returns a path to the prebuilt all-flags.csv or nil if none is
-// specified.
-func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, _ HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
+func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
 	pathForOptionalSrc := func(src *string) android.Path {
 		if src == nil {
 			// TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
@@ -847,12 +845,19 @@
 		return android.PathForModuleSrc(ctx, *src)
 	}
 
-	output := HiddenAPIFlagOutput{
-		StubFlagsPath:       pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags),
-		AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags),
-		MetadataPath:        pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata),
-		IndexPath:           pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index),
-		AllFlagsPath:        pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags),
+	// Retrieve the dex files directly from the content modules. They in turn should retrieve the
+	// encoded dex jars from the prebuilt .apex files.
+	encodedBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, contents)
+
+	output := HiddenAPIOutput{
+		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
+			StubFlagsPath:       pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags),
+			AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags),
+			MetadataPath:        pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata),
+			IndexPath:           pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index),
+			AllFlagsPath:        pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags),
+		},
+		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
 	}
 
 	return &output
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 643c5cb..60300af 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -580,6 +580,23 @@
 	b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
 }
 
+// bootDexJars returns the boot dex jar paths sorted by their keys.
+func (b bootDexJarByModule) bootDexJars() android.Paths {
+	paths := android.Paths{}
+	for _, k := range android.SortedStringKeys(b) {
+		paths = append(paths, b[k])
+	}
+	return paths
+}
+
+// HiddenAPIOutput encapsulates the output from the hidden API processing.
+type HiddenAPIOutput struct {
+	HiddenAPIFlagOutput
+
+	// The map from base module name to the path to the encoded boot dex file.
+	EncodedBootDexFilesByModule bootDexJarByModule
+}
+
 // pathForValidation creates a path of the same type as the supplied type but with a name of
 // <path>.valid.
 //
@@ -665,8 +682,8 @@
 	rule.Build(name, desc)
 }
 
-// hiddenAPIGenerateAllFlagsForBootclasspathFragment will generate all the flags for a fragment
-// of the bootclasspath.
+// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
+// bootclasspath and then encode the flags into the boot dex files.
 //
 // It takes:
 // * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
@@ -679,15 +696,16 @@
 // * metadata.csv
 // * index.csv
 // * all-flags.csv
-func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+// * encoded boot dex files
+func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
 	hiddenApiSubDir := "modular-hiddenapi"
 
-	// Gather the dex files for the boot libraries provided by this fragment.
-	bootDexJars := extractBootDexJarsFromModules(ctx, contents)
+	// Gather information about the boot dex files for the boot libraries provided by this fragment.
+	bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
 
 	// Generate the stub-flags.csv.
 	stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
-	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, input)
+	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input)
 	rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
 
 	// Extract the classes jars from the contents.
@@ -715,16 +733,29 @@
 
 	// Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
 	// files.
-	outputPath := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
-	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, annotationFlagsCSV, input.FlagFilesByCategory, nil, removedDexSignatures)
+	allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
+	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, annotationFlagsCSV, input.FlagFilesByCategory, nil, removedDexSignatures)
+
+	// Encode the flags into the boot dex files.
+	encodedBootDexJarsByModule := map[string]android.Path{}
+	outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
+	for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
+		bootDexInfo := bootDexInfoByModule[name]
+		unencodedDex := bootDexInfo.path
+		encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
+		encodedBootDexJarsByModule[name] = encodedDex
+	}
 
 	// Store the paths in the info for use by other modules and sdk snapshot generation.
-	output := HiddenAPIFlagOutput{
-		StubFlagsPath:       stubFlagsCSV,
-		AnnotationFlagsPath: annotationFlagsCSV,
-		MetadataPath:        metadataCSV,
-		IndexPath:           indexCSV,
-		AllFlagsPath:        outputPath,
+	output := HiddenAPIOutput{
+		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
+			StubFlagsPath:       stubFlagsCSV,
+			AnnotationFlagsPath: annotationFlagsCSV,
+			MetadataPath:        metadataCSV,
+			IndexPath:           indexCSV,
+			AllFlagsPath:        allFlagsCSV,
+		},
+		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
 	}
 	return &output
 }
@@ -747,37 +778,15 @@
 }
 
 // extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
-func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) android.Paths {
-	bootDexJars := android.Paths{}
+func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
+	bootDexJars := bootDexJarByModule{}
 	for _, module := range contents {
 		hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
 		if hiddenAPIModule == nil {
 			continue
 		}
-		bootDexJar := hiddenAPIModule.bootDexJar()
-		if bootDexJar == nil {
-			if ctx.Config().AlwaysUsePrebuiltSdks() {
-				// TODO(b/179354495): Remove this workaround when it is unnecessary.
-				// Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
-				// create a fake one that will cause a build error only if it is used.
-				fake := android.PathForModuleOut(ctx, "fake/boot-dex/%s.jar", module.Name())
-
-				// Create an error rule that pretends to create the output file but will actually fail if it
-				// is run.
-				ctx.Build(pctx, android.BuildParams{
-					Rule:   android.ErrorRule,
-					Output: fake,
-					Args: map[string]string{
-						"error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
-					},
-				})
-				bootDexJars = append(bootDexJars, fake)
-			} else {
-				ctx.ModuleErrorf("module %s does not provide a dex jar", module)
-			}
-		} else {
-			bootDexJars = append(bootDexJars, bootDexJar)
-		}
+		bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
+		bootDexJars.addPath(module, bootDexJar)
 	}
 	return bootDexJars
 }
@@ -794,6 +803,60 @@
 	return nil
 }
 
+// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
+type bootDexInfo struct {
+	// The path to the dex jar that has not had hidden API flags encoded into it.
+	path android.Path
+
+	// Indicates whether the dex jar needs uncompressing before encoding.
+	uncompressDex bool
+}
+
+// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
+// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
+type bootDexInfoByModule map[string]bootDexInfo
+
+// bootDexJars returns the boot dex jar paths sorted by their keys.
+func (b bootDexInfoByModule) bootDexJars() android.Paths {
+	paths := android.Paths{}
+	for _, m := range android.SortedStringKeys(b) {
+		paths = append(paths, b[m].path)
+	}
+	return paths
+}
+
+// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
+// each of the supplied modules which must implement hiddenAPIModule.
+func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
+	bootDexJarsByModule := bootDexInfoByModule{}
+	for _, module := range contents {
+		hiddenAPIModule := module.(hiddenAPIModule)
+		bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
+		bootDexJarsByModule[module.Name()] = bootDexInfo{
+			path:          bootDexJar,
+			uncompressDex: *hiddenAPIModule.uncompressDex(),
+		}
+	}
+
+	return bootDexJarsByModule
+}
+
+// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
+//
+// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then  that
+// create a fake path and either report an error immediately or defer reporting of the error until
+// the path is actually used.
+func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
+	bootDexJar := module.bootDexJar()
+	if bootDexJar == nil {
+		fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
+		bootDexJar = fake
+
+		handleMissingDexBootFile(ctx, module, fake)
+	}
+	return bootDexJar
+}
+
 // extractClassesJarsFromModules extracts the class jars from the supplied modules.
 func extractClassesJarsFromModules(contents []android.Module) android.Paths {
 	classesJars := android.Paths{}
@@ -822,6 +885,11 @@
 		return true
 	}
 
+	// Any missing dependency should be allowed.
+	if ctx.Config().AllowMissingDependencies() {
+		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.
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 1a4f9b7..1ba463c 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -291,9 +291,9 @@
 	input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory
 
 	// Generate the monolithic stub-flags.csv file.
-	bootDexJars := extractBootDexJarsFromModules(ctx, modules)
+	bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules)
 	stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
-	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, input)
+	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJarByModule.bootDexJars(), input)
 	rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
 
 	// Extract the classes jars from the contents.