Lớp trừu tượng Cgroup

Android 10 trở lên sử dụng lớp trừu tượng nhóm điều khiển (cgroup) với hồ sơ tác vụ mà nhà phát triển có thể sử dụng để mô tả một bộ (hoặc nhiều bộ) hạn chế để áp dụng cho một luồng hoặc một quy trình. Sau đó, hệ thống sẽ tuân theo các hành động được quy định trong hồ sơ tác vụ để chọn một hoặc nhiều nhóm thích hợp, qua đó áp dụng các hạn chế và có thể thực hiện các thay đổi đối với bộ tính năng nhóm cơ bản mà không ảnh hưởng đến các lớp phần mềm cao hơn.

Giới thiệu về cgroups

Các nhóm cung cấp một cơ chế để tổng hợp và phân chia các nhóm nhiệm vụ (bao gồm các tiến trình, luồng và tất cả các phần tử con tương lai của chúng) thành các nhóm phân cấp với hành vi chuyên biệt. Android sử dụng cgroups để kiểm soát và tính toán các tài nguyên hệ thống như việc sử dụng và phân bổ CPU và bộ nhớ, với sự hỗ trợ cho cgroups nhân Linux v1cgroups v2 .

Android 9 trở xuống

Trong Android 9 trở xuống, tập lệnh khởi tạo init.rc chứa tập hợp các nhóm có sẵn, điểm gắn kết và phiên bản của chúng. Mặc dù những điều này có thể được thay đổi, nhưng khung công tác Android mong muốn một nhóm nhóm cụ thể tồn tại ở các vị trí cụ thể với phiên bản cụ thể và hệ thống phân cấp nhóm con, dựa trên tập lệnh. Điều này hạn chế khả năng chọn phiên bản cgroup tiếp theo để sử dụng hoặc thay đổi hệ thống phân cấp của nhóm để sử dụng các tính năng mới.

Android 10 trở lên

Android 10 trở lên sử dụng nhóm có hồ sơ tác vụ:

  • Thiết lập Cgroup - nhà phát triển mô tả thiết lập cgroups trong tệp cgroups.json của họ để xác định các nhóm cgroup cũng như vị trí và thuộc tính gắn kết của chúng. Tất cả các nhóm được gắn kết trong giai đoạn đầu của quá trình khởi tạo.
  • Hồ sơ nhiệm vụ - những hồ sơ này cung cấp một sự trừu tượng giúp tách biệt chức năng cần thiết khỏi các chi tiết triển khai nó. Khung Android áp dụng cấu hình tác vụ như được mô tả trong tệp task_profiles.json cho một quy trình hoặc luồng bằng cách sử dụng API SetTaskProfilesSetProcessProfiles . (Các API này chỉ dành riêng cho Android 11 trở lên.)

Để cung cấp khả năng tương thích ngược, các hàm cũ set_cpuset_policy , set_sched_policyget_sched_policy cung cấp cùng một API và chức năng nhưng việc triển khai chúng đã được sửa đổi để sử dụng hồ sơ tác vụ. Đối với các trường hợp sử dụng mới, AOSP khuyên bạn nên sử dụng API hồ sơ tác vụ mới thay vì hàm set_sched_policy cũ.

Tệp mô tả nhóm

Các nhóm được mô tả trong tệp cgroups.json nằm trong <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Mỗi bộ điều khiển được mô tả trong một tiểu mục và phải có tối thiểu những điều sau:

  • Tên, được xác định bởi trường Bộ điều khiển .
  • Đường dẫn gắn kết, được xác định bởi trường Đường dẫn .
  • Mode , UID (ID người dùng) và GID (ID nhóm) mô tả chủ sở hữu và chế độ truy cập cho các tệp trong đường dẫn này (tất cả đều tùy chọn).
  • Thuộc tính tùy chọn , được đặt thành true để cho phép hệ thống bỏ qua lỗi gắn kết do bộ điều khiển cgroup mà kernel không hỗ trợ gắn kết gây ra.

Ví dụ về tệp cgroups.json

Ví dụ bên dưới hiển thị mô tả cho bộ điều khiển cgroup v1 ( Cgroups ) và cgroup v2 ( Cgroups2 ) với các đường dẫn tương ứng của chúng.

{
  "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"
     }
   ]
 }
}

Tệp ví dụ này chứa hai phần, Cgroups (mô tả bộ điều khiển cgroup v1) và Cgroups2 (mô tả bộ điều khiển cgroup v2). Tất cả các bộ điều khiển trong hệ thống phân cấp cgroups v2 đều được gắn ở cùng một vị trí. Do đó, phần Cgroups2 có các thuộc tính Path , Mode , UIDGID riêng để mô tả vị trí và thuộc tính cho gốc của hệ thống phân cấp. Thuộc tính Đường dẫn cho Bộ điều khiển trong Cgroups2 có liên quan đến đường dẫn gốc đó. Trong Android 12 trở lên, bạn có thể xác định bộ điều khiển cgroup được chỉ định bằng đường dẫn và chế độ là "Optional" bằng cách đặt thành true .

Tệp cgroups.json được phân tích cú pháp như một phần của quy trình init, trong giai đoạn khởi tạo ban đầu và các nhóm được gắn kết tại các vị trí đã chỉ định. Để sau này có được vị trí gắn cgroup, hãy sử dụng hàm API CgroupGetControllerPath .

Tệp hồ sơ nhiệm vụ

Tệp task_profiles.json nằm trong <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Sử dụng nó để mô tả một tập hợp các hành động cụ thể được áp dụng cho một tiến trình hoặc một luồng. Một tập hợp các hành động được liên kết với tên hồ sơ, được sử dụng trong các lệnh gọi SetTaskProfilesSetProcessProfiles để gọi các hành động hồ sơ.

Ví dụ về tệp 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" ]
     }
}

Gán tên cho các tệp nhóm cụ thể làm mục nhập trong danh sách Thuộc tính của bạn. Mỗi mục có nội dung sau:

  • Trường tên - chỉ định tên của Thuộc tính.
  • Trường bộ điều khiển - tham chiếu bộ điều khiển cgroup từ tệp cgroups.json , theo tên của nó.
  • Trường tệp - đặt tên một tệp cụ thể trong bộ điều khiển này.

Các thuộc tính là các tham chiếu trong định nghĩa hồ sơ nhiệm vụ. Ngoài hồ sơ nhiệm vụ, chỉ sử dụng chúng khi khung yêu cầu quyền truy cập trực tiếp vào các tệp đó và không thể trừu tượng hóa quyền truy cập bằng hồ sơ nhiệm vụ. Trong tất cả các trường hợp khác, hãy sử dụng hồ sơ nhiệm vụ; chúng cung cấp khả năng tách rời tốt hơn giữa hành vi được yêu cầu và chi tiết triển khai của nó.

Phần Hồ sơ chứa các định nghĩa hồ sơ nhiệm vụ như sau:

  • Trường tên - xác định tên hồ sơ.
  • Phần hành động - liệt kê một tập hợp các hành động được thực hiện khi áp dụng cấu hình. Mỗi hành động có những điều sau đây:

    • Trường tên chỉ định hành động
    • Phần Params chỉ định một bộ tham số cho hành động

Các hành động được hỗ trợ được liệt kê trong bảng bên dưới.

Hoạt động Tham số Sự miêu tả
SetTimerSlack Slack Độ trễ của bộ đếm thời gian tính bằng ns
SetAttribute Name Tên tham chiếu một thuộc tính từ phần Thuộc tính
Value Một giá trị được ghi vào tệp được biểu thị bằng thuộc tính được đặt tên
WriteFile FilePath đường dẫn đến tập tin
Value một giá trị được ghi vào tập tin
JoinCgroup Controller Tên của bộ điều khiển cgroup từ cgroups.json
Path Đường dẫn nhóm phụ trong hệ thống phân cấp của bộ điều khiển cgroup

Android 12 trở lên có phần AggregateProfiles chứa hồ sơ tổng hợp, mỗi hồ sơ là bí danh cho một tập hợp gồm một hoặc nhiều hồ sơ. Các định nghĩa hồ sơ tổng hợp bao gồm:

  • Trường tên - chỉ định tên của hồ sơ tổng hợp.
  • Trường Hồ sơ - liệt kê tên của các hồ sơ có trong hồ sơ tổng hợp.

Khi một hồ sơ tổng hợp được áp dụng, tất cả các hồ sơ chứa trong đó cũng được tự động áp dụng. Cấu hình tổng hợp có thể chứa cả cấu hình riêng lẻ hoặc cấu hình tổng hợp khác, miễn là không có sự đệ quy (một cấu hình bao gồm chính nó).

lệnh ngôn ngữ khởi tạo task_profiles

Lệnh task_profiles trong Ngôn ngữ khởi tạo Android có sẵn cho Android 12 trở lên để tạo điều kiện kích hoạt hồ sơ tác vụ cho một quy trình cụ thể. Lệnh này thay thế lệnh writepid (không dùng nữa trong Android 12) dùng để di chuyển một tiến trình giữa các nhóm. Lệnh task_profiles mang lại sự linh hoạt trong việc thay đổi các triển khai cơ bản mà không ảnh hưởng đến các lớp trên. Trong ví dụ bên dưới, hai lệnh này thực hiện cùng một thao tác một cách hiệu quả:

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

    Không được dùng nữa trong Android 12 - Được dùng để ghi PID của tác vụ hiện tại vào tệp /dev/cpuctl/top-app/tasks .

  • task_profiles MaxPerformance

    Tham gia quy trình hiện tại vào nhóm ứng dụng hàng đầu trong bộ điều khiển "cpu" ( cpuctl ), dẫn đến việc ghi PID của quy trình vào dev/cpuctl/top-app/tasks .

Luôn sử dụng lệnh task_profiles để di chuyển các tác vụ theo hệ thống phân cấp cgroup trong Android 12 trở lên. Nó chấp nhận một hoặc nhiều tham số, đại diện cho tên của các cấu hình được chỉ định trong tệp task_profiles.json .

Mỗi hồ sơ tác vụ cấp API

Trong Android 12 trở lên, bạn có thể sửa đổi hoặc ghi đè các định nghĩa trong tệp cgroups.jsontask_profiles.json mặc định, dựa trên thay đổi của bạn ở cấp độ API Android hoặc thực hiện thay đổi đó từ phân vùng của nhà cung cấp.

Để ghi đè các định nghĩa dựa trên cấp độ API, các tệp sau phải có trên thiết bị:

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

    Sử dụng điều này cho các nhóm cụ thể ở cấp độ API.

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

    Sử dụng tùy chọn này cho các cấu hình cụ thể ở cấp độ API.

Để ghi đè các định nghĩa từ phân vùng của nhà cung cấp, các tệp sau phải có trên thiết bị:

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

Nếu một thuộc tính hoặc định nghĩa hồ sơ trong các tệp này sử dụng cùng tên như trong tệp mặc định thì định nghĩa tệp (cấp API hoặc cấp nhà cung cấp) sẽ ghi đè định nghĩa trước đó. Cũng lưu ý rằng các định nghĩa cấp nhà cung cấp sẽ ghi đè các định nghĩa cấp API. Nếu định nghĩa mới có tên mới thì tập thuộc tính hoặc hồ sơ sẽ được sửa đổi với định nghĩa mới.

Hệ thống Android tải các tệp cgrouptask_profile theo thứ tự sau:

  1. Các tệp cgroups.jsontask_profiles.json mặc định.
  2. Các tệp dành riêng cho cấp độ API, nếu có.
  3. Tệp phân vùng của nhà cung cấp, nếu có.

Những thay đổi đối với API hiện có

Android 10 trở lên giữ nguyên các hàm set_cpuset_policy , set_sched_policyget_sched_policy mà không thay đổi API. Tuy nhiên, Android 10 chuyển các chức năng này sang libprocessgroup , hiện chứa tất cả chức năng liên quan đến cgroup.

Mặc dù tiêu đề cutils/sched_policy.h vẫn tồn tại, nhưng để tránh phá vỡ mã hiện có, hãy đảm bảo rằng mã mới bao gồm tiêu đề processgroup/sched_policy.h mới thay thế.

Các mô-đun sử dụng bất kỳ chức năng nào trong số này nên thêm phần phụ thuộc vào thư viện libprocessgroup vào tệp tạo tệp của chúng. Nếu một mô-đun không sử dụng bất kỳ chức năng libcutils nào khác, hãy loại bỏ phần phụ thuộc thư viện libcutils khỏi tệp tạo tệp.

API hồ sơ nhiệm vụ

Các API riêng tư trong processgroup/processgroup.h được xác định trong bảng bên dưới:

Kiểu API và định nghĩa
bool SetTaskProfiles(int tid, const std::vector & profiles) SetTaskProfiles(int tid, const std::vector & profiles)

Áp dụng các cấu hình tác vụ được chỉ định trong profiles cho luồng được chỉ định bởi ID luồng (tid) bằng cách sử dụng tham số tid của nó.

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

Áp dụng các cấu hình tác vụ được chỉ định trong profiles cho quy trình được chỉ định bởi người dùng và ID quy trình bằng cách sử dụng các tham số uidpid

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

Trả về xem bộ điều khiển cgroup được chỉ định bởi cgroup_name có tồn tại hay không; nếu true , đặt biến path dẫn vào thư mục gốc của nhóm đó

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

Trả về xem thuộc tính hồ sơ được chỉ định bởi attr_name có tồn tại hay không; nếu true , đặt biến path thành đường dẫn của tệp được liên kết với thuộc tính hồ sơ đó.

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

Trả về xem thuộc tính hồ sơ được chỉ định bởi attr_name có tồn tại hay không; nếu true , đặt biến path thành đường dẫn của tệp được liên kết với thuộc tính hồ sơ đó và tới luồng được chỉ định bởi ID luồng của nó bằng cách sử dụng tham số tid .

bool UsePerAppMemcg()

Trả về việc hệ thống có được cấu hình để sử dụng các nhóm bộ nhớ cho mỗi ứng dụng hay không.