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

Commit cd2a90d5 authored by T.J. Mercier's avatar T.J. Mercier
Browse files

Reapply "libprocessgroup: Look for memcg v2 MaxActivationDepth override"

This reverts commit c53f9f8d.

webview_zygote is its own user and was attempting to read the metadata
override file, but the /metadata/libprocessgroup directory and the
memcg_v2_max_activation_depth contained therein had directory/file
permissions which were too restrictive and did not allow any readers
other than system. These are now globally readable which matches the
sepolicy for these items.

Bug: 390228674
Ignore-AOSP-First: Reapply reverted commit
Change-Id: I36117b564575b1c2c6538214c025fe5f607866ec
parent f9079176
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -287,6 +287,9 @@ cc_binary {
        "make_f2fs",
        "mke2fs",
        "sload_f2fs",

        // TODO: Revert after go/android-memcgv2-exp b/386797433
        "memcgv2_activation_depth",
    ],
}

@@ -685,3 +688,10 @@ phony {
        default: ["init_first_stage"],
    }),
}

// TODO: Revert after go/android-memcgv2-exp b/386797433
sh_binary {
    name: "memcgv2_activation_depth",
    src: "memcgv2_activation_depth.sh",
    filename_from_src: true,
}
+87 −0
Original line number Diff line number Diff line
#!/bin/sh

# This script adjusts overrides of the memcg v2 MaxActivationDepth value at runtime.
# The override value needs to be accessible starting very early in the Android boot, where aconfig
# flags and system properties do not work. A file on /metadata is used instead.

# The kernel allows this to be as high as 65535, but our Android hierarchy is never that deep.
MAX_ALLOWED_DEPTH=5

# Store overridden MaxActivationDepths here for libprocessgroup to find them
OVERRIDE_FILE_PATH="/metadata/libprocessgroup/memcg_v2_max_activation_depth"

if [ "$#" -ne 1 ]
then
    echo "Usage: $0 <memcg v2 MaxActivationDepth value>"
    exit 99
fi

max_activation_depth=$1

if [[ $max_activation_depth != +([0-9]) ]]
then
    echo "MaxActivationDepth value must be a positive integer: $max_activation_depth"
    exit 98
fi

if [ $max_activation_depth -lt 0 ]
then
    echo "Negative MaxActivationDepth is invalid: $max_activation_depth"
    exit 97
fi

if [ $max_activation_depth -gt $MAX_ALLOWED_DEPTH ]
then
    echo "MaxActivationDepth is too large: $max_activation_depth"
    exit 96
fi

grep memory /sys/fs/cgroup/cgroup.controllers
if [ $? -ne 0 ]
then
    echo "memcg v2 is not available on this device!"
    exit 95
fi

current_activation_depth=$(cat $OVERRIDE_FILE_PATH)
if [ $? -ne 0 ]
then
    # Find the default activation depth in the absence of any properties / overrides.
    #
    # To do this 100% correctly requires JSON parsing which we don't really want to do here.
    # We know that this will be called only for Pixel (for a limited-duration experiment), and that
    # Pixel does not override cgroups.json, therefore we can assume that the system cgroups.json has
    # only a single MaxActivationDepth entry which corresponds to the v2 memory controller. So we
    # can just grep for the default value.
    default_activation_depth=$(grep MaxActivationDepth /system/etc/cgroups.json | tr -dc '0-9')
    if [ $? -ne 0 -o $default_activation_depth -gt $MAX_ALLOWED_DEPTH ]
    then
        # If MaxActivationDepth is not present, libprocessgroup does not limit how deep it will activate
        default_activation_depth=$MAX_ALLOWED_DEPTH
    fi
    current_activation_depth=$default_activation_depth
fi

# libprocessgroup will pick this up for all future cgroup creations, including on the next boot
echo $max_activation_depth > $OVERRIDE_FILE_PATH
chmod ugo+r $OVERRIDE_FILE_PATH

if [ $max_activation_depth -lt $current_activation_depth ]
then
    # We can deactivate memcgs which are deeper than the new depth value, however that would leave
    # behind zombie memcgs which would ruin the metrics produced from this device. The only way to
    # eliminate those zombies is to remove the entire cgroup, which we cannot do without killing
    # all the contained processes. So the only real option we have is to reboot here.
    # This should only happen once at the end of the experiment.
    echo "Rebooting due to decreased memcg v2 MaxActivationDepth"
    reboot
elif [ $max_activation_depth -gt $current_activation_depth ]
then
    for d in $(seq $max_activation_depth)
    do
        for f in $(find /sys/fs/cgroup/ -mindepth $d -maxdepth $d -name cgroup.subtree_control)
        do
            echo "+memory" > $f
        done
    done
fi
+40 −1
Original line number Diff line number Diff line
@@ -18,15 +18,19 @@

#include <algorithm>
#include <iterator>
#include <mutex>
#include <optional>
#include <string_view>

#include <mntent.h>
#include <unistd.h>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <json/reader.h>
#include <json/value.h>

@@ -174,6 +178,38 @@ static std::optional<std::map<MountDir, MountOpts>> ReadCgroupV1Mounts() {
    return mounts;
}

// Keep the override file open to reduce open syscalls, but read it every time.
// Note that memcgv2_activation_depth.sh can race with us here.
std::optional<unsigned int> ReadMaxActivationDepthMetadataOverride() {
    static const char* OVERRIDE_FILE_PATH =
        "/metadata/libprocessgroup/memcg_v2_max_activation_depth";
    static int override_fd = open(OVERRIDE_FILE_PATH, O_RDONLY | O_CLOEXEC);
    static std::mutex mtx;

    std::unique_lock lock(mtx);
    if (override_fd < 0) {
        override_fd = open(OVERRIDE_FILE_PATH, O_RDONLY | O_CLOEXEC);
        if (override_fd < 0) return std::nullopt;
    }

    std::string depth_str;
    const bool ret = android::base::ReadFdToString(override_fd, &depth_str);
    lseek(override_fd, 0, SEEK_SET);
    lock.unlock();

    if (!ret) {
        PLOG(ERROR) << "Failed to read max activation depth override";
        return std::nullopt;
    }

    unsigned int depth;
    if (!android::base::ParseUint(android::base::Trim(depth_str), &depth)) {
        PLOG(ERROR) << "Failed to convert max activation depth override (" << depth_str << ')';
        return std::nullopt;
    }
    return depth;
}

}  // anonymous namespace


@@ -235,7 +271,10 @@ bool ReadDescriptors(CgroupDescriptorMap* descriptors) {
bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors) {
    for (const auto& [name, descriptor] : descriptors) {
        const uint32_t flags = descriptor.controller()->flags();
        const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth();
        uint32_t max_activation_depth;
        std::optional<unsigned int> metadataMaxDepth = ReadMaxActivationDepthMetadataOverride();
        if (metadataMaxDepth) max_activation_depth = *metadataMaxDepth;
        else max_activation_depth = descriptor.controller()->max_activation_depth();
        const unsigned int depth = GetCgroupDepth(descriptor.controller()->path(), path);

        if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) {
+9 −0
Original line number Diff line number Diff line
@@ -614,6 +614,9 @@ on post-fs

    mkdir /metadata/staged-install 0770 root system

    # TODO: Revert after go/android-memcgv2-exp b/386797433
    mkdir /metadata/libprocessgroup 0775 root system

on late-fs
    # Ensure that tracefs has the correct permissions.
    # This does not work correctly if it is called in post-fs.
@@ -1318,6 +1321,9 @@ on init && property:ro.debuggable=1
# Multi-Gen LRU Experiment
on property:persist.device_config.mglru_native.lru_gen_config=none
  write /sys/kernel/mm/lru_gen/enabled 0
  # Memcg v2 Experiment
  # TODO: Revert after go/android-memcgv2-exp b/386797433
  exec - system system -- /system/bin/memcgv2_activation_depth.sh 0
on property:persist.device_config.mglru_native.lru_gen_config=core
  write /sys/kernel/mm/lru_gen/enabled 1
on property:persist.device_config.mglru_native.lru_gen_config=core_and_mm_walk
@@ -1326,6 +1332,9 @@ on property:persist.device_config.mglru_native.lru_gen_config=core_and_nonleaf_y
  write /sys/kernel/mm/lru_gen/enabled 5
on property:persist.device_config.mglru_native.lru_gen_config=all
  write /sys/kernel/mm/lru_gen/enabled 7
  # Memcg v2 Experiment
  # TODO: Revert after go/android-memcgv2-exp b/386797433
  exec - system system -- /system/bin/memcgv2_activation_depth.sh 3

# Allow other processes to run `snapshotctl` through `init`. This requires
# `set_prop` permission on `snapshotctl_prop`.