Lý do khởi động theo chuẩn

Android 9 có các thay đổi sau đây đối với quy cách lý do khởi động của trình tải khởi động.

Lý do khởi động

Trình tải khởi động sử dụng các tài nguyên bộ nhớ và phần cứng có sẵn riêng biệt để xác định lý do thiết bị khởi động lại, sau đó thông báo quyết định đó bằng cách thêm androidboot.bootreason=<reason> vào dòng lệnh hạt nhân Android để khởi chạy. Sau đó, init sẽ dịch dòng lệnh này để truyền đến thuộc tính Android bootloader_boot_reason_prop (ro.boot.bootreason). Đối với các thiết bị khởi chạy bằng Android 12 trở lên, sử dụng hạt nhân phiên bản 5.10 trở lên, androidboot.bootreason=<reason> sẽ được thêm vào bootconfig thay vì dòng lệnh hạt nhân.

Thông số kỹ thuật về lý do khởi động

Các bản phát hành trước đây của Android đã chỉ định định dạng lý do khởi động không sử dụng dấu cách, tất cả đều là chữ thường, kèm theo một số yêu cầu (chẳng hạn như đối với báo cáo kernel_panic, watchdog, cold/warm/hard) và định dạng cho phép vì những lý do riêng biệt khác. Thông số kỹ thuật lỏng lẻo này đã dẫn đến việc hàng trăm chuỗi lý do khởi động tuỳ chỉnh (và đôi khi vô nghĩa) xuất hiện, từ đó dẫn đến một tình huống không thể quản lý. Kể từ bản phát hành Android hiện tại, động lực thuần tuý của nội dung gần như không thể phân tích cú pháp hoặc vô nghĩa do trình tải khởi động gửi đã tạo ra các vấn đề về việc tuân thủ đối với bootloader_boot_reason_prop.

Với bản phát hành Android 9, nhóm Android nhận thấy rằng bootloader_boot_reason_prop cũ có động lực đáng kể và không thể viết lại trong thời gian chạy. Do đó, mọi điểm cải tiến đối với thông số kỹ thuật về lý do khởi động phải đến từ các hoạt động tương tác với nhà phát triển trình tải khởi động và các điều chỉnh đối với hệ thống hiện có. Để đạt được mục tiêu đó, nhóm Android sẽ:

  • Tương tác với các nhà phát triển trình tải khởi động để khuyến khích họ:
    • Cung cấp lý do chính thống, có thể phân tích cú pháp và dễ nhận biết cho bootloader_boot_reason_prop.
    • Tham gia danh sách system/core/bootstat/bootstat.cpp kBootReasonMap.
  • Thêm một nguồn được kiểm soát và có thể ghi lại trong thời gian chạy của system_boot_reason_prop (sys.boot.reason). Một nhóm ứng dụng hệ thống có giới hạn (chẳng hạn như bootstatinit) có thể ghi lại thuộc tính này, nhưng tất cả ứng dụng đều có thể được cấp quyền sepolicy để đọc thuộc tính này.
  • Thông báo cho người dùng về lý do khởi động phải đợi cho đến khi dữ liệu người dùng được kết nối rồi mới tin tưởng nội dung trong thuộc tính lý do khởi động hệ thống system_boot_reason_prop.

Tại sao lại trễ vậy? Mặc dù bootloader_boot_reason_prop có sẵn trong quá trình khởi động, nhưng chính sách bảo mật của Android sẽ chặn bootloader_boot_reason_prop khi cần vì bootloader_boot_reason_prop đại diện cho thông tin không chính xác, không phân tích cú pháp và không chuẩn. Trong hầu hết các trường hợp, chỉ những nhà phát triển có kiến thức chuyên sâu về hệ thống khởi động mới cần truy cập vào thông tin này. Bạn chỉ có thể chọn một API tinh tế, có thể phân tích cú pháp và chuẩn hoá cho lý do khởi động bằng system_boot_reason_prop một cách đáng tin cậy và chính xác sau khi dữ liệu người dùng được gắn. Cụ thể:

  • Trước khi userdata được gắn, system_boot_reason_prop sẽ chứa giá trị từ bootloader_boot_reason_prop.
  • Sau khi dữ liệu người dùng được gắn kết, system_boot_reason_prop có thể được cập nhật để tuân thủ chính sách hoặc để báo cáo thông tin chính xác hơn.

Vì lý do này, Android 9 kéo dài khoảng thời gian trước khi có thể thu thập chính thức lý do khởi động, thay đổi từ việc ngay lập tức chính xác trong quá trình khởi động (với bootloader_boot_reason_prop) thành chỉ có sẵn sau khi userdata được gắn (với system_boot_reason_prop).

Logic Bootstat phụ thuộc vào một bootloader_boot_reason_prop tuân thủ và cung cấp nhiều thông tin hơn. Khi thuộc tính đó sử dụng định dạng có thể dự đoán, thuộc tính đó sẽ cải thiện độ chính xác của tất cả các trường hợp khởi động lại và tắt được kiểm soát, từ đó tinh chỉnh và mở rộng độ chính xác cũng như ý nghĩa của system_boot_reason_prop.

Định dạng lý do khởi động chuẩn

Định dạng lý do khởi động chuẩn cho bootloader_boot_reason_prop trong Android 9 sử dụng cú pháp sau:

<reason>,<subreason>,<detail>…

Quy tắc định dạng:

  • Chữ thường
  • Không có khoảng trống (sử dụng dấu gạch chân)
  • Tất cả ký tự in được
  • reason, subreason và một hoặc nhiều thực thể detail được phân tách bằng dấu phẩy.
    • reason bắt buộc thể hiện lý do có mức độ ưu tiên cao nhất khiến thiết bị phải khởi động lại hoặc tắt.
    • subreason không bắt buộc, trình bày tóm tắt ngắn gọn lý do thiết bị phải khởi động lại hoặc tắt (hoặc người đã khởi động lại hoặc tắt thiết bị).
    • Một hoặc nhiều giá trị detail không bắt buộc. detail có thể trỏ đến một hệ thống phụ để hỗ trợ việc xác định hệ thống cụ thể nào đã dẫn đến subreason. Bạn có thể chỉ định nhiều giá trị detail, thường tuân theo hệ thống phân cấp theo mức độ quan trọng. Tuy nhiên, bạn cũng có thể báo cáo nhiều giá trị detail có tầm quan trọng như nhau.

Giá trị trống cho bootloader_boot_reason_prop được coi là bất hợp pháp (vì điều này cho phép các tác nhân khác chèn lý do khởi động sau khi thực tế).

Yêu cầu về lý do

Giá trị được cung cấp cho reason (span đầu tiên, trước dấu chấm hoặc dấu phẩy) phải thuộc tập hợp sau đây, được chia thành các lý do chính, mạnh và thẳng thắn:

  • bộ nhân hệ điều hành:
    • "watchdog"
    • "kernel_panic"
  • tập hợp mạnh:
    • "recovery"
    • "bootloader"
  • bộ blunt:
    • "cold". Nói chung, biểu tượng này cho biết tất cả thiết bị đã được đặt lại hoàn toàn, bao gồm cả bộ nhớ.
    • "hard". Thường cho biết phần cứng đã đặt lại trạng thái và ramoops sẽ giữ lại nội dung ổn định.
    • "warm". Thường thì biểu thị bộ nhớ và các thiết bị giữ lại một số trạng thái và kho lưu trữ sao lưu ramoops (xem trình điều khiển pstore trong nhân) chứa nội dung cố định.
    • "shutdown"
    • "reboot". Nói chung, có nghĩa là không xác định được trạng thái của ramoops và không xác định được trạng thái phần cứng. Giá trị này là một giá trị tổng hợp vì các giá trị cold, hardwarm cung cấp các gợi ý về chiều sâu của quá trình đặt lại thiết bị.

Trình tải khởi động phải cung cấp một nhóm hạt nhân hoặc một nhóm cùn reason, và bạn nên cung cấp một subreason nếu có thể xác định được. Ví dụ: thao tác nhấn và giữ phím nguồn có thể có hoặc không có bản sao lưu ramoops sẽ có lý do khởi động là "reboot,longkey".

Không có reason span đầu tiên nào có thể là một phần của subreason hoặc detail. Tuy nhiên, vì không gian người dùng không thể tạo lý do đặt hạt nhân, nên "watchdog" có thể được sử dụng lại sau khi đặt lý do thô, cùng với thông tin chi tiết về nguồn (ví dụ: "reboot,watchdog,service_manager_unresponsive" hoặc "reboot,software,watchdog").

Lý do khởi động không đòi hỏi kiến thức nội bộ của chuyên gia để giải mã và/hoặc phải dễ đọc đối với con người thông qua một báo cáo trực quan. Ví dụ: "shutdown,vbxd" (không tốt), "shutdown,uv" (tốt hơn), "shutdown,undervoltage" (ưu tiên).

Các tổ hợp lý do-lý do phụ

Android dành riêng một tập hợp các tổ hợp reason-subreason không được nạp chồng trong trường hợp sử dụng thông thường nhưng có thể được sử dụng theo từng trường hợp nếu tổ hợp phản ánh chính xác điều kiện liên quan. Ví dụ về các kiểu kết hợp đặt trước bao gồm:

  • "reboot,userrequested"
  • "shutdown,userrequested"
  • "shutdown,thermal" (từ thermald)
  • "shutdown,battery"
  • "shutdown,battery,thermal" (từ BatteryStatsService)
  • "reboot,adb"
  • "reboot,shell"
  • "reboot,bootloader"
  • "reboot,recovery"

Để biết thêm thông tin chi tiết, hãy tham khảo kBootReasonMap trong system/core/bootstat/bootstat.cpp và nhật ký thay đổi git liên quan trong kho lưu trữ nguồn Android.

Báo cáo lý do khởi động

Tất cả lý do khởi động, từ trình tải khởi động hoặc được ghi lại trong lý do khởi động chính tắc, phải được ghi lại trong phần kBootReasonMap của system/core/bootstat/bootstat.cpp. Danh sách kBootReasonMap bao gồm cả lý do tuân thủ và lý do không tuân thủ cũ. Nhà phát triển trình tải khởi động chỉ nên đăng ký các lý do mới tuân thủ tại đây (và không nên đăng ký các lý do không tuân thủ trừ phi sản phẩm đã được vận chuyển và không thể thay đổi).

Bạn nên sử dụng các mục hiện có, tuân thủ trong system/core/bootstat/bootstat.cpp và hạn chế sử dụng chuỗi không tuân thủ. Theo nguyên tắc, công cụ này:

  • OK để báo cáo "kernel_panic" từ trình tải khởi động, vì bootstat có thể kiểm tra ramoops cho kernel_panic signatures để tinh chỉnh các lý do phụ thành system_boot_reason_prop chuẩn.
  • Không được báo cáo một chuỗi không tuân thủ trong kBootReasonMap (chẳng hạn như "panic") từ trình tải khởi động, vì điều này cuối cùng sẽ làm hỏng khả năng tinh chỉnh reason.

Ví dụ: nếu kBootReasonMap chứa "wdog_bark", thì nhà phát triển trình tải khởi động nên:

  • Thay đổi thành "watchdog,bark" và thêm vào danh sách trong kBootReasonMap.
  • Hãy cân nhắc ý nghĩa của "bark" đối với những người không quen thuộc với công nghệ này và xác định xem có subreason nào có ý nghĩa hơn không.

Xác minh việc tuân thủ lý do khởi động

Hiện tại, Android chưa cung cấp chương trình kiểm thử CTS đang hoạt động có thể kích hoạt hoặc kiểm tra chính xác mọi lý do khởi động mà trình tải khởi động có thể đưa ra. Các đối tác vẫn có thể thử chạy kiểm thử thụ động để xác định khả năng tương thích.

Do đó, để tuân thủ quy định về trình tải khởi động, nhà phát triển trình tải khởi động phải tự nguyện tuân thủ tinh thần của các quy tắc và nguyên tắc được mô tả ở trên. Chúng tôi khuyến khích những nhà phát triển như vậy đóng góp cho AOSP (cụ thể là cho system/core/bootstat/bootstat.cpp) và sử dụng cơ hội này làm diễn đàn để thảo luận về các vấn đề liên quan đến lý do khởi động.