cgroup 추상화 계층

Android 10 및 이후 버전은 작업 프로필과 함께 통제 그룹(cgroup) 추상화 레이어를 사용합니다. 개발자는 이를 사용하여 스레드나 프로세스에 적용하는 제한사항 세트를 한 개 이상 설명할 수 있습니다. 그러면 시스템은 작업 프로필에 미리 설정된 작업에 따라 하나 이상의 적절한 cgroup을 선택하고 이러한 cgroup을 통해 제한사항이 적용됩니다. 기본 cgroup 특성 세트의 변경사항은 상위 소프트웨어 레이어에 영향을 미치지 않고 적용될 수 있습니다.

cgroup 정보

cgroup은 작업 세트(프로세스, 스레드 및 앞으로 생성될 모든 하위 요소로 구성)를 집계하고 특정 동작을 하는 계층 구조 그룹으로 분할하기 위한 메커니즘을 제공합니다. Android는 cgroup을 사용하여 시스템 리소스(예: CPU와 메모리 사용 및 할당)를 제어하고 처리하며 Linux 커널 cgroups v1cgroups v2를 지원합니다.

Android 9 이하

Android 9 이하에서는 init.rc 초기화 스크립트에 사용할 수 있는 cgroup 세트와 마운트 지점 및 버전이 포함되었습니다. 그러나 이러한 항목은 변경될 수 있으며 Android 프레임워크는 스크립트를 기반으로 지정된 위치에 지정된 버전과 하위 그룹 계층 구조를 사용하는 특정 cgroup 세트가 있을 것으로 예상했습니다. 이로 인해 사용할 다음 cgroup 버전을 선택하거나 새 기능을 사용할 cgroup 계층 구조를 변경하는 기능이 제한되었습니다.

Android 10 이상

Android 10 이상은 작업 프로필과 함께 cgroup을 사용합니다.

  • cgroup 설정: 개발자는 cgroups.json 파일에 cgroup 설정을 설명하여 cgroup 세트와 마운트 위치 및 속성을 정의합니다. 모든 cgroup은 초기화 프로세스의 early-init 단계에서 마운트됩니다.
  • 작업 프로필: 세부 구현에서 필수 기능을 분리하는 추상화를 제공합니다. Android 프레임워크는 작업 프로필을 task_profiles.json 파일에 설명된 대로 SetTaskProfilesSetProcessProfiles API를 사용하여 프로세스 또는 스레드에 적용합니다. (이러한 API는 Android 11 이상에서만 지원됩니다.)

이전 버전과의 호환성을 제공하기 위해 기존 함수 set_cpuset_policy, set_sched_policyget_sched_policy는 동일한 API 및 기능을 제공하지만, 함수 구현은 작업 프로필을 사용하도록 수정되었습니다. 새로운 사용 사례의 경우 AOSP는 기존 set_sched_policy 함수 대신 새 작업 프로필 API를 사용할 것을 권장합니다.

cgroup 설명 파일

cgroup은 <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ 아래에 있는 cgroups.json 파일에 설명되어 있습니다. 각 컨트롤러는 하위 섹션에 설명하며 최소 다음 내용을 포함해야 합니다.

  • 이름, Controller 필드에 정의됨
  • 마운트 경로, Path 필드에 정의됨
  • Mode, UID(사용자 ID), GID(그룹 ID), 이 경로 아래에 있는 파일의 소유자와 액세스 모드를 설명함(모두 선택사항임)
  • Optional 속성, 커널이 마운트를 지원하지 않는 cgroup 컨트롤러로 인해 발생하는 마운트 오류를 시스템이 무시하도록 true로 설정됨

cgroups.json 파일 예

아래 예는 각각의 경로를 갖는 cgroup v1(Cgroups)과 cgroup v2(Cgroups2)에 관한 설명을 보여줍니다.

{
  "Cgroups": [
    {
      "Controller": "cpu",
      "Path": "/dev/cpuctl",
      "Mode": "0755",
      "UID": "system",
      "GID": "system"
    },
    {
      "Controller": "memory",
      "Path": "/dev/memcg",
      "Mode": "0700",
      "Optional": true
    }
  ],
 "Cgroups2": {
   "Path": "/sys/fs/cgroup",
   "Mode": "0755",
   "UID": "system",
   "GID": "system",
   "Controllers": [
     {
       "Controller": "freezer",
       "Path": ".",
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
     }
   ]
 }
}

이 예시 파일에는 두 개의 섹션, Cgroups(cgroup v1 컨트롤러 설명)와 Cgroups2(cgroup v2 컨트롤러 설명)가 포함되어 있습니다. Cgroups v2 계층 구조의 모든 컨트롤러는 동일한 위치에 마운트됩니다. 따라서 Cgroups2 섹션에는 계층 구조에서 루트의 위치와 속성을 설명하는 자체 Path, Mode, UID, GID 속성이 있습니다. Cgroups2 아래에 있는 ControllersPath 속성은 루트 경로를 기준으로 합니다. Android 12 이상에서는 cgroup 컨트롤러를 true로 설정하여 경로 및 모드가 "Optional"로 지정된 cgroup 컨트롤러를 정의할 수 있습니다.

cgroups.json 파일은 early-init 단계 중 init 프로세스의 일부로 파싱되며, cgroup은 지정된 위치에 마운트됩니다. 나중에 cgroup 마운트 위치를 가져오려면 CgroupGetControllerPath API 함수를 사용합니다.

작업 프로필 파일

task_profiles.json 파일은 <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/에 있습니다. 이 파일을 사용하여 프로세스 또는 스레드에 적용할 특정 작업 세트를 설명합니다. 작업 세트는 프로필 이름과 연결되어 있으며, 이 이름은 프로필 작업을 호출하기 위해 SetTaskProfilesSetProcessProfiles 호출에서 사용합니다.

task_profiles.json 파일 예

{
  "Attributes": [
    {
      "Name": "MemSoftLimit",
      "Controller": "memory",
      "File": "memory.soft_limit_in_bytes"
    },
    {
      "Name": "MemSwappiness",
      "Controller": "memory",
      "File": "memory.swappiness"
    }
  ],
  "Profiles": [
    {
      "Name": "MaxPerformance",
      "Actions" : [
        {
          "Name" : "JoinCgroup",
          "Params" :
          {
            "Controller": "schedtune",
            "Path": "top-app"
          }
        }
      ]
    },
    {
      "Name": "TimerSlackHigh",
      "Actions" : [
        {
          "Name" : "SetTimerSlack",
          "Params" :
          {
            "Slack": "40000000"
          }
        }
      ]
    },
    {
      "Name": "LowMemoryUsage",
      "Actions" : [
        {
          "Name" : "SetAttribute",
          "Params" :
          {
            "Name" : "MemSoftLimit",
            "Value" : "16MB"
          }
        },
        {
          "Name" : "SetAttribute",
          "Params" :
          {
            "Name" : "MemSwappiness",
            "Value" : "150"

          }
        }
      ]
    }
  ]
  "AggregateProfiles": [
     {
       "Name": "SCHED_SP_DEFAULT",
       "Profiles": [ "TimerSlackHigh", "MaxPerformance" ]
     },
     {
       "Name": "SCHED_SP_BACKGROUND",
       "Profiles": [ "LowMemoryUsage" ]
     }
}

Attributes 목록의 항목으로 특정 cgroup 파일의 이름을 할당합니다. 각 항목에는 다음이 포함됩니다.

  • Name 필드: 속성의 이름을 지정합니다.
  • Controller 필드: cgroups.json 파일에서 이름을 기준으로 cgroup 컨트롤러를 참조합니다.
  • File 필드: 이 컨트롤러 아래에 있는 특정 파일의 이름을 지정합니다.

Attributes는 작업 프로필 정의의 참조입니다. 작업 프로필 외부에서는 프레임워크가 이러한 파일에 직접 액세스해야 하고 액세스가 작업 프로필을 사용하여 추상화될 수 없는 경우에만 이러한 속성을 사용합니다. 다른 모든 경우에는 작업 프로필을 사용하세요. 작업 프로필을 사용하면 필수 동작과 세부 구현을 더 잘 분리할 수 있습니다.

Profiles 섹션에는 다음 항목을 갖는 작업 프로필 정의가 포함됩니다.

  • Name 필드: 프로필 이름을 정의합니다.
  • Actions 섹션에는 프로필이 적용될 때 실행되는 작업 세트가 나열되어 있습니다. 각 작업에는 다음이 포함됩니다.

    • 작업을 지정하는 Name 필드
    • 작업의 매개변수 세트를 지정하는 Params 섹션

지원되는 작업은 아래 표에 나와 있습니다.

작업 매개변수 설명
SetTimerSlack Slack 타이머 슬랙(단위: ns)
SetAttribute Name Attributes 섹션의 속성을 참조하는 이름
Value 파일에 쓸 값으로, 이름이 지정된 속성으로 표현됨
WriteFileFilePath파일의 경로
Value파일에 쓸 값
JoinCgroup Controller cgroups.json의 cgroup 컨트롤러 이름
Path cgroup 컨트롤러 계층 구조의 하위 그룹 경로

Android 12 이상에는 집계 프로필을 포함하는 AggregateProfiles 섹션이 있습니다. 각 프로필은 하나 이상의 프로필 집합의 별칭입니다. 집계 프로필 정의는 다음으로 구성됩니다.

  • Name 필드 - 집계 프로필의 이름을 지정합니다.
  • Profiles 필드 - 집계 프로필에 포함된 프로필의 이름을 나열합니다.

집계 프로필이 적용되면 포함된 모든 프로필도 자동으로 적용됩니다. 재귀 프로필(자신을 포함하는 프로필)이 없는 한 집계 프로필은 개별 프로필과 다른 집계 프로필을 모두 포함할 수 있습니다.

task_profile init 언어 명령어

Android 12 이상에서는 특정 프로세스의 작업 프로필 활성화를 위해 Android Init 언어task_profiles 명령어를 사용할 수 있습니다. 이 명령어는 cgroup 간의 프로세스를 마이그레이션하는 데 사용되었던 writepid 명령어(Android 12에서 지원 중단됨)를 대체합니다. task_profiles 명령어는 상위 레이어에 영향을 주지 않으면서 기본 구현을 변경할 수 있는 유연성을 제공합니다. 아래 예에서는 이 두 명령어가 동일한 연산을 실행하는 것을 볼 수 있습니다.

  • writepid /dev/cpuctl/top-app/tasks

    Android 12에서 지원 중단됨 - 현재 작업의 PID를 /dev/cpuctl/top-app/tasks 파일에 쓰는 데 사용되었음.

  • task_profiles MaxPerformance

    현재 프로세스를 'cpu' 컨트롤러(cpuctl) 아래의 최상위 앱 그룹에 조인합니다. 결과적으로 프로세스의 PID가 dev/cpuctl/top-app/tasks에 쓰여집니다.

Android 12 이상에서는 항상 task_profiles 명령어를 사용하여 cgroup 계층 구조의 작업을 마이그레이션하세요. task_profiles 명령어는 task_profiles.json 파일에 지정된, 프로필의 이름을 나타내는 하나 이상의 매개변수를 받습니다.

API 수준별 작업 프로필

Android 12 이상에서는 Android API 수준을 기반으로 변경사항을 적용하거나 공급업체 파티션에서 변경사항을 만들어서 기본 cgroups.jsontask_profiles.json 파일의 정의를 수정 또는 재정의할 수 있습니다.

API 수준을 기반으로 정의를 재정의하려면 기기에 다음 파일이 있어야 합니다.

  • pro/system/etc/task_profiles/cgroups_<API level>.json

    API 수준에 적용되는 cgroup에 사용합니다.

  • /system/etc/task_profiles/task_profiles_<API level>.json

    API 수준에 적용되는 프로필에 사용합니다.

공급업체 파티션에서 정의를 재정의하려면 기기에 다음 파일이 있어야 합니다.

  • /vendor/etc/cgroups.json
  • /vendor/etc/task_profiles.json

이러한 파일의 속성 또는 프로필 정의가 기본 파일의 이름과 동일한 이름을 사용하는 경우 파일(API 수준 또는 벤더 수준) 정의가 이전 정의를 재정의합니다. 공급업체 수준 정의는 API 수준 정의를 재정의합니다. 새 정의에 새 이름이 지정된 경우, 속성 또는 프로필 집합이 새 정의로 수정됩니다.

Android 시스템은 다음과 같은 순서로 cgrouptask_profile 파일을 로드합니다.

  1. 기본 cgroups.jsontask_profiles.json 파일.
  2. API 수준 파일(있는 경우).
  3. 공급업체 파티션 파일(있는 경우).

기존 API의 변경사항

Android 10 이상에서는 API 변경 없이 set_cpuset_policy, set_sched_policy, get_sched_policy 함수를 유지합니다. 하지만, 이제 Android 10은 모든 cgroup 관련 기능을 포함하는 libprocessgroup으로 이러한 함수를 이동합니다.

cutils/sched_policy.h 헤더는 여전히 존재하지만, 기존 코드가 손상되는 것을 막기 위해 새로운 코드가 새 processgroup/sched_policy.h 헤더를 포함하도록 합니다.

이러한 함수를 사용하는 모듈은 libprocessgroup 라이브러리의 종속 항목을 Makefile에 추가해야 합니다. 모듈이 다른 libcutils 기능을 사용하지 않으면 Makefile에서 libcutils 라이브러리 종속 항목을 삭제합니다.

작업 프로필 API

아래 표에 processgroup/processgroup.h의 비공개 API가 정의되어 있습니다.

유형 API 및 정의
bool SetTaskProfiles(int tid, const std::vector& profiles)

profiles에 지정된 작업 프로필을 tid 매개변수를 사용하여 스레드 ID(tid)로 지정한 스레드에 적용합니다.

bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)

profiles에 지정된 작업 프로필을 uidpid 매개변수를 사용하여 사용자 및 프로세스 ID로 지정한 프로세스에 적용합니다.

bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)

cgroup_name으로 지정된 cgroup 컨트롤러의 존재 여부를 반환합니다. true인 경우, path 변수를 cgroup의 루트로 설정합니다.

bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)

attr_name으로 지정된 프로필 속성의 존재 여부를 반환합니다. true인 경우, path 변수를 이 프로필 속성에 연결된 파일의 경로로 설정합니다.

bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)

attr_name으로 지정된 프로필 속성의 존재 여부를 반환합니다. true인 경우, path 변수를 이 프로필 속성에 연결된 파일 경로와 tid 매개변수를 사용하여 스레드 ID로 지정한 스레드로 설정합니다.

bool UsePerAppMemcg()

애플리케이션별 메모리 cgroup을 사용하도록 시스템이 구성되었는지 여부를 반환합니다.