Lý do khởi động 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 Android trước đây đã chỉ định định dạng lý do khởi động không sử dụng dấu cách, toàn bộ chữ thường, bao gồm một số yêu cầu (chẳng hạn như để báo cáo kernel_panic, watchdog, cold/warm/hard) và cho phép các 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 đều phải xuất phát 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 để đợi cho đến khi userdata được gắn trước khi 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 userdata được gắn, bạn có thể cập nhật system_boot_reason_prop để tuân thủ 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 ư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 về 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 con để hỗ trợ 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:

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

Trình tải khởi động phải cung cấp một tập hợp hạt nhân hoặc một tập hợp blunt reason và bạn nên cung cấp subreason nếu có thể xác định được. Ví dụ: thao tác nhấn và giữ nút 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 được yêu cầu kiến thức nội bộ chuyên sâu để giải mã và/hoặc phải là báo cáo trực quan mà con người có thể đọc được. 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. Sau đây là một số ví dụ về các tổ hợp được đặt trước:

  • "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ủ. Dưới đây là nguyên tắc chung:

  • 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 phải:

  • 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 có ý nghĩa hơn hay không.

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

Hiện tại, Android không cung cấp quy trình kiểm thử CTS chủ động có thể kích hoạt hoặc kiểm tra chính xác tất cả lý do khởi động có thể có mà trình tải khởi động có thể cung cấp; các đối tác vẫn có thể thử chạy quy trình 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.