Android 11 (cấp độ API 30) trở lên hỗ trợ tính năng đóng băng ứng dụng được lưu vào bộ nhớ đệm. Tính năng này dừng thực thi cho các quy trình được lưu vào bộ nhớ đệm và giảm mức sử dụng tài nguyên của các ứng dụng có hành vi sai trái có thể cố gắng hoạt động trong khi được lưu vào bộ nhớ đệm.
Tính năng đóng băng ứng dụng được lưu vào bộ nhớ đệm sẽ giữ các ứng dụng trong RAM trong khi vẫn tắt các ứng dụng đó trên CPU. Nếu Android xác định rằng một ứng dụng không nên thực hiện công việc nhưng có thể cần thiết trong tương lai, thì hệ thống sẽ đóng băng quy trình của ứng dụng thay vì chấm dứt quy trình đó. Điều này ngăn chặn quá trình khởi động nguội khi ứng dụng cần được dùng lại.
Android sẽ đóng băng các ứng dụng được lưu vào bộ nhớ đệm bằng cách di chuyển các quy trình của ứng dụng vào một cgroup đóng băng. Điều này giúp giảm mức tiêu thụ CPU ở trạng thái hoạt động và trạng thái rảnh khi có các ứng dụng đang hoạt động được lưu vào bộ nhớ đệm. Bạn có thể bật tính năng đóng băng ứng dụng bằng cờ cấu hình hệ thống hoặc lựa chọn dành cho nhà phát triển.
Trong Android 14 (cấp độ API 34) trở lên, tính năng đóng băng ứng dụng được lưu vào bộ nhớ đệm có những hành vi mạnh mẽ sau đây:
- Các quy trình ứng dụng ở trạng thái đã lưu vào bộ nhớ đệm sẽ bị đóng băng 10 giây sau khi chuyển sang trạng thái đã lưu vào bộ nhớ đệm.
- Hệ thống sẽ ngay lập tức giải phóng một quy trình ứng dụng bị đóng băng trong một sự kiện vòng đời. Các sự kiện này bao gồm việc nhận một ý định, bắt đầu một dịch vụ công việc hoặc người dùng tiếp tục một hoạt động.
ActivityManagerService quản lý tất cả các quy trình của ứng dụng và đưa ra quyết định về vòng đời của ứng dụng. CachedAppOptimizer chịu trách nhiệm làm treo quy trình ứng dụng.
Khi một quy trình ứng dụng bị đóng băng, tất cả các luồng của quy trình đó sẽ bị tạm ngưng và không thể thực hiện công việc trên CPU cho đến khi được giải phóng. Do đó, ứng dụng không thể thực hiện thu gom rác (GC) và không thể phản hồi các sự kiện giảm bộ nhớ. Để biết thêm thông tin, hãy xem ComponentCallbacks2.onTrimMemory(int). Để đáp ứng yêu cầu này, kể từ Android 14:
- Các ứng dụng có một phiên bản
Activityhiển thị sẽ được thông báo vềTRIM_MEMORY_UI_HIDDENngay khi chuyển sang nền. Những ứng dụng duy trì vòng đời mà không có giao diện người dùng, chẳng hạn như ứng dụng có dịch vụ nền trước, có thể nhận đượcTRIM_MEMORY_BACKGROUND. Các sự kiện cắt khác sẽ không được gửi vì khi đủ điều kiện nhận những sự kiện đó, các ứng dụng dự kiến sẽ bị đóng băng. - Ngay sau khi chuyển sang trạng thái đã lưu vào bộ nhớ đệm, hệ thống có thể yêu cầu thời gian chạy ứng dụng thực hiện một GC để chuẩn bị cho việc có thể bị đóng băng.
- Khi một quy trình ứng dụng bị đóng băng, các bước nén bộ nhớ bổ sung có thể xảy ra, chẳng hạn như ghi các trang có sửa đổi vào bộ nhớ dự phòng và hoán đổi các trang ẩn danh sang ZRAM.
- Nếu tất cả các quy trình cho một ứng dụng cụ thể bị đóng băng, hệ thống sẽ chấm dứt mọi ổ cắm TCP đang hoạt động do ứng dụng duy trì. Điều này ngăn phía máy chủ của ổ cắm gửi các lệnh ping TCP keepalive sẽ đánh thức modem của thiết bị.
Các quy trình ứng dụng được lưu vào bộ nhớ đệm sẽ được giải phóng khi trạng thái quy trình của chúng tăng từ trạng thái đã lưu vào bộ nhớ đệm lên trạng thái có mức độ quan trọng cao hơn. Để giảm các sự kiện giải phóng trong Android 14 trở lên, hệ thống sẽ đưa các tin truyền đã đăng ký theo bối cảnh vào hàng đợi trong khi ứng dụng ở trạng thái lưu vào bộ nhớ đệm. Tin truyền đã đăng ký theo bối cảnh là những receiver mà một ứng dụng đăng ký một cách linh động bằng cách gọi Context.registerReceiver. Hệ thống chỉ phân phối những tin truyền đã xếp hàng đợi này sau khi ứng dụng được rã đông. Ngược lại, hệ thống không đưa các tin truyền do tệp kê khai khai báo vào hàng đợi.
Các tin truyền do tệp kê khai khai báo là các receiver được khai báo tĩnh trong AndroidManifest.xml bằng phần tử <receiver>. Hệ thống sẽ ngay lập tức giải phóng ứng dụng đã lưu vào bộ nhớ đệm để phân phối các tin truyền do tệp kê khai khai báo.
Ảnh hưởng đến tình trạng hệ thống
Android sẽ chấm dứt quy trình ứng dụng được lưu vào bộ nhớ đệm ít được dùng gần đây nhất nếu có nhiều hơn MAX_CACHED_PROCESSES quy trình ứng dụng được lưu vào bộ nhớ đệm. Trên các thiết bị được hỗ trợ chạy Android 14 trở lên, MAX_CACHED_PROCESSES sẽ tăng lên đáng kể, cho phép các thiết bị duy trì nhiều quy trình ứng dụng được lưu vào bộ nhớ đệm hơn đáng kể trong RAM.
Việc duy trì nhiều ứng dụng được lưu vào bộ nhớ đệm trong RAM giúp giảm tới 30% số lượt khởi động nguội, với mức giảm tỷ lệ thuận với tổng dung lượng RAM của thiết bị. Đồng thời, mức tiêu thụ CPU của các ứng dụng được lưu vào bộ nhớ đệm sẽ giảm thiểu, giúp tiết kiệm pin đáng kể.
Trường hợp miễn trừ đối với tủ đông
Trong một số điều kiện nhất định, quy trình ứng dụng có thể chuyển sang trạng thái đã lưu vào bộ nhớ đệm nhưng vẫn không bị đóng băng. Những trường hợp ngoại lệ này là thông tin chi tiết về việc triển khai và có thể thay đổi trong các phiên bản Android sau này:
- Khoá tệp: Nếu một quy trình được lưu vào bộ nhớ đệm giữ một khoá tệp chặn các quy trình khác không được lưu vào bộ nhớ đệm, thì quy trình giữ khoá sẽ không bị đóng băng.
- Các liên kết
BIND_WAIVE_PRIORITY: Các quy trình ứng dụng có các liên kết đến được tạo bằngContext.BIND_WAIVE_PRIORITYcó thể chuyển sang trạng thái đã lưu vào bộ nhớ đệm nhưng vẫn không bị đóng băng cho đến khi tất cả các quy trình ứng dụng khách được kết nối cũng được lưu vào bộ nhớ đệm. Ngoại lệ này hỗ trợ các ứng dụng có nhiều quy trình, chẳng hạn như trình duyệt web sử dụng Thẻ tuỳ chỉnh.
Triển khai tính năng đóng băng ứng dụng
Trình đóng băng ứng dụng được lưu vào bộ nhớ đệm sử dụng trình đóng băng cgroup v2 của nhân. Các thiết bị đi kèm với một nhân tương thích có thể bật tính năng này. Bật tuỳ chọn cho nhà phát triển Suspend execution for cached apps (Tạm ngưng thực thi cho các ứng dụng được lưu vào bộ nhớ đệm) hoặc đặt cờ cấu hình thiết bị activity_manager_native_boot use_freezer thành true. Ví dụ:
adb shell device_config put activity_manager_native_boot use_freezer true && adb rebootTính năng đóng băng sẽ bị vô hiệu hoá khi bạn đặt cờ use_freezer thành false hoặc vô hiệu hoá lựa chọn cho nhà phát triển. Ví dụ:
adb shell device_config put activity_manager_native_boot use_freezer false && adb rebootBạn có thể bật/tắt chế độ cài đặt này bằng cách thay đổi cấu hình thiết bị trong bản phát hành hoặc bản cập nhật phần mềm.
Để ghi đè MAX_CACHED_PROCESSES, ví dụ: để đặt giá trị thành 1024 cho mục đích kiểm thử:
adb shell device_config put activity_manager max_cached_processes 1024adb shell device_config set_sync_disabled_for_tests persistent
Cách huỷ chế độ ghi đè MAX_CACHED_PROCESSES:
adb shell device_config delete activity_manager max_cached_processesadb shell device_config set_sync_disabled_for_tests none
Kể từ Android 16 (API cấp 36) trở lên, Android cung cấp các API công khai chính thức, chẳng hạn như IBinder.FrozenStateChangeCallback và IBinder.addFrozenStateChangeCallback, để theo dõi thời điểm các quy trình từ xa bị đóng băng hoặc không bị đóng băng. Các thành phần tương tác với những ứng dụng có thể được lưu vào bộ nhớ đệm có thể sử dụng các API này để theo dõi trạng thái đóng băng của các quy trình từ xa.
Yêu cầu về thiết bị và nhân
Tính năng đóng băng ứng dụng được lưu vào bộ nhớ đệm yêu cầu hỗ trợ cgroup v2 của nhân. Ngoài ra, các thông báo thay đổi trạng thái đóng băng bằng IBinder.FrozenStateChangeCallback yêu cầu hỗ trợ trình điều khiển liên kết nhân, đây là tiêu chuẩn trong Nhân chung của Android (ACK) và Hình ảnh nhân chung (GKI) bắt đầu từ Android 14 (API cấp 34) trở lên.
Bạn có thể xác minh xem một thiết bị có hỗ trợ các chức năng này hay không bằng cách sử dụng các lệnh adb tiêu chuẩn, như sau:
Kiểm tra xem ngăn chứa có được bật trên thiết bị hay không (đối với bản dựng người dùng hoặc bản gỡ lỗi):
adb shell device_config get activity_manager_native_boot use_freezerHoặc xác minh rằng hệ thống đang chủ động đóng băng các quy trình:
adb shell dumpsys activity | grep -A 20 "Apps frozen:"Kiểm tra khả năng hỗ trợ bộ điều khiển đóng băng cgroup v2 (cho mọi thiết bị):
Xác minh rằng
freezercó trong danh sách các bộ điều khiển cgroup v2 hiện có:adb shell cat /sys/fs/cgroup/cgroup.controllersNgoài ra, trên thiết bị bị can thiệp hệ thống hoặc bản dựng userdebug, hãy xác minh rằng nút cgroup v2 freezer được gắn trong một cgroup con:
adb root && adb shell ls /sys/fs/cgroup/uid_0/cgroup.freezeNếu tệp này tồn tại, tức là nhân hỗ trợ trình đóng băng cgroup phiên bản 2.
Kiểm tra khả năng hỗ trợ thông báo thay đổi trạng thái đóng băng (cho mọi thiết bị):
Trên các thiết bị chạy Android 14 trở lên có trình điều khiển trình liên kết Hình ảnh hạt nhân chung (GKI) tương thích,
IBinder.addFrozenStateChangeCallbackđăng ký thành công các lệnh gọi lại. Nếu trình điều khiển liên kết nhân cơ bản không hỗ trợ thông báo đóng băng, thì phương thức này sẽ gửiUnsupportedOperationException.
Xử lý các tính năng tuỳ chỉnh
Các quy trình của ứng dụng không được phép thực hiện bất kỳ thao tác nào khi được lưu vào bộ nhớ đệm, nhưng một số ứng dụng có thể có các tính năng tuỳ chỉnh được hỗ trợ bởi các quy trình dự kiến sẽ chạy trong khi được lưu vào bộ nhớ đệm. Khi trình đóng băng ứng dụng được bật trên một thiết bị đang chạy các ứng dụng như vậy, các quy trình được lưu vào bộ nhớ đệm sẽ bị đóng băng và có thể ngăn các tính năng tuỳ chỉnh hoạt động.
Để khắc phục, bạn có thể thay đổi trạng thái quy trình thành không lưu vào bộ nhớ đệm trước khi quy trình cần thực hiện bất kỳ thao tác nào. Thay đổi này giúp các ứng dụng vẫn hoạt động. Ví dụ về trạng thái hoạt động bao gồm dịch vụ nền trước được liên kết hoặc trạng thái nền trước.
Các chế độ lỗi thường gặp
Khi các quy trình của ứng dụng bị tạm ngưng, hoạt động giao tiếp liên quy trình (IPC) hoặc lập lịch tác vụ không đúng cách có thể dẫn đến việc ứng dụng bị chấm dứt hoặc có hành vi không mong muốn.
Giao dịch Trình liên kết đồng bộ với các quy trình bị tạm dừng
Khi một quy trình ứng dụng khách gửi một giao dịch binder đồng bộ đến một quy trình ứng dụng máy chủ bị đóng băng, hệ thống sẽ ngay lập tức chấm dứt quy trình ứng dụng máy chủ. Điều này ngăn luồng ứng dụng chặn vô thời hạn trong khi chờ phản hồi từ máy chủ bị treo. Sau đó, luồng ứng dụng sẽ nhận được RemoteException và mọi trình nghe đã đăng ký đều được kích hoạt. Để biết thêm thông tin, hãy xem IBinder.linkToDeath.
Nguyên nhân gốc: Lỗi này thường là do một lỗi trong ứng dụng khách. Khi một ứng dụng khách liên kết với một dịch vụ, quy trình máy chủ sẽ được liên kết với ứng dụng khách và không được phép chuyển sang trạng thái được lưu vào bộ nhớ đệm trước khi ứng dụng khách thực hiện. Để biết thêm thông tin, hãy xem Context.bindService. Tuy nhiên, sau khi ứng dụng gọi Context.unbindService, quy trình máy chủ có thể được lưu vào bộ nhớ đệm và bị đóng băng. Nếu tiếp tục sử dụng tham chiếu IBinder được lưu vào bộ nhớ đệm sau khi huỷ liên kết, ứng dụng có nguy cơ giao tiếp với một quy trình bị treo.
Để tránh vấn đề này, hãy đảm bảo các ứng dụng khách loại bỏ các tham chiếu IBinder ngay sau khi gọi Context.unbindService.
Quản lý lệnh gọi lại từ xa đến các quy trình của ứng dụng
Các dịch vụ và thành phần hệ thống duy trì lệnh gọi lại trình liên kết có thời gian tồn tại lâu dài cho các quy trình ứng dụng có thể ngăn chặn lỗi đồng bộ và tràn bộ nhớ đệm không đồng bộ bằng cách theo dõi trạng thái đóng băng của ứng dụng:
- Đăng ký trình nghe thay đổi trạng thái: Sử dụng
IBinder.addFrozenStateChangeCallbacktrên các mã thông báo trình liên kết ứng dụng khách đến để nhận thông báo khi quy trình ứng dụng khách chuyển sang hoặc thoát khỏi trạng thái đóng băng. - Tạm dừng gửi khi bị đóng băng: Khi một ứng dụng khách nhập
STATE_FROZEN, hãy tạm dừng gửi các lệnh gọi lại hoặc bản cập nhật trạng thái cho ứng dụng khách đó. - Tiếp tục và phân phối khi huỷ đóng băng: Khi ứng dụng chuyển sang
STATE_UNFROZEN, hãy tiếp tục gửi lệnh gọi lại và phân phối mọi bản cập nhật theo lô hoặc bản cập nhật hợp nhất cần thiết. - Sử dụng RemoteCallbackList: Các dịch vụ hệ thống sử dụng
RemoteCallbackListcó thể định cấu hình các chính sách hàm được gọi bị đóng băng để tự động tạm dừng và tiếp tục gửi lệnh gọi lại mà không cần duy trì logic theo dõi thủ công. Để biết thêm thông tin, hãy xem bài viết Đề xuất về trình liên kết cho các dịch vụ hệ thống.
Tràn bộ đệm giao dịch trình liên kết không đồng bộ
Khi một quy trình ứng dụng máy chủ nhận được các giao dịch liên kết không đồng bộ (oneway) trong khi bị đóng băng, các giao dịch sẽ được lưu vào bộ nhớ đệm theo từng quy trình. Nếu máy chủ nhận được quá nhiều giao dịch không đồng bộ trong khi bị đóng băng, thì bộ nhớ đệm sẽ tràn và hệ thống sẽ chấm dứt quy trình ứng dụng máy chủ.
Để ngăn chặn tình trạng tràn vùng đệm này, hãy tránh gửi quá nhiều giao dịch trình liên kết không đồng bộ đến các quy trình có thể được lưu vào bộ nhớ đệm hoặc bị đóng băng.
Thực hiện lặp lại các tác vụ theo lịch sau khi bỏ đóng băng
Nếu một ứng dụng thực hiện các tác vụ lặp lại, thì các tác vụ đó sẽ bị tạm ngưng trong khi quy trình bị đóng băng. Để biết thêm thông tin, hãy xem ScheduledThreadPoolExecutor.scheduleAtFixedRate hoặc Timer.scheduleAtFixedRate. Khi quy trình ngừng đóng băng, các lần thực thi bị bỏ lỡ tích luỹ có thể chạy liên tục mà hầu như không có độ trễ.
Để ngăn chặn tình trạng tăng đột biến số lần thực thi khi ứng dụng ngừng đóng băng, hãy dùng scheduleWithFixedDelay thay vì scheduleAtFixedRate cho các tác vụ ở chế độ nền. Bạn cũng có thể dùng WorkManager.
Kiểm thử và khắc phục sự cố liên quan đến tính năng đóng băng ứng dụng
Để xác minh xem app freezer có hoạt động như dự kiến hay không hoặc để khắc phục các vấn đề liên quan đến freezer, hãy sử dụng các công cụ và lệnh chẩn đoán sau:
Các lệnh của trình quản lý hoạt động
Bạn có thể dùng các lệnh adb shell am để kiểm soát thủ công việc đóng băng và nén cho một quy trình cụ thể:
Buộc một quy trình bị treo:
adb shell am freeze <process>Buộc một quy trình hủy cố định:
adb shell am unfreeze <process>Buộc một quy trình nén bộ nhớ đầy đủ:
adb shell am compact full <process>
Kiểm tra Logcat
Xem logcat để xem các mục nhập bị đóng băng và không bị đóng băng mỗi khi một quy trình di chuyển vào hoặc ra khỏi trình đóng băng:
adb logcat | grep -i "\(freezing\|froze\)"Đầu ra nhật ký lý do huỷ đóng băng liệt kê các giá trị từ enum bộ đệm giao thức UnfreezeReason.
Kiểm tra dumpsys
Kiểm tra danh sách các quy trình bị treo bằng cách sử dụng dumpsys activity:
adb shell dumpsys activity | grep -A 20 "Apps frozen:"Kiểm tra xem có tệp /sys/fs/cgroup/uid_0/cgroup.freeze hay không.
ApplicationExitInfo
Để truy vấn lý do chấm dứt quy trình trước đó, hãy xem ActivityManager.getHistoricalProcessExitReasons.
Nếu một quy trình ứng dụng bị chấm dứt do vấn đề liên quan đến trình kết xuất, chẳng hạn như nhận giao dịch liên kết đồng bộ trong khi bị kết xuất, thì lý do thoát sẽ được đặt thành ApplicationExitInfo.REASON_FREEZER.
Theo dõi Perfetto
Các sự kiện liên quan đến tính năng đóng băng được phát ra một dấu vết có tên là Freezer trong quy trình system_server trong dấu vết Perfetto:
- Các lát
FreezevàUnfreezecho biết thời điểm một quy trình thay đổi trạng thái. - Các sự kiện
updateAppFreezeStateLSPcho biết thời điểm máy chủ hệ thống kiểm tra lại các thuộc tính của quy trình để đưa ra quyết định đóng băng hoặc giải phóng.
Bạn có thể kiểm tra trực tiếp các sự kiện này trong giao diện người dùng Perfetto hoặc phân tích chúng bằng 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 %");
Trong thư viện chuẩn PerfettoSQL, các sự kiện đóng băng cũng được tóm tắt trong bảng android_freezer_events.