Merge "java_sdk_library - Allow it to be replaced by prebuilt"
diff --git a/apex/apex.go b/apex/apex.go
index d15b6c9..eafc186 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2094,12 +2094,12 @@
 					}
 					filesInfo = append(filesInfo, af)
 
-					pf, _ := sdkLib.OutputFiles(".xml")
-					if len(pf) != 1 {
+					pf := sdkLib.XmlPermissionsFile()
+					if pf == nil {
 						ctx.PropertyErrorf("java_libs", "%q failed to generate permission XML", depName)
 						return false
 					}
-					filesInfo = append(filesInfo, newApexFile(ctx, pf[0], pf[0].Base(), "etc/permissions", etc, nil))
+					filesInfo = append(filesInfo, newApexFile(ctx, pf, pf.Base(), "etc/permissions", etc, nil))
 					return true // track transitive dependencies
 				} else {
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c5b89e6..508bde6 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3488,8 +3488,9 @@
 		"etc/permissions/foo.xml",
 	})
 	// Permission XML should point to the activated path of impl jar of java_sdk_library
-	xml := ctx.ModuleForTests("foo", "android_common_myapex").Output("foo.xml")
-	ensureContains(t, xml.Args["content"], `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
+	sdkLibrary := ctx.ModuleForTests("foo", "android_common_myapex").Module().(*java.SdkLibrary)
+	xml := sdkLibrary.XmlPermissionsFileContent()
+	ensureContains(t, xml, `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
 }
 
 func TestCompatConfig(t *testing.T) {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 94c2d13..f1c565f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/genrule"
 
 	"fmt"
 	"io"
@@ -264,6 +265,8 @@
 	}
 }
 
+var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
+
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	for _, apiScope := range module.getActiveApiScopes() {
 		// Add dependencies to the stubs library
@@ -273,6 +276,11 @@
 		ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.docsName(apiScope))
 	}
 
+	if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
+		// Add dependency to the rule for generating the xml permissions file
+		ctx.AddDependency(module, xmlPermissionsFileTag, module.genXmlPermissionsFileName())
+	}
+
 	module.Library.deps(ctx)
 }
 
@@ -282,8 +290,6 @@
 		module.Library.GenerateAndroidBuildActions(ctx)
 	}
 
-	module.buildPermissionsFile(ctx)
-
 	// Record the paths to the header jars of the library (stubs and impl).
 	// When this java_sdk_library is depended upon from others via "libs" property,
 	// the recorded paths will be returned depending on the link type of the caller.
@@ -308,33 +314,21 @@
 				ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
 			}
 		}
+		if tag == xmlPermissionsFileTag {
+			if genRule, ok := to.(genrule.SourceFileGenerator); ok {
+				pf := genRule.GeneratedSourceFiles()
+				if len(pf) != 1 {
+					ctx.ModuleErrorf("%q failed to generate permission XML", otherName)
+				} else {
+					module.permissionsFile = pf[0]
+				}
+			} else {
+				ctx.ModuleErrorf("depends on module %q to generate xml permissions file but it does not provide any outputs", otherName)
+			}
+		}
 	})
 }
 
-func (module *SdkLibrary) buildPermissionsFile(ctx android.ModuleContext) {
-	xmlContent := fmt.Sprintf(permissionsTemplate, module.BaseModuleName(), module.implPath())
-	permissionsFile := android.PathForModuleOut(ctx, module.xmlFileName())
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      permissionsFile,
-		Description: "Generating " + module.BaseModuleName() + " permissions",
-		Args: map[string]string{
-			"content": xmlContent,
-		},
-	})
-
-	module.permissionsFile = permissionsFile
-}
-
-func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
-	switch tag {
-	case ".xml":
-		return android.Paths{module.permissionsFile}, nil
-	}
-	return module.Library.OutputFiles(tag)
-}
-
 func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
 	if proptools.Bool(module.sdkLibraryProperties.Api_only) {
 		return nil
@@ -421,6 +415,11 @@
 	return module.BaseModuleName() + sdkXmlFileSuffix
 }
 
+// Module name of the rule for generating the XML permissions file
+func (module *SdkLibrary) genXmlPermissionsFileName() string {
+	return "gen-" + module.BaseModuleName() + sdkXmlFileSuffix
+}
+
 // Get the sdk version for use when compiling the stubs library.
 func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -614,8 +613,34 @@
 	mctx.CreateModule(DroidstubsFactory, &props)
 }
 
+func (module *SdkLibrary) XmlPermissionsFile() android.Path {
+	return module.permissionsFile
+}
+
+func (module *SdkLibrary) XmlPermissionsFileContent() string {
+	return fmt.Sprintf(permissionsTemplate, module.BaseModuleName(), module.implPath())
+}
+
 // Creates the xml file that publicizes the runtime library
 func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
+
+	xmlContent := module.XmlPermissionsFileContent()
+
+	genRuleName := module.genXmlPermissionsFileName()
+
+	// Create a genrule module to create the XML permissions file.
+	genRuleProps := struct {
+		Name *string
+		Cmd  *string
+		Out  []string
+	}{
+		Name: proptools.StringPtr(genRuleName),
+		Cmd:  proptools.StringPtr("echo -e '" + xmlContent + "' > '$(out)'"),
+		Out:  []string{module.xmlFileName()},
+	}
+
+	mctx.CreateModule(genrule.GenRuleFactory, &genRuleProps)
+
 	// creates a prebuilt_etc module to actually place the xml file under
 	// <partition>/etc/permissions
 	etcProps := struct {
@@ -628,7 +653,7 @@
 		System_ext_specific *bool
 	}{}
 	etcProps.Name = proptools.StringPtr(module.xmlFileName())
-	etcProps.Src = proptools.StringPtr(":" + module.BaseModuleName() + "{.xml}")
+	etcProps.Src = proptools.StringPtr(":" + genRuleName)
 	etcProps.Sub_dir = proptools.StringPtr("permissions")
 	if module.SocSpecific() {
 		etcProps.Soc_specific = proptools.BoolPtr(true)