שכבת הפשטה של קבוצה

במכשירי 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 ערך שייכתב אל הקובץ שמיוצג על ידי מאפיין בעל השם
WriteFileFilePathנתיב לקובץ
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 לפי הסדר הבא:

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

שינויים בממשק 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)
המערכת מחילה את הפרופילים של המשימות שצוינו ב-profiles על השרשור שצוין על ידי מזהה שרשור (מזהה) באמצעות הפרמטר tid שלו.
bool 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 כרמה הבסיסית (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()
חוזרת אם המערכת מוגדרת לשימוש בקבוצות זיכרון לכל אפליקציה.