Add a nice install paths for module SDKs and exports.

Following how NDK also creates its own install path.

Bug: 142935992
Bug: 153306490
Test: cc_sdk_test.go, java_sdk_test.go
Merged-In: I98a3656903f37f6d7c90e6cf609431b2461a6161
Change-Id: I98a3656903f37f6d7c90e6cf609431b2461a6161
diff --git a/android/paths.go b/android/paths.go
index 66725c6..0edda38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1238,8 +1238,8 @@
 	return ret
 }
 
-func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
-	paths = append([]string{"ndk"}, paths...)
+func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
+	paths = append([]string{prefix}, paths...)
 	path, err := validatePath(paths...)
 	if err != nil {
 		reportPathError(ctx, err)
@@ -1247,6 +1247,14 @@
 	return InstallPath{basePath{path, ctx.Config(), ""}, ""}
 }
 
+func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
+	return pathForNdkOrSdkInstall(ctx, "ndk", paths)
+}
+
+func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
+	return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
+}
+
 func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
 	rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())
 
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 14e44bf..db71575 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -281,7 +281,9 @@
 		}
 
 		// Generate the snapshot from the member info.
-		s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx, sdkVariants))
+		p := s.buildSnapshot(ctx, sdkVariants)
+		s.snapshotFile = android.OptionalPathForPath(p)
+		ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), s.Name()+"-current.zip", p)
 	}
 }
 
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index b13b90c..96837e3 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -206,3 +206,19 @@
 }
 `))
 }
+
+func TestSDkInstall(t *testing.T) {
+	sdk := `
+		sdk {
+			name: "mysdk",
+		}
+	`
+	result := testSdkWithFs(t, ``,
+		map[string][]byte{
+			"Android.bp": []byte(sdk),
+		})
+
+	result.CheckSnapshot("mysdk", "",
+		checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
+	)
+}
diff --git a/sdk/testing.go b/sdk/testing.go
index 3ae8b5d..625b460 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -188,19 +188,22 @@
 
 	buildParams := sdk.BuildParamsForTests()
 	copyRules := &strings.Builder{}
+	otherCopyRules := &strings.Builder{}
 	snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"
 	for _, bp := range buildParams {
 		switch bp.Rule.String() {
 		case android.Cp.String():
 			output := bp.Output
-			// Only check copies into the snapshot directory.
+			// Get destination relative to the snapshot root
+			dest := output.Rel()
+			src := android.NormalizePathForTesting(bp.Input)
+			// We differentiate between copy rules for the snapshot, and copy rules for the install file.
 			if strings.HasPrefix(output.String(), snapshotDirPrefix) {
 				// Get source relative to build directory.
-				src := android.NormalizePathForTesting(bp.Input)
-				// Get destination relative to the snapshot root
-				dest := output.Rel()
 				_, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
 				info.snapshotContents = append(info.snapshotContents, dest)
+			} else {
+				_, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
 			}
 
 		case repackageZip.String():
@@ -234,6 +237,7 @@
 	}
 
 	info.copyRules = copyRules.String()
+	info.otherCopyRules = otherCopyRules.String()
 
 	return info
 }
@@ -309,6 +313,13 @@
 	}
 }
 
+func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
+	return func(info *snapshotBuildInfo) {
+		info.r.t.Helper()
+		info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
+	}
+}
+
 // Check that the specified path is in the list of zips to merge with the intermediate zip.
 func checkMergeZip(expected string) snapshotBuildInfoChecker {
 	return func(info *snapshotBuildInfo) {
@@ -335,10 +346,14 @@
 	// snapshot.
 	snapshotContents []string
 
-	// A formatted representation of the src/dest pairs, one pair per line, of the format
-	// src -> dest
+	// A formatted representation of the src/dest pairs for a snapshot, one pair per line,
+	// of the format src -> dest
 	copyRules string
 
+	// A formatted representation of the src/dest pairs for files not in a snapshot, one pair
+	// per line, of the format src -> dest
+	otherCopyRules string
+
 	// The path to the intermediate zip, which is a zip created from the source files copied
 	// into the snapshot directory and which will be merged with other zips to form the final output.
 	// Is am empty string if there is no intermediate zip because there are no zips to merge in.