androidmk conversion logic for android_app_import

Test: androidmk_test.go, bpfix_test.go
Bug: 128610294
Change-Id: Ide183ba1e696fa0ffb4245e3288ffc47535b39af
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index b54ad5e..a23879f 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -936,6 +936,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 88c5304..42bd44b 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -1196,6 +1196,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 f217da6..1bc737a 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)
+			})
+		})
+	}
+}