cgroup_map.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Copyright (C) 2019 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. //#define LOG_NDEBUG 0
  17. #define LOG_TAG "libprocessgroup"
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <grp.h>
  21. #include <pwd.h>
  22. #include <sys/mman.h>
  23. #include <sys/mount.h>
  24. #include <sys/stat.h>
  25. #include <sys/types.h>
  26. #include <time.h>
  27. #include <unistd.h>
  28. #include <regex>
  29. #include <android-base/file.h>
  30. #include <android-base/logging.h>
  31. #include <android-base/properties.h>
  32. #include <android-base/stringprintf.h>
  33. #include <android-base/unique_fd.h>
  34. #include <cgroup_map.h>
  35. #include <json/reader.h>
  36. #include <json/value.h>
  37. #include <processgroup/processgroup.h>
  38. using android::base::GetBoolProperty;
  39. using android::base::StringPrintf;
  40. using android::base::unique_fd;
  41. static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
  42. static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
  43. static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.tasks";
  44. uint32_t CgroupController::version() const {
  45. CHECK(HasValue());
  46. return ACgroupController_getVersion(controller_);
  47. }
  48. const char* CgroupController::name() const {
  49. CHECK(HasValue());
  50. return ACgroupController_getName(controller_);
  51. }
  52. const char* CgroupController::path() const {
  53. CHECK(HasValue());
  54. return ACgroupController_getPath(controller_);
  55. }
  56. bool CgroupController::HasValue() const {
  57. return controller_ != nullptr;
  58. }
  59. bool CgroupController::IsUsable() {
  60. if (!HasValue()) return false;
  61. if (state_ == UNKNOWN) {
  62. state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING;
  63. }
  64. return state_ == USABLE;
  65. }
  66. std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const {
  67. std::string tasks_path = path();
  68. if (!rel_path.empty()) {
  69. tasks_path += "/" + rel_path;
  70. }
  71. return (version() == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2;
  72. }
  73. std::string CgroupController::GetProcsFilePath(const std::string& rel_path, uid_t uid,
  74. pid_t pid) const {
  75. std::string proc_path(path());
  76. proc_path.append("/").append(rel_path);
  77. proc_path = regex_replace(proc_path, std::regex("<uid>"), std::to_string(uid));
  78. proc_path = regex_replace(proc_path, std::regex("<pid>"), std::to_string(pid));
  79. return proc_path.append(CGROUP_PROCS_FILE);
  80. }
  81. bool CgroupController::GetTaskGroup(int tid, std::string* group) const {
  82. std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
  83. std::string content;
  84. if (!android::base::ReadFileToString(file_name, &content)) {
  85. PLOG(ERROR) << "Failed to read " << file_name;
  86. return false;
  87. }
  88. // if group is null and tid exists return early because
  89. // user is not interested in cgroup membership
  90. if (group == nullptr) {
  91. return true;
  92. }
  93. std::string cg_tag = StringPrintf(":%s:", name());
  94. size_t start_pos = content.find(cg_tag);
  95. if (start_pos == std::string::npos) {
  96. return false;
  97. }
  98. start_pos += cg_tag.length() + 1; // skip '/'
  99. size_t end_pos = content.find('\n', start_pos);
  100. if (end_pos == std::string::npos) {
  101. *group = content.substr(start_pos, std::string::npos);
  102. } else {
  103. *group = content.substr(start_pos, end_pos - start_pos);
  104. }
  105. return true;
  106. }
  107. CgroupMap::CgroupMap() {
  108. if (!LoadRcFile()) {
  109. LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
  110. }
  111. }
  112. CgroupMap& CgroupMap::GetInstance() {
  113. // Deliberately leak this object to avoid a race between destruction on
  114. // process exit and concurrent access from another thread.
  115. static auto* instance = new CgroupMap;
  116. return *instance;
  117. }
  118. bool CgroupMap::LoadRcFile() {
  119. if (!loaded_) {
  120. loaded_ = (ACgroupFile_getVersion() != 0);
  121. }
  122. return loaded_;
  123. }
  124. void CgroupMap::Print() const {
  125. if (!loaded_) {
  126. LOG(ERROR) << "CgroupMap::Print called for [" << getpid()
  127. << "] failed, RC file was not initialized properly";
  128. return;
  129. }
  130. LOG(INFO) << "File version = " << ACgroupFile_getVersion();
  131. LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount();
  132. LOG(INFO) << "Mounted cgroups:";
  133. auto controller_count = ACgroupFile_getControllerCount();
  134. for (uint32_t i = 0; i < controller_count; ++i) {
  135. const ACgroupController* controller = ACgroupFile_getController(i);
  136. LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver "
  137. << ACgroupController_getVersion(controller) << " path "
  138. << ACgroupController_getPath(controller);
  139. }
  140. }
  141. CgroupController CgroupMap::FindController(const std::string& name) const {
  142. if (!loaded_) {
  143. LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
  144. << "] failed, RC file was not initialized properly";
  145. return CgroupController(nullptr);
  146. }
  147. auto controller_count = ACgroupFile_getControllerCount();
  148. for (uint32_t i = 0; i < controller_count; ++i) {
  149. const ACgroupController* controller = ACgroupFile_getController(i);
  150. if (name == ACgroupController_getName(controller)) {
  151. return CgroupController(controller);
  152. }
  153. }
  154. return CgroupController(nullptr);
  155. }