Merge "build-ndk-prebuilts: Remove unused device config"
diff --git a/android/variable.go b/android/variable.go
index f2ba89b..2686049 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -95,6 +95,9 @@
 			Lto      struct {
 				Never *bool
 			}
+			Sanitize struct {
+				Address *bool
+			}
 		}
 
 		Pdk struct {
diff --git a/apex/apex.go b/apex/apex.go
index 41c7a97..e6c4d88 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -71,15 +71,17 @@
 }
 
 var (
-	sharedLibTag  = dependencyTag{name: "sharedLib"}
-	executableTag = dependencyTag{name: "executable"}
-	javaLibTag    = dependencyTag{name: "javaLib"}
-	prebuiltTag   = dependencyTag{name: "prebuilt"}
-	keyTag        = dependencyTag{name: "key"}
+	sharedLibTag   = dependencyTag{name: "sharedLib"}
+	executableTag  = dependencyTag{name: "executable"}
+	javaLibTag     = dependencyTag{name: "javaLib"}
+	prebuiltTag    = dependencyTag{name: "prebuilt"}
+	keyTag         = dependencyTag{name: "key"}
+	certificateTag = dependencyTag{name: "certificate"}
 )
 
 func init() {
 	pctx.Import("android/soong/common")
+	pctx.Import("android/soong/java")
 	pctx.HostBinToolVariable("apexer", "apexer")
 	// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
 	// projects, and hence cannot built 'aapt2'. Use the SDK prebuilt instead.
@@ -188,6 +190,10 @@
 	// Name of the apex_key module that provides the private key to sign APEX
 	Key *string
 
+	// The name of a certificate in the default certificate directory, blank to use the default product certificate,
+	// or an android_app_certificate module name in the form ":module".
+	Certificate *string
+
 	Multilib struct {
 		First struct {
 			// List of native libraries whose compile_multilib is "first"
@@ -324,6 +330,11 @@
 		return
 	}
 	ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
+
+	cert := android.SrcIsModule(String(a.properties.Certificate))
+	if cert != "" {
+		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+	}
 }
 
 func getCopyManifestForNativeLibrary(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
@@ -366,6 +377,7 @@
 	copyManifest := make(map[android.Path]string)
 
 	var keyFile android.Path
+	var certificate java.Certificate
 
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		if _, ok := parent.(*apexBundle); ok {
@@ -412,6 +424,13 @@
 				} else {
 					ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
 				}
+			case certificateTag:
+				if dep, ok := child.(*java.AndroidAppCertificate); ok {
+					certificate = dep.Certificate
+					return false
+				} else {
+					ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
+				}
 			}
 		} else {
 			// indirect dependencies
@@ -426,6 +445,18 @@
 		return false
 	})
 
+	cert := String(a.properties.Certificate)
+	if cert != "" && android.SrcIsModule(cert) == "" {
+		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+		certificate = java.Certificate{
+			defaultDir.Join(ctx, cert+".x509.pem"),
+			defaultDir.Join(ctx, cert+".pk8"),
+		}
+	} else if cert == "" {
+		pem, key := ctx.Config().DefaultAppCertificate(ctx)
+		certificate = java.Certificate{pem, key}
+	}
+
 	// files and dirs that will be created in apex
 	var readOnlyPaths []string
 	var executablePaths []string // this also includes dirs
@@ -455,7 +486,7 @@
 	manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "manifest.json"))
 	fileContexts := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.File_contexts, "file_contexts"))
 
-	a.outputFile = android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix)
+	unsignedOutputFile := android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix+".unsigned")
 
 	filesToCopy := []android.Path{}
 	for file := range copyManifest {
@@ -479,7 +510,7 @@
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:      apexRule,
 		Implicits: implicitInputs,
-		Output:    a.outputFile,
+		Output:    unsignedOutputFile,
 		Args: map[string]string{
 			"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 			"image_dir":        android.PathForModuleOut(ctx, "image").String(),
@@ -491,6 +522,17 @@
 		},
 	})
 
+	a.outputFile = android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        java.Signapk,
+		Description: "signapk",
+		Output:      a.outputFile,
+		Input:       unsignedOutputFile,
+		Args: map[string]string{
+			"certificates": strings.Join([]string{certificate.Pem.String(), certificate.Key.String()}, " "),
+		},
+	})
+
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 }
 
diff --git a/java/aapt2.go b/java/aapt2.go
index 5553bfd..86eb9c8 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -188,3 +188,18 @@
 		},
 	})
 }
+
+var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert",
+	blueprint.RuleParams{
+		Command:     `${config.Aapt2Cmd} convert --output-format proto $in -o $out`,
+		CommandDeps: []string{"${config.Aapt2Cmd}"},
+	})
+
+func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aapt2ConvertRule,
+		Input:       in,
+		Output:      out,
+		Description: "convert to proto",
+	})
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 359594c..0d4edfe 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -209,6 +209,9 @@
 				if app.headerJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", app.headerJarFile.String())
 				}
+				if app.bundleFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_BUNDLE :=", app.bundleFile.String())
+				}
 				if app.jacocoReportClassesFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
 				}
@@ -239,7 +242,7 @@
 					fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
 				}
 
-				fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.pem.String())
+				fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
 				if len(app.appProperties.Overrides) > 0 {
 					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES := "+strings.Join(app.appProperties.Overrides, " "))
 				}
@@ -290,6 +293,9 @@
 	data := a.Library.AndroidMk()
 
 	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
+		if a.aarFile != nil {
+			fmt.Fprintln(w, "LOCAL_SOONG_AAR :=", a.aarFile.String())
+		}
 		if a.proguardDictionary != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", a.proguardDictionary.String())
 		}
diff --git a/java/app.go b/java/app.go
index db6c15c..392ad3f 100644
--- a/java/app.go
+++ b/java/app.go
@@ -76,13 +76,15 @@
 	Library
 	aapt
 
-	certificate certificate
+	certificate Certificate
 
 	appProperties appProperties
 
 	extraLinkFlags []string
 
 	installJniLibs []jniLib
+
+	bundleFile android.Path
 }
 
 func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
@@ -99,8 +101,8 @@
 
 var _ AndroidLibraryDependency = (*AndroidApp)(nil)
 
-type certificate struct {
-	pem, key android.Path
+type Certificate struct {
+	Pem, Key android.Path
 }
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -237,7 +239,7 @@
 		dexJarFile = nil
 	}
 
-	var certificates []certificate
+	var certificates []Certificate
 
 	var jniJarFile android.WritablePath
 	jniLibs, certificateDeps := a.collectAppDeps(ctx)
@@ -262,21 +264,25 @@
 		certificateDeps = certificateDeps[1:]
 	} else if cert != "" {
 		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		a.certificate = certificate{
+		a.certificate = Certificate{
 			defaultDir.Join(ctx, cert+".x509.pem"),
 			defaultDir.Join(ctx, cert+".pk8"),
 		}
 	} else {
 		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		a.certificate = certificate{pem, key}
+		a.certificate = Certificate{pem, key}
 	}
 
-	certificates = append([]certificate{a.certificate}, certificateDeps...)
+	certificates = append([]Certificate{a.certificate}, certificateDeps...)
 
 	packageFile := android.PathForModuleOut(ctx, "package.apk")
 	CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
 	a.outputFile = packageFile
 
+	bundleFile := android.PathForModuleOut(ctx, "base.zip")
+	BuildBundleModule(ctx, bundleFile, a.exportPackage, jniJarFile, dexJarFile)
+	a.bundleFile = bundleFile
+
 	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)
@@ -287,9 +293,9 @@
 	}
 }
 
-func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []certificate) {
+func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
 	var jniLibs []jniLib
-	var certificates []certificate
+	var certificates []Certificate
 
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
@@ -313,7 +319,7 @@
 			}
 		} else if tag == certificateTag {
 			if dep, ok := module.(*AndroidAppCertificate); ok {
-				certificates = append(certificates, dep.certificate)
+				certificates = append(certificates, dep.Certificate)
 			} else {
 				ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
 			}
@@ -446,7 +452,7 @@
 type AndroidAppCertificate struct {
 	android.ModuleBase
 	properties  AndroidAppCertificateProperties
-	certificate certificate
+	Certificate Certificate
 }
 
 type AndroidAppCertificateProperties struct {
@@ -466,7 +472,7 @@
 
 func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	cert := String(c.properties.Certificate)
-	c.certificate = certificate{
+	c.Certificate = Certificate{
 		android.PathForModuleSrc(ctx, cert+".x509.pem"),
 		android.PathForModuleSrc(ctx, cert+".pk8"),
 	}
diff --git a/java/app_builder.go b/java/app_builder.go
index 7577444..476eb60 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -29,7 +29,7 @@
 )
 
 var (
-	signapk = pctx.AndroidStaticRule("signapk",
+	Signapk = pctx.AndroidStaticRule("signapk",
 		blueprint.RuleParams{
 			Command: `${config.JavaCmd} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
 				`-jar $signapkCmd $certificates $in $out`,
@@ -63,7 +63,7 @@
 	})
 
 func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	resJarFile, jniJarFile, dexJarFile android.Path, certificates []certificate) {
+	resJarFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
 
 	unsignedApk := android.PathForModuleOut(ctx, "unsigned.apk")
 
@@ -84,11 +84,11 @@
 
 	var certificateArgs []string
 	for _, c := range certificates {
-		certificateArgs = append(certificateArgs, c.pem.String(), c.key.String())
+		certificateArgs = append(certificateArgs, c.Pem.String(), c.Key.String())
 	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        signapk,
+		Rule:        Signapk,
 		Description: "signapk",
 		Output:      outputFile,
 		Input:       unsignedApk,
@@ -134,6 +134,50 @@
 	})
 }
 
+var buildBundleModule = pctx.AndroidStaticRule("buildBundleModule",
+	blueprint.RuleParams{
+		Command: `${config.Zip2ZipCmd} -i ${in} -o ${out}.res.zip AndroidManifest.xml:manifest/AndroidManifest.xml resources.pb "res/**/*" "assets/**/*" &&` +
+			`${config.Zip2ZipCmd} -i ${dexJar} -o ${out}.dex.zip "classes*.dex:dex/" && ` +
+			`${config.MergeZipsCmd} ${out} ${out}.res.zip ${out}.dex.zip ${jniJar} && ` +
+			`rm ${out}.res.zip ${out}.dex.zip`,
+		CommandDeps: []string{
+			"${config.Zip2ZipCmd}",
+			"${config.MergeZipsCmd}",
+		},
+	}, "dexJar", "jniJar")
+
+// Builds an app into a module suitable for input to bundletool
+func BuildBundleModule(ctx android.ModuleContext, outputFile android.WritablePath,
+	resJarFile, jniJarFile, dexJarFile android.Path) {
+
+	protoResJarFile := android.PathForModuleOut(ctx, "package-res.pb.apk")
+	aapt2Convert(ctx, protoResJarFile, resJarFile)
+
+	var deps android.Paths
+	var jniPath string
+	var dexPath string
+	if dexJarFile != nil {
+		deps = append(deps, dexJarFile)
+		dexPath = dexJarFile.String()
+	}
+	if jniJarFile != nil {
+		deps = append(deps, jniJarFile)
+		jniPath = jniJarFile.String()
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        buildBundleModule,
+		Implicits:   deps,
+		Input:       protoResJarFile,
+		Output:      outputFile,
+		Description: "bundle",
+		Args: map[string]string{
+			"dexJar": dexPath,
+			"jniJar": jniPath,
+		},
+	})
+}
+
 func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	jniLibs []jniLib) {
 
diff --git a/ui/build/path.go b/ui/build/path.go
index 52658ef..8260ff9 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -19,6 +19,7 @@
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"runtime"
 	"strings"
 
 	"github.com/google/blueprint/microfactory"
@@ -144,6 +145,13 @@
 	}
 
 	myPath, _ = filepath.Abs(myPath)
+
+	// Use the toybox prebuilts on linux
+	if runtime.GOOS == "linux" {
+		toyboxPath, _ := filepath.Abs("prebuilts/build-tools/toybox/linux-x86")
+		myPath = toyboxPath + string(os.PathListSeparator) + myPath
+	}
+
 	config.Environment().Set("PATH", myPath)
 	config.pathReplaced = true
 }
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index e846b03..b4d76c4 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -25,6 +25,10 @@
 
 	// Whether to exit with an error instead of invoking the underlying tool.
 	Error bool
+
+	// Whether we use a toybox prebuilt for this tool. Since we don't have
+	// toybox for Darwin, we'll use the host version instead.
+	Toybox bool
 }
 
 var Allowed = PathConfig{
@@ -55,6 +59,13 @@
 	Error:   true,
 }
 
+var Toybox = PathConfig{
+	Symlink: false,
+	Log:     true,
+	Error:   true,
+	Toybox:  true,
+}
+
 func GetConfig(name string) PathConfig {
 	if config, ok := Configuration[name]; ok {
 		return config
@@ -138,8 +149,6 @@
 	"todos":     Allowed,
 	"touch":     Allowed,
 	"tr":        Allowed,
-	"true":      Allowed,
-	"uname":     Allowed,
 	"uniq":      Allowed,
 	"unix2dos":  Allowed,
 	"unzip":     Allowed,
@@ -166,10 +175,9 @@
 	"ld.gold":    Forbidden,
 	"pkg-config": Forbidden,
 
-	// We've got prebuilts of these
-	//"dtc":  Forbidden,
-	//"lz4":  Forbidden,
-	//"lz4c": Forbidden,
+	// On linux we'll use the toybox version of these instead
+	"true":  Toybox,
+	"uname": Toybox,
 }
 
 func init() {
@@ -177,5 +185,13 @@
 		Configuration["md5"] = Allowed
 		Configuration["sw_vers"] = Allowed
 		Configuration["xcrun"] = Allowed
+
+		// We don't have toybox prebuilts for darwin, so allow the
+		// host versions.
+		for name, config := range Configuration {
+			if config.Toybox {
+				Configuration[name] = Allowed
+			}
+		}
 	}
 }