Allow building framework.jar and framework-res.apk

Update app support enough to build framework-res.apk, link
framework.jar against its generated files, and export it to
make.

Bug: 69917341
Test: m checkbuild tests docs
Change-Id: I7db29cd1f5fabb22e844483ecc7c38abfedbbe0a
diff --git a/java/androidmk.go b/java/androidmk.go
index df83faa..86e000d 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -46,6 +46,14 @@
 				if library.jacocoReportClassesFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", library.jacocoReportClassesFile.String())
 				}
+
+				// Temporary hack: export sources used to compile framework.jar to Make
+				// to be used for droiddoc
+				// TODO(ccross): remove this once droiddoc is in soong
+				if library.Name() == "framework" {
+					fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCS :=", strings.Join(library.compiledJavaSrcs.Strings(), " "))
+					fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCJARS :=", strings.Join(library.compiledSrcJars.Strings(), " "))
+				}
 			},
 		},
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
@@ -111,3 +119,33 @@
 		},
 	}
 }
+
+func (app *AndroidApp) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "APPS",
+		OutputFile: android.OptionalPathForPath(app.outputFile),
+		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				if Bool(app.appProperties.Export_package_resources) {
+					if app.dexJarFile != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
+					}
+					fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
+
+					if app.jacocoReportClassesFile != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
+					}
+
+					if app.Name() == "framework-res" {
+						fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+						// Make base_rules.mk not put framework-res in a subdirectory called
+						// framework_res.
+						fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
+					}
+				}
+			},
+		},
+	}
+
+}
diff --git a/java/app.go b/java/app.go
index bd9ed2a..b66eb4b 100644
--- a/java/app.go
+++ b/java/app.go
@@ -27,6 +27,7 @@
 
 func init() {
 	android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+	android.RegisterModuleType("android_app", AndroidAppFactory)
 }
 
 // AAR prebuilts
@@ -76,7 +77,7 @@
 
 	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
 		switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
-		case "current", "system_current", "":
+		case "current", "system_current", "test_current", "":
 			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
 		default:
 			// We'll already have a dependency on an sdk prebuilt android.jar
@@ -116,7 +117,13 @@
 	//	a.properties.Proguard.Enabled = true
 	//}
 
-	a.Module.compile(ctx)
+	if String(a.appProperties.Instrumentation_for) == "" {
+		a.properties.Instrument = true
+	}
+
+	if ctx.ModuleName() != "framework-res" {
+		a.Module.compile(ctx, a.aaptSrcJar)
+	}
 
 	certificate := String(a.appProperties.Certificate)
 	if certificate == "" {
@@ -138,7 +145,12 @@
 
 	a.outputFile = packageFile
 
-	ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	if ctx.ModuleName() == "framework-res" {
+		// framework-res.apk is installed as system/framework/framework-res.apk
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".apk", a.outputFile)
+	} else {
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	}
 }
 
 var aaptIgnoreFilenames = []string{
diff --git a/java/app_builder.go b/java/app_builder.go
index 82574ae..676ed58 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -29,8 +29,9 @@
 var (
 	signapk = pctx.AndroidStaticRule("signapk",
 		blueprint.RuleParams{
-			Command:     `java -jar $signapkCmd $certificates $in $out`,
-			CommandDeps: []string{"$signapkCmd"},
+			Command: `${config.JavaCmd} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
+				`-jar $signapkCmd $certificates $in $out`,
+			CommandDeps: []string{"$signapkCmd", "$signapkJniLibrary"},
 		},
 		"certificates")
 
@@ -48,6 +49,9 @@
 	pctx.SourcePathVariable("androidManifestMergerCmd", "prebuilts/devtools/tools/lib/manifest-merger.jar")
 	pctx.HostBinToolVariable("aaptCmd", "aapt")
 	pctx.HostJavaToolVariable("signapkCmd", "signapk.jar")
+	// TODO(ccross): this should come from the signapk dependencies, but we don't have any way
+	// to express host JNI dependencies yet.
+	pctx.HostJNIToolVariable("signapkJniLibrary", "libconscrypt_openjdk_jni")
 }
 
 var combineApk = pctx.AndroidStaticRule("combineApk",
@@ -79,6 +83,9 @@
 		certificateArgs = append(certificateArgs, c+".x509.pem", c+".pk8")
 	}
 
+	// TODO(ccross): sometimes uncompress dex
+	// TODO(ccross): sometimes strip dex
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        signapk,
 		Description: "signapk",
diff --git a/java/app_test.go b/java/app_test.go
index 0b1491e..8e50b9f 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -35,17 +35,7 @@
 )
 
 func testApp(t *testing.T, bp string) *android.TestContext {
-	bp += `
-		android_app {
-			name: "framework-res",
-			no_framework_libs: true,
-		}
-	`
-
-	appFs := map[string][]byte{
-		"AndroidManifest.xml":                   nil,
-		"build/target/product/security/testkey": nil,
-	}
+	appFs := map[string][]byte{}
 
 	for _, file := range resourceFiles {
 		appFs[file] = nil
diff --git a/java/java.go b/java/java.go
index 82ff827..f875c79 100644
--- a/java/java.go
+++ b/java/java.go
@@ -41,7 +41,6 @@
 	android.RegisterModuleType("java_binary_host", BinaryHostFactory)
 	android.RegisterModuleType("java_import", ImportFactory)
 	android.RegisterModuleType("java_import_host", ImportFactoryHost)
-	android.RegisterModuleType("android_app", AndroidAppFactory)
 
 	android.RegisterSingletonType("logtags", LogtagsSingleton)
 }
@@ -206,6 +205,10 @@
 
 	// installed file for binary dependency
 	installFile android.Path
+
+	// list of .java files and srcjars that was passed to javac
+	compiledJavaSrcs android.Paths
+	compiledSrcJars  android.Paths
 }
 
 type Dependency interface {
@@ -349,6 +352,9 @@
 		} else if *j.deviceProperties.System_modules != "none" && ctx.Config().TargetOpenJDK9() {
 			ctx.AddDependency(ctx.Module(), systemModulesTag, *j.deviceProperties.System_modules)
 		}
+		if ctx.ModuleName() == "framework" {
+			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
+		}
 	}
 
 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
@@ -612,6 +618,10 @@
 		}
 	}
 
+	// Store the list of .java files that was passed to javac
+	j.compiledJavaSrcs = uniqueSrcFiles
+	j.compiledSrcJars = srcJars
+
 	enable_sharding := false
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
 		if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
diff --git a/java/java_test.go b/java/java_test.go
index cf5047b..0a9eba9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -97,6 +97,13 @@
 		`, extra)
 	}
 
+	bp += `
+		android_app {
+			name: "framework-res",
+			no_framework_libs: true,
+		}
+	`
+
 	if config.TargetOpenJDK9() {
 		systemModules := []string{
 			"core-system-modules",
@@ -134,6 +141,10 @@
 		"prebuilts/sdk/system_current/framework.aidl": nil,
 		"prebuilts/sdk/test_current/android.jar":      nil,
 		"prebuilts/sdk/test_current/framework.aidl":   nil,
+
+		// For framework-res, which is an implicit dependency for framework
+		"AndroidManifest.xml":                   nil,
+		"build/target/product/security/testkey": nil,
 	}
 
 	for k, v := range fs {