Android 10 以降では、タスク プロファイルによるコントロール グループ(cgroup)抽象化レイヤを使用します。これによりデベロッパーは、スレッドまたはプロセスに適用する制限のセットを記述できます。システムはその後、タスク プロファイルの所定のアクションに従って、制限を適用する 1 つ以上の適切な cgroup を選択します。また、上位のソフトウェア レイヤに影響を与えることなく、基となる cgroup 機能セットを変更できます。
cgroup について
cgroup は、タスクのセット(プロセス、スレッド、その将来のすべての子から構成)を、特定の動作の階層グループに集約し分割するメカニズムを提供します。Android では cgroups を使用して、CPU とメモリの使用量や割り当てなどのシステム リソースを制御、考慮しており、Linux カーネルの cgroups v1 と cgroups v2 をサポートしています。
Android 9 以前
Android 9 以前では、init.rc
初期化スクリプトに、利用可能な cgroup のセット、マウント ポイント、バージョンが含まれていました。これらは変更できますが、Android フレームワークでは、スクリプトに基づいて、特定の cgroup セットが特定の場所に存在し、固有のバージョンとサブグループ階層を持つことが想定されていました。このため、次に使用する cgroup バージョンを選択する機能や、cgroup の階層を変更して新しい機能を使用する機能が制限されていました。
Android 10 以降
Android 10 以降では、タスク プロファイルで cgroup を使用します。
- cgroup のセットアップ: デベロッパーは
cgroups.json
ファイルに cgroup のセットアップを記述して、cgroup のセット、マウント場所と属性を定義します。cgroup はすべて、初期化プロセスの初期段階でマウントされます。 - タスク プロファイル: 必要な機能を実装の詳細から切り離す抽象化を行います。Android フレームワークは、
task_profiles.json
ファイルに記載されているタスク プロファイルを、SetTaskProfiles
API とSetProcessProfiles
API を使用してプロセスまたはスレッドに適用します(これらの API は Android 11 以降に固有のものです)。
下位互換性を確保するために、以前の関数 set_cpuset_policy
、set_sched_policy
、get_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 属性。true に設定すると、カーネルがマウントをサポートしていない cgroup コントローラが原因で発生するマウントエラーが無視されます。
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 コントローラを記述)という 2 つのセクションがあります。cgroups v2 階層のコントローラはすべて、同じ場所にマウントされます。したがって、Cgroups2 セクションには、階層のルートの場所と属性を記述する固有の Path、Mode、UID、および GID 属性があります。Cgroups2 にある Controller の Path 属性は、そのルートパスに対する相対パスです。Android 12 以降では、"Optional"
を true
に設定することにより、パスとモードが省略可能として指定された cgroup コントローラを定義できます。
cgroups.json
ファイルは初期の init ステージで init プロセスの一部として解析され、指定された場所に cgroup がマウントされます。cgroup のマウント場所を後で取得するには、CgroupGetControllerPath
API 関数を使用します。
タスク プロファイルのファイル
task_profiles.json
ファイルは <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
にあります。プロセスまたはスレッドに適用される一連のアクションを記述するために使用します。一連のアクションはプロファイル名に関連付けられます。プロファイル名はプロファイル アクションを実行するために SetTaskProfiles
と SetProcessProfiles
の呼び出しで使用されます。
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 |
タイマーのゆとり(ナノ秒) |
SetAttribute |
Name |
[Attributes] セクションの属性を参照する名前 |
Value |
名前付き属性で表される、ファイルに書き込まれる値 | |
WriteFile | FilePath | ファイルのパス |
Value | ファイルに書き込まれる値 | |
JoinCgroup |
Controller |
cgroups.json の cgroup コントローラの名前 |
Path |
cgroup コントローラの階層内のサブグループ パス |
Android 12 以降では、集計プロファイルを含む AggregateProfiles セクションが導入されています(各プロファイルは 1 つ以上のプロファイルのセットのエイリアスです)。集計プロファイルの定義は以下の要素で構成されます。
- Name フィールド - 集計プロファイルの名前を指定します。
- Profiles フィールド - 集計プロファイルに含まれるプロファイルの名前のリストです。
集計プロファイルが適用されると、含まれているすべてのプロファイルも自動的に適用されます。再帰プロファイル(自分自身を含むプロファイル)がなければ、個々のプロファイルまたは他の集計プロファイルの両方を集計プロファイルに含めることができます。
init 言語の task_profiles コマンド
Android 12 以降では、特定のプロセスのタスク プロファイルのアクティブ化を容易にするために、Android init 言語の task_profiles
コマンドを使用できます。これは、cgroup 間でプロセスを移行するために使用されていた writepid
コマンド(Android 12 でサポート終了)に代わるものです。task_profiles
コマンドを使用すると、上位レイヤに影響を与えることなく、基盤となる実装を柔軟に変更できます。以下の例に示す 2 つのコマンドは、結果的に同じオペレーションを実行します。
writepid /dev/cpuctl/top-app/tasks
Android 12 でサポートが終了しました。現在のタスクの PID を
/dev/cpuctl/top-app/tasks
ファイルに書き込むために使用されていました。task_profiles MaxPerformance
現在のプロセスを「cpu」コントローラ(
cpuctl
)の下の top-app グループに追加します。これにより、プロセスの PID がdev/cpuctl/top-app/tasks
に書き込まれます。
Android 12 以降では、cgroup 階層のタスクを移行するには、常に task_profiles
コマンドを使用します。このコマンドは、task_profiles.json
ファイルで指定されたプロファイルの名前を表す 1 つ以上のパラメータを受け入れます。
API レベルのタスク プロファイル
Android 12 以降では、Android API レベルでの変更に基づいて、またはベンダー パーティションから、デフォルトの cgroups.json
ファイルと task_profiles.json
ファイルで定義を修正またはオーバーライドできます。
API レベルに基づいて定義をオーバーライドするには、以下のファイルがデバイスに存在する必要があります。
/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 システムは、cgroup
ファイルと task_profile
ファイルを次の順序で読み込みます。
- デフォルトの
cgroups.json
ファイルとtask_profiles.json
ファイル - API レベル固有のファイル(存在する場合)
- ベンダー パーティション ファイル(存在する場合)
既存の API の変更
Android 10 以降では、関数 set_cpuset_policy
、set_sched_policy
、get_sched_policy
が維持され、API は変更されていません。ただし、Android 10 ではこれらの関数が libprocessgroup
に移動され、ここに cgroup 関連のすべての機能が含まれるようになりました。
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 で指定されたタスク プロファイルを、tid パラメータを使用してスレッド ID(tid)で指定されたスレッドに適用します。 |
bool |
SetProcessProfiles(uid_t uid, pid_t pid, const std::vector
profiles で指定されたタスク プロファイルを、uid パラメータと pid パラメータを使用してユーザー ID とプロセス 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 を使用するようにシステムが構成されているかどうかを返します。 |