Android 11 (ระดับ API 30) ขึ้นไปรองรับการหยุดทำงานของแอปที่แคชไว้ ฟีเจอร์นี้จะหยุดการดำเนินการสำหรับกระบวนการที่แคชไว้และลดการใช้ทรัพยากรโดยแอปที่ทำงานไม่ถูกต้องซึ่งอาจพยายามดำเนินการขณะแคชไว้
เครื่องมือหยุดแอปที่แคชไว้จะเก็บแอปไว้ใน RAM ขณะที่ปิดแอปไว้ใน CPU หาก Android พิจารณาว่าแอปไม่ควรทำงานแต่คุณอาจต้องใช้แอปในอนาคต ระบบจะระงับกระบวนการของแอปแทนที่จะสิ้นสุดกระบวนการ ซึ่งจะ ป้องกันไม่ให้เกิด Cold Start เมื่อต้องใช้แอปอีกครั้ง
Android จะหยุดแอปที่แคชไว้ชั่วคราวโดยการย้ายกระบวนการของแอปไปยัง cgroup ที่หยุดชั่วคราว ซึ่งจะช่วยลดการใช้ CPU ที่ใช้งานอยู่และไม่มีการใช้งานในกรณีที่มีแอปที่แคชไว้ซึ่งใช้งานอยู่ คุณเปิดใช้การหยุดแอปชั่วคราวได้โดยใช้ค่าสถานะการกำหนดค่าระบบหรือ ตัวเลือกสำหรับนักพัฒนาแอป
ใน Android 14 (ระดับ API 34) ขึ้นไป โปรแกรมระงับแอปที่แคชไว้จะมีลักษณะการทำงานที่เสถียรต่อไปนี้
- กระบวนการของแอปในสถานะแคชจะหยุดทำงาน 10 วินาทีหลังจากเข้าสู่สถานะแคช
- ระบบจะยกเลิกการหยุดกระบวนการของแอปทันทีในระหว่างเหตุการณ์วงจร เหตุการณ์เหล่านี้รวมถึงการรับ Intent การเริ่มต้นบริการงาน หรือผู้ใช้กลับมาใช้กิจกรรมต่อ
ActivityManagerService จัดการกระบวนการของแอปทั้งหมดและตัดสินใจเกี่ยวกับวงจรของแอป
CachedAppOptimizer มีหน้าที่หยุดกระบวนการของแอปชั่วคราว
เมื่อกระบวนการของแอปหยุดทำงานชั่วคราว เธรดทั้งหมดจะถูกระงับและไม่สามารถ
ทำงานของ CPU ได้จนกว่าจะยกเลิกการหยุดทำงานชั่วคราว ด้วยเหตุนี้ แอปจึงไม่สามารถดำเนินการเก็บขยะ (GC) และไม่สามารถตอบสนองต่อเหตุการณ์การตัดหน่วยความจำได้ ดูรายละเอียดได้ที่
ComponentCallbacks2.onTrimMemory(int) เพื่อรองรับการเปลี่ยนแปลงนี้ ตั้งแต่ Android 14 เป็นต้นไป
- แอปที่มีอินสแตนซ์
Activityที่มองเห็นได้จะได้รับการแจ้งเตือนเกี่ยวกับTRIM_MEMORY_UI_HIDDENทันทีที่ย้ายไป ที่พื้นหลัง แอปที่อยู่ในวงจรโดยไม่มี UI เช่น แอป ที่มีบริการที่ทำงานอยู่เบื้องหน้า อาจได้รับTRIM_MEMORY_BACKGROUNDระบบจะไม่ส่งเหตุการณ์การตัดอื่นๆ เนื่องจากเมื่อแอปมีสิทธิ์สำหรับเหตุการณ์เหล่านั้น ระบบจะ คาดหวังให้แอปหยุดทำงาน - หลังจากเข้าสู่สถานะแคชได้ไม่นาน ระบบอาจขอให้รันไทม์ของแอปทำการรวบรวมขยะเพื่อเตรียมพร้อมสำหรับการหยุดทำงานที่อาจเกิดขึ้น
- เมื่อกระบวนการของแอปหยุดทำงาน อาจมีขั้นตอนการบีบอัดหน่วยความจำเพิ่มเติมเกิดขึ้น เช่น การเขียนหน้าที่ได้รับการแก้ไขไปยังพื้นที่เก็บข้อมูลสำรองและการสลับหน้าแบบไม่ระบุชื่อไปยัง ZRAM
- หากกระบวนการทั้งหมดของแอปหนึ่งๆ ถูกระงับ ระบบจะสิ้นสุดซ็อกเก็ต TCP ที่ใช้งานอยู่ซึ่งแอปนั้นดูแลอยู่ ซึ่งจะป้องกันไม่ให้ฝั่งเซิร์ฟเวอร์ของซ็อกเก็ตส่งการปิง Keepalive ของ TCP ที่จะปลุกโมเด็มของอุปกรณ์
ระบบจะยกเลิกการหยุดกระบวนการของแอปที่แคชไว้ชั่วคราวเมื่อสถานะกระบวนการเปลี่ยนจากแคช
เป็นสถานะที่มีความสำคัญสูงขึ้น ระบบจะจัดคิวการออกอากาศที่ลงทะเบียนบริบทไว้ขณะที่แอปอยู่ในสถานะแคชเพื่อลดเหตุการณ์การเลิกตรึงใน Android 14 ขึ้นไป การออกอากาศที่ลงทะเบียนตามบริบทคือตัวรับที่แอปจดทะเบียน
แบบไดนามิกโดยการเรียก Context.registerReceiver
ระบบจะส่งการออกอากาศที่อยู่ในคิวเหล่านี้หลังจากที่แอปเลิกถูกระงับเท่านั้น
ในทางตรงกันข้าม ระบบจะไม่จัดคิวการออกอากาศที่ประกาศในไฟล์ Manifest
การออกอากาศที่ประกาศในไฟล์ Manifest คือตัวรับที่ประกาศแบบคงที่ใน AndroidManifest.xml โดยใช้องค์ประกอบ <receiver> ระบบจะยกเลิกการตรึงแอปที่แคชไว้ทันที
เพื่อส่งการออกอากาศที่ประกาศในไฟล์ Manifest
ผลกระทบต่อสถานะของระบบ
Android จะสิ้นสุดกระบวนการของแอปที่แคชไว้ซึ่งใช้งานล่าสุดน้อยที่สุดหากมีกระบวนการของแอปที่แคชไว้มากกว่า MAX_CACHED_PROCESSES รายการ ในอุปกรณ์ที่รองรับซึ่งใช้ Android 14 ขึ้นไป MAX_CACHED_PROCESSES จะเพิ่มขึ้นอย่างมาก
ทำให้อุปกรณ์สามารถเก็บกระบวนการของแอปที่แคชไว้ใน RAM ได้มากขึ้น
การแคชแอปเพิ่มเติมใน RAM จะช่วยลด Cold Start ได้สูงสุด 30% โดยการลดจะปรับขนาดตาม RAM ทั้งหมดของอุปกรณ์ ในขณะเดียวกัน ระบบจะลดการใช้ CPU ของแอปที่แคชไว้ให้เหลือน้อยที่สุด ซึ่งจะช่วยประหยัดแบตเตอรี่ได้อย่างมาก
การยกเว้นตู้แช่แข็ง
ในบางกรณี กระบวนการของแอปอาจเข้าสู่สถานะแคชแต่ยังคง ไม่หยุดทำงาน ข้อยกเว้นเหล่านี้เป็นรายละเอียดการใช้งานและอาจมีการเปลี่ยนแปลงใน Android เวอร์ชันต่อๆ ไป
- การล็อกไฟล์: หากกระบวนการที่แคชไว้มีการล็อกไฟล์ที่บล็อกกระบวนการอื่นๆ ที่ไม่ได้แคชไว้ ระบบจะไม่หยุดกระบวนการที่ล็อกไฟล์ชั่วคราว
BIND_WAIVE_PRIORITYการเชื่อมโยง: กระบวนการของแอปที่มีการเชื่อมโยงขาเข้า ซึ่งสร้างขึ้นโดยใช้Context.BIND_WAIVE_PRIORITYจะ เข้าสู่สถานะแคชได้ แต่จะยังคงไม่หยุดทำงานจนกว่ากระบวนการไคลเอ็นต์ที่เชื่อมต่อทั้งหมด จะแคชด้วย ข้อยกเว้นนี้รองรับแอปแบบหลายกระบวนการ เช่น เว็บเบราว์เซอร์ที่ใช้แท็บที่กำหนดเอง
ใช้ฟีเจอร์หยุดการทำงานของแอป
โปรแกรมหยุดแอปที่แคชไว้จะใช้ประโยชน์จากโปรแกรมหยุด cgroup v2 ของเคอร์เนล อุปกรณ์ที่จัดส่งพร้อมเคอร์เนลที่เข้ากันได้จะเปิดใช้ได้ เปิดใช้ตัวเลือกสำหรับนักพัฒนาแอป Suspend
execution for cached apps หรือตั้งค่า Flag การกำหนดค่าอุปกรณ์
activity_manager_native_boot use_freezer เป็น true เช่น
adb shell device_config put activity_manager_native_boot use_freezer true && adb rebootระบบจะปิดใช้ฟีเจอร์การหยุดแอปชั่วคราวเมื่อคุณตั้งค่าสถานะ use_freezer เป็น false หรือ
ปิดใช้ตัวเลือกสำหรับนักพัฒนาแอป เช่น
adb shell device_config put activity_manager_native_boot use_freezer false && adb rebootคุณสามารถสลับการตั้งค่านี้ได้โดยเปลี่ยนการกำหนดค่าอุปกรณ์ในการ เผยแพร่หรืออัปเดตซอฟต์แวร์
หากต้องการลบล้าง MAX_CACHED_PROCESSES เช่น ตั้งค่าเป็น 1024 สำหรับ
การทดสอบ ให้ทำดังนี้
adb shell device_config put activity_manager max_cached_processes 1024
adb shell device_config set_sync_disabled_for_tests persistentวิธีเปลี่ยนกลับการลบล้าง MAX_CACHED_PROCESSES
adb shell device_config delete activity_manager max_cached_processes
adb shell device_config set_sync_disabled_for_tests noneเครื่องมือหยุดแอปชั่วคราวไม่ได้เปิดเผย API อย่างเป็นทางการและไม่มีไคลเอ็นต์การใช้งานอ้างอิง แต่ใช้ API ของระบบที่ซ่อนอยู่ setProcessFrozen เพื่อหยุดกระบวนการแต่ละอย่างชั่วคราว และ enableFreezer เพื่อเปิดหรือปิดใช้การหยุดชั่วคราวทั่วโลก
จัดการฟีเจอร์ที่กำหนดเอง
โดยปกติแล้วกระบวนการของแอปจะไม่ทำงานเมื่อแคชไว้ แต่บางแอปอาจมีฟีเจอร์ที่กำหนดเองซึ่งรองรับโดยกระบวนการที่คาดว่าจะทำงานขณะแคชไว้ เมื่อเปิดใช้การหยุดแอปชั่วคราวในอุปกรณ์ที่เรียกใช้แอปดังกล่าว ระบบจะหยุดกระบวนการที่แคชไว้ชั่วคราวและอาจทำให้ฟีเจอร์ที่กำหนดเองใช้งานไม่ได้
วิธีแก้ปัญหาชั่วคราวคือคุณสามารถเปลี่ยนสถานะของกระบวนการเป็น "ไม่ได้แคช" ก่อนที่กระบวนการจะต้องทำงานใดๆ การเปลี่ยนแปลงนี้จะช่วยให้แอปยังคงใช้งานได้ ตัวอย่าง ของสถานะที่ใช้งานอยู่ ได้แก่ บริการที่ทำงานอยู่เบื้องหน้าที่เชื่อมโยงไว้หรือสถานะเบื้องหน้า
โหมดความล้มเหลวที่พบบ่อย
เมื่อกระบวนการของแอปถูกระงับ การสื่อสารระหว่างกระบวนการ (IPC) ที่ไม่เหมาะสมหรือการกำหนดเวลางานอาจทำให้แอปสิ้นสุดการทำงานหรือมีลักษณะการทำงานที่ไม่คาดคิด
ธุรกรรมการผูกแบบซิงโครนัสกับกระบวนการที่หยุดชั่วคราว
เมื่อกระบวนการแอปไคลเอ็นต์ส่งธุรกรรม Binder แบบซิงโครนัสไปยังกระบวนการแอปเซิร์ฟเวอร์
ที่หยุดทำงาน ระบบจะสิ้นสุดกระบวนการแอปเซิร์ฟเวอร์
ทันที ซึ่งจะช่วยป้องกันไม่ให้เธรดไคลเอ็นต์ถูกบล็อกอย่างไม่มีกำหนดขณะ
รอการตอบกลับจากเซิร์ฟเวอร์ที่หยุดทำงาน จากนั้นเธรดไคลเอ็นต์จะได้รับ
RemoteException และระบบจะทริกเกอร์
ผู้ฟังที่ลงทะเบียน ดูรายละเอียดได้ที่ IBinder.linkToDeath
สาเหตุหลัก: ความล้มเหลวนี้มักเกิดจากข้อบกพร่องในแอปไคลเอ็นต์
เมื่อไคลเอ็นต์เชื่อมโยงกับบริการ กระบวนการของเซิร์ฟเวอร์จะเชื่อมโยงกับไคลเอ็นต์และ
จะเข้าสู่สถานะที่แคชไว้ไม่ได้ก่อนที่ไคลเอ็นต์จะเข้า ดูรายละเอียดได้ที่ Context.bindService อย่างไรก็ตาม เมื่อไคลเอ็นต์เรียกใช้ Context.unbindService กระบวนการของเซิร์ฟเวอร์อาจได้รับการแคชและหยุดทำงาน หากไคลเอ็นต์ยังคงใช้การอ้างอิง IBinder ที่แคชไว้หลังจากยกเลิกการเชื่อมโยง ก็อาจเสี่ยงต่อการสื่อสารกับกระบวนการที่หยุดทำงาน
หากต้องการหลีกเลี่ยงปัญหานี้ ให้ตรวจสอบว่าแอปไคลเอ็นต์ทิ้งการอ้างอิง IBinder
ทันทีหลังจากเรียกใช้ Context.unbindService
บัฟเฟอร์ล้นของธุรกรรม Binder แบบไม่พร้อมกัน
เมื่อกระบวนการแอปเซิร์ฟเวอร์ได้รับธุรกรรม Binder แบบอะซิงโครนัส (oneway) ขณะที่หยุดชั่วคราว ระบบจะบัฟเฟอร์ธุรกรรมในบัฟเฟอร์ต่อกระบวนการ หาก
เซิร์ฟเวอร์ได้รับธุรกรรมแบบอะซิงโครนัสมากเกินไปขณะที่หยุดทำงาน บัฟเฟอร์
จะล้น และระบบจะสิ้นสุดกระบวนการแอปเซิร์ฟเวอร์
เพื่อป้องกันบัฟเฟอร์ล้นนี้ ให้หลีกเลี่ยงการส่งธุรกรรม Binder แบบอะซิงโครนัสมากเกินไปไปยังกระบวนการที่อาจแคชหรือหยุดชั่วคราว
การเรียกใช้งานที่กำหนดเวลาไว้ซ้ำๆ เมื่อเลิกตรึง
หากแอปทำงานที่ซ้ำกัน ระบบจะระงับแอปในขณะที่กระบวนการ
หยุดชั่วคราว ดูรายละเอียดได้ที่
ScheduledThreadPoolExecutor.scheduleAtFixedRate
หรือ Timer.scheduleAtFixedRate เมื่อ
กระบวนการกลับมาทำงานได้ตามปกติ การดำเนินการที่พลาดไปซึ่งสะสมไว้
อาจทำงานอย่างรวดเร็วต่อเนื่องกันโดยไม่มีการหน่วงเวลา
หากต้องการป้องกันไม่ให้มีการเรียกใช้จำนวนมากเมื่อแอปเลิกหยุดชั่วคราว ให้ใช้
scheduleWithFixedDelay แทน
scheduleAtFixedRate สำหรับงานในเบื้องหลัง นอกจากนี้ คุณยังใช้ WorkManager ได้ด้วย
ทดสอบและแก้ปัญหาเกี่ยวกับเครื่องมือหยุดแอปชั่วคราว
หากต้องการยืนยันว่าเครื่องมือหยุดแอปทำงานได้ตามที่ต้องการหรือเพื่อแก้ปัญหาที่เกี่ยวข้องกับเครื่องมือหยุดแอป ให้ใช้เครื่องมือวินิจฉัยและคำสั่งต่อไปนี้
คำสั่งเครื่องมือจัดการกิจกรรม
คุณสามารถใช้adb shell amคำสั่งเพื่อควบคุมการหยุดชั่วคราวและการบีบอัดด้วยตนเอง
สำหรับกระบวนการที่เฉพาะเจาะจงได้
บังคับให้กระบวนการหยุดทำงาน
adb shell am freeze <process>บังคับให้กระบวนการเลิกตรึง
adb shell am unfreeze <process>บังคับให้กระบวนการบีบอัดหน่วยความจำแบบเต็ม:
adb shell am compact full <process>
การตรวจสอบ Logcat
ดู Logcat เพื่อดูรายการที่หยุดทำงานและไม่หยุดทำงานทุกครั้งที่กระบวนการย้ายข้อมูลเข้าหรือออกจาก Freezer โดยทำดังนี้
adb logcat | grep -i "\(freezing\|froze\)"เอาต์พุตบันทึกเหตุผลในการเลิกตรึงค่าที่แจกแจงจาก enum UnfreezeReason Protocol
Buffer
การตรวจสอบ Dumpsys
ตรวจสอบรายการกระบวนการที่หยุดชั่วคราวโดยใช้ dumpsys activity
adb shell dumpsys activity | grep -A 20 "Apps frozen:"ตรวจสอบว่ามีไฟล์ /sys/fs/cgroup/uid_0/cgroup.freeze
ApplicationExitInfo
หากต้องการค้นหาสาเหตุของการสิ้นสุดกระบวนการก่อนหน้า โปรดดู
ActivityManager.getHistoricalProcessExitReasons
หากกระบวนการของแอปสิ้นสุดลงเนื่องจากปัญหาที่เกี่ยวข้องกับฟีเจอร์การหยุดแอปชั่วคราว เช่น
ได้รับธุรกรรม Binder แบบซิงโครนัสขณะที่แอปหยุดชั่วคราว ระบบจะตั้งค่าเหตุผลในการออกเป็น ApplicationExitInfo.REASON_FREEZER
การติดตาม Perfetto
ระบบจะปล่อยเหตุการณ์ที่เกี่ยวข้องกับ Freezer ไปยังแทร็กชื่อ Freezer ในกระบวนการ
system_server ในการติดตาม Perfetto ดังนี้
FreezeและUnfreezeแสดงเมื่อกระบวนการเปลี่ยนสถานะ- เหตุการณ์
updateAppFreezeStateLSPจะแสดงเมื่อเซิร์ฟเวอร์ของระบบตรวจสอบอีกครั้ง แอตทริบิวต์ของกระบวนการเพื่อตัดสินใจว่าจะหยุดชั่วคราวหรือยกเลิกการหยุดชั่วคราว
คุณตรวจสอบเหตุการณ์เหล่านี้ได้โดยตรงใน UI ของ Perfetto หรือวิเคราะห์โดยใช้ PerfettoSQL:
INCLUDE PERFETTO MODULE slices.with_context;
SELECT *
FROM process_slice
WHERE process_name = "system_server"
AND track_name = "Freezer"
AND (name LIKE "Freeze %" OR name LIKE "Unfreeze %");
ในไลบรารีมาตรฐาน PerfettoSQL เหตุการณ์การหยุดทำงานจะสรุปไว้ในตาราง
android_freezer_events ด้วย