จัดการแอปที่แคชไว้และแอปที่หยุดทำงาน

เมื่อใช้ Binder เพื่อสื่อสารระหว่างกระบวนการ ให้ระมัดระวังเป็นพิเศษเมื่อ กระบวนการระยะไกลอยู่ในสถานะแคชหรือหยุดชั่วคราว การเรียกใช้แอปที่แคชไว้หรือแอปที่หยุดทำงาน อาจทำให้แอปขัดข้องหรือใช้ทรัพยากรโดยไม่จำเป็น

สถานะแอปที่แคชไว้และหยุดชั่วคราว

Android จะดูแลแอปในสถานะต่างๆ เพื่อจัดการทรัพยากรระบบ เช่น หน่วยความจำและ CPU

สถานะแคช

เมื่อแอปไม่มีคอมโพเนนต์ที่ผู้ใช้มองเห็นได้ เช่น กิจกรรมหรือบริการ ระบบจะย้ายแอปไปยังสถานะแคชได้ ดูรายละเอียดได้ที่กระบวนการและวงจรชีวิตของแอป ระบบจะเก็บแอปที่แคชไว้ในหน่วยความจำในกรณีที่ผู้ใช้เปลี่ยนกลับไปใช้แอปเหล่านั้น แต่คาดว่าแอปเหล่านั้นจะไม่ได้ทำงานอยู่

เมื่อเชื่อมโยงจากกระบวนการแอปหนึ่งไปยังอีกกระบวนการหนึ่ง เช่น การใช้ bindService สถานะกระบวนการของกระบวนการเซิร์ฟเวอร์จะได้รับการยกระดับให้มีความสำคัญอย่างน้อย เท่ากับกระบวนการไคลเอ็นต์ (ยกเว้นเมื่อระบุ Context#BIND_WAIVE_PRIORITY) เช่น หากไคลเอ็นต์ไม่ได้อยู่ในสถานะแคช เซิร์ฟเวอร์ก็จะไม่ใช่เช่นกัน

ในทางกลับกัน สถานะของกระบวนการเซิร์ฟเวอร์ไม่ได้กำหนดสถานะของไคลเอ็นต์ ดังนั้นเซิร์ฟเวอร์อาจมีการเชื่อมต่อ Binder กับไคลเอ็นต์ ซึ่งมักอยู่ในรูปแบบของ Callback และในขณะที่กระบวนการระยะไกลอยู่ในสถานะแคช เซิร์ฟเวอร์จะไม่ได้อยู่ในแคช

เมื่อออกแบบ API ที่มีการเรียกกลับซึ่งมาจากกระบวนการที่มีสิทธิ์สูงและส่งไปยังแอป ให้พิจารณาหยุดการเรียกกลับชั่วคราวเมื่อแอปเข้าสู่สถานะแคช และกลับมาดำเนินการต่อเมื่อแอปออกจากสถานะนี้ ซึ่งจะช่วยป้องกัน ไม่ให้มีการทำงานที่ไม่จำเป็นในกระบวนการของแอปที่แคชไว้

หากต้องการติดตามเมื่อแอปเข้าหรือออกจากสถานะแคช ให้ใช้ ActivityManager.addOnUidImportanceListener

// in ActivityManager or Context
activityManager.addOnUidImportanceListener(
    new UidImportanceListener() { ... },
    IMPORTANCE_CACHED);

สถานะถูกระงับ

ระบบสามารถหยุดแอปที่แคชไว้เพื่อประหยัดทรัพยากร เมื่อแอป ถูกระงับ แอปจะไม่ได้รับเวลา CPU และจะทำงานใดๆ ไม่ได้ โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อเครื่องมือหยุดทำงานของแอปที่แคชไว้

เมื่อกระบวนการส่งธุรกรรม Binder แบบซิงโครนัส (ไม่ใช่ oneway) ไปยังกระบวนการระยะไกลอื่นที่หยุดทำงาน ระบบจะปิดกระบวนการระยะไกลนั้น ซึ่งจะช่วย ป้องกันไม่ให้เธรดการโทรในกระบวนการโทรหยุดทำงานอย่างไม่มีกำหนด ขณะรอให้กระบวนการระยะไกลเลิกหยุดทำงาน ซึ่งอาจทำให้เกิด การขาดแคลนเธรดหรือการหยุดชะงักในแอปการโทร

เมื่อกระบวนการส่งธุรกรรม Binder แบบไม่พร้อมกัน (oneway) ไปยังแอปที่หยุดทำงาน (โดยทั่วไปคือการแจ้งเตือนการเรียกกลับ ซึ่งมักจะเป็นเมธอด oneway) ระบบจะบัฟเฟอร์ธุรกรรมจนกว่ากระบวนการระยะไกลจะกลับมาทำงานอีกครั้ง หากบัฟเฟอร์ ล้น กระบวนการของแอปผู้รับอาจขัดข้อง นอกจากนี้ ธุรกรรมที่บัฟเฟอร์ไว้ อาจล้าสมัยเมื่อแอปเลิกตรึงและ ประมวลผลธุรกรรมเหล่านั้น

คุณต้องหยุดการเรียกกลับของการจัดส่งชั่วคราวขณะที่กระบวนการของแอปผู้รับถูก หยุดชั่วคราว เพื่อไม่ให้แอปทำงานหนักเกินไปเนื่องจากมีเหตุการณ์ที่ล้าสมัยหรือบัฟเฟอร์ล้น

หากต้องการติดตามเวลาที่แอปถูกระงับหรือยกเลิกการระงับ ให้ใช้ IBinder.addFrozenStateChangeCallback

// The binder token of the remote process
IBinder binder = service.getBinder();

// Keep track of frozen state
AtomicBoolean remoteFrozen = new AtomicBoolean(false);

// Update remoteFrozen when the remote process freezes or unfreezes
binder.addFrozenStateChangeCallback(
    myExecutor,
    new IBinder.FrozenStateChangeCallback() {
        @Override
        public void onFrozenStateChanged(boolean isFrozen) {
            remoteFrozen.set(isFrozen);
        }
    });

// When dispatching callbacks to the remote process, pause dispatch if frozen:
if (!remoteFrozen.get()) {
    // dispatch callback to remote process
}

ใช้ RemoteCallbackList

คลาส RemoteCallbackList เป็นตัวช่วยในการจัดการรายการของ IInterface การเรียกกลับที่กระบวนการระยะไกลลงทะเบียน คลาสนี้จะจัดการการแจ้งเตือนการหยุดทำงานของ Binder โดยอัตโนมัติ และมีตัวเลือกสำหรับการจัดการการเรียกกลับ ไปยังแอปที่หยุดทำงาน

เมื่อสร้าง RemoteCallbackList คุณสามารถระบุนโยบายผู้เรียกที่หยุดชั่วคราวได้ดังนี้

  • FROZEN_CALLEE_POLICY_DROP: ระบบจะทิ้งการเรียกกลับไปยังแอปที่หยุดทำงานโดยไม่มีการแจ้งเตือน ใช้นโยบายนี้เมื่อเหตุการณ์ที่เกิดขึ้นขณะที่แคชแอปไม่สำคัญต่อแอป เช่น เหตุการณ์เซ็นเซอร์แบบเรียลไทม์
  • FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT: หากมีการออกอากาศการเรียกกลับหลายรายการขณะที่แอปถูกระงับ ระบบจะจัดคิวเฉพาะการเรียกกลับล่าสุดและ ส่งเมื่อแอปถูกยกเลิกการระงับ ซึ่งจะเป็นประโยชน์สำหรับการเรียกกลับตามสถานะ ในกรณีที่การอัปเดตสถานะล่าสุดเท่านั้นที่สำคัญ เช่น การเรียกกลับ ที่แจ้งให้แอปทราบระดับเสียงสื่อปัจจุบัน
  • FROZEN_CALLEE_POLICY_ENQUEUE_ALL: ระบบจะจัดคิวและส่งการเรียกกลับทั้งหมดที่ออกอากาศขณะที่แอป ถูกระงับเมื่อแอปได้รับการยกเลิกการระงับ โปรดระมัดระวังในการใช้นโยบายนี้ เนื่องจากอาจทำให้เกิดบัฟเฟอร์ล้นหากมีการจัดคิวการเรียกกลับมากเกินไป หรือทำให้เกิดการสะสมของเหตุการณ์ที่ล้าสมัย

ตัวอย่างต่อไปนี้แสดงวิธีสร้างและใช้อินสแตนซ์ RemoteCallbackList ที่ส่งการเรียกกลับไปยังแอปที่หยุดทำงาน

RemoteCallbackList<IMyCallbackInterface> callbacks =
        new RemoteCallbackList.Builder<IMyCallbackInterface>(
                        RemoteCallbackList.FROZEN_CALLEE_POLICY_DROP)
                .setExecutor(myExecutor)
                .build();

// Registering a callback:
callbacks.register(callback);

// Broadcasting to all registered callbacks:
callbacks.broadcast((callback) -> callback.onSomeEvent(eventData));

หากคุณใช้ FROZEN_CALLEE_POLICY_DROP ระบบจะเรียกใช้ callback.onSomeEvent() ก็ต่อเมื่อกระบวนการที่โฮสต์การเรียกกลับไม่ได้ถูกระงับ

บริการของระบบและการโต้ตอบกับแอป

บริการของระบบมักจะโต้ตอบกับแอปต่างๆ มากมายโดยใช้ Binder เนื่องจาก แอปสามารถเข้าสู่สถานะแคชและสถานะหยุดทำงานได้ บริการของระบบจึงต้องดูแลเป็นพิเศษ เพื่อจัดการการโต้ตอบเหล่านี้อย่างราบรื่นเพื่อช่วยรักษาความเสถียรและ ประสิทธิภาพของระบบ

บริการของระบบต้องจัดการสถานการณ์ที่กระบวนการของแอปถูกปิดด้วยเหตุผลต่างๆ อยู่แล้ว ซึ่งรวมถึงการหยุดดำเนินการในนามของแอปและไม่พยายามส่งการเรียกกลับไปยังกระบวนการที่หยุดทำงาน การพิจารณา การระงับแอปเป็นการขยายความรับผิดชอบในการตรวจสอบที่มีอยู่

ติดตามสถานะแอปจากบริการของระบบ

บริการของระบบที่ทำงานใน system_server หรือเป็น daemon ดั้งเดิมยังสามารถใช้ API ที่อธิบายไว้ก่อนหน้านี้เพื่อติดตามความสำคัญและสถานะหยุดทำงานของกระบวนการแอปได้ด้วย

  • ActivityManager.addOnUidImportanceListener: บริการของระบบสามารถ ลงทะเบียน Listener เพื่อติดตามการเปลี่ยนแปลงความสำคัญของ UID ได้ เมื่อได้รับ Binder Call หรือ Callback จากแอป บริการจะใช้ Binder.getCallingUid() เพื่อรับ UID และเชื่อมโยงกับ สถานะความสําคัญที่ Listener ติดตามได้ ซึ่งจะช่วยให้บริการของระบบทราบว่าแอปโทรอยู่ในสถานะแคชหรือไม่

  • IBinder.addFrozenStateChangeCallback: เมื่อบริการของระบบ ได้รับออบเจ็กต์ Binder จากแอป (เช่น เป็นส่วนหนึ่งของการลงทะเบียน สำหรับการเรียกกลับ) บริการควรลงทะเบียน FrozenStateChangeCallback ในอินสแตนซ์ IBinder นั้นๆ ซึ่งจะแจ้งให้ระบบ บริการทราบโดยตรงเมื่อกระบวนการของแอปที่โฮสต์ Binder นั้นหยุดทำงานหรือกลับมาทำงานอีกครั้ง

คำแนะนำสำหรับบริการของระบบ

เราขอแนะนำให้บริการของระบบทั้งหมดที่อาจโต้ตอบกับแอปติดตาม สถานะที่แคชและสถานะหยุดทำงานของกระบวนการแอปที่บริการเหล่านั้นสื่อสารด้วย การไม่ดำเนินการดังกล่าวอาจส่งผลให้เกิดปัญหาต่อไปนี้

  • การใช้ทรัพยากร: การทำงานสำหรับแอปที่แคชไว้และผู้ใช้มองไม่เห็นอาจทำให้สิ้นเปลืองทรัพยากรของระบบ
  • แอปขัดข้อง: การเรียกใช้ Binder แบบซิงโครนัสไปยังแอปที่หยุดทำงานจะทำให้แอปขัดข้อง การเรียกใช้ Binder แบบอะซิงโครนัสไปยังแอปที่หยุดทำงานจะทำให้เกิดข้อขัดข้องหากบัฟเฟอร์ธุรกรรมแบบอะซิงโครนัสล้น
  • ลักษณะการทำงานของแอปที่ไม่คาดคิด: แอปที่เลิกตรึงจะได้รับธุรกรรม Binder แบบอะซิงโครนัสที่บัฟเฟอร์ไว้ซึ่งส่งมาให้ทันที ขณะที่แอปถูกตรึง แอปอาจอยู่ในสถานะหยุดทำงานเป็นระยะเวลาไม่สิ้นสุด ดังนั้นธุรกรรมที่บัฟเฟอร์ไว้จึงอาจเก่ามาก

บริการของระบบมักใช้ RemoteCallbackList เพื่อจัดการการเรียกกลับจากระยะไกล และจัดการกระบวนการที่หยุดทำงานโดยอัตโนมัติ หากต้องการจัดการแอปที่หยุดทำงาน ให้ขยาย การใช้งาน RemoteCallbackList ที่มีอยู่โดยใช้นโยบายผู้เรียกที่หยุดทำงาน ตามที่อธิบายไว้ในใช้ RemoteCallbackList