השירות SystemSuspend

ב-Android 9 ובגרסאות קודמות, יש שרשור ב-libsuspend שאחראי על הפעלת השהיית המערכת. ב-Android 10 נוספה פונקציונליות מקבילה בשירות SystemSuspend HIDL. השירות הזה נמצא בקובץ אימג' של המערכת ומופעל על ידי פלטפורמת Android. הלוגיקה מ-libsuspend נשארת ברובה ללא שינוי, חוץ מזה שכל תהליך במרחב המשתמשים שחוסם את השעיית המערכת צריך לתקשר עם SystemSuspend.

‫libsuspend ו-libpower

ב-Android 10, שירות SystemSuspend מחליף את libsuspend. הפונקציה libpower הוטמעה מחדש כדי להסתמך על השירות SystemSuspend במקום על /sys/power/wake[un]lock, בלי לשנות את C API.

הקוד המדומה הבא מראה איך מטמיעים את acquire_wake_lock ואת release_wake_lock.


static std::unordered_map<std::string, sp<IWakeLock>> gWakeLockMap;

int acquire_wake_lock(int, const char* id) {
    ...
    if (!gWakeLockMap[id]) {
        gWakeLockMap[id] = suspendService->acquireWakeLock(WakeLockType::PARTIAL, id);
    }
    ...
    return 0;
}

int release_wake_lock(const char* id) {
    ...
    if (gWakeLockMap[id]) {
        auto ret = gWakeLockMap[id]->release();
        gWakeLockMap[id].clear();
        return 0;
    }
    ...
    return -1;
}

שרשורי ביצוע

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

  • ה-thread הראשי עונה להפעלות של Binder.
  • ההשעיה של השרשור suspend שולטת בהשעיה של המערכת.

Thread ראשי

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

השעיית השרשור

השרשור של ההשעיה מבצע את הפעולות הבאות בלולאה:

  1. קריאה מתוך /sys/power/wakeup_count.
  2. מקבלים את ה-mutex. כך מוודאים שה-thread של ההשהיה לא ישפיע על מונה ההשהיה בזמן שה-thread הראשי מנסה להגדיל או להקטין אותו. ה-thread הראשי נחסם במהלך הנפקה או הסרה של נעילות השהיה כשהמונה של ההשהיה הגיע לאפס וה-thread של ההשהיה מנסה לפעול.
  3. מחכים עד שהמונה יגיע לאפס.
  4. כותבים את הערך שנקרא מ-/sys/power /wakeup_count (משלב 1) לקובץ הזה. אם הפעולה נכשלת, חוזרים לתחילת הלולאה
  5. כדי להשהות את המערכת, כותבים mem ב-/sys/power/state.
  6. משחררים את ה-mutex.

כשבקשה לחסימת מצב שינה מוחזרת בהצלחה, ה-Thread של ההשעיה נחסם.

איור 1. השהיית לולאת השרשור

SystemSuspend API

‫SystemSuspend API מורכב משני ממשקים. ממשק HIDL משמש תהליכים מקוריים כדי לקבל נעילות השכמה, וממשק AIDL משמש לתקשורת בין SystemServer ל-SystemSuspend.

ממשק HIDL של ISystemSuspend


enum WakeLockType : uint32_t {
    PARTIAL,
    FULL
};

interface IWakeLock {
    oneway release();
};

interface ISystemSuspend {
    acquireWakeLock(WakeLockType type, string debugName)
        generates (IWakeLock lock);
};

כל לקוח שמבקש חסימת מצב שינה מקבל מופע IWakeLock ייחודי. היא שונה מ-/sys/power/wake_lock, שמאפשרת לכמה לקוחות להשתמש בחסימת מצב שינה באותו שם. אם לקוח שמחזיק במופע של IWakeLock מסיים את הפעולה, מנהל ההתקן של ה-binder והשירות SystemSuspend מנקים אותו.

ממשק AIDL‏ ISuspendControlService

הממשק ISuspendControlService מיועד לשימוש רק על ידי SystemServer.


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

interface ISuspendControlService {
    boolean enableAutosuspend();
    boolean registerCallback(ISuspendCallback callback);
    boolean forceSuspend();
}

היתרונות של שימוש ב-Android HIDL:

  • אם תהליך שמונע השעיה מסתיים, אפשר לקבל על כך הודעה מ-SystemSuspend.
  • אפשר להגדיר קריאה חוזרת לשרשור שאחראי על השהיית המערכת.