שכבת הפשטה של ​​Cgroup

אנדרואיד 10 ומעלה משתמש בשכבת הפשטה של ​​קבוצת בקרה (cgroup) עם פרופילי משימות, שבה מפתחים יכולים להשתמש כדי לתאר קבוצה (או קבוצות) של הגבלות להחלה על שרשור או תהליך. לאחר מכן, המערכת עוקבת אחר הפעולות שנקבעו בפרופילי המשימות כדי לבחור קבוצת cgroup מתאימות אחת או יותר, שדרכן מוחלות הגבלות, וניתן לבצע שינויים בערכת התכונות הבסיסית של cgroup מבלי להשפיע על שכבות תוכנה גבוהות יותר.

על cgroups

Cgroups מספקות מנגנון לצבירה וחלוקה של קבוצות של משימות (המורכבות מתהליכים, חוטים וכל ילדיהם העתידיים) לקבוצות היררכיות בעלות התנהגות מיוחדת. אנדרואיד משתמשת ב-cgroups כדי לשלוט ולהתחשב במשאבי מערכת כגון שימוש והקצאת מעבד וזיכרון, עם תמיכה ב- Cgroups v1 ו- cgroups v2 של ליבת לינוקס.

אנדרואיד 9 ומטה

באנדרואיד 9 ומטה, סקריפט האתחול init.rc הכיל את קבוצת ה-cgroups הזמינות, נקודות ההרכבה והגרסאות שלהן. למרות שניתן לשנות את אלה, מסגרת האנדרואיד ציפתה שקבוצה מסוימת של cgroups תתקיים במיקומים ספציפיים עם גרסה ספציפית והיררכיית תת-קבוצות, בהתבסס על הסקריפט. זה הגביל את היכולת לבחור את גרסת ה-cgroup הבאה לשימוש, או לשנות את היררכיית ה-cgroup כדי להשתמש בתכונות חדשות.

אנדרואיד 10 ומעלה

אנדרואיד 10 ואילך משתמש בקבוצות cgroups עם פרופילי משימות:

  • הגדרת Cgroup - מפתחים מתארים את הגדרת cgroups בקובץ cgroups.json שלהם כדי להגדיר קבוצות של cgroups, ואת מיקומי ההרכבה והתכונות שלהם. כל קבוצות cgroups מותקנות בשלב הראשוני של תהליך האתחול.
  • פרופילי משימות - אלו מספקים הפשטה המנתקת את הפונקציונליות הנדרשת מפרטי היישום שלה. מסגרת Android מיישמת את פרופילי המשימות כמתואר בקובץ task_profiles.json על תהליך או שרשור באמצעות ה-API של SetTaskProfiles ו- SetProcessProfiles . (ממשקי API אלה ייחודיים לאנדרואיד 11 ומעלה.)

כדי לספק תאימות לאחור, הפונקציות מדור קודם set_cpuset_policy , set_sched_policy ו- get_sched_policy מספקות את אותם API ופונקציונליות, אך היישום שלהן שונה לשימוש בפרופילי משימות. למקרי שימוש חדשים, AOSP ממליצה להשתמש בממשקי API חדשים של פרופילי משימות במקום בפונקציית set_sched_policy מדור קודם.

קובץ תיאור Cgroups

Cgroups מתוארות בקובץ cgroups.json שנמצא תחת <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . כל בקר מתואר בסעיף משנה וחייב לכלול מינימום מהאפשרויות הבאות:

  • שם, מוגדר על ידי השדה Controller .
  • נתיב הרכבה, מוגדר על ידי השדה Path .
  • מצב , UID (מזהה משתמש) ו- GID (מזהה קבוצה) המתארים את הבעלים ומצבי הגישה לקבצים בנתיב זה (הכל אופציונלי).
  • מאפיין אופציונלי , מוגדר כ- 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 ו- GID משלו לתיאור המיקום והתכונות של שורש ההיררכיה. התכונה Path עבור בקרים תחת Cgroups2 היא יחסית לנתיב השורש הזה. באנדרואיד 12 ומעלה אתה יכול להגדיר בקר cgroup שצוין עם נתיב ומצב "Optional" על ידי הגדרתו ל- true .

הקובץ cgroups.json מנותח כחלק מתהליך ה-init, בשלב ה-init המוקדם, וה-cgroups מותקנים במיקומים שצוינו. כדי להשיג מאוחר יותר את מיקומי ההרכבה של cgroup, השתמש בפונקציית ה-API CgroupGetControllerPath .

קובץ פרופילי משימות

הקובץ 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" ]
     }
}

הקצה שמות לקבצי cgroup ספציפיים כערכים ברשימת התכונות שלך. כל ערך מכיל את הדברים הבאים:

  • שדה שם - מציין את שם התכונה.
  • שדה בקר - מפנה לבקר cgroup מקובץ cgroups.json , לפי שמו.
  • שדה קובץ - נותן שם לקובץ ספציפי תחת בקר זה.

תכונות הן הפניות בהגדרות פרופיל המשימות. מחוץ לפרופילי משימות, השתמש בהם רק כאשר המסגרת דורשת גישה ישירה לקבצים אלה, ולא ניתן להקטין את הגישה באמצעות פרופילי משימות. בכל שאר המקרים, השתמש בפרופילי משימות; הם מספקים ניתוק טוב יותר בין ההתנהגות הנדרשת לבין פרטי היישום שלה.

הקטע 'פרופילים' מכיל הגדרות של פרופיל משימות עם הפרטים הבאים:

  • שדה שם - מגדיר את שם הפרופיל.
  • קטע פעולות - מפרט קבוצה של פעולות שבוצעו כאשר הפרופיל מוחל. לכל פעולה יש את הדברים הבאים:

    • שדה שם המציין את הפעולה
    • סעיף פרמטרים המציין קבוצה של פרמטרים עבור הפעולה

הפעולות הנתמכות מופיעות בטבלה למטה.

פעולה פָּרָמֶטֶר תיאור
SetTimerSlack Slack רפיון טיימר ב-ns
SetAttribute Name שם המתייחס לתכונה מקטע תכונות
Value ערך שייכתב לקובץ המיוצג על ידי התכונה בעלת השם
WriteFile FilePath נתיב לקובץ
Value ערך שייכתב לקובץ
JoinCgroup Controller שם של בקר cgroup מ- cgroups.json
Path נתיב תת-קבוצה בהיררכיה של בקר ה-cgroup

אנדרואיד 12 ואילך כולל קטע AggregateProfiles שמכיל פרופילים מצטברים, שכל אחד מהם הוא כינוי לקבוצה של פרופיל אחד או יותר. הגדרות פרופיל מצטבר מורכבות מהאפשרויות הבאות:

  • שדה שם - מציין את שם הפרופיל המצטבר.
  • שדה פרופילים - מפרט את שמות הפרופילים הכלולים בפרופיל המצטבר.

כאשר מוחל פרופיל מצטבר, כל הפרופילים המכילים מוחלים גם הם באופן אוטומטי. פרופילים מצטברים יכולים להכיל גם פרופילים בודדים או פרופילים מצטברים אחרים, כל עוד אין רקורסיות (פרופיל שכולל את עצמו).

task_profiles פקודת שפה init

פקודת task_profiles בשפת Android Init זמינה עבור Android 12 ומעלה כדי להקל על הפעלת פרופיל המשימה עבור תהליך ספציפי. זה מחליף את פקודת writepid (הוצאה משימוש באנדרואיד 12) ששימשה להעברת תהליך בין cgroups. הפקודה task_profiles מספקת גמישות לשינוי יישומים בסיסיים ללא השפעה על השכבות העליונות. בדוגמה למטה, שתי הפקודות הללו מבצעות למעשה את אותה פעולה:

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

    הוצא משימוש באנדרואיד 12 - שימש לכתיבת ה-PID של המשימה הנוכחית לקובץ /dev/cpuctl/top-app/tasks .

  • task_profiles MaxPerformance

    מצטרף לתהליך הנוכחי לקבוצת האפליקציות העליונות תחת בקר "מעבד" ( cpuctl ), מה שגורם לכתיבת ה-PID של התהליך ל- dev/cpuctl/top-app/tasks .

השתמש תמיד בפקודה task_profiles כדי להעביר משימות בהיררכיות cgroup באנדרואיד 12 ומעלה. הוא מקבל פרמטר אחד או יותר, המייצג את שמות הפרופילים המצוינים בקובץ task_profiles.json .

לכל פרופילי משימות ברמת API

באנדרואיד 12 ומעלה, אתה יכול לשנות או לעקוף הגדרות בקובצי ברירת המחדל cgroups.json ו- task_profiles.json , בין אם לבסס את השינוי שלך על רמת ה-API של Android, או לבצע אותו ממחיצת הספק.

כדי לעקוף את ההגדרות המבוססות על רמת API, הקבצים הבאים חייבים להיות נוכחים במכשיר:

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

    השתמש בזה עבור cgroups ספציפיות לרמת API.

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

    השתמש בזה עבור פרופילים ספציפיים לרמת API.

כדי לעקוף את ההגדרות ממחיצת הספק, הקבצים הבאים חייבים להיות נוכחים במכשיר:

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

אם תכונה או הגדרת פרופיל בקבצים אלה משתמשת באותו שם כמו בקובץ ברירת המחדל, הגדרת הקובץ (רמת API או רמת ספק) עוקפת את ההגדרה הקודמת. שימו לב גם שהגדרות ברמת הספק עוקפות הגדרות ברמת ה-API. אם להגדרה החדשה יש שם חדש, ערכת המאפיינים או הפרופילים תשתנה עם ההגדרה החדשה.

מערכת אנדרואיד טוענת את קבצי cgroup ו- task_profile בסדר הזה:

  1. ברירת המחדל של קבצי cgroups.json ו- task_profiles.json .
  2. קבצים ספציפיים לרמת API, אם קיימים.
  3. קבצי מחיצות של ספק, אם קיימים.

שינויים ב-API קיים

אנדרואיד 10 ומעלה שומרת על הפונקציות set_cpuset_policy , set_sched_policy ו- get_sched_policy ללא שינויים ב-API. עם זאת, אנדרואיד 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) SetTaskProfiles(int tid, const std::vector & profiles)

מחיל את פרופילי המשימות המצוינים profiles על השרשור שצוין על ידי מזהה שרשור (tid) באמצעות פרמטר tid שלו.

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

מחיל את פרופילי המשימות המצוינים profiles על התהליך שצוין על ידי המשתמש ומזהי התהליך באמצעות פרמטרי uid ו- pid

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

מחזירה אם קיים בקר cgroup שצוין על ידי cgroup_name ; אם 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 .

bool UsePerAppMemcg()

מחזירה אם המערכת מוגדרת להשתמש בקבוצות זיכרון cgroups לכל יישום.