השירות 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.

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

איור 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 מנקים אותו.

ממשק ISuspendControlService AIDL

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


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

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

השימוש ב-Android HIDL מציע את היתרונות הבאים:

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