ב-Android 9 וגרסאות קודמות, יש שרשור ב-libsuspend שאחראי להפעלת השהיה של המערכת. ב-Android 10 נוספה פונקציונליות מקבילה בשירות SystemSuspend HIDL.
השירות הזה נמצא בתמונת המערכת ומופעל על ידי פלטפורמת Android.
הלוגיקה מ-libsuspend
נשארת זהה במידה רבה, מלבד העובדה שכל תהליך במרחב המשתמש שחוסם את השהיה המערכת צריך לתקשר עם SystemSuspend.
libightend ו-libpower
ב-Android 10, השירות SystemSuspend מחליף את libsuspend
. libpower
הוטמע מחדש כך שיסתמך על השירות SystemSuspend במקום על /sys/power/wake[un]lock
, בלי לשנות את ה-API ל-C.
הקוד המדומה הזה מראה איך מטמיעים את 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.
- השעיה של מערכת ההשעיה של אמצעי הבקרה לשרשורים.
Thread ראשי
השרשור הראשי עונה לבקשות של לקוחות להקצות מנעולים חדשים להפעלה מחדש, ומגדיל או מקטין את מונה ההשעיה.
השעיית השרשור
חוט ההשהיה מבצע את הפעולות הבאות בלולאה:
- קוראים את
/sys/power/wakeup_count
. - רכישת ה-mutex. כך מוודאים ששרשור ההשעיה לא נוגע למונה ההשעיה בזמן ששרשור הראשי מנסה להגדיל או להקטין אותו. כשמספר העצירות ב-suspend counter מגיע לאפס וה-thread suspend מנסה לפעול, ה-thread main נחסם במהלך הניסיון להוסיף או להסיר את נעילת ההתעוררות.
- ממתינים עד שהמספר בספירה לאפס.
- כותבים בקובץ הזה את הערך שנקרא מ-
/sys/power /wakeup_count
(משלב 1). אם הכתיבה נכשלה, חוזרים לתחילת הלולאה - כדי להפעיל את השעיית המערכת, כותבים
mem
עד/sys/power/state
. - משחררים את מנעול ה-mutex.
כשהבקשה לנעילה של מצב שינה חוזרת בהצלחה, השרשור המושעה נחסם.
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
מסתיים, מנהל ההתקן של הקישור והשירות System suspended מנקים אותו.
ממשק AIDL של ISuspendControlService
השירות ISuspendControlService מיועד לשימוש רק על ידי SystemServer.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
היתרונות של שימוש ב-Android HIDL:
- אם תהליך שחוסם השהיה יסתיים, ניתן יהיה להודיע ל-SystemSuspend.
- אפשר להעביר קריאה חוזרת לשרשור שאחראי להשעיית המערכת.