Use /bootstrap-apex for bootstrap APEXes
This new directory is bind-mounted to /apex in the bootstrap mount namespace so that apexd-bootstrap mounts bootstrap APEXes there via /apex. The directory is detached from /apex in the default mount namespace but still visible in case bootstrap APEXes are needed. However, there are (mostly, virtual) devices which don't need two mount namespaces. Those devices don't need to make /bootstrap-apex directory at all. Bug: 290148078 Test: atest VendorApexHostTestCases Test: atest MicrodroidTests Change-Id: I541cec71d9970b14971d46e01e4808b23590dbed
This commit is contained in:
parent
1db90d0aac
commit
201801ce8e
|
@ -1262,6 +1262,51 @@ static Result<void> MountLinkerConfigForDefaultNamespace() {
|
|||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Result<void> MountApexRootForDefaultNamespace() {
|
||||
auto mount_namespace_id = GetCurrentMountNamespace();
|
||||
if (!mount_namespace_id.ok()) {
|
||||
return mount_namespace_id.error();
|
||||
}
|
||||
// There's nothing to do if it's still in the bootstrap mount namespace.
|
||||
// This happens when we don't need to update APEXes (e.g. Microdroid)
|
||||
// where bootstrap mount namespace == default mount namespace.
|
||||
if (mount_namespace_id.value() == NS_BOOTSTRAP) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Now, we're in the "default" mount namespace and need a fresh /apex for
|
||||
// the default mount namespace.
|
||||
//
|
||||
// At this point, there are two mounts at the same mount point: /apex
|
||||
// - to tmpfs (private)
|
||||
// - to /bootstrap-apex (shared)
|
||||
//
|
||||
// We need unmount the second mount so that /apex in the default mount
|
||||
// namespace becomes RW/empty and "private" (we don't want mount events to
|
||||
// propagate to the bootstrap mount namespace).
|
||||
//
|
||||
// Likewise, we don't want the unmount event itself to propagate to the
|
||||
// bootstrap mount namespace. Otherwise, /apex in the bootstrap mount
|
||||
// namespace would become empty due to the unmount.
|
||||
//
|
||||
// Hence, before unmounting, we make /apex (the second one) "private" first.
|
||||
// so that the unmouting below doesn't affect to the bootstrap mount namespace.
|
||||
if (mount(nullptr, "/apex", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
|
||||
return ErrnoError() << "Failed to remount /apex as private";
|
||||
}
|
||||
|
||||
// Now we can unmount /apex (bind-mount to /bootstrap-apex). This only affects
|
||||
// in the default mount namespace and /apex is now seen as tmpfs mount.
|
||||
// Note that /apex in the bootstrap mount namespace is still a bind-mount to
|
||||
// /bootstrap-apex and holds the APEX mounts.
|
||||
if (umount2("/apex", MNT_DETACH) == -1) {
|
||||
return ErrnoError() << "Failed to umount /apex";
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Result<void> do_update_linker_config(const BuiltinArguments&) {
|
||||
return GenerateLinkerConfiguration();
|
||||
}
|
||||
|
@ -1314,6 +1359,11 @@ static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) {
|
|||
if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
if (auto result = MountApexRootForDefaultNamespace(); !result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
|
|
@ -832,6 +832,12 @@ static void MountExtraFilesystems() {
|
|||
CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
|
||||
"mode=0755,uid=0,gid=0"));
|
||||
|
||||
if (NeedsTwoMountNamespaces()) {
|
||||
// /bootstrap-apex is used to mount "bootstrap" APEXes.
|
||||
CHECKCALL(mount("tmpfs", "/bootstrap-apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
|
||||
"mode=0755,uid=0,gid=0"));
|
||||
}
|
||||
|
||||
// /linkerconfig is used to keep generated linker configuration
|
||||
CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
|
||||
"mode=0755,uid=0,gid=0"));
|
||||
|
|
|
@ -66,15 +66,6 @@ static std::string GetMountNamespaceId() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount
|
||||
// namespaces.
|
||||
static bool NeedsTwoMountNamespaces() {
|
||||
if (IsRecoveryMode()) return false;
|
||||
// In microdroid, there's only one set of APEXes in built-in directories include block devices.
|
||||
if (IsMicrodroid()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static android::base::unique_fd bootstrap_ns_fd;
|
||||
static android::base::unique_fd default_ns_fd;
|
||||
|
||||
|
@ -83,6 +74,15 @@ static std::string default_ns_id;
|
|||
|
||||
} // namespace
|
||||
|
||||
// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount
|
||||
// namespaces.
|
||||
bool NeedsTwoMountNamespaces() {
|
||||
if (IsRecoveryMode()) return false;
|
||||
// In microdroid, there's only one set of APEXes in built-in directories include block devices.
|
||||
if (IsMicrodroid()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetupMountNamespaces() {
|
||||
// Set the propagation type of / as shared so that any mounting event (e.g.
|
||||
// /data) is by default visible to all processes. When private mounting is
|
||||
|
@ -96,6 +96,27 @@ bool SetupMountNamespaces() {
|
|||
// the bootstrap namespace get APEXes from the read-only partition.
|
||||
if (!(ChangeMount("/apex", MS_PRIVATE))) return false;
|
||||
|
||||
// However, some components (e.g. servicemanager) need to access bootstrap
|
||||
// APEXes from the default mount namespace. To achieve that, we bind-mount
|
||||
// /apex with /bootstrap-apex (not private) in the bootstrap mount namespace.
|
||||
// Bootstrap APEXes are mounted in /apex and also visible in /bootstrap-apex.
|
||||
// In the default mount namespace, we detach /bootstrap-apex from /apex and
|
||||
// bootstrap APEXes are still be visible in /bootstrap-apex.
|
||||
//
|
||||
// The end result will look like:
|
||||
// in the bootstrap mount namespace:
|
||||
// /apex (== /bootstrap-apex)
|
||||
// {bootstrap APEXes from the read-only partition}
|
||||
//
|
||||
// in the default mount namespace:
|
||||
// /bootstrap-apex
|
||||
// {bootstrap APEXes from the read-only partition}
|
||||
// /apex
|
||||
// {APEXes, can be from /data partition}
|
||||
if (NeedsTwoMountNamespaces()) {
|
||||
if (!(BindMount("/bootstrap-apex", "/apex"))) return false;
|
||||
}
|
||||
|
||||
// /linkerconfig is a private mountpoint to give a different linker configuration
|
||||
// based on the mount namespace. Subdirectory will be bind-mounted based on current mount
|
||||
// namespace
|
||||
|
|
|
@ -24,9 +24,12 @@ namespace init {
|
|||
enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT };
|
||||
|
||||
bool SetupMountNamespaces();
|
||||
|
||||
base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace);
|
||||
|
||||
base::Result<MountNamespace> GetCurrentMountNamespace();
|
||||
|
||||
bool NeedsTwoMountNamespaces();
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
@ -766,7 +766,7 @@ void SelinuxRestoreContext() {
|
|||
selinux_android_restorecon("/dev/device-mapper", 0);
|
||||
|
||||
selinux_android_restorecon("/apex", 0);
|
||||
|
||||
selinux_android_restorecon("/bootstrap-apex", 0);
|
||||
selinux_android_restorecon("/linkerconfig", 0);
|
||||
|
||||
// adb remount, snapshot-based updates, and DSUs all create files during
|
||||
|
|
|
@ -91,7 +91,7 @@ endif
|
|||
#
|
||||
# create some directories (some are mount points) and symlinks
|
||||
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
|
||||
dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \
|
||||
dev proc sys system data data_mirror odm oem acct config storage mnt apex bootstrap-apex debug_ramdisk \
|
||||
linkerconfig second_stage_resources postinstall $(BOARD_ROOT_EXTRA_FOLDERS)); \
|
||||
ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
|
||||
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
|
||||
|
|
Loading…
Reference in New Issue