במכשירי Android מגרסה 10 ואילך נעשה שימוש בקבוצת בקרה (cgroup) בשכבת הפשטה של פרופילים של משימות, שמפתחים יכולים להשתמש בה כדי לתאר קבוצה (או קבוצות) של הגבלות שיחולו על שרשור או תהליך. לאחר מכן המערכת עוקב אחר הפעולות שנקבעו מראש של פרופילי המשימות כדי לבחור אחד או יותר של קבוצות מתאים, שבאמצעותן חלות ההגבלות, ושינויים ניתן ליצור קבוצת תכונות בסיסית של cgroup בלי להשפיע על תוכנה ברמה גבוהה יותר ארבע שכבות שונות.
מידע על קבוצות
קבוצות Google מספקות מנגנון לצבירה ולחלוקה למחיצות של קבוצות של משימות (שמכילות תהליכים, שרשורים ואת כל הצאצאים שלהם בעתיד) לקבוצות היררכיות עם התנהגות ייחודית. מערכת Android משתמשת בקבוצות Google כדי לשלוט ב במשאבי מערכת כמו יחידת עיבוד מרכזי (CPU) והקצאת זיכרון, עם תמיכה ליבת Linux גרסה 1 ו-cgroups v2.
Android מגרסה 9 ומטה
ב-Android 9 ומטה, סקריפט האתחול init.rc
הכיל את קבוצת
קבוצות זמינות, נקודות הטעינה והגרסאות שלהן. אומנם האפשרויות האלה
המסגרת של Android ציפתה שקבוצה ספציפית של קבוצות תהיה קיימת
מיקומים ספציפיים עם גרסה ספציפית והיררכיה ספציפית של קבוצות משנה, על סמך
סקריפט. כך הגבלנו את היכולת לבחור את הגרסה הבאה של cgroup שבה רוצים להשתמש, או
לשנות את היררכיית הקבוצות כדי להשתמש בתכונות חדשות.
Android מגרסה 10 ואילך
ב-Android מגרסה 10 ואילך נעשה שימוש בקבוצות עם פרופילים של משימות:
- הגדרת Cgroup. המפתחים מתארים את הגדרת הקבוצות של הקבוצות ב-
cgroups.json
שלהם כדי להגדיר קבוצות של קבוצות, ואת מיקומי הטעינה והמאפיינים שלהן. כל הקבוצות טוענות בשלב הראשוני של האתחול תהליך האימות. - אפשר לבצע משימות בפרופילים. הן מספקות מופשטות שמפרידות
מעבר לפונקציונליות של פרטי ההטמעה. מסגרת Android
מחילה את הפרופילים של המשימות כמו שמתואר בקובץ
task_profiles.json
על או שרשור באמצעות ממשקי ה-API שלSetTaskProfiles
ו-SetProcessProfiles
. (ממשקי ה-API האלה ייחודיים ל-Android מגרסה 11 ואילך.)
כדי לספק תאימות לאחור, הפונקציה הקודמת כוללת set_cpuset_policy
,
set_sched_policy
ו-get_sched_policy
מספקים את אותם API ואותה פונקציונליות,
אבל ההטמעה שלהן שונתה ועכשיו היא משתמשת בפרופילי משימות. לשימוש חדש
במקרים שבהם AOSP ממליץ להשתמש בממשקי API חדשים של פרופילי משימות במקום בממשקי ה-API הקודמים
set_sched_policy
.
קובץ תיאור של קבוצות Google
קבוצות Google מתוארות בcgroups.json
הקובץ נמצא ב-<ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
.
כל אחד מהבקרים מתואר בקטע משנה ועליהם לעמוד בדרישות הבאות לפחות:
- שם, מוגדר בשדה נאמן מידע.
- נתיב הטעינה, מוגדר על ידי השדה נתיב.
- Mode , UID (מזהה משתמש) ו-GID (מזהה קבוצה) שמתארים את הבעלים וגם מצבי הגישה של הקבצים שבנתיב הזה (הכול אופציונלי).
- המאפיין 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). הכול
בקרים בהיררכיה של cgroups v2 נטענים באותו מיקום.
לכן, לקטע Cgroups2 יש Path, Mode, UID ו-UID משלו משלו.
GID שמתארים את המיקום ואת המאפיינים של הרמה הבסיסית (root)
ההיררכיה. המאפיין Path של נאמני מידע בקטע Cgroups2 הוא
יחסית לנתיב השורש הזה. ב-Android מגרסה 12 ואילך אפשר להגדיר Cgroup
בקר שצוין עם נתיב ומצב בתור "Optional"
על ידי הגדרת הערך true
.
הקובץ cgroups.json
מנותח כחלק מהתהליך הראשוני, במהלך הבדיקה הראשונית
וכל הקבוצות של הקבוצות טוענות במיקומים שצוינו. כדי לקבל מאוחר יותר
מיקומי הטעינה של cgroup, צריך להשתמש בפונקציית ה-API CgroupGetControllerPath
.
קובץ פרופילים של משימות
task_profiles.json
הקובץ נמצא ב-<ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
.
משמש לתיאור קבוצה ספציפית של פעולות שצריך ליישם בתהליך,
של שרשור. קבוצת פעולות משויכת לשם פרופיל, שנמצא בשימוש ב-
SetTaskProfiles
ו-SetProcessProfiles
שיחות כדי לבצע פעולות בפרופיל.
דוגמה לקובץ Tasks_profile.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" ]
}
}
אפשר להקצות שמות לקובצי cgroup ספציפיים כרשומות ברשימת המאפיינים. כל רשומה מכילה את הפרטים הבאים:
- השדה Name מציין את שם המאפיין.
- השדה בקר מפנה לבקר cgroup מ-
cgroups.json
לפי שמו. - השדה קובץ מציין שם של קובץ ספציפי בבקר הזה.
מאפיינים הם הפניות בהגדרות של פרופיל משימה. מחוץ למשימה פרופילים, להשתמש בהם רק כאשר ה-framework דורש גישה ישירה קבצים, ולא ניתן להפשט את הגישה באמצעות פרופילים של משימות. בכל שאר המקרים, להשתמש בפרופילים של משימות, הם מספקים הפרדה טובה יותר בין ההתנהגות הנדרשת את פרטי ההטמעה שלו.
הקטע פרופילים מכיל הגדרות של פרופילים של משימות, כולל ההגדרות הבאות:
- השדה שם מגדיר את שם הפרופיל.
בקטע פעולות מוצגת קבוצת הפעולות שבוצעו כשהפרופיל הוחלו. כל פעולה כוללת את הפרטים הבאים:
- השדה Name מציין את הפעולה.
- הקטע Params מציין קבוצת פרמטרים לפעולה.
הפעולות הנתמכות מפורטות בטבלה:
פעולה | פרמטר | תיאור |
---|---|---|
SetTimerSlack |
Slack |
הזמן חוסר פעילות בטיימר ב-ns |
SetAttribute |
Name |
שם שמפנה למאפיין מהקטע מאפיינים |
Value |
ערך שייכתב אל הקובץ שמיוצג על ידי מאפיין בעל השם | |
WriteFile | FilePath | נתיב לקובץ |
Value | ערך שייכתב לקובץ | |
JoinCgroup |
Controller |
השם של בקר ה-cgroup מאת cgroups.json |
Path |
נתיב של קבוצת משנה בהיררכיה של בקר קבוצת משנה |
ב-Android מגרסה 12 ואילך יש AggregateProfiles שמכיל פרופילים נצברים, שכל אחד מהם הוא כינוי של קבוצה פרופיל אחד או יותר. ההגדרות של פרופיל מצטבר כוללות את הפרטים הבאים:
- השדה Name מציין את שם הפרופיל המצטבר.
- בשדה פרופילים מפורטים שמות הפרופילים שכלולים פרופיל מצטבר.
כאשר מופעל פרופיל מצטבר, כל הפרופילים שמכילים גם מוחלת באופן אוטומטי. פרופילים נצברים יכולים להכיל שני פרופילים נפרדים או פרופילים אחרים של צבירה, כל עוד אין חזרות (פרופיל כולל את עצמו).
משימה_פרופילים באתחול שפה
פקודת task_profiles
בשפה של Android Init
זמינה ב-Android מגרסה 12 ואילך כדי
הפעלת פרופיל משימה לתהליך ספציפי. הוא מחליף את 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
.
צריך להשתמש תמיד בפקודה task_profiles
כדי להעביר משימות בהיררכיות של קבוצות Cgroup
Android מגרסה 12 ואילך. היא מקבלת פרמטר אחד או יותר, שמייצג
שמות הפרופילים שצוינו בקובץ task_profiles.json
.
לכל פרופילים של משימות ברמת ה-API
ב-Android מגרסה 12 ואילך, אפשר לתקן או לשנות
הגדרות בקובצי ברירת המחדל cgroups.json
ו-task_profiles.json
, או
התבססות על השינוי ברמת ה-API של Android או ביצוע השינוי על ידי הספק
מחיצה.
כדי לשנות את ההגדרות שמבוססות על רמת ה-API, הקבצים הבאים צריכים להיות במכשיר:
/system/etc/task_profiles/cgroups_<API level>.json
שימוש באפשרות הזו כשמדובר בקבוצות ספציפיות לרמת API.
/system/etc/task_profiles/task_profiles_<API level>.json
יש להשתמש באפשרות הזו לפרופילים ספציפיים לרמת API.
כדי לשנות את ההגדרות ממחיצת הספק, הקבצים הבאים צריכים להיות במכשיר:
/vendor/etc/cgroups.json
/vendor/etc/task_profiles.json
אם מאפיין או הגדרת פרופיל בקבצים האלה משתמשים באותו שם כמו נמצא בקובץ ברירת המחדל, הגדרת הקובץ (ברמת ה-API או ברמת הספק) מבטלת את ההגדרה של הקובץ (ברמת ה-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
, צריך לשחרר את libcutils
שתלויות בספרייה מסוימת בקובץ makefile.
ממשקי API לפרופילים של משימות
ממשקי ה-API הפרטיים ב-processgroup/processgroup.h
מוגדרים בטבלה:
סוג | API והגדרה |
---|---|
bool |
SetTaskProfiles(int tid, const std::vector
המערכת מחילה את הפרופילים של המשימות שצוינו ב- profiles על השרשור שצוין על ידי
מזהה שרשור (מזהה) באמצעות הפרמטר tid שלו. |
bool |
SetProcessProfiles(uid_t uid, pid_t pid, const std::vector
המערכת מחילה את הפרופילים של המשימות שצוינו ב- profiles על התהליך שצוין
על ידי המשתמש שלו ומעבד את המזהים באמצעות הפרמטרים uid ו-pid |
bool |
CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
חוזרת אם קיים בקר cgroup שצוין על ידי cgroup_name ;
אם true , הפונקציה הזו מגדירה את המשתנה path כרמה הבסיסית (root) של ה-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 . |
bool |
UsePerAppMemcg()
חוזרת אם המערכת מוגדרת לשימוש בקבוצות זיכרון לכל אפליקציה. |