Create symlink for bionic files

This change creates following symlinks for bionic files.

/system/lib/libc.so -> /apex/com.android.runtime/lib/bionic/libc.so
/system/lib/libm.so -> /apex/com.android.runtime/lib/bionic/libm.so
/system/lib/libdl.so -> /apex/com.android.runtime/lib/bionic/libdl.so
/system/bin/linker -> /apex/com.android.runtime/bin/linker
...

This allows us to not have mountpoints under /bionic.

Bug: 125549215
Test: m and inspect the symlinks in the system partition.
Change-Id: I3a58bf4f88c967862dbf06065a1af8fc4700dda3
diff --git a/cc/androidmk.go b/cc/androidmk.go
index fc791fe..d229d0c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -158,6 +158,9 @@
 			if len(library.Properties.Overrides) > 0 {
 				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(library.Properties.Overrides, " "))
 			}
+			if len(library.post_install_cmds) > 0 {
+				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
+			}
 		})
 	} else if library.header() {
 		ret.Class = "HEADER_LIBRARIES"
@@ -231,6 +234,9 @@
 		if len(binary.Properties.Overrides) > 0 {
 			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(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/binary.go b/cc/binary.go
index 4794815..9952943 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -15,6 +15,8 @@
 package cc
 
 import (
+	"path/filepath"
+
 	"github.com/google/blueprint"
 
 	"android/soong/android"
@@ -91,6 +93,8 @@
 
 	// Location of the file that should be copied to dist dir when requested
 	distFile android.OptionalPath
+
+	post_install_cmds []string
 }
 
 var _ linker = (*binaryDecorator)(nil)
@@ -249,7 +253,7 @@
 				} else {
 					switch ctx.Os() {
 					case android.Android:
-						if ctx.bootstrap() {
+						if ctx.bootstrap() && !ctx.inRecovery() {
 							flags.DynamicLinker = "/system/bin/bootstrap/linker"
 						} else {
 							flags.DynamicLinker = "/system/bin/linker"
@@ -413,7 +417,29 @@
 	return binary.symlinks
 }
 
+// /system/bin/linker -> /apex/com.android.runtime/bin/linker
+func (binary *binaryDecorator) installSymlinkToRuntimeApex(ctx ModuleContext, file android.Path) {
+	dir := binary.baseInstaller.installDir(ctx)
+	dirOnDevice := android.InstallPathToOnDevicePath(ctx, dir)
+	target := "/" + filepath.Join("apex", "com.android.runtime", dir.Base(), file.Base())
+
+	ctx.InstallAbsoluteSymlink(dir, file.Base(), target)
+	binary.post_install_cmds = append(binary.post_install_cmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
+
+	for _, symlink := range binary.symlinks {
+		ctx.InstallAbsoluteSymlink(dir, symlink, target)
+		binary.post_install_cmds = append(binary.post_install_cmds, makeSymlinkCmd(dirOnDevice, symlink, target))
+	}
+}
+
 func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
+	// Bionic binaries (e.g. linker) is installed to the bootstrap subdirectory.
+	// The original path becomes a symlink to the corresponding file in the
+	// runtime APEX.
+	if isBionic(ctx.baseModuleName()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
+		binary.installSymlinkToRuntimeApex(ctx, file)
+		binary.baseInstaller.subDir = "bootstrap"
+	}
 	binary.baseInstaller.install(ctx, file)
 	for _, symlink := range binary.symlinks {
 		ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path)
diff --git a/cc/cc.go b/cc/cc.go
index 284b58d..c036b84 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -599,6 +599,14 @@
 	return Bool(c.Properties.Bootstrap)
 }
 
+func isBionic(name string) bool {
+	switch name {
+	case "libc", "libm", "libdl", "linker":
+		return true
+	}
+	return false
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
diff --git a/cc/library.go b/cc/library.go
index 71a9df6..6404906 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"path/filepath"
 	"regexp"
 	"sort"
 	"strconv"
@@ -290,6 +291,8 @@
 
 	versionScriptPath android.ModuleGenPath
 
+	post_install_cmds []string
+
 	// Decorated interafaces
 	*baseCompiler
 	*baseLinker
@@ -888,6 +891,14 @@
 	return library.tocFile
 }
 
+func (library *libraryDecorator) installSymlinkToRuntimeApex(ctx ModuleContext, file android.Path) {
+	dir := library.baseInstaller.installDir(ctx)
+	dirOnDevice := android.InstallPathToOnDevicePath(ctx, dir)
+	target := "/" + filepath.Join("apex", "com.android.runtime", dir.Base(), "bionic", file.Base())
+	ctx.InstallAbsoluteSymlink(dir, file.Base(), target)
+	library.post_install_cmds = append(library.post_install_cmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
+}
+
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if library.shared() {
 		if ctx.Device() && ctx.useVndk() {
@@ -905,15 +916,11 @@
 				}
 			}
 		} else if len(library.Properties.Stubs.Versions) > 0 && android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
-			// If a library in an APEX has stable versioned APIs, we basically don't need
-			// to have the platform variant of the library in /system partition because
-			// platform components can just use the lib from the APEX without fearing about
-			// compatibility. However, if the library is required for some early processes
-			// before the APEX is activated, the platform variant may also be required.
-			// In that case, it is installed to the subdirectory 'bootstrap' in order to
-			// be distinguished/isolated from other non-bootstrap libraries in /system/lib
-			// so that the bootstrap libraries are used only when the APEX isn't ready.
-			if !library.buildStubs() && ctx.Arch().Native {
+			// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
+			// The original path becomes a symlink to the corresponding file in the
+			// runtime APEX.
+			if isBionic(ctx.baseModuleName()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
+				library.installSymlinkToRuntimeApex(ctx, file)
 				library.baseInstaller.subDir = "bootstrap"
 			}
 		}
diff --git a/cc/util.go b/cc/util.go
index 925dd74..782bf61 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -133,3 +133,10 @@
 
 	return root, suffix, ext
 }
+
+// linkDirOnDevice/linkName -> target
+func makeSymlinkCmd(linkDirOnDevice string, linkName string, target string) string {
+	dir := filepath.Join("$(PRODUCT_OUT)", linkDirOnDevice)
+	return "mkdir -p " + dir + " && " +
+		"ln -sf " + target + " " + filepath.Join(dir, linkName)
+}