เมื่อใช้ 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