Support extract_apk in soong

The feature is to use the extracted apk as source apk in
android_app_import.

Bug: 385056659
Test: presubmit
Change-Id: I7f04ad86e7453d6717c00f724029cc4fb4379b4d
diff --git a/java/app_import.go b/java/app_import.go
index f593c02..e209135 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -56,6 +56,11 @@
 		CommandDeps: []string{"build/soong/scripts/check_prebuilt_presigned_apk.py", "${config.Aapt2Cmd}", "${config.ZipAlign}"},
 		Description: "Check presigned apk",
 	}, "extraArgs")
+
+	extractApkRule = pctx.AndroidStaticRule("extract-apk", blueprint.RuleParams{
+		Command:     "unzip -p $in $extract_apk > $out",
+		Description: "Extract specific sub apk",
+	}, "extract_apk")
 )
 
 func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -154,6 +159,9 @@
 	// In case of mainline modules, the .prebuilt_info file contains the build_id that was used
 	// to generate the prebuilt.
 	Prebuilt_info *string `android:"path"`
+
+	// Path of extracted apk which is extracted from prebuilt apk. Use this extracted to import.
+	Extract_apk *string
 }
 
 func (a *AndroidAppImport) IsInstallable() bool {
@@ -278,6 +286,19 @@
 	})
 }
 
+func (a *AndroidAppImport) extractSubApk(
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
+	extractApkPath := *a.properties.Extract_apk
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   extractApkRule,
+		Input:  inputPath,
+		Output: outputPath,
+		Args: map[string]string{
+			"extract_apk": extractApkPath,
+		},
+	})
+}
+
 // Returns whether this module should have the dex file stored uncompressed in the APK.
 func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
 	if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
@@ -336,10 +357,14 @@
 		ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set")
 	}
 
-	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
 
 	srcApk := a.prebuilt.SingleSourcePath(ctx)
+	if a.properties.Extract_apk != nil {
+		extract_apk := android.PathForModuleOut(ctx, "extract-apk", ctx.ModuleName()+".apk")
+		a.extractSubApk(ctx, srcApk, extract_apk)
+		srcApk = extract_apk
+	}
 
 	// TODO: Install or embed JNI libraries
 
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 70c487c..408d376 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -685,6 +685,22 @@
 	}
 }
 
+func TestAndroidAppImport_ExtractApk(t *testing.T) {
+	ctx, _ := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			extract_apk: "extract_path/sub_app.apk"
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+	extractRuleArgs := variant.Output("extract-apk/foo.apk").BuildParams.Args
+	if extractRuleArgs["extract_apk"] != "extract_path/sub_app.apk" {
+		t.Errorf("Unexpected extract apk args: %s", extractRuleArgs["extract_apk"])
+	}
+}
 func TestAndroidTestImport(t *testing.T) {
 	ctx, _ := testJava(t, `
 		android_test_import {