Merge "Fix use_embedded_native_libs handling for android_test"
diff --git a/Android.bp b/Android.bp
index 1fdd44e..25e2796 100644
--- a/Android.bp
+++ b/Android.bp
@@ -276,6 +276,7 @@
         "java/plugin.go",
         "java/prebuilt_apis.go",
         "java/proto.go",
+        "java/robolectric.go",
         "java/sdk.go",
         "java/sdk_library.go",
         "java/support_libraries.go",
diff --git a/android/module.go b/android/module.go
index 6743412..e3c37bb 100644
--- a/android/module.go
+++ b/android/module.go
@@ -143,6 +143,7 @@
 	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 
+	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
 	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
 
@@ -1093,6 +1094,18 @@
 	}
 }
 
+func (a *androidModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
+	var deps []Module
+	a.VisitDirectDepsBlueprint(func(m blueprint.Module) {
+		if aModule, _ := m.(Module); aModule != nil {
+			if a.ModuleContext.OtherModuleDependencyTag(aModule) == tag {
+				deps = append(deps, aModule)
+			}
+		}
+	})
+	return deps
+}
+
 func (a *androidModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
 	m, _ := a.getDirectDepInternal(name, tag)
 	return m
diff --git a/android/neverallow.go b/android/neverallow.go
index fba43b3..9314483 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -97,32 +97,15 @@
 		"external/wycheproof",
 	}
 
-	var coreModules = []string{
-		"core-all",
-		"core-oj",
-		"core-libart",
-		"okhttp",
-		"bouncycastle",
-		"conscrypt",
-		"apache-xml",
-	}
-
-	// Core library constraints. Prevent targets adding dependencies on core
-	// library internals, which could lead to compatibility issues with the ART
-	// mainline module. They should use core.platform.api.stubs instead.
+	// Core library constraints. The no_standard_libs can only be used in core
+	// library projects. Access to core library targets is restricted using
+	// visibility rules.
 	rules := []*rule{
 		neverallow().
 			notIn(append(coreLibraryProjects, "development")...).
 			with("no_standard_libs", "true"),
 	}
 
-	for _, m := range coreModules {
-		r := neverallow().
-			notIn(coreLibraryProjects...).
-			with("libs", m).
-			because("Only core libraries projects can depend on " + m)
-		rules = append(rules, r)
-	}
 	return rules
 }
 
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index d55ca57..00c51ea 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -138,17 +138,6 @@
 		expectedError: "",
 	},
 	{
-		name: "dependency on core-libart",
-		fs: map[string][]byte{
-			"Blueprints": []byte(`
-				java_library {
-					name: "needs_core_libart",
-					libs: ["core-libart"],
-				}`),
-		},
-		expectedError: "Only core libraries projects can depend on core-libart",
-	},
-	{
 		name: "java_device_for_host",
 		fs: map[string][]byte{
 			"Blueprints": []byte(`
diff --git a/cmd/diff_target_files/known_nondeterminism.whitelist b/cmd/diff_target_files/known_nondeterminism.whitelist
index 6d71403..a8ade49 100644
--- a/cmd/diff_target_files/known_nondeterminism.whitelist
+++ b/cmd/diff_target_files/known_nondeterminism.whitelist
@@ -3,8 +3,6 @@
 [
   {
     "Paths": [
-       // b/120039850
-      "system/framework/oat/*/services.art"
     ]
   }
 ]
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index f1fa0ff..3b77042 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -59,6 +59,7 @@
 	NeverAllowStripping bool // whether stripping should not be done - used as build time check to make sure dex files are always available
 
 	NoDebugInfo                 bool // don't generate debug info by default
+	DontResolveStartupStrings   bool // don't resolve string literals loaded during application startup.
 	AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true)
 	NeverSystemServerDebugInfo  bool // never generate mini debug info for system server modules (overrides NoDebugInfo=false)
 	AlwaysOtherDebugInfo        bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
@@ -301,6 +302,7 @@
 		GenerateDMFiles:                    false,
 		NeverAllowStripping:                false,
 		NoDebugInfo:                        false,
+		DontResolveStartupStrings:          false,
 		AlwaysSystemServerDebugInfo:        false,
 		NeverSystemServerDebugInfo:         false,
 		AlwaysOtherDebugInfo:               false,
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 01ee15e..5b658d9 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -461,6 +461,9 @@
 		appImageInstallPath := pathtools.ReplaceExtension(odexInstallPath, "art")
 		cmd.FlagWithOutput("--app-image-file=", appImagePath).
 			FlagWithArg("--image-format=", "lz4")
+		if !global.DontResolveStartupStrings {
+			cmd.FlagWithArg("--resolve-startup-const-strings=", "true")
+		}
 		rule.Install(appImagePath, appImageInstallPath)
 	}
 
diff --git a/java/OWNERS b/java/OWNERS
index d68a5b0..16ef4d8 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1 @@
-per-file dexpreopt.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
diff --git a/java/androidmk.go b/java/androidmk.go
index aa1a81b..5491b3e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -590,6 +590,32 @@
 	}
 }
 
+func (app *AndroidAppImport) 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.properties.Privileged) {
+					fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
+				}
+				if app.certificate != nil {
+					fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
+				} else {
+					fmt.Fprintln(w, "LOCAL_CERTIFICATE := PRESIGNED")
+				}
+				if len(app.properties.Overrides) > 0 {
+					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(app.properties.Overrides, " "))
+				}
+				if len(app.dexpreopter.builtInstalled) > 0 {
+					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
+				}
+			},
+		},
+	}
+}
+
 func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
 	var testFiles []string
 	for _, d := range data {
diff --git a/java/app.go b/java/app.go
index e897dca..4f0b7ac 100644
--- a/java/app.go
+++ b/java/app.go
@@ -34,6 +34,7 @@
 	android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory)
 	android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
 	android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
+	android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
 }
 
 // AndroidManifest.xml merging
@@ -302,37 +303,38 @@
 	return jniJarFile
 }
 
-func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx android.ModuleContext) []Certificate {
-	cert := a.getCertString(ctx)
-	certModule := android.SrcIsModule(cert)
-	if certModule != "" {
-		a.certificate = certificateDeps[0]
-		certificateDeps = certificateDeps[1:]
-	} else if cert != "" {
-		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		a.certificate = Certificate{
-			defaultDir.Join(ctx, cert+".x509.pem"),
-			defaultDir.Join(ctx, cert+".pk8"),
+// Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
+// isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
+func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
+	if android.SrcIsModule(certPropValue) == "" {
+		var mainCert Certificate
+		if certPropValue != "" {
+			defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+			mainCert = Certificate{
+				defaultDir.Join(ctx, certPropValue+".x509.pem"),
+				defaultDir.Join(ctx, certPropValue+".pk8"),
+			}
+		} else {
+			pem, key := ctx.Config().DefaultAppCertificate(ctx)
+			mainCert = Certificate{pem, key}
 		}
-	} else {
-		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		a.certificate = Certificate{pem, key}
+		certificates = append([]Certificate{mainCert}, certificates...)
 	}
 
-	if !a.Module.Platform() {
-		certPath := a.certificate.Pem.String()
+	if !m.Platform() {
+		certPath := certificates[0].Pem.String()
 		systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
 		if strings.HasPrefix(certPath, systemCertPath) {
 			enforceSystemCert := ctx.Config().EnforceSystemCertificate()
 			whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
 
-			if enforceSystemCert && !inList(a.Module.Name(), whitelist) {
+			if enforceSystemCert && !inList(m.Name(), whitelist) {
 				ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
 			}
 		}
 	}
 
-	return append([]Certificate{a.certificate}, certificateDeps...)
+	return certificates
 }
 
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
@@ -346,25 +348,26 @@
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, certificateDeps := a.collectAppDeps(ctx)
+	jniLibs, certificateDeps := collectAppDeps(ctx)
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
 
 	if ctx.Failed() {
 		return
 	}
 
-	certificates := a.certificateBuildActions(certificateDeps, ctx)
+	certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
+	a.certificate = certificates[0]
 
 	// Build a final signed app package.
 	// TODO(jungjw): Consider changing this to installApkName.
 	packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
-	CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
 	a.outputFile = packageFile
 
 	for _, split := range a.aapt.splits {
 		// Sign the split APKs
 		packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
-		CreateAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 	}
 
@@ -390,7 +393,7 @@
 	}
 }
 
-func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
 	var jniLibs []jniLib
 	var certificates []Certificate
 
@@ -412,7 +415,6 @@
 				}
 			} else {
 				ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
-
 			}
 		} else if tag == certificateTag {
 			if dep, ok := module.(*AndroidAppCertificate); ok {
@@ -622,3 +624,135 @@
 	android.InitOverrideModule(m)
 	return m
 }
+
+type AndroidAppImport struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	prebuilt android.Prebuilt
+
+	properties AndroidAppImportProperties
+
+	outputFile  android.Path
+	certificate *Certificate
+
+	dexpreopter
+}
+
+type AndroidAppImportProperties struct {
+	// A prebuilt apk to import
+	Apk 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
+
+	// Set this flag to true if the prebuilt apk is already signed. The certificate property must not
+	// be set for presigned modules.
+	Presigned *bool
+
+	// Specifies that this app should be installed to the priv-app directory,
+	// where the system will grant it additional privileges not available to
+	// normal apps.
+	Privileged *bool
+
+	// Names of modules to be overridden. Listed modules can only be other binaries
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden binaries, but if both
+	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+	// from PRODUCT_PACKAGES.
+	Overrides []string
+}
+
+func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+	cert := android.SrcIsModule(String(a.properties.Certificate))
+	if cert != "" {
+		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+	}
+}
+
+func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		FlagWithInput("-i ", inputPath).
+		FlagWithOutput("-o ", outputPath).
+		FlagWithArg("-0 ", "'lib/**/*.so'").
+		Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+	rule.Build(pctx, ctx, "uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
+}
+
+func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
+		ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
+	}
+	if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
+		ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
+	}
+
+	_, certificates := collectAppDeps(ctx)
+
+	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
+	// TODO: LOCAL_DPI_VARIANTS
+	// TODO: LOCAL_PACKAGE_SPLITS
+
+	srcApk := a.prebuilt.SingleSourcePath(ctx)
+
+	// TODO: Install or embed JNI libraries
+
+	// Uncompress JNI libraries in the apk
+	jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
+	a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
+
+	// TODO: Uncompress dex if applicable
+
+	installDir := android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+	a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
+	a.dexpreopter.isInstallable = true
+	a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
+	dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+
+	// Sign or align the package
+	// TODO: Handle EXTERNAL
+	if !Bool(a.properties.Presigned) {
+		certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
+		if len(certificates) != 1 {
+			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
+		}
+		a.certificate = &certificates[0]
+		signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
+		SignAppPackage(ctx, signed, dexOutput, certificates)
+		a.outputFile = signed
+	} else {
+		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+		TransformZipAlign(ctx, alignedApk, dexOutput)
+		a.outputFile = alignedApk
+	}
+
+	// TODO: Optionally compress the output apk.
+
+	ctx.InstallFile(installDir, a.BaseModuleName()+".apk", a.outputFile)
+
+	// TODO: androidmk converter jni libs
+}
+
+func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
+	return &a.prebuilt
+}
+
+func (a *AndroidAppImport) Name() string {
+	return a.prebuilt.Name(a.ModuleBase.Name())
+}
+
+// android_app_import imports a prebuilt apk with additional processing specified in the module.
+func AndroidAppImportFactory() android.Module {
+	module := &AndroidAppImport{}
+	module.AddProperties(&module.properties)
+	module.AddProperties(&module.dexpreoptProperties)
+
+	InitJavaModule(module, android.DeviceSupported)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
+
+	return module
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index 5bacb67..82a390f 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -62,7 +62,7 @@
 		CommandDeps: []string{"${config.MergeZipsCmd}"},
 	})
 
-func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
+func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
 	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
@@ -83,6 +83,11 @@
 		Output: unsignedApk,
 	})
 
+	SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+}
+
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+
 	var certificateArgs []string
 	var deps android.Paths
 	for _, c := range certificates {
@@ -93,7 +98,7 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        Signapk,
 		Description: "signapk",
-		Output:      outputFile,
+		Output:      signedApk,
 		Input:       unsignedApk,
 		Implicits:   deps,
 		Args: map[string]string{
diff --git a/java/app_test.go b/java/app_test.go
index a084c9c..e4c6afe 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -968,3 +968,87 @@
 		}
 	}
 }
+
+func TestAndroidAppImport(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+
+	// Check cert signing flag.
+	signedApk := variant.Output("signed/foo.apk")
+	signingFlag := signedApk.Args["certificates"]
+	expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
+	if expected != signingFlag {
+		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+	}
+}
+
+func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			dex_preopt: {
+				enabled: false,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs. They shouldn't exist.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
+		t.Errorf("dexpreopt shouldn't have run.")
+	}
+}
+
+func TestAndroidAppImport_Presigned(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			presigned: true,
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+	// Make sure stripping wasn't done.
+	stripRule := variant.Output("dexpreopt/foo.apk")
+	if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
+		t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
+	}
+
+	// Make sure signing was skipped and aligning was done instead.
+	if variant.MaybeOutput("signed/foo.apk").Rule != nil {
+		t.Errorf("signing rule shouldn't be included.")
+	}
+	if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
+		t.Errorf("can't find aligning rule")
+	}
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index b502d07..a7938c8 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -22,11 +22,12 @@
 type dexpreopter struct {
 	dexpreoptProperties DexpreoptProperties
 
-	installPath     android.OutputPath
-	uncompressedDex bool
-	isSDKLibrary    bool
-	isTest          bool
-	isInstallable   bool
+	installPath         android.OutputPath
+	uncompressedDex     bool
+	isSDKLibrary        bool
+	isTest              bool
+	isInstallable       bool
+	isPresignedPrebuilt bool
 
 	builtInstalled string
 }
@@ -177,6 +178,8 @@
 		NoCreateAppImage:    !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
 		ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
 
+		PresignedPrebuilt: d.isPresignedPrebuilt,
+
 		NoStripping:     Bool(d.dexpreoptProperties.Dex_preopt.No_stripping),
 		StripInputPath:  dexJarFile,
 		StripOutputPath: strippedDexJarFile.OutputPath,
diff --git a/java/java.go b/java/java.go
index 6168b38..47dd957 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1253,9 +1253,9 @@
 	// merge implementation jar with resources if necessary
 	implementationAndResourcesJar := outputFile
 	if j.resourceJar != nil {
-		jars := android.Paths{implementationAndResourcesJar, j.resourceJar}
+		jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
 		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
 			false, nil, nil)
 		implementationAndResourcesJar = combinedJar
 	}
diff --git a/java/java_test.go b/java/java_test.go
index 3fab43d..5335d78 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -63,6 +63,7 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
 	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(AndroidAppCertificateFactory))
+	ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(AndroidAppImportFactory))
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
 	ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
@@ -163,6 +164,8 @@
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":   nil,
 		"prebuilts/sdk/Android.bp":                    []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
 
+		"prebuilts/apk/app.apk": nil,
+
 		// For framework-res, which is an implicit dependency for framework
 		"AndroidManifest.xml":                        nil,
 		"build/make/target/product/security/testkey": nil,
diff --git a/java/robolectric.go b/java/robolectric.go
new file mode 100644
index 0000000..26f1e9d
--- /dev/null
+++ b/java/robolectric.go
@@ -0,0 +1,110 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"fmt"
+	"io"
+	"strings"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+}
+
+var robolectricDefaultLibs = []string{
+	"robolectric_android-all-stub",
+	"Robolectric_all-target",
+	"mockito-robolectric-prebuilt",
+	"truth-prebuilt",
+}
+
+type robolectricProperties struct {
+	// The name of the android_app module that the tests will run against.
+	Instrumentation_for *string
+
+	Test_options struct {
+		// Timeout in seconds when running the tests.
+		Timeout *string
+	}
+}
+
+type robolectricTest struct {
+	Library
+
+	robolectricProperties robolectricProperties
+
+	libs []string
+}
+
+func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	r.Library.DepsMutator(ctx)
+
+	if r.robolectricProperties.Instrumentation_for != nil {
+		ctx.AddVariationDependencies(nil, instrumentationForTag, String(r.robolectricProperties.Instrumentation_for))
+	} else {
+		ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
+	}
+
+	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+}
+
+func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.Library.GenerateAndroidBuildActions(ctx)
+
+	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+		r.libs = append(r.libs, ctx.OtherModuleName(dep))
+	}
+}
+
+func (r *robolectricTest) AndroidMk() android.AndroidMkData {
+	data := r.Library.AndroidMk()
+
+	data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+		android.WriteAndroidMkData(w, data)
+
+		fmt.Fprintln(w, "")
+		fmt.Fprintln(w, "include $(CLEAR_VARS)")
+		fmt.Fprintln(w, "LOCAL_MODULE := Run"+name)
+		fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES :=", name)
+		fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES += ", strings.Join(r.libs, " "))
+		fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
+		if t := r.robolectricProperties.Test_options.Timeout; t != nil {
+			fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
+		}
+		fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+	}
+
+	return data
+}
+
+// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
+// instead of on a device.  It also generates a rule with the name of the module prefixed with "Run" that can be
+// used to run the tests.  Running the tests with build rule will eventually be deprecated and replaced with atest.
+func RobolectricTestFactory() android.Module {
+	module := &robolectricTest{}
+
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.protoProperties,
+		&module.robolectricProperties)
+
+	module.Module.dexpreopter.isTest = true
+
+	InitJavaModule(module, android.DeviceSupported)
+	return module
+}
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 54bc5a8..f965f24 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,8 +74,11 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"bash":     Allowed,
-	"bc":       Allowed,
+	"bash": Allowed,
+	"bc":   Allowed,
+	// We need bzip2 here even though we provide a bzip2 binary because
+	// GNU tar seems to avoid calling ours.
+	"bzip2":    Allowed,
 	"date":     Allowed,
 	"dd":       Allowed,
 	"diff":     Allowed,