From 098323ba5bf4f5e585337369146fd52f032baeec Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Mon, 4 Mar 2019 18:20:02 -0800 Subject: [PATCH] libprocessgroup: Add libcgrouprc This module is an LL-NDK library that can be loaded by modules that link to libprocessgroup (which is in VNDK). This module defines APIs that reads cgroups.rc file programatically. Internally, it uses libcgrouprc_format to do so. Test: builds Bug: 123664216 Change-Id: I9c13c0528461758154e23cbab3a94ade7fb351ee Merged-In: I9c13c0528461758154e23cbab3a94ade7fb351ee --- libprocessgroup/cgrouprc/Android.bp | 52 +++++++++ .../cgrouprc/cgroup_controller.cpp | 38 +++++++ libprocessgroup/cgrouprc/cgroup_file.cpp | 106 ++++++++++++++++++ libprocessgroup/cgrouprc/cgrouprc_internal.h | 24 ++++ .../cgrouprc/include/android/cgrouprc.h | 84 ++++++++++++++ libprocessgroup/cgrouprc/libcgrouprc.map.txt | 11 ++ 6 files changed, 315 insertions(+) create mode 100644 libprocessgroup/cgrouprc/Android.bp create mode 100644 libprocessgroup/cgrouprc/cgroup_controller.cpp create mode 100644 libprocessgroup/cgrouprc/cgroup_file.cpp create mode 100644 libprocessgroup/cgrouprc/cgrouprc_internal.h create mode 100644 libprocessgroup/cgrouprc/include/android/cgrouprc.h create mode 100644 libprocessgroup/cgrouprc/libcgrouprc.map.txt diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp new file mode 100644 index 000000000..f5ff7eb9d --- /dev/null +++ b/libprocessgroup/cgrouprc/Android.bp @@ -0,0 +1,52 @@ +// 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. + +cc_library_shared { + name: "libcgrouprc", + host_supported: true, + recovery_available: true, + srcs: [ + "cgroup_controller.cpp", + "cgroup_file.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + export_include_dirs: [ + "include", + ], + header_libs: [ + "libprocessgroup_headers", + ], + shared_libs: [ + "libbase", + ], + static_libs: [ + "libcgrouprc_format", + ], + stubs: { + symbol_file: "libcgrouprc.map.txt", + versions: ["29"], + }, + version_script: "libcgrouprc.map.txt", +} + +llndk_library { + name: "libcgrouprc", + symbol_file: "libcgrouprc.map.txt", + export_include_dirs: [ + "include", + ], +} diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/cgroup_controller.cpp new file mode 100644 index 000000000..d064d312e --- /dev/null +++ b/libprocessgroup/cgrouprc/cgroup_controller.cpp @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include +#include + +#include "cgrouprc_internal.h" + +// All ACgroupController_* functions implicitly convert the pointer back +// to the original CgroupController pointer before invoking the member functions. + +uint32_t ACgroupController_getVersion(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->version(); +} + +const char* ACgroupController_getName(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->name(); +} + +const char* ACgroupController_getPath(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->path(); +} diff --git a/libprocessgroup/cgrouprc/cgroup_file.cpp b/libprocessgroup/cgrouprc/cgroup_file.cpp new file mode 100644 index 000000000..e26d84114 --- /dev/null +++ b/libprocessgroup/cgrouprc/cgroup_file.cpp @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "cgrouprc_internal.h" + +using android::base::StringPrintf; +using android::base::unique_fd; + +using android::cgrouprc::format::CgroupController; +using android::cgrouprc::format::CgroupFile; + +static CgroupFile* LoadRcFile() { + struct stat sb; + + unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; + return nullptr; + } + + if (fstat(fd, &sb) < 0) { + PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH; + return nullptr; + } + + size_t file_size = sb.st_size; + if (file_size < sizeof(CgroupFile)) { + LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH; + return nullptr; + } + + CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); + if (file_data == MAP_FAILED) { + PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH; + return nullptr; + } + + if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) { + LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch"; + munmap(file_data, file_size); + return nullptr; + } + + auto expected = sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController); + if (file_size != expected) { + LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size, expected " << expected + << ", actual " << file_size; + munmap(file_data, file_size); + return nullptr; + } + + return file_data; +} + +static CgroupFile* GetInstance() { + // Deliberately leak this object (not munmap) to avoid a race between destruction on + // process exit and concurrent access from another thread. + static auto* file = LoadRcFile(); + return file; +} + +uint32_t ACgroupFile_getVersion() { + auto file = GetInstance(); + if (file == nullptr) return 0; + return file->version_; +} + +uint32_t ACgroupFile_getControllerCount() { + auto file = GetInstance(); + if (file == nullptr) return 0; + return file->controller_count_; +} + +const ACgroupController* ACgroupFile_getController(uint32_t index) { + auto file = GetInstance(); + if (file == nullptr) return nullptr; + CHECK(index < file->controller_count_); + // Although the object is not actually an ACgroupController object, all ACgroupController_* + // functions implicitly convert ACgroupController* back to CgroupController* before invoking + // member functions. + return static_cast(&file->controllers_[index]); +} diff --git a/libprocessgroup/cgrouprc/cgrouprc_internal.h b/libprocessgroup/cgrouprc/cgrouprc_internal.h new file mode 100644 index 000000000..cd02f0304 --- /dev/null +++ b/libprocessgroup/cgrouprc/cgrouprc_internal.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include + +struct ACgroupController : android::cgrouprc::format::CgroupController {}; diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h new file mode 100644 index 000000000..4edd239e2 --- /dev/null +++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#pragma once + +#include + +__BEGIN_DECLS + +// For host builds, __INTRODUCED_IN is not defined. +#ifndef __INTRODUCED_IN +#define __INTRODUCED_IN(x) +#endif + +struct ACgroupController; +typedef struct ACgroupController ACgroupController; + +#if __ANDROID_API__ >= __ANDROID_API_Q__ + +// ACgroupFile + +/** + * Returns file version. See android::cgrouprc::format::CgroupFile for a list of valid versions + * for the file. + * If ACgroupFile_init() isn't called, initialization will be done first. + * If initialization failed, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupFile_getVersion() __INTRODUCED_IN(29); + +/** + * Returns the number of controllers. + * If ACgroupFile_init() isn't called, initialization will be done first. + * If initialization failed, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupFile_getControllerCount() __INTRODUCED_IN(29); + +/** + * Returns the controller at the given index. + * Returnss nullptr if the given index exceeds getControllerCount(). + * If ACgroupFile_init() isn't called, initialization will be done first. + * If initialization failed, return 0. + */ +__attribute__((warn_unused_result)) const ACgroupController* ACgroupFile_getController( + uint32_t index) __INTRODUCED_IN(29); + +// ACgroupController + +/** + * Returns the version of the given controller. + * If the given controller is null, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const ACgroupController*) + __INTRODUCED_IN(29); + +/** + * Returns the name of the given controller. + * If the given controller is null, return nullptr. + */ +__attribute__((warn_unused_result)) const char* ACgroupController_getName(const ACgroupController*) + __INTRODUCED_IN(29); + +/** + * Returns the path of the given controller. + * If the given controller is null, return nullptr. + */ +__attribute__((warn_unused_result)) const char* ACgroupController_getPath(const ACgroupController*) + __INTRODUCED_IN(29); + +__END_DECLS + +#endif diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt new file mode 100644 index 000000000..91df3929d --- /dev/null +++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt @@ -0,0 +1,11 @@ +LIBCGROUPRC { # introduced=29 + global: + ACgroupFile_getVersion; + ACgroupFile_getControllerCount; + ACgroupFile_getController; + ACgroupController_getVersion; + ACgroupController_getName; + ACgroupController_getPath; + local: + *; +};