سرویس SystemSuspend

در اندروید ۹ و پایین‌تر، یک نخ در libsuspend وجود دارد که مسئول شروع تعلیق سیستم است. اندروید ۱۰ عملکرد مشابهی را در سرویس HIDL SystemSuspend معرفی می‌کند. این سرویس در تصویر سیستم قرار دارد و توسط پلتفرم اندروید ارائه می‌شود. منطق libsuspend تا حد زیادی یکسان باقی می‌ماند، به جز اینکه هر فرآیند فضای کاربری که تعلیق سیستم را مسدود می‌کند، باید با SystemSuspend ارتباط برقرار کند.

لیب‌ساپسند و لیب‌پاور

در اندروید ۱۰، سرویس SystemSuspend جایگزین libsuspend شده است. libpower بدون تغییر API زبان C، مجدداً پیاده‌سازی شده تا به جای /sys/ power /wake[un]lock به سرویس SystemSuspend متکی باشد.

این شبه‌کد نحوه‌ی پیاده‌سازی 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 تعداد قفل‌های بیداری صادر شده را با یک شمارنده‌ی تعلیق پیگیری می‌کند. این سرویس دو رشته‌ی اجرایی دارد:

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

رشته اصلی

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

تعلیق نخ

نخ معلق (suspend thread) کارهای زیر را در یک حلقه انجام می‌دهد:

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

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

شکل 1. حلقه نخ را معلق کنید

رابط برنامه‌نویسی سیستم تعلیق

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

رابط HIDL سیستم تعلیق


enum WakeLockType : uint32_t {
    PARTIAL,
    FULL
};

interface IWakeLock {
    oneway release();
};

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

هر کلاینتی که درخواست قفل بیداری (wake lock) را می‌دهد، یک نمونه منحصر به فرد IWakeLock دریافت می‌کند. این با /sys/ power /wake_lock متفاوت است، که به چندین کلاینت اجازه می‌دهد از قفل بیداری با نام یکسان استفاده کنند. اگر کلاینتی که نمونه IWakeLock را در اختیار دارد، خاتمه یابد، درایور اتصال‌دهنده و سرویس SystemSuspend آن را پاک می‌کنند.

رابط AIDL سرویس کنترل تعلیق (ISuspendControlService)

سرویس ISuspendControlService فقط برای استفاده توسط SystemServer در نظر گرفته شده است.


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

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

استفاده از HIDL اندروید مزایای زیر را ارائه می‌دهد:

  • اگر یک فرآیند مسدودکننده‌ی تعلیق از کار بیفتد، می‌توان به SystemSuspend اطلاع داد.
  • می‌توان به نخی که مسئول تعلیق سیستم است، یک فراخوانی برگشتی (callback) داد.