Merge "Use /bootstrap-apex for bootstrap APEXes" into main am: 58ba0b44c2
am: 6b0c2c3cc6
am: 3249f9ff35
am: b47809dd10
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2666915 Change-Id: I83b59cb169d2c83a7f3e7dbce29d3c11345e1f29 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
dd90936be1
6 changed files with 91 additions and 11 deletions
|
@ -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();
|
||||
}
|
||||
|
@ -1315,6 +1360,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 a new issue