Tái cấu trúc RIL

Android 7.0 đã tái cấu trúc Lớp giao diện vô tuyến (RIL) bằng cách sử dụng một bộ tính năng để cải thiện chức năng RIL. Bạn bắt buộc phải thay đổi mã đối tác để triển khai các tính năng này. Tuy không bắt buộc nhưng bạn nên triển khai. Các thay đổi tái cấu trúc tương thích ngược, vì vậy, các phương thức triển khai trước đây của các tính năng được tái cấu trúc vẫn tiếp tục hoạt động.

Việc tái cấu trúc RIL bao gồm những điểm cải tiến sau:

  • Mã lỗi RIL. Cho phép các mã lỗi cụ thể ngoài mã GENERIC_FAILURE hiện có. Điều này giúp khắc phục lỗi bằng cách cung cấp thông tin cụ thể hơn về nguyên nhân gây ra lỗi.
  • Định phiên bản RIL. Cung cấp thông tin phiên bản chính xác và dễ định cấu hình hơn.
  • Giao tiếp RIL bằng cách sử dụng khoá ở chế độ thức. Cải thiện hiệu suất pin của thiết bị.

Bạn có thể triển khai một hoặc tất cả các điểm cải tiến nêu trên. Để biết thêm thông tin chi tiết, hãy tham khảo phần bình luận về mã liên quan đến việc tạo phiên bản RIL trong https://android.googlesource.com/platform/hardware/ril/+/android16-release/include/telephony/ril.h.

Triển khai mã lỗi RIL nâng cao

Hầu hết các lệnh gọi yêu cầu RIL đều có thể trả về mã lỗi GENERIC_FAILURE để phản hồi lỗi. Đây là vấn đề với tất cả các phản hồi được yêu cầu do OEM trả về. Vấn đề này có thể gây khó khăn cho việc gỡ lỗi từ báo cáo lỗi nếu các lệnh gọi RIL trả về cùng một mã lỗi GENERIC_FAILURE vì nhiều lý do. Có thể mất khá nhiều thời gian để các nhà cung cấp xác định xem phần nào của mã có thể đã trả về mã GENERIC_FAILURE.

Trong Android 7.x trở lên, các OEM có thể trả về một giá trị mã lỗi riêng biệt được liên kết với từng lỗi khác nhau hiện được phân loại là GENERIC_FAILURE. Những OEM không muốn công khai mã lỗi tuỳ chỉnh của mình có thể trả về lỗi dưới dạng một tập hợp riêng biệt gồm các số nguyên (chẳng hạn như từ 1 đến x) được ánh xạ dưới dạng OEM_ERROR_1 đến OEM_ERROR_X. Các nhà cung cấp phải đảm bảo mỗi mã lỗi được che giấu như vậy được trả về sẽ liên kết với một lý do lỗi riêng biệt trong mã. Việc sử dụng mã lỗi cụ thể có thể tăng tốc quá trình gỡ lỗi RIL bất cứ khi nào OEM trả về lỗi chung, vì thường mất quá nhiều thời gian để xác định nguyên nhân chính xác của mã lỗi GENERIC_FAILURE (và đôi khi không thể tìm ra).

Ngoài ra, ril.h sẽ thêm nhiều mã lỗi hơn cho các enum RIL_LastCallFailCauseRIL_DataCallFailCause để mã nhà cung cấp có thể tránh trả về các lỗi chung như CALL_FAIL_ERROR_UNSPECIFIEDPDP_FAIL_ERROR_UNSPECIFIED.

Xác thực mã lỗi RIL nâng cao

Sau khi thêm mã lỗi mới để thay thế mã GENERIC_FAILURE, hãy xác minh rằng lệnh gọi RIL trả về mã lỗi mới thay vì GENERIC_FAILURE.

Triển khai tính năng lập phiên bản RIL nâng cao

Việc lập phiên bản RIL trong các bản phát hành Android cũ có vấn đề: bản thân phiên bản này không chính xác, cơ chế báo cáo phiên bản RIL không rõ ràng (khiến một số nhà cung cấp báo cáo phiên bản không chính xác) và giải pháp ước tính phiên bản dễ bị không chính xác.

Trong Android 7.x trở lên, ril.h ghi lại tất cả các giá trị phiên bản RIL, mô tả phiên bản RIL tương ứng và liệt kê tất cả các thay đổi cho phiên bản đó. Khi thực hiện các thay đổi tương ứng với một phiên bản RIL, các nhà cung cấp phải cập nhật phiên bản của họ trong mã và trả về phiên bản đó trong RIL_REGISTER.

Xác thực việc tạo phiên bản RIL nâng cao

Xác minh rằng phiên bản RIL tương ứng với mã RIL của bạn được trả về trong RIL_REGISTER (thay vì RIL_VERSION được xác định trong ril.h).

Triển khai giao tiếp RIL bằng cách sử dụng wakelock

Wakelock có thời gian chờ được dùng trong giao tiếp RIL theo cách không chính xác, điều này ảnh hưởng tiêu cực đến hiệu suất pin. Trong Android 7.x trở lên, bạn có thể cải thiện hiệu suất bằng cách phân loại các yêu cầu RIL và cập nhật mã để xử lý các wakelock theo cách khác nhau cho các loại yêu cầu khác nhau.

Phân loại yêu cầu RIL

Yêu cầu RIL có thể là yêu cầu được yêu cầu hoặc không được yêu cầu. Nhà cung cấp nên phân loại thêm các yêu cầu được chào mời là một trong những yêu cầu sau:

  • đồng bộ. Những yêu cầu không mất nhiều thời gian để phản hồi. Ví dụ: RIL_REQUEST_GET_SIM_STATUS.
  • không đồng bộ. Các yêu cầu mất nhiều thời gian để phản hồi. Ví dụ: RIL_REQUEST_QUERY_AVAILABLE_NETWORKS.

Các yêu cầu RIL không đồng bộ có thể mất khá nhiều thời gian. Sau khi nhận được tín hiệu xác nhận từ mã nhà cung cấp, RIL Java sẽ giải phóng wakelock. Điều này có thể khiến bộ xử lý ứng dụng chuyển từ trạng thái rảnh sang trạng thái tạm ngưng. Khi phản hồi có sẵn từ mã nhà cung cấp, RIL Java (trình xử lý ứng dụng) sẽ lấy lại wakelock, xử lý phản hồi, sau đó quay lại trạng thái rảnh. Việc chuyển từ trạng thái không hoạt động sang trạng thái tạm ngưng rồi lại sang trạng thái không hoạt động có thể tiêu tốn nhiều năng lượng.

Nếu thời gian phản hồi không đủ dài, việc giữ wakelock và duy trì trạng thái rảnh trong toàn bộ thời gian cần thiết để phản hồi có thể tiết kiệm pin hơn so với việc chuyển sang trạng thái tạm ngưng bằng cách giải phóng wakelock và đánh thức khi nhận được phản hồi. Nhà cung cấp nên sử dụng các phép đo nguồn điện dành riêng cho nền tảng để xác định giá trị ngưỡng của thời gian T khi nguồn điện tiêu thụ khi ở trạng thái nhàn rỗi trong toàn bộ thời gian T lớn hơn nguồn điện tiêu thụ khi chuyển từ trạng thái nhàn rỗi sang trạng thái tạm ngưng và sang trạng thái nhàn rỗi trong cùng thời gian T. Khi biết thời gian T, các lệnh RIL mất nhiều thời gian hơn T có thể được phân loại là không đồng bộ và các lệnh còn lại được phân loại là đồng bộ.

Các trường hợp giao tiếp RIL

Các sơ đồ sau đây minh hoạ các tình huống giao tiếp RIL phổ biến và đưa ra giải pháp để sửa đổi mã nhằm xử lý các yêu cầu được và không được yêu cầu RIL.

Lưu ý: Để biết thông tin chi tiết về cách triển khai các hàm được dùng trong các sơ đồ sau, hãy tham khảo các phương thức acquireWakeLock(), decrementWakeLock()clearWakeLock( trong ril.cpp.

Tình huống: Yêu cầu RIL và phản hồi không đồng bộ được yêu cầu

Trong trường hợp này, nếu phản hồi được yêu cầu của RIL dự kiến sẽ mất nhiều thời gian (tức là phản hồi cho RIL_REQUEST_GET_AVAILABLE_NETWORKS), thì wakelock sẽ được giữ trong thời gian dài ở phía bộ xử lý ứng dụng. Sự cố về modem cũng có thể khiến bạn phải chờ đợi lâu.

Hình 1. RIL đã yêu cầu phản hồi không đồng bộ.

Giải pháp 1: Modem giữ wakelock cho yêu cầu RIL và phản hồi không đồng bộ.

Hình 2. Chế độ thức do modem giữ.
  1. Yêu cầu RIL được gửi và modem sẽ nhận được wakelock để xử lý yêu cầu đó.
  2. Modem gửi tín hiệu xác nhận khiến phía Java giảm bộ đếm wakelock và giải phóng bộ đếm này khi giá trị bộ đếm là 0.

    Lưu ý: Khoảng thời gian chờ wakelock cho chuỗi yêu cầu-xác nhận sẽ nhỏ hơn khoảng thời gian chờ hiện đang được sử dụng vì tín hiệu xác nhận sẽ được nhận khá nhanh.

  3. Sau khi xử lý yêu cầu, modem sẽ gửi một tín hiệu ngắt đến mã nhà cung cấp để lấy wakelock và gửi phản hồi đến ril.cpp. Sau đó, ril.cpp sẽ lấy wakelock và gửi phản hồi đến phía Java.
  4. Khi phản hồi đến phía Java, wakelock sẽ được thu thập và phản hồi sẽ được trả về cho người gọi.
  5. Sau khi tất cả các mô-đun xử lý phản hồi, thông báo xác nhận sẽ được gửi (thông qua ổ cắm) trở lại ril.cpp. Sau đó, ril.cpp sẽ giải phóng wakelock thu được ở bước 3.

Giải pháp 2: Modem không giữ wakelock và phản hồi nhanh (yêu cầu và phản hồi RIL đồng bộ). Hành vi đồng bộ so với hành vi không đồng bộ được mã hoá cứng cho một lệnh RIL cụ thể và được quyết định trên cơ sở từng lệnh gọi.

Hình 3. Modem không giữ wakelock.
  1. Yêu cầu RIL được gửi bằng cách gọi acquireWakeLock() ở phía Java.
  2. Mã nhà cung cấp không cần có wakelock và có thể xử lý yêu cầu cũng như phản hồi nhanh chóng.
  3. Khi phản hồi được phía Java nhận, decrementWakeLock() sẽ được gọi, thao tác này sẽ giảm bộ đếm wakelock và giải phóng wakelock nếu giá trị bộ đếm là 0.

Tình huống: Phản hồi không mong muốn của RIL

Trong trường hợp này, các phản hồi không mong muốn của RIL có một cờ loại wakelock trong đó cho biết liệu có cần thu được wakelock cho phản hồi của nhà cung cấp hay không. Nếu cờ được đặt, thì wakelock có thời gian sẽ được đặt và phản hồi sẽ được gửi qua một ổ cắm đến phía Java. Khi hết thời gian, wakelock sẽ được giải phóng. Thời gian đánh thức theo thời gian có thể quá dài hoặc quá ngắn đối với các phản hồi không mong muốn của RIL.

Hình 4. Phản hồi không mong muốn của RIL.

Giải pháp: Một tín hiệu xác nhận được gửi từ mã Java đến phía gốc (ril.cpp) thay vì giữ một wakelock có thời gian ở phía gốc trong khi gửi một phản hồi không được yêu cầu.

Hình 5. Sử dụng ack thay vì timed wakelock.

Xác thực wakelock được thiết kế lại

Xác minh rằng các lệnh gọi RIL được xác định là đồng bộ hay không đồng bộ. Vì mức tiêu thụ pin có thể phụ thuộc vào phần cứng/nền tảng, nên các nhà cung cấp cần tiến hành một số thử nghiệm nội bộ để tìm hiểu xem việc sử dụng ngữ nghĩa wakelock mới cho các lệnh gọi không đồng bộ có giúp tiết kiệm pin hay không.