Merge "Convert LOCAL_COMPATIBILITY_SUPPORT_FILES to data: attribute in androidmk"
diff --git a/android/androidmk.go b/android/androidmk.go
index 2bbd452..7d0aa3b 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -28,10 +28,6 @@
 	"github.com/google/blueprint/bootstrap"
 )
 
-var (
-	NativeBridgeSuffix = ".native_bridge"
-)
-
 func init() {
 	RegisterSingletonType("androidmk", AndroidMkSingleton)
 }
@@ -165,10 +161,6 @@
 		}
 	}
 
-	if amod.Target().NativeBridge {
-		a.SubName += NativeBridgeSuffix
-	}
-
 	fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
 
 	// Collect make variable assignment entries.
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 9387b5f..cb71725 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -937,6 +937,7 @@
 	"STATIC_LIBRARIES": "cc_prebuilt_library_static",
 	"EXECUTABLES":      "cc_prebuilt_binary",
 	"JAVA_LIBRARIES":   "java_import",
+	"APPS":             "android_app_import",
 	"ETC":              "prebuilt_etc",
 }
 
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 86776ec..2eab0cc 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -1237,6 +1237,32 @@
 }
 		`,
 	},
+	{
+		desc: "android_app_import",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_SRC_FILES := foo.apk
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MODULE_CLASS := APPS
+LOCAL_MODULE_TAGS := optional
+LOCAL_DEX_PREOPT := false
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+android_app_import {
+	name: "foo",
+
+	privileged: true,
+
+	dex_preopt: {
+		enabled: false,
+	},
+	apk: "foo.apk",
+
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index c898196..17cff18 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -102,6 +102,10 @@
 		name: "rewriteAndroidTest",
 		fix:  rewriteAndroidTest,
 	},
+	{
+		name: "rewriteAndroidAppImport",
+		fix:  rewriteAndroidAppImport,
+	},
 }
 
 func NewFixRequest() FixRequest {
@@ -525,27 +529,8 @@
 			continue
 		}
 
-		// The rewriter converts LOCAL_SRC_FILES to `srcs` attribute. Convert
-		// it to 'src' attribute (which is where the file is installed). If the
-		// value 'srcs' is a list, we can convert it only if it contains a single
-		// element.
-		if srcs, ok := mod.GetProperty("srcs"); ok {
-			if srcList, ok := srcs.Value.(*parser.List); ok {
-				removeProperty(mod, "srcs")
-				if len(srcList.Values) == 1 {
-					mod.Properties = append(mod.Properties,
-						&parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcList.Values[0])})
-				} else if len(srcList.Values) > 1 {
-					indicateAttributeError(mod, "src", "LOCAL_SRC_FILES should contain at most one item")
-				}
-			} else if _, ok = srcs.Value.(*parser.Variable); ok {
-				removeProperty(mod, "srcs")
-				mod.Properties = append(mod.Properties,
-					&parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcs.Value)})
-			} else {
-				renameProperty(mod, "srcs", "src")
-			}
-		}
+		// 'srcs' --> 'src' conversion
+		convertToSingleSource(mod, "src")
 
 		// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
 		// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
@@ -603,6 +588,62 @@
 	return nil
 }
 
+func rewriteAndroidAppImport(f *Fixer) error {
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !(ok && mod.Type == "android_app_import") {
+			continue
+		}
+		// 'srcs' --> 'apk' conversion
+		convertToSingleSource(mod, "apk")
+		// Handle special certificate value, "PRESIGNED".
+		if cert, ok := mod.GetProperty("certificate"); ok {
+			if certStr, ok := cert.Value.(*parser.String); ok {
+				if certStr.Value == "PRESIGNED" {
+					removeProperty(mod, "certificate")
+					prop := &parser.Property{
+						Name: "presigned",
+						Value: &parser.Bool{
+							Value: true,
+						},
+					}
+					mod.Properties = append(mod.Properties, prop)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// Converts the default source list property, 'srcs', to a single source property with a given name.
+// "LOCAL_MODULE" reference is also resolved during the conversion process.
+func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
+	if srcs, ok := mod.GetProperty("srcs"); ok {
+		if srcList, ok := srcs.Value.(*parser.List); ok {
+			removeProperty(mod, "srcs")
+			if len(srcList.Values) == 1 {
+				mod.Properties = append(mod.Properties,
+					&parser.Property{
+						Name:     srcPropertyName,
+						NamePos:  srcs.NamePos,
+						ColonPos: srcs.ColonPos,
+						Value:    resolveLocalModule(mod, srcList.Values[0])})
+			} else if len(srcList.Values) > 1 {
+				indicateAttributeError(mod, srcPropertyName, "LOCAL_SRC_FILES should contain at most one item")
+			}
+		} else if _, ok = srcs.Value.(*parser.Variable); ok {
+			removeProperty(mod, "srcs")
+			mod.Properties = append(mod.Properties,
+				&parser.Property{Name: srcPropertyName,
+					NamePos:  srcs.NamePos,
+					ColonPos: srcs.ColonPos,
+					Value:    resolveLocalModule(mod, srcs.Value)})
+		} else {
+			renameProperty(mod, "srcs", "apk")
+		}
+	}
+}
+
 func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
 	return func(f *Fixer) error {
 		// Make sure all the offsets are accurate
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 459cd36..5e0b817 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -784,3 +784,52 @@
 		})
 	}
 }
+
+func TestRewriteAndroidAppImport(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "android_app_import apk",
+			in: `
+				android_app_import {
+					name: "foo",
+					srcs: ["package.apk"],
+				}
+			`,
+			out: `
+				android_app_import {
+					name: "foo",
+					apk: "package.apk",
+				}
+			`,
+		},
+		{
+			name: "android_app_import presigned",
+			in: `
+				android_app_import {
+					name: "foo",
+					apk: "package.apk",
+					certificate: "PRESIGNED",
+				}
+			`,
+			out: `
+				android_app_import {
+					name: "foo",
+					apk: "package.apk",
+					presigned: true,
+
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return rewriteAndroidAppImport(fixer)
+			})
+		})
+	}
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index c7883e2..ae34e3d 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -24,8 +24,9 @@
 )
 
 var (
-	vendorSuffix   = ".vendor"
-	recoverySuffix = ".recovery"
+	nativeBridgeSuffix = ".native_bridge"
+	vendorSuffix       = ".vendor"
+	recoverySuffix     = ".recovery"
 )
 
 type AndroidMkContext interface {
@@ -105,6 +106,10 @@
 	}
 	c.subAndroidMk(&ret, c.installer)
 
+	if c.Target().NativeBridge == android.NativeBridgeEnabled {
+		ret.SubName += nativeBridgeSuffix
+	}
+
 	if c.useVndk() && c.hasVendorVariant() {
 		// .vendor suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
@@ -134,6 +139,18 @@
 	}
 }
 
+func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string {
+	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		var result []string
+		for _, override := range overrides {
+			result = append(result, override+nativeBridgeSuffix)
+		}
+		return result
+	}
+
+	return overrides
+}
+
 func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
 	exportedFlags := library.exportedFlags()
 	if len(exportedFlags) > 0 {
@@ -166,7 +183,7 @@
 				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
 			}
 			if len(library.Properties.Overrides) > 0 {
-				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(library.Properties.Overrides, " "))
+				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
 			}
 			if len(library.post_install_cmds) > 0 {
 				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
@@ -241,7 +258,7 @@
 		}
 
 		if len(binary.Properties.Overrides) > 0 {
-			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(binary.Properties.Overrides, " "))
+			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
 		}
 		if len(binary.post_install_cmds) > 0 {
 			fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
diff --git a/cc/cc.go b/cc/cc.go
index de108b4..2e551e1 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1826,7 +1826,7 @@
 			} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
 				return libName + recoverySuffix
 			} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
-				return libName + android.NativeBridgeSuffix
+				return libName + nativeBridgeSuffix
 			} else {
 				return libName
 			}
diff --git a/java/app.go b/java/app.go
index 9f37836..f7f08a8 100644
--- a/java/app.go
+++ b/java/app.go
@@ -85,6 +85,9 @@
 	// list of native libraries that will be provided in or alongside the resulting jar
 	Jni_libs []string `android:"arch_variant"`
 
+	// STL library to use for JNI libraries.
+	Stl *string `android:"arch_variant"`
+
 	// Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
 	// flag so that they are used from inside the APK at runtime.  Defaults to true for android_test modules unless
 	// sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
@@ -149,10 +152,15 @@
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
 
+	if String(a.appProperties.Stl) == "c++_shared" && a.sdkVersion() == "" {
+		ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
+	}
+
 	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
 		a.aapt.deps(ctx, sdkContext(a))
 	}
 
+	embedJni := a.shouldEmbedJnis(ctx)
 	for _, jniTarget := range ctx.MultiTargets() {
 		variation := []blueprint.Variation{
 			{Mutator: "arch", Variation: jniTarget.String()},
@@ -162,6 +170,11 @@
 			target: jniTarget,
 		}
 		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+		if String(a.appProperties.Stl) == "c++_shared" {
+			if embedJni {
+				ctx.AddFarVariationDependencies(variation, tag, "libc++")
+			}
+		}
 	}
 }
 
@@ -217,6 +230,11 @@
 	return shouldUncompressDex(ctx, &a.dexpreopter)
 }
 
+func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
+	return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
+		a.appProperties.AlwaysPackageNativeLibs
+}
+
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
 	a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
 
@@ -305,9 +323,7 @@
 func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
 	var jniJarFile android.WritablePath
 	if len(jniLibs) > 0 {
-		embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
-			a.appProperties.AlwaysPackageNativeLibs
-		if embedJni {
+		if a.shouldEmbedJnis(ctx) {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
 			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
 		} else {
diff --git a/java/app_test.go b/java/app_test.go
index 347139e..40a64af 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1178,3 +1178,64 @@
 		}
 	}
 }
+
+func TestStl(t *testing.T) {
+	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+		cc_library {
+			name: "libjni",
+		}
+
+		android_test {
+			name: "stl",
+			jni_libs: ["libjni"],
+			compile_multilib: "both",
+			sdk_version: "current",
+			stl: "c++_shared",
+		}
+
+		android_test {
+			name: "system",
+			jni_libs: ["libjni"],
+			compile_multilib: "both",
+			sdk_version: "current",
+		}
+		`)
+
+	testCases := []struct {
+		name string
+		jnis []string
+	}{
+		{"stl",
+			[]string{
+				"libjni.so",
+				"libc++.so",
+			},
+		},
+		{"system",
+			[]string{
+				"libjni.so",
+			},
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			app := ctx.ModuleForTests(test.name, "android_common")
+			jniLibZip := app.Output("jnilibs.zip")
+			var jnis []string
+			args := strings.Fields(jniLibZip.Args["jarArgs"])
+			for i := 0; i < len(args); i++ {
+				if args[i] == "-f" {
+					jnis = append(jnis, args[i+1])
+					i += 1
+				}
+			}
+			jnisJoined := strings.Join(jnis, " ")
+			for _, jni := range test.jnis {
+				if !strings.Contains(jnisJoined, jni) {
+					t.Errorf("missing jni %q in %q", jni, jnis)
+				}
+			}
+		})
+	}
+}