سرویس SystemSuspend

در Android 9 و نسخه‌های پایین‌تر، رشته‌ای در libsuspend مسئول شروع تعلیق سیستم است. Android 10 عملکردی معادل را در سرویس SystemSuspend HIDL معرفی می‌کند. این سرویس در تصویر سیستم قرار دارد و توسط پلاتفرم Android ارائه می‌شود. منطق libsuspend تا حد زیادی یکسان است، با این تفاوت که هر فرایند فضای کاربر که تعلیق سیستم را مسدود می‌کند باید با SystemSuspend ارتباط برقرار کند.

libsuspend و libpower

در Android 10، سرویس SystemSuspend جایگزین libsuspend می‌شود. libpower دوباره پیاده‌سازی شد تا به‌جای /sys/power/wake[un]lock به سرویس SystemSuspend متکی باشد بدون اینکه «میانای برنامه‌سازی کاربردی 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 تعداد قفل‌های بیداری صادرشده را با شمارنده تعلیق پیگیری می‌کند. دو رشته اجرا دارد:

  • رشته اصلی به فراخوانی‌های binder پاسخ می‌دهد.
  • رشته تعلیق کنترل تعلیق سیستم را انجام می‌دهد.

رشته اصلی

رشته اصلی به درخواست‌های مشتریان برای تخصیص قفل‌های بیداری جدید پاسخ می‌دهد و شمارنده تعلیق را افزایش/کاهش می‌دهد.

تعلیق کردن رشته

رشته تعلیق در یک حلقه، موارد زیر را انجام می‌دهد:

  1. از /sys/power/wakeup_count بخوان.
  2. موتکس را به‌دست آورید. این کار تضمین می‌کند که رشته تعلیق درحالی‌که رشته اصلی درحال تلاش برای افزایش یا کاهش شمارنده تعلیق است، شمارنده تعلیق را لمس نکند. رشته اصلی هنگام صدور یا برداشتن قفل‌های بیدارباش وقتی شمارنده تعلیق به صفر رسیده است و رشته تعلیق درحال تلاش برای اجرا است، مسدود می‌شود.
  3. صبر کنید تا شمارنده به صفر برسد.
  4. مقدار خوانده‌شده از /sys/power /wakeup_count (از مرحله ۱) را در این فایل بنویسید. اگر نوشتن ناموفق بود، به ابتدای حلقه برگردید
  5. تعلیق سیستم را با نوشتن mem در /sys/power/state شروع کنید.
  6. ‫mutex را رها کنید.

وقتی درخواست قفل بیداری باموفقیت برمی‌گردد، رشته تعلیق مسدود می‌شود.

شکل ۱. تعلیق حلقه رشته

SystemSuspend API

‫SystemSuspend API از دو میان‌واره تشکیل شده است. از میانای HIDL برای فرایندهای بومی برای دریافت قفل‌های بیداری استفاده می‌شود و از میانای AIDL برای ارتباط بین SystemServer و SystemSuspend استفاده می‌شود.

میانای ISystemSuspend HIDL


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 اطلاع داد.
  • رشته مسئول تعلیق سیستم می‌تواند یک پاسخ تماس دریافت کند.