Merge "libprocessgroup: Add MaxActivationDepth" into main
This commit is contained in:
commit
3d54c32e33
16 changed files with 290 additions and 13 deletions
|
|
@ -84,6 +84,7 @@ cc_library {
|
|||
header_libs: [
|
||||
"libcutils_headers",
|
||||
"libprocessgroup_headers",
|
||||
"libprocessgroup_util",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
export_header_lib_headers: [
|
||||
|
|
|
|||
|
|
@ -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 @@ int CgroupMap::ActivateControllers(const std::string& path) const {
|
|||
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")) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ uint32_t ACgroupController_getFlags(const ACgroupController* controller) {
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -78,6 +78,14 @@ __attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const
|
|||
__attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getFlags(
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -16,3 +16,10 @@ LIBCGROUPRC_30 { # introduced=30
|
|||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
LIBCGROUPRC_36 { # introduced=36
|
||||
global:
|
||||
ACgroupController_getMaxActivationDepth; # llndk=202504 systemapi
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,13 +21,11 @@ namespace cgrouprc {
|
|||
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 @@ uint32_t CgroupController::flags() const {
|
|||
return flags_;
|
||||
}
|
||||
|
||||
uint32_t CgroupController::max_activation_depth() const {
|
||||
return max_activation_depth_;
|
||||
}
|
||||
|
||||
const char* CgroupController::name() const {
|
||||
return name_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@ struct CgroupController {
|
|||
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 @@ struct CgroupController {
|
|||
|
||||
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] = {};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ message Cgroups {
|
|||
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 @@ message Cgroup {
|
|||
// 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
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ cc_library_shared {
|
|||
],
|
||||
header_libs: [
|
||||
"libprocessgroup_headers",
|
||||
"libprocessgroup_util",
|
||||
],
|
||||
export_header_lib_headers: [
|
||||
"libprocessgroup_headers",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ namespace cgrouprc {
|
|||
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_; }
|
||||
|
|
|
|||
|
|
@ -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 @@ static void MergeCgroupToDescriptors(std::map<std::string, CgroupDescriptor>* de
|
|||
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 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) {
|
|||
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 @@ static bool WriteRcFile(const std::map<std::string, CgroupDescriptor>& descripto
|
|||
|
||||
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 @@ static bool CreateV2SubHierarchy(
|
|||
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")) {
|
||||
|
|
|
|||
47
libprocessgroup/util/Android.bp
Normal file
47
libprocessgroup/util/Android.bp
Normal file
|
|
@ -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"],
|
||||
}
|
||||
3
libprocessgroup/util/OWNERS
Normal file
3
libprocessgroup/util/OWNERS
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Bug component: 1293033
|
||||
surenb@google.com
|
||||
tjmercier@google.com
|
||||
7
libprocessgroup/util/TEST_MAPPING
Normal file
7
libprocessgroup/util/TEST_MAPPING
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"postsubmit": [
|
||||
{
|
||||
"name": "libprocessgroup_util_test"
|
||||
}
|
||||
]
|
||||
}
|
||||
61
libprocessgroup/util/include/processgroup/util.h
Normal file
61
libprocessgroup/util/include/processgroup/util.h
Normal file
|
|
@ -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
|
||||
109
libprocessgroup/util/tests/util.cpp
Normal file
109
libprocessgroup/util/tests/util.cpp
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue