Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dcbaf9f4 authored by Jiyong Park's avatar Jiyong Park
Browse files

Activate system APEXes early

Summary: Boot sequence around apexd is changed to make it possible for
pre-apexd processes to use libraries from APEXes. They no longer need to
wait for the apexd to finish activating APEXes, which again can be
done only after /data/ is mounted. This improves overall boot
performance.

Detail: This change fixes the problem that processes that are started
before apexd (so called pre-apexd processes) can't access libraries
that are provided only by the APEXes but are not found in the system
partition (e.g. libdexfile_external.so, etc.). Main idea is to activate
system APEXes (/system/apex/*.apex) before /data is mounted and then
activate the updated APEXes (/data/apex/*.apex) after the /data mount.

Detailed boot sequence is as follows.

1) init prepares the bootstrap and default mount namespaces. A tmpfs is
mounted on /apex and the propagation type of the mountpoint is set to
private.

2) before any other process is started, apexd is started in bootstrap
mode. When executed in the mode, apexd only activates APEXes under
/system/apex. Note that APEXes activated in this phase are mounted in
the bootstrap mount namespace only.

3) other pre-apexd processes are started. They are in the bootstrap
mount namespace and thus are provided with the libraries from the system
APEXes.

4) /data is mounted. init switches into the default mount namespace and
starts apexd as a daemon as usual.

5) apexd scans both /data/apex and /system/apex, and activate latest
APEXes from the directories. Note that APEXes activated in this phase
are mounted in the default namespaces only and thus are not visible to
the pre-apexd processes.

Bug: 125549215
Test: m; device boots
Change-Id: I21c60d0ebe188fa4f24d6e6861f85ca204843069
parent 4ba548d8
Loading
Loading
Loading
Loading
+10 −1
Original line number Original line Diff line number Diff line
@@ -1119,13 +1119,21 @@ static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
}
}


static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
    if (SwitchToDefaultMountNamespace()) {
    if (SetupRuntimeBionic()) {
        return Success();
        return Success();
    } else {
    } else {
        return Error() << "Failed to setup runtime bionic";
        return Error() << "Failed to setup runtime bionic";
    }
    }
}
}


static Result<Success> do_enter_default_mount_ns(const BuiltinArguments& args) {
    if (SwitchToDefaultMountNamespace()) {
        return Success();
    } else {
        return Error() << "Failed to enter into default mount namespace";
    }
}

// Builtin-function-map start
// Builtin-function-map start
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1177,6 +1185,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        {"start",                   {1,     1,    {false,  do_start}}},
        {"start",                   {1,     1,    {false,  do_start}}},
        {"stop",                    {1,     1,    {false,  do_stop}}},
        {"stop",                    {1,     1,    {false,  do_stop}}},
        {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
        {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
        {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
        {"symlink",                 {2,     2,    {true,   do_symlink}}},
        {"symlink",                 {2,     2,    {true,   do_symlink}}},
        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
        {"trigger",                 {1,     1,    {false,  do_trigger}}},
        {"trigger",                 {1,     1,    {false,  do_trigger}}},
+17 −1
Original line number Original line Diff line number Diff line
@@ -172,6 +172,11 @@ bool SetupMountNamespaces() {
                         kBionicLibsMountPointDir64))
                         kBionicLibsMountPointDir64))
        return false;
        return false;


    // /apex is also a private mountpoint to give different sets of APEXes for
    // the bootstrap and default mount namespaces. The processes running with
    // the bootstrap namespace get APEXes from the read-only partition.
    if (!(MakePrivate("/apex"))) return false;

    bootstrap_ns_fd.reset(OpenMountNamespace());
    bootstrap_ns_fd.reset(OpenMountNamespace());
    bootstrap_ns_id = GetMountNamespaceId();
    bootstrap_ns_id = GetMountNamespaceId();


@@ -227,6 +232,17 @@ bool SwitchToDefaultMountNamespace() {
        }
        }
    }
    }


    LOG(INFO) << "Switched to default mount namespace";
    return true;
}

// TODO(jiyong): remove this when /system/lib/libc.so becomes
// a symlink to /apex/com.android.runtime/lib/bionic/libc.so
bool SetupRuntimeBionic() {
    if (IsRecoveryMode()) {
        // We don't have multiple namespaces in recovery mode
        return true;
    }
    // Bind-mount bionic from the runtime APEX since it is now available. Note
    // Bind-mount bionic from the runtime APEX since it is now available. Note
    // that in case of IsBionicUpdatable() == false, these mounts are over the
    // that in case of IsBionicUpdatable() == false, these mounts are over the
    // existing existing bind mounts for the bootstrap bionic, which effectively
    // existing existing bind mounts for the bootstrap bionic, which effectively
@@ -238,7 +254,7 @@ bool SwitchToDefaultMountNamespace() {
                         kBionicLibsMountPointDir64))
                         kBionicLibsMountPointDir64))
        return false;
        return false;


    LOG(INFO) << "Switched to default mount namespace";
    LOG(INFO) << "Runtime bionic is set up";
    return true;
    return true;
}
}


+1 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ namespace android {
namespace init {
namespace init {


bool SetupMountNamespaces();
bool SetupMountNamespaces();
bool SetupRuntimeBionic();
bool SwitchToDefaultMountNamespace();
bool SwitchToDefaultMountNamespace();
bool SwitchToBootstrapMountNamespaceIfNeeded();
bool SwitchToBootstrapMountNamespaceIfNeeded();


+21 −25
Original line number Original line Diff line number Diff line
@@ -13,12 +13,6 @@ import /init.${ro.zygote}.rc


# Cgroups are mounted right before early-init using list from /etc/cgroups.json
# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
on early-init
    # Mount shared so changes propagate into child namespaces
    # Do this before other processes are started from init. Otherwise,
    # processes launched while the propagation type of / is 'private'
    # won't get mount events from others.
    mount rootfs rootfs / shared rec

    # Set init and its forked children's oom_adj.
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000
    write /proc/1/oom_score_adj -1000


@@ -43,6 +37,11 @@ on early-init


    start ueventd
    start ueventd


    # Run apexd-bootstrap so that APEXes that provide critical libraries
    # become available. Note that this is executed as exec_start to ensure that
    # the libraries are available to the processes started after this statement.
    exec_start apexd-bootstrap

on init
on init
    sysclktz 0
    sysclktz 0


@@ -281,9 +280,6 @@ on init
    # Start logd before any other services run to ensure we capture all of their logs.
    # Start logd before any other services run to ensure we capture all of their logs.
    start logd
    start logd


    # Start apexd as soon as we can
    start apexd

    # Start essential services.
    # Start essential services.
    start servicemanager
    start servicemanager
    start hwservicemanager
    start hwservicemanager
@@ -419,8 +415,16 @@ on post-fs-data
    mkdir /data/bootchart 0755 shell shell
    mkdir /data/bootchart 0755 shell shell
    bootchart start
    bootchart start


    # /data/apex is now available. Let apexd to scan and activate APEXes.
    # Make sure that apexd is started in the default namespace
    setprop apexd.data.status ready
    enter_default_mount_ns

    # /data/apex is now available. Start apexd to scan and activate APEXes.
    mkdir /data/apex 0750 root system
    mkdir /data/apex/active 0750 root system
    mkdir /data/apex/backup 0700 root system
    mkdir /data/apex/sessions 0700 root system
    mkdir /data/pkg_staging 0750 system system
    start apexd


    # Avoid predictable entropy pool. Carry over entropy from previous boot.
    # Avoid predictable entropy pool. Carry over entropy from previous boot.
    copy /data/system/entropy.dat /dev/urandom
    copy /data/system/entropy.dat /dev/urandom
@@ -537,12 +541,6 @@ on post-fs-data


    mkdir /data/anr 0775 system system
    mkdir /data/anr 0775 system system


    mkdir /data/apex 0750 root system
    mkdir /data/apex/active 0750 root system
    mkdir /data/apex/backup 0700 root system
    mkdir /data/apex/sessions 0700 root system
    mkdir /data/pkg_staging 0750 system system

    # NFC: create data/nfc for nv storage
    # NFC: create data/nfc for nv storage
    mkdir /data/nfc 0770 nfc nfc
    mkdir /data/nfc 0770 nfc nfc
    mkdir /data/nfc/param 0770 nfc nfc
    mkdir /data/nfc/param 0770 nfc nfc
@@ -575,6 +573,12 @@ on post-fs-data
    mkdir /data/cache/backup_stage 0700 system system
    mkdir /data/cache/backup_stage 0700 system system
    mkdir /data/cache/backup 0700 system system
    mkdir /data/cache/backup 0700 system system


    # Wait for apexd to finish activating APEXes before starting more processes.
    wait_for_prop apexd.status ready
    # TODO(jiyong): remove setup_runtime_bionic
    setup_runtime_bionic
    parse_apex_configs

    init_user0
    init_user0


    # Set SELinux security contexts on upgrade or policy update.
    # Set SELinux security contexts on upgrade or policy update.
@@ -583,14 +587,6 @@ on post-fs-data
    # load fsverity keys
    # load fsverity keys
    exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity
    exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity


    # Wait for apexd to finish activating APEXes before starting more processes.
    # This certainly reduces the parallelism but is required to make as many processes
    # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms
    # so the impact on the booting time is not significant.
    wait_for_prop apexd.status ready
    setup_runtime_bionic
    parse_apex_configs

    # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
    # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
    exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
    exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo