Merge "Call sync() to guarantee blocks were released by unlink" into main
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 79c0b6d..f91d232 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -171,11 +171,12 @@
}
if (show_help) {
show_help = false;
- std::cerr << "WARNING: Userdata checkpoint is in progress. To force end checkpointing, "
- "call 'vdc checkpoint commitChanges'. This can lead to data corruption if "
- "rolled back."
+ std::cerr << "WARNING: Userdata checkpoint is in progress. "
+ "To forcibly end checkpointing, "
+ "call 'vdc checkpoint commitChanges'. "
+ "This can lead to data corruption if rolled back."
<< std::endl;
- LOG(INFO) << "Waiting for checkpoint to complete and then continue remount.";
+ LOG(INFO) << "Waiting for checkpoint to complete before remounting...";
}
std::this_thread::sleep_for(4s);
}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 39b5b76..cc6db35 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -316,6 +316,12 @@
test_options: {
// Legacy VAB launched in Android R.
min_shipping_api_level: 30,
+ test_runner_options: [
+ {
+ name: "force-no-test-error",
+ value: "false",
+ },
+ ],
},
}
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 649309d..d83524a 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -168,7 +168,7 @@
vendor_ramdisk_available: true,
}
-// This target will install to /system/bin/snapuserd_ramdisk
+// This target will install to /system/bin/snapuserd_ramdisk
// It will also create a symblink on /system/bin/snapuserd that point to
// /system/bin/snapuserd_ramdisk .
// This way, init can check if generic ramdisk copy exists.
@@ -249,6 +249,14 @@
test_suites: [
"device-tests",
],
+ test_options: {
+ test_runner_options: [
+ {
+ name: "force-no-test-error",
+ value: "false",
+ },
+ ],
+ },
}
// vts tests cannot be host_supported.
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index d40be9f..33e00bc 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -84,6 +84,7 @@
header_libs: [
"libcutils_headers",
"libprocessgroup_headers",
+ "libprocessgroup_util",
],
export_include_dirs: ["include"],
export_header_lib_headers: [
diff --git a/libprocessgroup/TEST_MAPPING b/libprocessgroup/TEST_MAPPING
index 29a9ff0..0f670ef 100644
--- a/libprocessgroup/TEST_MAPPING
+++ b/libprocessgroup/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit-large": [
{
"name": "StagedRollbackTest"
}
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index ebc0599..52b5afe 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -28,6 +28,7 @@
#include <android-base/strings.h>
#include <cgroup_map.h>
#include <processgroup/processgroup.h>
+#include <processgroup/util.h>
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -216,7 +217,13 @@
for (uint32_t i = 0; i < controller_count; ++i) {
const ACgroupController* controller = ACgroupFile_getController(i);
const uint32_t flags = ACgroupController_getFlags(controller);
- if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+ uint32_t max_activation_depth = UINT32_MAX;
+ if (__builtin_available(android 36, *)) {
+ max_activation_depth = ACgroupController_getMaxActivationDepth(controller);
+ }
+ const int depth = util::GetCgroupDepth(ACgroupController_getPath(controller), path);
+
+ if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) {
std::string str("+");
str.append(ACgroupController_getName(controller));
if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) {
diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/cgroup_controller.cpp
index 5a326e5..889b3be 100644
--- a/libprocessgroup/cgrouprc/cgroup_controller.cpp
+++ b/libprocessgroup/cgrouprc/cgroup_controller.cpp
@@ -32,6 +32,11 @@
return controller->flags();
}
+uint32_t ACgroupController_getMaxActivationDepth(const ACgroupController* controller) {
+ CHECK(controller != nullptr);
+ return controller->max_activation_depth();
+}
+
const char* ACgroupController_getName(const ACgroupController* controller) {
CHECK(controller != nullptr);
return controller->name();
diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
index e704a36..3a57df5 100644
--- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h
+++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
@@ -79,6 +79,14 @@
const ACgroupController*) __INTRODUCED_IN(30);
/**
+ * Returns the maximum activation depth of the given controller.
+ * Only applicable to cgroup v2 controllers.
+ * Returns UINT32_MAX if no maximum activation depth is set.
+ */
+__attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getMaxActivationDepth(
+ const ACgroupController* controller) __INTRODUCED_IN(36);
+
+/**
* Returns the name of the given controller.
* If the given controller is null, return nullptr.
*/
diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt
index b62b10f..30bd25f 100644
--- a/libprocessgroup/cgrouprc/libcgrouprc.map.txt
+++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt
@@ -16,3 +16,10 @@
local:
*;
};
+
+LIBCGROUPRC_36 { # introduced=36
+ global:
+ ACgroupController_getMaxActivationDepth; # llndk=202504 systemapi
+ local:
+ *;
+};
diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
index 56e67df..0dd909a 100644
--- a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
+++ b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
@@ -21,13 +21,11 @@
namespace format {
CgroupController::CgroupController(uint32_t version, uint32_t flags, const std::string& name,
- const std::string& path)
-{
+ const std::string& path, uint32_t max_activation_depth)
+ : version_(version), flags_(flags), max_activation_depth_(max_activation_depth) {
// strlcpy isn't available on host. Although there is an implementation
// in licutils, libcutils itself depends on libcgrouprc_format, causing
// a circular dependency.
- version_ = version;
- flags_ = flags;
strncpy(name_, name.c_str(), sizeof(name_) - 1);
name_[sizeof(name_) - 1] = '\0';
strncpy(path_, path.c_str(), sizeof(path_) - 1);
@@ -42,6 +40,10 @@
return flags_;
}
+uint32_t CgroupController::max_activation_depth() const {
+ return max_activation_depth_;
+}
+
const char* CgroupController::name() const {
return name_;
}
diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
index 9427a1c..c0c1f60 100644
--- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
+++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
@@ -29,10 +29,11 @@
public:
CgroupController() = default;
CgroupController(uint32_t version, uint32_t flags, const std::string& name,
- const std::string& path);
+ const std::string& path, uint32_t max_activation_depth);
uint32_t version() const;
uint32_t flags() const;
+ uint32_t max_activation_depth() const;
const char* name() const;
const char* path() const;
@@ -44,6 +45,7 @@
uint32_t version_ = 0;
uint32_t flags_ = 0;
+ uint32_t max_activation_depth_ = UINT32_MAX;
char name_[CGROUP_NAME_BUF_SZ] = {};
char path_[CGROUP_PATH_BUF_SZ] = {};
};
diff --git a/libprocessgroup/profiles/cgroups.proto b/libprocessgroup/profiles/cgroups.proto
index f2de345..d2fd472 100644
--- a/libprocessgroup/profiles/cgroups.proto
+++ b/libprocessgroup/profiles/cgroups.proto
@@ -24,7 +24,7 @@
Cgroups2 cgroups2 = 2 [json_name = "Cgroups2"];
}
-// Next: 8
+// Next: 9
message Cgroup {
string controller = 1 [json_name = "Controller"];
string path = 2 [json_name = "Path"];
@@ -36,6 +36,7 @@
// https://developers.google.com/protocol-buffers/docs/proto3#default
bool needs_activation = 6 [json_name = "NeedsActivation"];
bool is_optional = 7 [json_name = "Optional"];
+ uint32 max_activation_depth = 8 [json_name = "MaxActivationDepth"];
}
// Next: 6
diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp
index 1e0783a..76f0a11 100644
--- a/libprocessgroup/setup/Android.bp
+++ b/libprocessgroup/setup/Android.bp
@@ -37,6 +37,7 @@
],
header_libs: [
"libprocessgroup_headers",
+ "libprocessgroup_util",
],
export_header_lib_headers: [
"libprocessgroup_headers",
diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h
index 9982bfc..06ce186 100644
--- a/libprocessgroup/setup/cgroup_descriptor.h
+++ b/libprocessgroup/setup/cgroup_descriptor.h
@@ -30,7 +30,8 @@
class CgroupDescriptor {
public:
CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path,
- mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags);
+ mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags,
+ uint32_t max_activation_depth);
const format::CgroupController* controller() const { return &controller_; }
mode_t mode() const { return mode_; }
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 1b26fbc..bd41874 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -42,6 +42,7 @@
#include <processgroup/format/cgroup_file.h>
#include <processgroup/processgroup.h>
#include <processgroup/setup.h>
+#include <processgroup/util.h>
#include "../build_flags.h"
#include "cgroup_descriptor.h"
@@ -173,9 +174,15 @@
controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL;
}
+ uint32_t max_activation_depth = UINT32_MAX;
+ if (cgroup.isMember("MaxActivationDepth")) {
+ max_activation_depth = cgroup["MaxActivationDepth"].asUInt();
+ }
+
CgroupDescriptor descriptor(
cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8),
- cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags);
+ cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags,
+ max_activation_depth);
auto iter = descriptors->find(name);
if (iter == descriptors->end()) {
@@ -324,7 +331,8 @@
return false;
}
- if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+ if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION &&
+ controller->max_activation_depth() > 0) {
std::string str = "+";
str += controller->name();
std::string path = controller->path();
@@ -433,8 +441,12 @@
CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name,
const std::string& path, mode_t mode, const std::string& uid,
- const std::string& gid, uint32_t flags = 0)
- : controller_(version, flags, name, path), mode_(mode), uid_(uid), gid_(gid) {}
+ const std::string& gid, uint32_t flags,
+ uint32_t max_activation_depth)
+ : controller_(version, flags, name, path, max_activation_depth),
+ mode_(mode),
+ uid_(uid),
+ gid_(gid) {}
void CgroupDescriptor::set_mounted(bool mounted) {
uint32_t flags = controller_.flags();
@@ -502,8 +514,11 @@
for (const auto& [name, descriptor] : descriptors) {
const format::CgroupController* controller = descriptor.controller();
std::uint32_t flags = controller->flags();
+ std::uint32_t max_activation_depth = controller->max_activation_depth();
+ const int depth = util::GetCgroupDepth(controller->path(), path);
+
if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME &&
- flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+ flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) {
std::string str("+");
str += controller->name();
if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) {
diff --git a/libprocessgroup/util/Android.bp b/libprocessgroup/util/Android.bp
new file mode 100644
index 0000000..4a940b7
--- /dev/null
+++ b/libprocessgroup/util/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2019 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.
+//
+
+package {
+ default_team: "trendy_team_android_kernel",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_headers {
+ name: "libprocessgroup_util",
+ vendor_available: true,
+ product_available: true,
+ ramdisk_available: true,
+ vendor_ramdisk_available: true,
+ recovery_available: true,
+ host_supported: true,
+ native_bridge_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ min_sdk_version: "30",
+ export_include_dirs: [
+ "include",
+ ],
+ defaults: ["libprocessgroup_build_flags_cc"],
+}
+
+cc_test {
+ name: "libprocessgroup_util_test",
+ header_libs: ["libprocessgroup_util"],
+ srcs: ["tests/util.cpp"],
+ test_suites: ["general-tests"],
+}
diff --git a/libprocessgroup/util/OWNERS b/libprocessgroup/util/OWNERS
new file mode 100644
index 0000000..54ea400
--- /dev/null
+++ b/libprocessgroup/util/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1293033
+surenb@google.com
+tjmercier@google.com
diff --git a/libprocessgroup/util/TEST_MAPPING b/libprocessgroup/util/TEST_MAPPING
new file mode 100644
index 0000000..6ae2658
--- /dev/null
+++ b/libprocessgroup/util/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "libprocessgroup_util_test"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h
new file mode 100644
index 0000000..5240744
--- /dev/null
+++ b/libprocessgroup/util/include/processgroup/util.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+
+namespace util {
+
+namespace internal {
+
+const char SEP = '/';
+
+std::string DeduplicateAndTrimSeparators(const std::string& path) {
+ bool lastWasSep = false;
+ std::string ret;
+
+ std::copy_if(path.begin(), path.end(), std::back_inserter(ret), [&lastWasSep](char c) {
+ if (lastWasSep) {
+ if (c == SEP) return false;
+ lastWasSep = false;
+ } else if (c == SEP) {
+ lastWasSep = true;
+ }
+ return true;
+ });
+
+ if (ret.length() > 1 && ret.back() == SEP) ret.pop_back();
+
+ return ret;
+}
+
+} // namespace internal
+
+unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path) {
+ const std::string deduped_root = internal::DeduplicateAndTrimSeparators(controller_root);
+ const std::string deduped_path = internal::DeduplicateAndTrimSeparators(cgroup_path);
+
+ if (deduped_root.empty() || deduped_path.empty() || !deduped_path.starts_with(deduped_root))
+ return 0;
+
+ return std::count(deduped_path.begin() + deduped_root.size(), deduped_path.end(),
+ internal::SEP);
+}
+
+} // namespace util
diff --git a/libprocessgroup/util/tests/util.cpp b/libprocessgroup/util/tests/util.cpp
new file mode 100644
index 0000000..1de7d6f
--- /dev/null
+++ b/libprocessgroup/util/tests/util.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include <processgroup/util.h>
+
+#include "gtest/gtest.h"
+
+using util::GetCgroupDepth;
+
+TEST(EmptyInputs, bothEmpty) {
+ EXPECT_EQ(GetCgroupDepth({}, {}), 0);
+}
+
+TEST(EmptyInputs, rootEmpty) {
+ EXPECT_EQ(GetCgroupDepth({}, "foo"), 0);
+}
+
+TEST(EmptyInputs, pathEmpty) {
+ EXPECT_EQ(GetCgroupDepth("foo", {}), 0);
+}
+
+TEST(InvalidInputs, pathNotInRoot) {
+ EXPECT_EQ(GetCgroupDepth("foo", "bar"), 0);
+}
+
+TEST(InvalidInputs, rootLargerThanPath) {
+ EXPECT_EQ(GetCgroupDepth("/a/long/path", "/short"), 0);
+}
+
+TEST(InvalidInputs, pathLargerThanRoot) {
+ EXPECT_EQ(GetCgroupDepth("/short", "/a/long/path"), 0);
+}
+
+TEST(InvalidInputs, missingSeparator) {
+ EXPECT_EQ(GetCgroupDepth("/controller/root", "/controller/rootcgroup"), 0);
+}
+
+TEST(ExtraSeparators, root) {
+ EXPECT_EQ(GetCgroupDepth("///sys/fs/cgroup", "/sys/fs/cgroup/a/b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys///fs/cgroup", "/sys/fs/cgroup/a/b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs///cgroup", "/sys/fs/cgroup/a/b/c"), 3);
+
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "///sys/fs/cgroup/a/b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys///fs/cgroup/a/b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs///cgroup/a/b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup///a/b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/a///b/c"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/a/b///c"), 3);
+}
+
+TEST(SeparatorEndings, rootEndsInSeparator) {
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup/", "/sys/fs/cgroup/a/b"), 2);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup///", "/sys/fs/cgroup/a/b"), 2);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup/", "/sys/fs/cgroup/a/b/"), 2);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup///", "/sys/fs/cgroup/a/b/"), 2);
+}
+
+TEST(SeparatorEndings, pathEndsInSeparator) {
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/a/b/"), 2);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/a/b///"), 2);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup/", "/sys/fs/cgroup/a/b/"), 2);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup/", "/sys/fs/cgroup/a/b///"), 2);
+}
+
+TEST(ValidInputs, rootHasZeroDepth) {
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup"), 0);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup/", "/sys/fs/cgroup"), 0);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/"), 0);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup/", "/sys/fs/cgroup/"), 0);
+}
+
+TEST(ValidInputs, atLeastDepth10) {
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/a/b/c/d/e/f/g/h/i/j"), 10);
+}
+
+TEST(ValidInputs, androidCgroupNames) {
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/system/uid_0/pid_1000"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/uid_0/pid_1000"), 2);
+
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/apps/uid_100000/pid_1000"), 3);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/uid_100000/pid_1000"), 2);
+
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/apps"), 1);
+ EXPECT_EQ(GetCgroupDepth("/sys/fs/cgroup", "/sys/fs/cgroup/system"), 1);
+}
+
+TEST(ValidInputs, androidCgroupNames_nonDefaultRoot) {
+ EXPECT_EQ(GetCgroupDepth("/custom/root", "/custom/root/system/uid_0/pid_1000"), 3);
+ EXPECT_EQ(GetCgroupDepth("/custom/root", "/custom/root/uid_0/pid_1000"), 2);
+
+ EXPECT_EQ(GetCgroupDepth("/custom/root", "/custom/root/apps/uid_100000/pid_1000"), 3);
+ EXPECT_EQ(GetCgroupDepth("/custom/root", "/custom/root/uid_100000/pid_1000"), 2);
+
+ EXPECT_EQ(GetCgroupDepth("/custom/root", "/custom/root/apps"), 1);
+ EXPECT_EQ(GetCgroupDepth("/custom/root", "/custom/root/system"), 1);
+}
diff --git a/libutils/CallStack_test.cpp b/libutils/CallStack_test.cpp
index 7afc2c3..bfe6b87 100644
--- a/libutils/CallStack_test.cpp
+++ b/libutils/CallStack_test.cpp
@@ -72,7 +72,8 @@
TEST(CallStackTest, log_stack) {
android::CallStack::logStack("callstack_test");
auto logger_list = android_logger_list_open(android_name_to_log_id("main"),
- ANDROID_LOG_NONBLOCK, 1000, getpid());
+ ANDROID_LOG_NONBLOCK,
+ 10000 /* tail */, getpid());
ASSERT_NE(nullptr, logger_list);
std::string log;
while (true) {