Add install_symlink_host Soong module type

The `install_symlink_host` module type allows Soong to create symbolic
links on the host side. This functionality addresses the issue where a
`cc_binary` with `symlink_preferred_arch: true` cannot be used as a
tool in a `cc_genrule`.
The solution involves setting `symlink_preferred_arch` to `false` for
the `tool` and then using `install_symlink_host` to explicitly create
the originally intended symbolic link.

Bug: 342330305
Test: 1. Add install_symlink_host in Android.bp
      2. m the module and check in stall to $(HOST_OUT)/
      or Uint test
Change-Id: Ib7aa8ec462e0aed8e9196a519be592206469dbcd
diff --git a/etc/install_symlink.go b/etc/install_symlink.go
index 2182b86..aa33445 100644
--- a/etc/install_symlink.go
+++ b/etc/install_symlink.go
@@ -26,6 +26,7 @@
 
 func RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory)
+	ctx.RegisterModuleType("install_symlink_host", InstallSymlinkHostFactory)
 }
 
 // install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path
@@ -37,6 +38,14 @@
 	return module
 }
 
+// install_symlink can be used to install an symlink to an arbitrary path on the host.
+func InstallSymlinkHostFactory() android.Module {
+	module := &InstallSymlink{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidMultiTargetsArchModule(module, android.HostSupported, android.MultilibCommon)
+	return module
+}
+
 type InstallSymlinkProperties struct {
 	// Where to install this symlink, relative to the partition it's installed on.
 	// Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc.
diff --git a/etc/install_symlink_test.go b/etc/install_symlink_test.go
index d7165e5..c97d97c 100644
--- a/etc/install_symlink_test.go
+++ b/etc/install_symlink_test.go
@@ -133,3 +133,39 @@
 		}
 	`)
 }
+
+var prepareForInstallSymlinkHostTest = android.GroupFixturePreparers(
+	android.PrepareForTestWithAndroidBuildComponents,
+	android.FixtureRegisterWithContext(RegisterInstallSymlinkBuildComponents),
+)
+
+func TestInstallSymlinkHostBasic(t *testing.T) {
+	result := prepareForInstallSymlinkHostTest.RunTestWithBp(t, `
+		install_symlink_host {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "aa/bb/cc",
+		}
+	`)
+
+	buildOS := result.Config.BuildOS.String()
+	foo := result.ModuleForTests("foo", buildOS+"_common").Module()
+
+	androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo)
+	if len(androidMkEntries) != 1 {
+		t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries))
+	}
+
+	symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
+	if len(symlinks) != 1 {
+		t.Fatalf("Expected 1 symlink, got %d", len(symlinks))
+	}
+
+	if !strings.HasSuffix(symlinks[0], "bin/foo") {
+		t.Fatalf("Expected symlink install path to end in bin/foo, got: %s", symlinks[0])
+	}
+
+	if !strings.Contains(symlinks[0], "host") {
+		t.Fatalf("Expected symlink install path to contain `host`, got: %s", symlinks[0])
+	}
+}