Merge "Generalize deapexer module to export any files"
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 9bc5720..c7cdbfa 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -40,17 +40,29 @@
 // This is intentionally not registered by name as it is not intended to be used from within an
 // `Android.bp` file.
 
-// Properties that are specific to `deapexer` but which need to be provided on the `prebuilt_apex`
-// module.`
-type DeapexerProperties struct {
-	// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
-	// APEX bundle will create an APEX variant and provide dex implementation jars for use by
-	// dexpreopt and boot jars package check.
-	Exported_java_libs []string
+// DeapexerExportedFile defines the properties needed to expose a file from the deapexer module.
+type DeapexerExportedFile struct {
+	// The tag parameter which must be passed to android.OutputFileProducer OutputFiles(tag) method
+	// to retrieve the path to the unpacked file.
+	Tag string
 
-	// List of bootclasspath fragments inside this prebuiltd APEX bundle and for which this APEX
-	// bundle will create an APEX variant.
-	Exported_bootclasspath_fragments []string
+	// The path within the APEX that needs to be exported.
+	Path string `android:"path"`
+}
+
+// DeapexerProperties specifies the properties supported by the deapexer module.
+//
+// As these are never intended to be supplied in a .bp file they use a different naming convention
+// to make it clear that they are different.
+type DeapexerProperties struct {
+	// List of common modules that may need access to files exported by this module.
+	//
+	// A common module in this sense is one that is not arch specific but uses a common variant for
+	// all architectures, e.g. java.
+	CommonModules []string
+
+	// List of files exported from the .apex file by this module
+	ExportedFiles []DeapexerExportedFile
 }
 
 type SelectedApexProperties struct {
@@ -81,7 +93,7 @@
 func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies from the java modules to which this exports files from the `.apex` file onto
 	// this module so that they can access the `DeapexerInfo` object that this provides.
-	for _, lib := range p.properties.Exported_java_libs {
+	for _, lib := range p.properties.CommonModules {
 		dep := prebuiltApexExportedModuleName(ctx, lib)
 		ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
 	}
@@ -96,10 +108,12 @@
 	exports := make(map[string]android.Path)
 
 	// Create mappings from name+tag to all the required exported paths.
-	for _, l := range p.properties.Exported_java_libs {
-		// Populate the exports that this makes available. The path here must match the path of the
-		// file in the APEX created by apexFileForJavaModule(...).
-		exports[l+"{.dexjar}"] = deapexerOutput.Join(ctx, "javalib", l+".jar")
+	for _, e := range p.properties.ExportedFiles {
+		tag := e.Tag
+		path := e.Path
+
+		// Populate the exports that this makes available.
+		exports[tag] = deapexerOutput.Join(ctx, path)
 	}
 
 	// If the prebuilt_apex exports any files then create a build rule that unpacks the apex using
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 92694c9..9d632a9 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"strconv"
 	"strings"
 
@@ -57,10 +58,18 @@
 }
 
 type prebuiltCommonProperties struct {
-	DeapexerProperties
 	SelectedApexProperties
 
 	ForceDisable bool `blueprint:"mutated"`
+
+	// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
+	// APEX bundle will create an APEX variant and provide dex implementation jars for use by
+	// dexpreopt and boot jars package check.
+	Exported_java_libs []string
+
+	// List of bootclasspath fragments inside this prebuilt APEX bundle and for which this APEX
+	// bundle will create an APEX variant.
+	Exported_bootclasspath_fragments []string
 }
 
 func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
@@ -411,15 +420,20 @@
 	}
 
 	// Compute the deapexer properties from the transitive dependencies of this module.
-	deapexerProperties := &DeapexerProperties{}
+	javaModules := []string{}
+	exportedFiles := map[string]string{}
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
 
 		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
 		if java.IsBootclasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
-			deapexerProperties.Exported_java_libs = append(deapexerProperties.Exported_java_libs, name)
+			javaModules = append(javaModules, name)
+
+			// Add the dex implementation jar to the set of exported files. The path here must match the
+			// path of the file in the APEX created by apexFileForJavaModule(...).
+			exportedFiles[name+"{.dexjar}"] = filepath.Join("javalib", name+".jar")
+
 		} else if tag == exportedBootclasspathFragmentTag {
-			deapexerProperties.Exported_bootclasspath_fragments = append(deapexerProperties.Exported_bootclasspath_fragments, name)
 			// Only visit the children of the bootclasspath_fragment for now.
 			return true
 		}
@@ -427,9 +441,20 @@
 		return false
 	})
 
-	// Remove any duplicates from the deapexer lists.
-	deapexerProperties.Exported_bootclasspath_fragments = android.FirstUniqueStrings(deapexerProperties.Exported_bootclasspath_fragments)
-	deapexerProperties.Exported_java_libs = android.FirstUniqueStrings(deapexerProperties.Exported_java_libs)
+	// Create properties for deapexer module.
+	deapexerProperties := &DeapexerProperties{
+		// Remove any duplicates from the java modules lists as a module may be included via a direct
+		// dependency as well as transitive ones.
+		CommonModules: android.SortedUniqueStrings(javaModules),
+	}
+
+	// Populate the exported files property in a fixed order.
+	for _, tag := range android.SortedStringKeys(exportedFiles) {
+		deapexerProperties.ExportedFiles = append(deapexerProperties.ExportedFiles, DeapexerExportedFile{
+			Tag:  tag,
+			Path: exportedFiles[tag],
+		})
+	}
 
 	props := struct {
 		Name          *string