Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

cgroup 抽象化レイヤ

Android 10 では、cgroup 抽象化レイヤとタスク プロファイルが用意されていて、スレッドまたはプロセスに適用する一連の制限を記述するために使用できます。システムでは、プロファイルを使用して、利用可能な cgroup により制限を適用する方法を選択します。また、基になる cgroup 機能セットを変更しても、上位のソフトウェア レイヤには影響しません。

コントロール グループ(cgroup)について

コントロール グループは、複数のタスク(プロセス、スレッド、以降に作成されるすべての子タスク)を、特定の動作の階層グループに集約または分割するメカニズムを提供します。Android では cgroup を使用して、CPU やメモリなどのシステム リソースを制御します。

Android 9 以前では、使用可能な一連の cgroup とそのマウント ポイントおよびバージョンが init.rc 初期化スクリプトに記述されており、変更される可能性も(仮定の話としては)ありました。Android フレームワークでは、特定の cgroup が特定の場所に存在し、固有のバージョンとサブグループ階層を持つ必要があったため、次の cgroup バージョンを選択したり、cgroup 階層を変更して新しい機能を使用したりすることは実際には不可能でした。

Android 10 では次のようになります。

  • cgroup の設定(以前は init.rc 初期化スクリプトで行われていました)は cgroups.json ファイルを使用して記述され、初期化プロセスの早い段階ですべての cgroup がマウントされます。
  • タスク プロファイルにより、必要な機能とその機能の実装方法を切り離す抽象化を実施できます。プロファイルは task_profiles.json ファイルを使用して記述され、Android フレームワークで新しい SetTaskProfiles API と SetProcessProfiles API を使用してプロセスまたはスレッドに適用されます。

下位互換性を確保するために、以前の set_cpuset_policyset_sched_policyget_sched_policy 関数でも同じ API が提供されますが、タスク プロファイルを使用するように実装が変更されています。OEM、SoC、携帯通信会社は以前の API を使用することも、タスク プロファイルを直接使用することもできます。追加の cgroup は引き続き init.rc 初期化スクリプトによってマウントでき、ベンダーコードで以前と同じように使用可能です。ただし、Android フレームワークで新しい cgroup を認識して使用する必要がある場合は、cgroups.json ファイルでグループを記述し、新しいタスク プロファイルを task_profiles.json ファイルで定義する必要があります。

cgroup 記述ファイル

cgroup は、<ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ にある cgroups.json ファイルに記述します。各コントローラはサブセクションで記述し、少なくとも名前とマウントパスが必要です(Mode、UID、GID の属性は省略可能です)。

cgroups.json ファイルの例:

{
  "Cgroups": [
    {
      "Controller": "cpu",
      "Path": "/dev/cpuctl",
      "Mode": "0755",
      "UID": "system",
      "GID": "system"
    },
    {
      "Controller": "cpuacct",
      "Path": "/acct",
      "Mode": "0555"
    }
}

このファイルが init プロセスの初期段階の前に解析されて、cgroup が指定の場所にマウントされます。cgroup のマウント場所は、後で CgroupGetControllerPath API 関数を使用して取得できます。

タスク プロファイルのファイル

タスク プロファイルと属性は、<ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ にある task_profiles.json ファイルに記述します。プロファイルには、プロセスまたはスレッドに適用される一連のアクションを記述します。一連のアクションはプロファイル名に関連付けられます。プロファイル名はプロファイル アクションを実行するために SetTaskProfilesSetProcessProfiles の呼び出しで使用されます。サポートされているプロファイル アクションは SetTimerSlackSetAttributeJoinCgroup です。

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"

          }
        }
      ]
    }
  ]
}

Attributes は特定の cgroup ファイルを指定するもので、フレームワークがこれらのファイルに直接アクセスする必要があり、タスク プロファイルを使用してアクセスを抽象化できない場合にのみ使用する必要があります。それ以外ではタスク プロファイルを使用してください。タスク プロファイルでは必要な動作と実装の詳細を適切に切り離すことができます。

既存の API の変更

Android 10 では関数 set_cpuset_policyset_sched_policyget_sched_policy が保持され、API は変更されていません。ただし、これらの関数は libprocessgroup に移動され、ここに cgroup 関連のすべての機能が含まれるようになりました。

cutils/sched_policy.h ヘッダーがまだ存在しており、このヘッダーが含まれる場合がありますが、新しい processgroup/sched_policy.h ヘッダーが含まれているため、すべての新しいコードには processgroup/sched_policy.h が直接含まれることになります。

これらの関数を使用するモジュールでは、libprocessgroup ライブラリへの依存関係を makefile に追加する必要があります。モジュールで libcutils の他の機能が使用されていない場合は、libcutils ライブラリへの依存関係を makefile から削除してください。

タスク プロファイルの API

次の非公開 API が導入され、processgroup/processgroup.h で定義されています。

  • bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles)

    profiles で指定されたタスク プロファイルを、tid パラメータを使用してスレッド ID で指定されたスレッドに適用します。

  • bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles)

    profiles で指定されたタスク プロファイルを、uid および pid パラメータを使用してユーザー ID とプロセス ID で指定されたプロセスに適用します。

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

    cgroup_name で指定された cgroup コントローラの有無を返して、path 変数をその cgroup のルートに設定します。

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

    attr_name で指定されたプロファイル属性の有無を返して、path 変数をそのプロファイル属性に関連付けられたファイルのパスに設定します。

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

    attr_name で指定されたプロファイル属性の有無を返して、path 変数をそのプロファイル属性と、tid パラメータを使用してスレッド ID で指定されたスレッドに関連付けられたファイルのパスに設定します。

  • bool UsePerAppMemcg()

    アプリごとのメモリ cgroup を使用するようにシステムが設定されているかどうかを返します。