Add bionic mount points under /bionic

This change adds following files and symlinks:

Files:
/bionic/lib[64]/lib{c|dl|m}.so
/bionic/bin/linker[64]

Symlinks:
/system/lib[64]/lib{c|dl|m}.so -> /bionic/lib[64]/lib{c|dl|m}.so
/system/bin/linker[64] -> /bionic/bin/linker[64]
/system/bin/linker_asan[64] -> /bionic/bin/linker[64]

The files serve as mount points for either the bootstrap Bionic or the
default Bionic from the runtime APEX. init does the bind-mounting during
booting.

The symlinks are there to not change the ordinary paths to the bionic
files; there are many places that the paths are implied or hard-coded,
e.g., dlopen("/system/lib/libc.so") or DT_INTERP pointing to
/system/bin/linker in the vendor prebuilts.

Bug: 120266448
Test: m blueline, cf_x86, aosp_arm
The aforementioned files and symlinks are found

Change-Id: I97e38c29409ac0610dde285db8df6e94a7930094
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..376c250
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+bionic_mountpoint {
+    name: "libc.mountpoint",
+    stem: "libc.so",
+    src: "dummy_mountpoint",
+    library: true,
+    symlinks: ["libc.so"],
+}
+
+bionic_mountpoint {
+    name: "libdl.mountpoint",
+    stem: "libdl.so",
+    src: "dummy_mountpoint",
+    library: true,
+    symlinks: ["libdl.so"],
+}
+
+bionic_mountpoint {
+    name: "libm.mountpoint",
+    stem: "libm.so",
+    src: "dummy_mountpoint",
+    library: true,
+    symlinks: ["libm.so"],
+}
+
+bionic_mountpoint {
+    name: "linker.mountpoint",
+    stem: "linker",
+    multilib: {
+        lib64: {
+            suffix: "64",
+        },
+    },
+    src: "dummy_mountpoint",
+    binary: true,
+    symlinks: ["linker", "linker_asan"],
+}
diff --git a/build/Android.bp b/build/Android.bp
new file mode 100644
index 0000000..6cc160a
--- /dev/null
+++ b/build/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+bootstrap_go_package {
+    name: "soong-bionic",
+    pkgPath: "android/soong/bionic",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "blueprint-proptools",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "bionic.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/build/bionic.go b/build/bionic.go
new file mode 100644
index 0000000..3522aca
--- /dev/null
+++ b/build/bionic.go
@@ -0,0 +1,164 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bionic
+
+import (
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+)
+
+// bionic_mountpoint is a module type that is specialized to create
+// mount points for Bionic files (libc, libdl, libm, and linker).
+//
+// With following description,
+//
+// bionic_mountpoint {
+//    name: "libc.mountpoint",
+//    stem: "libc.so",
+//    src: "dummy_mountpoint",
+//    library: true,
+//    symlinks: ["libc.so"],
+// }
+//
+// , the build system does following jobs:
+//
+// A mount point /bionic/lib[64]/libc.so is created. Its content
+// is from the file 'dummy_mountpoint'.
+//
+// Then a symlink is created at /system/lib[64]/libc.so which points to
+// the created mountpoint.
+//
+// At runtime, on the mount point, either bootstrap Bionic or default Bionic
+// (which is from the runtime APEX) is mounted by the init process. The
+// symlink exists to provide consistent legacy path for compatibility
+// reason.
+func init() {
+	android.RegisterModuleType("bionic_mountpoint", bionicMountpointFactory)
+}
+
+type bionicMountpoint struct {
+	android.ModuleBase
+	properties bionicMountpointProperties
+
+	outputFile android.Path
+	pathInPartition string
+	stem string
+}
+
+type bionicMountpointProperties struct {
+	// The file that is installed as the mount point
+	Src *string
+
+	// True if the mount point is for a Bionic library such libc.so
+	Library *bool
+	// True if the mount point is for a Bionic binary such as linker
+	Binary *bool
+
+	// Base name of the mount point
+	Stem *string `android:"arch_variant"`
+
+	// Append to the name of the output
+	Suffix *string `android:"arch_variant"`
+
+	// Symlinks to the mountpoints from the system and recovery partitions
+	// Symlinks names will have the same suffix as the mount point
+	Symlinks []string
+}
+
+func (m *bionicMountpoint) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if Bool(m.properties.Library) == Bool(m.properties.Binary) {
+		ctx.ModuleErrorf("either binary or library must be set to true")
+		return
+	}
+	if m.properties.Stem == nil {
+		ctx.PropertyErrorf("stem", "stem must be set")
+		return
+	}
+	if m.properties.Src == nil {
+		ctx.PropertyErrorf("src", "src must be set")
+	}
+	android.ExtractSourceDeps(ctx, m.properties.Src)
+}
+
+func (m *bionicMountpoint) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if Bool(m.properties.Library) {
+		m.pathInPartition = "lib"
+		if m.Arch().ArchType.Multilib == "lib64" {
+			m.pathInPartition = "lib64"
+		}
+	} else if Bool(m.properties.Binary) {
+		m.pathInPartition = "bin"
+	}
+
+	m.stem = String(m.properties.Stem) + String(m.properties.Suffix)
+
+	m.outputFile = ctx.ExpandSource(String(m.properties.Src), "src")
+}
+
+func (m *bionicMountpoint) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData {
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			if !m.Arch().Native {
+				return
+			}
+			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+			fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+			fmt.Fprintln(w, "LOCAL_USE_CLANG_LLD := false")
+			fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+			if Bool(m.properties.Library) {
+				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := SHARED_LIBRARIES")
+			} else if Bool(m.properties.Binary) {
+				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := EXECUTABLES")
+			}
+			fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
+			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", m.outputFile.String())
+			fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", m.Arch().ArchType.String())
+			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(TARGET_ROOT_OUT)/bionic/" + m.pathInPartition)
+			fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", m.stem)
+
+			if len(m.properties.Symlinks) > 0 {
+				symlink_dir_in_system := "$(TARGET_OUT)/" + m.pathInPartition + "/"
+				symlink_dir_in_recovery := "$(TARGET_RECOVERY_ROOT_OUT)/system/" + m.pathInPartition + "/"
+				symlink_target := "/bionic/" + m.pathInPartition + "/" + m.stem
+				cmds := []string{}
+				cmds = append(cmds, "$(hide) mkdir -p " + symlink_dir_in_system)
+				cmds = append(cmds, "mkdir -p " + symlink_dir_in_recovery)
+				for _, s := range m.properties.Symlinks {
+					symlink := s + String(m.properties.Suffix)
+					cmds = append(cmds, "ln -sf " + symlink_target + " " + symlink_dir_in_system +  symlink)
+					cmds = append(cmds, "ln -sf " + symlink_target + " " + symlink_dir_in_recovery +  symlink)
+				}
+				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := " + strings.Join(cmds, " && "))
+			}
+			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+		},
+	}
+}
+
+func bionicMountpointFactory() android.Module {
+	m := &bionicMountpoint{}
+        m.AddProperties(&m.properties)
+	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
+	return m
+}
+
+var Bool = proptools.Bool
+var String = proptools.String
diff --git a/dummy_mountpoint b/dummy_mountpoint
new file mode 100644
index 0000000..2d13c55
--- /dev/null
+++ b/dummy_mountpoint
@@ -0,0 +1 @@
+This file serves as a mount point for bionic files either from /system partition or from /apex/com.android.runtime. This file is never meant to be accessed directly.
diff --git a/libc/Android.bp b/libc/Android.bp
index 226a81f..4cf31bc 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1548,7 +1548,7 @@
         ],
     },
 
-    required: ["tzdata"],
+    required: ["tzdata", "libc.mountpoint"],
 
     // Leave the symbols in the shared library so that stack unwinders can produce
     // meaningful name resolution.
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 262da6c..c17e72e 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -105,6 +105,7 @@
         symbol_file: "libdl.map.txt",
         versions: ["10000"],
     },
+    required: ["libdl.mountpoint"],
 }
 
 ndk_library {
diff --git a/libm/Android.bp b/libm/Android.bp
index 28cf1fd..079220b 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -515,6 +515,7 @@
         symbol_file: "libm.map.txt",
         versions: ["10000"],
     },
+    required: ["libm.mountpoint"],
 }
 
 ndk_library {
diff --git a/linker/Android.bp b/linker/Android.bp
index 033860a..8533c30 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -301,6 +301,7 @@
     },
     compile_multilib: "both",
     xom: false,
+    required: ["linker.mountpoint"],
 }
 
 cc_library {