Merge "Updated fuzz_config in Android.bp file" into main
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 235fdfd..2529516 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -373,7 +373,6 @@
 
     sanitize: {
         memtag_heap: true,
-        memtag_stack: true,
     },
 
     shared_libs: [
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 526e2ca..7c52e6e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -610,7 +610,7 @@
   setjmp(jump_buf);
 }
 
-TEST_F(CrasherTest, mte_illegal_setjmp) {
+TEST_F(CrasherTest, DISABLED_mte_illegal_setjmp) {
   // This setjmp is illegal because it jumps back into a function that already returned.
   // Quoting man 3 setjmp:
   //     If the function which called setjmp() returns before longjmp() is
@@ -1874,8 +1874,8 @@
   StartProcess([&recoverable]() {
     const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
                          "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
-    if (recoverable) {
-      env[3] = "GWP_ASAN_RECOVERABLE=true";
+    if (!recoverable) {
+      env[3] = "GWP_ASAN_RECOVERABLE=false";
     }
     std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
     test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 12a1ddc..6b9e493 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1547,9 +1547,14 @@
 
 void reboot_to_userspace_fastboot() {
     fb->RebootTo("fastboot");
+    if (fb->WaitForDisconnect() != fastboot::SUCCESS) {
+        die("Error waiting for USB disconnect.");
+    }
     fb->set_transport(nullptr);
 
-    // Give the current connection time to close.
+    // Not all platforms support WaitForDisconnect. There also isn't a great way to tell whether
+    // or not WaitForDisconnect is supported. So, just wait a bit extra for everyone, in order to
+    // make sure that the device has had time to initiate its reboot and disconnect itself.
     std::this_thread::sleep_for(std::chrono::seconds(1));
 
     fb->set_transport(open_device());
diff --git a/fastboot/fuzzer/Android.bp b/fastboot/fuzzer/Android.bp
index a898070..59533fa 100644
--- a/fastboot/fuzzer/Android.bp
+++ b/fastboot/fuzzer/Android.bp
@@ -55,7 +55,10 @@
     ],
     fuzz_config: {
         cc: [
-            "android-media-fuzzing-reports@google.com",
+            "dvander@google.com",
+            "elsk@google.com",
+            "enh@google.com",
+            "zhangkelvin@google.com",
         ],
         componentid: 533764,
         hotlists: [
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
index ac04245..21dc666 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <memory>
-#include <vector>
 #include "libsnapshot/cow_format.h"
 
 namespace android {
@@ -25,27 +24,30 @@
 
 class ICompressor {
   public:
-    explicit ICompressor(uint32_t compression_level, uint32_t block_size)
+    explicit ICompressor(const int32_t compression_level, const uint32_t block_size)
         : compression_level_(compression_level), block_size_(block_size) {}
 
     virtual ~ICompressor() {}
     // Factory methods for compression methods.
-    static std::unique_ptr<ICompressor> Gz(uint32_t compression_level, const int32_t block_size);
-    static std::unique_ptr<ICompressor> Brotli(uint32_t compression_level,
-                                               const int32_t block_size);
-    static std::unique_ptr<ICompressor> Lz4(uint32_t compression_level, const int32_t block_size);
-    static std::unique_ptr<ICompressor> Zstd(uint32_t compression_level, const int32_t block_size);
+    static std::unique_ptr<ICompressor> Gz(const int32_t compression_level,
+                                           const uint32_t block_size);
+    static std::unique_ptr<ICompressor> Brotli(const int32_t compression_level,
+                                               const uint32_t block_size);
+    static std::unique_ptr<ICompressor> Lz4(const int32_t compression_level,
+                                            const uint32_t block_size);
+    static std::unique_ptr<ICompressor> Zstd(const int32_t compression_level,
+                                             const uint32_t block_size);
 
     static std::unique_ptr<ICompressor> Create(CowCompression compression,
-                                               const int32_t block_size);
+                                               const uint32_t block_size);
 
-    uint32_t GetCompressionLevel() const { return compression_level_; }
+    int32_t GetCompressionLevel() const { return compression_level_; }
     uint32_t GetBlockSize() const { return block_size_; }
     [[nodiscard]] virtual std::vector<uint8_t> Compress(const void* data, size_t length) const = 0;
 
   private:
-    uint32_t compression_level_;
-    uint32_t block_size_;
+    const int32_t compression_level_;
+    const uint32_t block_size_;
 };
 }  // namespace snapshot
 }  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 6865b19..6a7153d 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -293,7 +293,7 @@
 };
 struct CowCompression {
     CowCompressionAlgorithm algorithm = kCowCompressNone;
-    uint32_t compression_level = 0;
+    int32_t compression_level = 0;
 };
 
 static constexpr uint8_t kCowReadAheadNotStarted = 0;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
index 0205f50..bff5257 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
@@ -17,6 +17,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <cstdint>
 #include <limits>
 #include <memory>
 #include <queue>
@@ -57,7 +58,7 @@
 }
 
 std::unique_ptr<ICompressor> ICompressor::Create(CowCompression compression,
-                                                 const int32_t block_size) {
+                                                 const uint32_t block_size) {
     switch (compression.algorithm) {
         case kCowCompressLz4:
             return ICompressor::Lz4(compression.compression_level, block_size);
@@ -101,7 +102,7 @@
 
 class GzCompressor final : public ICompressor {
   public:
-    GzCompressor(uint32_t compression_level, const uint32_t block_size)
+    GzCompressor(int32_t compression_level, const uint32_t block_size)
         : ICompressor(compression_level, block_size){};
 
     std::vector<uint8_t> Compress(const void* data, size_t length) const override {
@@ -122,7 +123,7 @@
 
 class Lz4Compressor final : public ICompressor {
   public:
-    Lz4Compressor(uint32_t compression_level, const uint32_t block_size)
+    Lz4Compressor(int32_t compression_level, const uint32_t block_size)
         : ICompressor(compression_level, block_size){};
 
     std::vector<uint8_t> Compress(const void* data, size_t length) const override {
@@ -154,7 +155,7 @@
 
 class BrotliCompressor final : public ICompressor {
   public:
-    BrotliCompressor(uint32_t compression_level, const uint32_t block_size)
+    BrotliCompressor(int32_t compression_level, const uint32_t block_size)
         : ICompressor(compression_level, block_size){};
 
     std::vector<uint8_t> Compress(const void* data, size_t length) const override {
@@ -180,7 +181,7 @@
 
 class ZstdCompressor final : public ICompressor {
   public:
-    ZstdCompressor(uint32_t compression_level, const uint32_t block_size)
+    ZstdCompressor(int32_t compression_level, const uint32_t block_size)
         : ICompressor(compression_level, block_size),
           zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) {
         ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level);
@@ -318,22 +319,23 @@
     }
 }
 
-std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level,
-                                                 const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Brotli(const int32_t compression_level,
+                                                 const uint32_t block_size) {
     return std::make_unique<BrotliCompressor>(compression_level, block_size);
 }
 
-std::unique_ptr<ICompressor> ICompressor::Gz(uint32_t compression_level, const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Gz(const int32_t compression_level,
+                                             const uint32_t block_size) {
     return std::make_unique<GzCompressor>(compression_level, block_size);
 }
 
-std::unique_ptr<ICompressor> ICompressor::Lz4(uint32_t compression_level,
-                                              const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Lz4(const int32_t compression_level,
+                                              const uint32_t block_size) {
     return std::make_unique<Lz4Compressor>(compression_level, block_size);
 }
 
-std::unique_ptr<ICompressor> ICompressor::Zstd(uint32_t compression_level,
-                                               const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Zstd(const int32_t compression_level,
+                                               const uint32_t block_size) {
     return std::make_unique<ZstdCompressor>(compression_level, block_size);
 }
 
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index d0864e0..0993dba 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -134,7 +134,7 @@
         return false;
     }
     if (parts.size() > 1) {
-        if (!android::base::ParseUint(parts[1], &compression_.compression_level)) {
+        if (!android::base::ParseInt(parts[1], &compression_.compression_level)) {
             LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1];
             return false;
         }
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index 73deafb..95398e4 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -149,7 +149,7 @@
     }
 
     if (parts.size() > 1) {
-        if (!android::base::ParseUint(parts[1], &compression_.compression_level)) {
+        if (!android::base::ParseInt(parts[1], &compression_.compression_level)) {
             LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1];
             return false;
         }
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 9503072..f55cadb 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -74,6 +74,7 @@
     ASSERT_EQ(access("/sys/fs/erofs", F_OK), 0);
 }
 
+// @VsrTest = 3.7.10
 TEST(fs, PartitionTypes) {
     // Requirements only apply to Android 13+, 5.10+ devices.
     int vsr_level = GetVsrLevel();
diff --git a/init/Android.bp b/init/Android.bp
index ff82f7f..6d63e41 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -259,6 +259,7 @@
         "avf_build_flags_cc",
         "libinit_defaults",
     ],
+    recovery_available: false,
     cflags: ["-DMICRODROID=1"],
 }
 
@@ -276,6 +277,13 @@
     defaults: ["init_defaults"],
     srcs: ["main.cpp"],
     symlinks: ["ueventd"],
+}
+
+cc_binary {
+    name: "init_second_stage",
+    defaults: ["init_second_stage_defaults"],
+    static_libs: ["libinit"],
+    visibility: ["//visibility:any_system_partition"],
     target: {
         platform: {
             required: [
@@ -310,18 +318,12 @@
 }
 
 cc_binary {
-    name: "init_second_stage",
-    defaults: ["init_second_stage_defaults"],
-    static_libs: ["libinit"],
-    visibility: ["//visibility:any_system_partition"],
-}
-
-cc_binary {
     name: "init_second_stage.microdroid",
     defaults: [
         "avf_build_flags_cc",
         "init_second_stage_defaults",
     ],
+    recovery_available: false,
     static_libs: ["libinit.microdroid"],
     cflags: ["-DMICRODROID=1"],
     installable: false,
diff --git a/init/service.cpp b/init/service.cpp
index eb24dd5..31308a0 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -355,20 +355,35 @@
     // If we crash > 4 times in 'fatal_crash_window_' minutes or before boot_completed,
     // reboot into bootloader or set crashing property
     boot_clock::time_point now = boot_clock::now();
+    constexpr const char native_watchdog_reboot_time[] = "persist.init.svc.last_fatal_reboot_epoch";
+    uint64_t throttle_window =
+            std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(24)).count();
     if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART) &&
         !was_last_exit_ok_) {
         bool boot_completed = GetBoolProperty("sys.boot_completed", false);
         if (now < time_crashed_ + fatal_crash_window_ || !boot_completed) {
             if (++crash_count_ > 4) {
-                auto exit_reason = boot_completed ?
-                    "in " + std::to_string(fatal_crash_window_.count()) + " minutes" :
-                    "before boot completed";
+                auto exit_reason =
+                        boot_completed
+                                ? "in " + std::to_string(fatal_crash_window_.count()) + " minutes"
+                                : "before boot completed";
                 if (flags_ & SVC_CRITICAL) {
                     if (!GetBoolProperty("init.svc_debug.no_fatal." + name_, false)) {
-                        // Aborts into `fatal_reboot_target_'.
-                        SetFatalRebootTarget(fatal_reboot_target_);
-                        LOG(FATAL) << "critical process '" << name_ << "' exited 4 times "
-                                   << exit_reason;
+                        uint64_t epoch_time =
+                                std::chrono::duration_cast<std::chrono::seconds>(
+                                        std::chrono::system_clock::now().time_since_epoch())
+                                        .count();
+                        // Do not reboot again If it was already initiated in the last 24hrs
+                        if (epoch_time - GetIntProperty(native_watchdog_reboot_time, 0) >
+                            throttle_window) {
+                            SetProperty(native_watchdog_reboot_time, std::to_string(epoch_time));
+                            // Aborts into `fatal_reboot_target_'.
+                            SetFatalRebootTarget(fatal_reboot_target_);
+                            LOG(FATAL) << "critical process '" << name_ << "' exited 4 times "
+                                       << exit_reason;
+                        } else {
+                            LOG(INFO) << "Reboot already performed in last 24hrs because of crash.";
+                        }
                     }
                 } else {
                     LOG(ERROR) << "process with updatable components '" << name_
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index c6a0737..bb855d5 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,15 +2,34 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_defaults {
-    name: "libprocessgroup_defaults",
-    cpp_std: "gnu++20",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wexit-time-destructors",
-        "-Wno-unused-parameter",
+soong_config_module_type {
+    name: "libprocessgroup_flag_aware_cc_defaults",
+    module_type: "cc_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: [
+        "memcg_v2_force_enabled",
+        "cgroup_v2_sys_app_isolation",
     ],
+    properties: [
+        "cflags",
+    ],
+}
+
+libprocessgroup_flag_aware_cc_defaults {
+    name: "libprocessgroup_build_flags_cc",
+    cpp_std: "gnu++20",
+    soong_config_variables: {
+        memcg_v2_force_enabled: {
+            cflags: [
+                "-DMEMCG_V2_FORCE_ENABLED=true",
+            ],
+        },
+        cgroup_v2_sys_app_isolation: {
+            cflags: [
+                "-DCGROUP_V2_SYS_APP_ISOLATION=true",
+            ],
+        },
+    },
 }
 
 cc_library_headers {
@@ -73,7 +92,7 @@
     export_header_lib_headers: [
         "libprocessgroup_headers",
     ],
-    defaults: ["libprocessgroup_defaults"],
+    defaults: ["libprocessgroup_build_flags_cc"],
     apex_available: [
         "//apex_available:platform",
         "//apex_available:anyapex",
@@ -84,7 +103,7 @@
 cc_test {
     name: "task_profiles_test",
     host_supported: true,
-    defaults: ["libprocessgroup_defaults"],
+    defaults: ["libprocessgroup_build_flags_cc"],
     srcs: [
         "task_profiles_test.cpp",
     ],
diff --git a/libprocessgroup/build_flags.h b/libprocessgroup/build_flags.h
new file mode 100644
index 0000000..bc3e7df
--- /dev/null
+++ b/libprocessgroup/build_flags.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#ifndef MEMCG_V2_FORCE_ENABLED
+#define MEMCG_V2_FORCE_ENABLED false
+#endif
+
+#ifndef CGROUP_V2_SYS_APP_ISOLATION
+#define CGROUP_V2_SYS_APP_ISOLATION false
+#endif
+
+namespace android::libprocessgroup_flags {
+
+inline consteval bool force_memcg_v2() {
+    return MEMCG_V2_FORCE_ENABLED;
+}
+
+inline consteval bool cgroup_v2_sys_app_isolation() {
+    return CGROUP_V2_SYS_APP_ISOLATION;
+}
+
+}  // namespace android::libprocessgroup_flags
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 94d9502..8df2805 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -78,14 +78,6 @@
     return true;
 }
 
-static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
-    return StringPrintf("%s/uid_%u", cgroup, uid);
-}
-
-static std::string ConvertUidPidToPath(const char* cgroup, uid_t uid, pid_t pid) {
-    return StringPrintf("%s/uid_%u/pid_%d", cgroup, uid, pid);
-}
-
 static bool CgroupKillAvailable() {
     static std::once_flag f;
     static bool cgroup_kill_available = false;
diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp
index ea6c247..1e0783a 100644
--- a/libprocessgroup/setup/Android.bp
+++ b/libprocessgroup/setup/Android.bp
@@ -41,8 +41,5 @@
     export_header_lib_headers: [
         "libprocessgroup_headers",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
+    defaults: ["libprocessgroup_build_flags_cc"],
 }
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 4e44c91..1b26fbc 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -29,7 +29,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <regex>
+#include <optional>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -43,6 +43,7 @@
 #include <processgroup/processgroup.h>
 #include <processgroup/setup.h>
 
+#include "../build_flags.h"
 #include "cgroup_descriptor.h"
 
 using android::base::GetUintProperty;
@@ -57,6 +58,8 @@
 
 static constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json";
 
+static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup";
+
 static bool ChangeDirModeAndOwner(const std::string& path, mode_t mode, const std::string& uid,
                                   const std::string& gid, bool permissive_mode = false) {
     uid_t pw_uid = -1;
@@ -182,6 +185,8 @@
     }
 }
 
+static const bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2();
+
 static bool ReadDescriptorsFromFile(const std::string& file_name,
                                     std::map<std::string, CgroupDescriptor>* descriptors) {
     std::vector<CgroupDescriptor> result;
@@ -205,22 +210,41 @@
         const Json::Value& cgroups = root["Cgroups"];
         for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) {
             std::string name = cgroups[i]["Controller"].asString();
+
+            if (force_memcg_v2 && name == "memory") continue;
+
             MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1);
         }
     }
 
+    bool memcgv2_present = false;
+    std::string root_path;
     if (root.isMember("Cgroups2")) {
         const Json::Value& cgroups2 = root["Cgroups2"];
-        std::string root_path = cgroups2["Path"].asString();
+        root_path = cgroups2["Path"].asString();
         MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME, "", 2);
 
         const Json::Value& childGroups = cgroups2["Controllers"];
         for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) {
             std::string name = childGroups[i]["Controller"].asString();
+
+            if (force_memcg_v2 && name == "memory") memcgv2_present = true;
+
             MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2);
         }
     }
 
+    if (force_memcg_v2 && !memcgv2_present) {
+        LOG(INFO) << "Forcing memcg to v2 hierarchy";
+        Json::Value memcgv2;
+        memcgv2["Controller"] = "memory";
+        memcgv2["NeedsActivation"] = true;
+        memcgv2["Path"] = ".";
+        memcgv2["Optional"] = true;  // In case of cgroup_disabled=memory, so we can still boot
+        MergeCgroupToDescriptors(descriptors, memcgv2, "memory",
+                                 root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2);
+    }
+
     return true;
 }
 
@@ -308,7 +332,8 @@
 
         if (!base::WriteStringToFile(str, path)) {
             if (IsOptionalController(controller)) {
-                PLOG(INFO) << "Failed to activate optional controller " << controller->name();
+                PLOG(INFO) << "Failed to activate optional controller " << controller->name()
+                           << " at " << path;
                 return true;
             }
             PLOG(ERROR) << "Failed to activate controller " << controller->name();
@@ -424,6 +449,76 @@
 }  // namespace cgrouprc
 }  // namespace android
 
+static std::optional<bool> MGLRUDisabled() {
+    const std::string file_name = "/sys/kernel/mm/lru_gen/enabled";
+    std::string content;
+    if (!android::base::ReadFileToString(file_name, &content)) {
+        PLOG(ERROR) << "Failed to read MGLRU state from " << file_name;
+        return {};
+    }
+
+    return content == "0x0000";
+}
+
+static std::optional<bool> MEMCGDisabled(
+        const std::map<std::string, android::cgrouprc::CgroupDescriptor>& descriptors) {
+    std::string cgroup_v2_root = android::cgrouprc::CGROUP_V2_ROOT_DEFAULT;
+    const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME);
+    if (it == descriptors.end()) {
+        LOG(WARNING) << "No Cgroups2 path found in cgroups.json. Vendor has modified Android, and "
+                     << "kernel memory use will be higher than intended.";
+    } else if (it->second.controller()->path() != cgroup_v2_root) {
+        cgroup_v2_root = it->second.controller()->path();
+    }
+
+    const std::string file_name = cgroup_v2_root + "/cgroup.controllers";
+    std::string content;
+    if (!android::base::ReadFileToString(file_name, &content)) {
+        PLOG(ERROR) << "Failed to read cgroup controllers from " << file_name;
+        return {};
+    }
+
+    // If we've forced memcg to v2 and it's not available, then it could only have been disabled
+    // on the kernel command line (GKI sets CONFIG_MEMCG).
+    return content.find("memory") == std::string::npos;
+}
+
+static bool CreateV2SubHierarchy(
+        const std::string& path,
+        const std::map<std::string, android::cgrouprc::CgroupDescriptor>& descriptors) {
+    using namespace android::cgrouprc;
+
+    const auto cgv2_iter = descriptors.find(CGROUPV2_HIERARCHY_NAME);
+    if (cgv2_iter == descriptors.end()) return false;
+    const android::cgrouprc::CgroupDescriptor cgv2_descriptor = cgv2_iter->second;
+
+    if (!Mkdir(path, cgv2_descriptor.mode(), cgv2_descriptor.uid(), cgv2_descriptor.gid())) {
+        PLOG(ERROR) << "Failed to create directory for " << path;
+        return false;
+    }
+
+    // Activate all v2 controllers in path so they can be activated in
+    // children as they are created.
+    for (const auto& [name, descriptor] : descriptors) {
+        const format::CgroupController* controller = descriptor.controller();
+        std::uint32_t flags = controller->flags();
+        if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME &&
+            flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+            std::string str("+");
+            str += controller->name();
+            if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) {
+                if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) {
+                    PLOG(WARNING) << "Activation of cgroup controller " << str << " failed in path "
+                                  << path;
+                } else {
+                    return false;
+                }
+            }
+        }
+    }
+    return true;
+}
+
 bool CgroupSetup() {
     using namespace android::cgrouprc;
 
@@ -457,6 +552,32 @@
         }
     }
 
+    if (force_memcg_v2) {
+        if (MGLRUDisabled().value_or(false)) {
+            LOG(WARNING) << "Memcg forced to v2 hierarchy with MGLRU disabled! "
+                         << "Global reclaim performance will suffer.";
+        }
+        if (MEMCGDisabled(descriptors).value_or(false)) {
+            LOG(WARNING) << "Memcg forced to v2 hierarchy while memcg is disabled by kernel "
+                         << "command line!";
+        }
+    }
+
+    // System / app isolation.
+    // This really belongs in early-init in init.rc, but we cannot use the flag there.
+    if (android::libprocessgroup_flags::cgroup_v2_sys_app_isolation()) {
+        const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME);
+        const std::string cgroup_v2_root = (it == descriptors.end())
+                                                   ? CGROUP_V2_ROOT_DEFAULT
+                                                   : it->second.controller()->path();
+
+        LOG(INFO) << "Using system/app isolation under: " << cgroup_v2_root;
+        if (!CreateV2SubHierarchy(cgroup_v2_root + "/apps", descriptors) ||
+            !CreateV2SubHierarchy(cgroup_v2_root + "/system", descriptors)) {
+            return false;
+        }
+    }
+
     // mkdir <CGROUPS_RC_DIR> 0711 system system
     if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) {
         LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file";
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 2353cf1..0c2252b 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -33,6 +33,8 @@
 #include <json/reader.h>
 #include <json/value.h>
 
+#include <build_flags.h>
+
 // To avoid issues in sdk_mac build
 #if defined(__ANDROID__)
 #include <sys/prctl.h>
@@ -126,11 +128,29 @@
     file_v2_name_ = file_v2_name;
 }
 
+static bool isSystemApp(uid_t uid) {
+    return uid < AID_APP_START;
+}
+
+std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid) {
+    if (android::libprocessgroup_flags::cgroup_v2_sys_app_isolation()) {
+        if (isSystemApp(uid))
+            return StringPrintf("%s/system/uid_%u", root_cgroup_path, uid);
+        else
+            return StringPrintf("%s/apps/uid_%u", root_cgroup_path, uid);
+    }
+    return StringPrintf("%s/uid_%u", root_cgroup_path, uid);
+}
+
+std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid) {
+    const std::string uid_path = ConvertUidToPath(root_cgroup_path, uid);
+    return StringPrintf("%s/pid_%d", uid_path.c_str(), pid);
+}
+
 bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const {
     if (controller()->version() == 2) {
-        // all cgroup v2 attributes use the same process group hierarchy
-        *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid,
-                             file_name().c_str());
+        const std::string cgroup_path = ConvertUidPidToPath(controller()->path(), uid, pid);
+        *path = cgroup_path + "/" + file_name();
         return true;
     }
     return GetPathForTask(pid, path);
@@ -155,12 +175,14 @@
     return true;
 }
 
+// NOTE: This function is for cgroup v2 only
 bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const {
     if (path == nullptr) {
         return true;
     }
 
-    *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str());
+    const std::string cgroup_path = ConvertUidToPath(controller()->path(), uid);
+    *path = cgroup_path + "/" + file_name();
     return true;
 }
 
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 2fa1931..7e3c50d 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -82,8 +82,8 @@
 
     virtual void EnableResourceCaching(ResourceCacheType) {}
     virtual void DropResourceCaching(ResourceCacheType) {}
-    virtual bool IsValidForProcess(uid_t uid, pid_t pid) const { return false; }
-    virtual bool IsValidForTask(pid_t tid) const { return false; }
+    virtual bool IsValidForProcess(uid_t, pid_t) const { return false; }
+    virtual bool IsValidForTask(pid_t) const { return false; }
 
   protected:
     enum CacheUseResult { SUCCESS, FAIL, UNUSED };
@@ -109,8 +109,8 @@
 
     const char* Name() const override { return "SetTimerSlack"; }
     bool ExecuteForTask(pid_t tid) const override;
-    bool IsValidForProcess(uid_t uid, pid_t pid) const override { return true; }
-    bool IsValidForTask(pid_t tid) const override { return true; }
+    bool IsValidForProcess(uid_t, pid_t) const override { return true; }
+    bool IsValidForTask(pid_t) const override { return true; }
 
   private:
     unsigned long slack_;
@@ -252,3 +252,6 @@
     std::map<std::string, std::shared_ptr<TaskProfile>, std::less<>> profiles_;
     std::map<std::string, std::unique_ptr<IProfileAttribute>, std::less<>> attributes_;
 };
+
+std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid);
+std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid);
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
index b17e695..d19da2b 100644
--- a/libprocessgroup/task_profiles_test.cpp
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -102,8 +102,7 @@
   public:
     ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {}
     ~ProfileAttributeMock() override = default;
-    void Reset(const CgroupController& controller, const std::string& file_name,
-               const std::string& file_v2_name) override {
+    void Reset(const CgroupController&, const std::string&, const std::string&) override {
         CHECK(false);
     }
     const CgroupController* controller() const override {
@@ -111,10 +110,10 @@
         return {};
     }
     const std::string& file_name() const override { return file_name_; }
-    bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override {
+    bool GetPathForProcess(uid_t, pid_t pid, std::string* path) const override {
         return GetPathForTask(pid, path);
     }
-    bool GetPathForTask(int tid, std::string* path) const override {
+    bool GetPathForTask(int, std::string* path) const override {
 #ifdef __ANDROID__
         CHECK(CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, path));
         CHECK_GT(path->length(), 0);
diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h
index 58cd18d..cf82fb7 100644
--- a/libvendorsupport/include_llndk/android/llndk-versioning.h
+++ b/libvendorsupport/include_llndk/android/llndk-versioning.h
@@ -14,22 +14,18 @@
 
 #pragma once
 
-/* As a vendor default header included in all vendor modules, this header MUST NOT include other
- * header files or any declarations. Only macros are allowed.
- */
-#if defined(__ANDROID_VENDOR__)
-
 // LLNDK (https://source.android.com/docs/core/architecture/vndk/build-system#ll-ndk) is similar to
 // NDK, but uses its own versioning of YYYYMM format for vendor builds. The LLNDK symbols are
-// enabled when the vendor api level is equal to or newer than the ro.board.api_level.
-#define __INTRODUCED_IN_LLNDK(vendor_api_level)                                             \
-    _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wgcc-compat\"")   \
-            __attribute__((enable_if(                                                       \
-                    __ANDROID_VENDOR_API__ >= vendor_api_level,                             \
-                    "available in vendor API level " #vendor_api_level " that "             \
-                    "is newer than the current vendor API level. Guard the API "            \
-                    "call with '#if (__ANDROID_VENDOR_API__ >= " #vendor_api_level ")'."))) \
-            _Pragma("clang diagnostic pop")
+// enabled when the vendor api level is equal to or newer than the ro.board.api_level. These symbols
+// must be annotated in map.txt files with the `# llndk=YYYYMM` annotation. They also must be marked
+// with `__INTRODUCED_IN_LLNDK(YYYYMM)` in the header files. It leaves a no-op annotation for ABI
+// analysis.
+#if !defined(__INTRODUCED_IN_LLNDK)
+#define __INTRODUCED_IN_LLNDK(vendor_api_level) \
+    __attribute__((annotate("introduced_in_llndk=" #vendor_api_level)))
+#endif
+
+#if defined(__ANDROID_VENDOR__)
 
 // Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK.
 // This returns true for the vendor modules if the vendor_api_level is less than or equal to the
@@ -39,13 +35,6 @@
 
 #else  // __ANDROID_VENDOR__
 
-// __INTRODUCED_IN_LLNDK is for LLNDK only but not for NDK. Ignore this for non-vendor modules.
-// It leaves a no-op annotation for ABI analysis.
-#if !defined(__INTRODUCED_IN_LLNDK)
-#define __INTRODUCED_IN_LLNDK(vendor_api_level) \
-    __attribute__((annotate("introduced_in_llndk=" #vendor_api_level)))
-#endif
-
 // For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to
 // guard the API for __INTRODUCED_IN.
 #if !defined(API_LEVEL_AT_LEAST)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index fb411b7..1af46c1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -648,6 +648,8 @@
     mkdir /metadata/aconfig 0775 root system
     mkdir /metadata/aconfig/flags 0770 root system
     mkdir /metadata/aconfig/boot 0775 root system
+
+    mkdir /metadata/aconfig_test_missions 0775 root system
     exec_start aconfigd-init
     start aconfigd
 
diff --git a/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp b/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp
index 6b8f90f..dec64e1 100644
--- a/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp
+++ b/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp
@@ -247,6 +247,7 @@
         return EXIT_FAILURE;
     } else {
         printf("done\n");
+        printf("\nNOTE: device reboot may be required before changes take effect.\n");
         return EXIT_SUCCESS;
     }
 }