Lỗi với khoá chế độ thức một phần

Khoá chế độ thức một phần là cơ chế trong PowerManager API cho phép các nhà phát triển tiếp tục chạy CPU sau khi màn hình của thiết bị tắt (cho dù do hệ thống hết thời gian chờ hay người dùng nhấn nút nguồn). Ứng dụng của bạn sử dụng tính năng khoá chế độ thức một phần bằng cách gọi acquire() với cờ PARTIAL_WAKE_LOCK. Khoá chế độ thức một phần sẽ bị lỗi nếu nó bị khoá trong thời gian dài khi ứng dụng đang chạy ở chế độ nền (nghĩa là người dùng không thể nhìn thấy phần nào của ứng dụng). Tình trạng này sẽ làm tiêu hao pin của thiết bị vì nó ngăn thiết bị chuyển sang trạng thái nguồn thấp hơn. Bạn chỉ nên sử dụng khoá chế độ thức một phần khi cần thiết và mở khoá ngay khi không còn cần dùng nữa.

Nếu ứng dụng của bạn bị lỗi một phần khoá chế độ thức, bạn có thể sử dụng hướng dẫn trong trang này để chẩn đoán và khắc phục sự cố.

Phát hiện vấn đề

Không phải lúc nào bạn cũng biết khóa chế độ thức một phần trong ứng dụng của mình bị lỗi. Nếu bạn đã phát hành ứng dụng, thì Android vitals có thể giúp bạn nhận biết được vấn đề đó.

Android vitals

Android vitals có thể giúp cải thiện hiệu suất của ứng dụng bằng cách cảnh báo cho bạn qua Play Console khi ứng dụng của bạn đang ở trạng thái lỗi với khoá chế độ thức một phần. Android vitals báo cáo khoá chế độ thức một phần gặp lỗi khi chế độ này kéo dài trong thời gian ít nhất một tiếng trong một phiên pin

Định nghĩa về phiên pin là tuỳ theo phiên bản nền tảng.

  • Trong Android 10, phiên pin là tổng hợp của tất cả các báo cáo pin nhận được trong khoảng thời gian 24 giờ nhất định. Báo cáo về pin được tính trong khoảng thời gian giữa hai lần sạc pin, kể cả khi sạc từ dưới 20% đến trên 80% hoặc từ bất kỳ mức sạc nào đến 100%.
  • Trong Android 11, phiên pin là khoảng thời gian 24 giờ cố định.

Số phiên pin hiển thị là số liệu tổng hợp của tất cả người dùng được đo lường trong ứng dụng. Để biết thêm thông tin về cách Google Play thu thập dữ liệu Android vitals, vui lòng xem tài liệu Play Console.

Khi tính năng khoá chế độ thức một phần trên ứng dụng lỗi quá nhiều lần, việc tiếp theo bạn cần làm là nhanh chóng giải quyết vấn đề.

Khắc phục vấn đề

Tính năng khóa chế độ thức đã được ra mắt trong các phiên bản đầu tiền của nền tảng Android, nhưng theo thời gian, nhiều trường hợp sử dụng khóa chế độ thức được yêu cầu trước đó nay đã hoàn thiện hơn nhờ các API mới hơn, chẳng hạn như WorkManager.

Phần này sẽ nói về các mẹo để khắc phục lỗi khoá chế độ thức, nhưng về lâu dài, hãy cân nhắc di chuyển ứng dụng của bạn theo các đề xuất ở phần các phương pháp hay nhất.

Xác định và sửa các vị trí trong mã có được khoá chế độ thức, chẳng hạn như các lệnh gọi đến newWakeLock(int, String) hoặc các lớp con WakefulBroadcastReceiver. Sau đây là một số mẹo:

  • Bạn nên đưa tên gói, lớp hoặc phương thức vào tên thẻ khoá chế độ thức để có thể dễ dàng xác định vị trí tạo khoá chế độ thức trong mã nguồn. Dưới đây là một số mẹo bổ sung:
    • Bỏ mọi thông tin nhận dạng cá nhân (PII) trong tên, chẳng hạn như địa chỉ email. Nếu không, thiết bị sẽ ghi nhật ký _UNKNOWN thay vì tên khoá chế độ thức.
    • Đừng dùng tên lớp hoặc phương thức thông qua mã, chẳng hạn như gọi getName(), vì điều này có thể khiến Proguard làm rối mã nguồn. Thay vào đó, hãy dùng một chuỗi được mã hoá cứng.
    • Đừng thêm bộ đếm hoặc giá trị nhận dạng duy nhất vào thẻ khoá chế độ thức. Hệ thống sẽ không thể tổng hợp các khoá chế độ thức được tạo bằng cùng một phương thức vì tất cả đều có giá trị nhận dạng riêng biệt.
  • Hãy đảm bảo mã của bạn huỷ bỏ tất cả khoá chế độ thức mà nó nhận được. Điều này phức tạp hơn so với việc đảm bảo mỗi lệnh gọi đến acquire() đều có lệnh gọi tương ứng đến release(). Dưới đây là ví dụ về một khoá chế độ thức không được phát hành do trường hợp ngoại lệ chưa được giải quyết:

    Kotlin

    @Throws(MyException::class)
    fun doSomethingAndRelease() {
        wakeLock.apply {
            acquire()
            doSomethingThatThrows()
            release()  // does not run if an exception is thrown
        }
    }

    Java

        void doSomethingAndRelease() throws MyException {
            wakeLock.acquire();
            doSomethingThatThrows();
            wakeLock.release();  // does not run if an exception is thrown
        }

    Dưới đây là phiên bản chính xác của mã:

    Kotlin

    @Throws(MyException::class)
    fun doSomethingAndRelease() {
        wakeLock.apply {
            try {
                acquire()
                doSomethingThatThrows()
            } finally {
                release()
            }
        }
    }

    Java

        void doSomethingAndRelease() throws MyException {
            try {
                wakeLock.acquire();
                doSomethingThatThrows();
            } finally {
                wakeLock.release();
            }
        }
  • Hãy đảm bảo khoá chế độ thức bị huỷ bỏ ngay khi không còn cần thiết nữa. Chẳng hạn như nếu bạn đang sử dụng khoá chế độ thức để cho phép hoàn thành một tác vụ ở chế độ nền, hãy đảm bảo quá trình huỷ bỏ đó diễn ra ngay khi kết thúc tác vụ. Nếu khoá chế độ thức được giữ lâu hơn dự kiến mà không bị huỷ bỏ, điều này có thể có nghĩa là tác vụ chạy trong nền của bạn mất nhiều thời gian hơn dự kiến.

Sau khi khắc phục sự cố về mã, hãy xác minh là ứng dụng của bạn phát hành khóa chế độ thức chính xác bằng cách sử dụng các công cụ Android sau:

  • dumpsys – một công cụ cung cấp thông tin về trạng thái của các dịch vụ hệ thống trên một thiết bị. Để xem trạng thái của dịch vụ nguồn, bao gồm danh sách các khóa chế độ thức, hãy chạy adb shell dumpsys power.

  • Battery Historian – một công cụ phân tích cú pháp kết quả của báo cáo lỗi trên Android thành một bảng trình bày hình ảnh về các sự kiện liên quan đến nguồn điện.

Các phương pháp hay nhất

Nhìn chung, ứng dụng của bạn nên tránh sử dụng chức năng khóa chế độ thức một phần, vì việc này quá dễ làm tiêu hao pin của người dùng. Android cung cấp các API thay thế cho hầu hết mọi trường hợp sử dụng trước đây đòi hỏi khoá chế độ thức một phần. Một trường hợp sử dụng nữa đối với khoá chế độ thức một phần là để đảm bảo ứng dụng âm nhạc tiếp tục được phát khi màn hình tắt. Nếu bạn đang sử dụng khoá chế độ thức để chạy tác vụ, hãy xem xét các lựa chọn thay thế được mô tả trong hướng dẫn xử lý cho chế độ nền.

Nếu bạn phải sử dụng tính năng khóa chế độ thức một phần, hãy làm theo các đề xuất sau:

  • Đảm bảo một số phần ứng dụng của bạn vẫn nằm ở nền trước. Chẳng hạn nếu bạn cần chạy một dịch vụ, hãy bắt đầu dịch vụ đó trên nền trước. Thông tin này sẽ được hiển thị cho người dùng để họ biết ứng dụng của bạn vẫn đang chạy.
  • Hãy đảm bảo các logic thu nạp và hủy bỏ khóa chế độ thức đơn giản nhất có thể. Khi logic khóa chế độ thức liên kết với các máy có trạng thái phức tạp, thời gian chờ, nhóm thực thi và/hoặc sự kiện gọi lại, thì bất kỳ lỗi nhỏ nào trong logic đó cũng có thể khiến khóa chế độ thức bị giữ lâu hơn dự kiến. Những lỗi này rất khó để chẩn đoán và gỡ lỗi.