Thêm thuộc tính hệ thống

Trang này cung cấp một phương thức chuẩn hoá để thêm hoặc xác định các thuộc tính của hệ thống trong Android, kèm theo nguyên tắc tái cấu trúc các thuộc tính hệ thống hiện có. Đảm bảo rằng bạn sử dụng các nguyên tắc này khi tái cấu trúc, trừ phi bạn gặp vấn đề về khả năng tương thích mạnh có thể đưa ra thông tin khác.

Bước 1: Xác định thuộc tính hệ thống

Khi bạn thêm một thuộc tính hệ thống, hãy quyết định tên cho thuộc tính đó và liên kết thuộc tính đó với ngữ cảnh thuộc tính SELinux. Nếu không có ngữ cảnh hiện có thích hợp, hãy tạo một ngữ cảnh mới. Tên này được dùng khi truy cập vào thuộc tính; ngữ cảnh của thuộc tính được dùng để kiểm soát khả năng hỗ trợ tiếp cận về SELinux. Tên có thể là chuỗi bất kỳ, nhưng AOSP khuyến nghị bạn nên tuân theo một định dạng có cấu trúc để làm rõ tên.

Tên thuộc tính

Sử dụng định dạng này với cách viết hoa ẩn_case:

[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]

Sử dụng "" (bị bỏ qua), ro (đối với các thuộc tính chỉ được đặt một lần) hoặc persist (đối với các thuộc tính vẫn tồn tại sau khi khởi động lại) cho phần tử prefix.

Chú ý

Chỉ sử dụng ro khi bạn chắc chắn rằng mình không cần prefix để có thể ghi trong tương lai. ** Đừng chỉ định tiền tố ro.** Thay vào đó, hãy dựa vào sepolicy để đặt prefix ở chế độ chỉ đọc (nói cách khác, chỉ có thể ghi bằng init).

Chỉ sử dụng persist khi bạn chắc chắn rằng giá trị đó phải được duy trì trong các lần khởi động lại và rằng việc sử dụng các thuộc tính hệ thống là lựa chọn duy nhất của bạn.

Google sẽ xem xét nghiêm ngặt các thuộc tính hệ thống có thuộc tính ro hoặc persist.

Từ khoá group được dùng để tổng hợp các thuộc tính có liên quan. Tệp này phải là tên hệ thống con, tương tự như cách sử dụng audio hoặc telephony. Không sử dụng các cụm từ không rõ ràng hoặc quá tải như sys, system, dev, default hoặc config.

Thông thường, bạn nên sử dụng tên của loại miền của một quy trình có quyền đọc hoặc ghi độc quyền đối với các thuộc tính hệ thống. Ví dụ: đối với các thuộc tính hệ thống mà quy trình vold có quyền ghi, bạn nên sử dụng vold (tên loại miền của quy trình) làm tên nhóm.

Nếu cần, hãy thêm subgroup để phân loại thêm các thuộc tính, nhưng tránh dùng các thuật ngữ không rõ ràng hoặc quá tải để mô tả phần tử này. (Bạn cũng có thể có nhiều subgroup.)

Nhiều tên nhóm đã được xác định. Kiểm tra tệp system/sepolicy/private/property_contexts và sử dụng tên nhóm hiện có nếu có thể, thay vì đặt tên mới. Bảng sau đây cung cấp ví dụ về tên nhóm thường được sử dụng.

Miền Nhóm (và nhóm con)
liên quan đến bluetooth bluetooth
sysprops từ lệnh cmdline nhân boot
sysprops giúp xác định một bản dựng build
liên quan đến điện thoại telephony
liên quan đến âm thanh audio
liên quan đến đồ hoạ graphics
liên quan đến vold vold

Nội dung sau đây xác định cách sử dụng nametype trong ví dụ về biểu thức chính quy trước đó.

[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]

  • name xác định một thuộc tính hệ thống trong một nhóm.

  • type là một phần tử không bắt buộc, làm rõ loại hoặc ý định của thuộc tính hệ thống. Ví dụ: thay vì đặt tên cho một sysprop là audio.awesome_feature_enabled hoặc chỉ audio.awesome_feature, hãy đổi tên nó thành audio.awesome_feature.enabled để phản ánh loại và ý định của thuộc tính hệ thống.

Không có quy tắc cụ thể nào về loại dữ liệu phải; sau đây là các đề xuất về cách sử dụng:

  • enabled: Sử dụng nếu kiểu dữ liệu này là một thuộc tính hệ thống boolean dùng để bật hoặc tắt một tính năng.
  • config: Sử dụng nếu ý định làm rõ rằng thuộc tính hệ thống không đại diện cho trạng thái động của hệ thống; thuộc tính này đại diện cho một giá trị được định cấu hình sẵn (ví dụ: một thứ chỉ có thể đọc).
  • List: Sử dụng nếu đó là một thuộc tính hệ thống có giá trị là một danh sách.
  • Timeoutmillis: Sử dụng nếu đó là thuộc tính hệ thống cho giá trị thời gian chờ, tính bằng đơn vị ms.

Ví dụ:

  • persist.radio.multisim.config
  • drm.service.enabled

Ngữ cảnh thuộc tính

Lược đồ ngữ cảnh thuộc tính SELinux mới cho phép chi tiết hơn và các tên mô tả cụ thể hơn. Tương tự như định dạng dùng cho tên thuộc tính, AOSP đề xuất định dạng sau:

{group}[_{subgroup}]*_prop

Các thuật ngữ được định nghĩa như sau:

groupsubgroup có cùng ý nghĩa như được định nghĩa cho biểu thức chính quy mẫu trước đó. Ví dụ: vold_config_prop biểu thị các thuộc tính là cấu hình của một nhà cung cấp và sẽ do vendor_init thiết lập, trong khi vold_status_prop hoặc chỉ vold_prop biểu thị các thuộc tính sẽ hiển thị trạng thái hiện tại của vold.

Khi đặt tên cho ngữ cảnh thuộc tính, hãy chọn tên phản ánh cách sử dụng chung của các thuộc tính. Cụ thể, hãy tránh các loại cụm từ sau:

  • Những cụm từ quá chung chung và không rõ ràng, chẳng hạn như sys, system, default.
  • Những cụm từ mã hoá trực tiếp khả năng hỗ trợ tiếp cận: chẳng hạn như exported, apponly, ro, public, private.

Ưu tiên sử dụng các tên như vold_config_prop đến exported_vold_prop hoặc vold_vendor_writable_prop.

Loại

Loại thuộc tính có thể là một trong những loại sau được liệt kê trong bảng.

Loại Định nghĩa
Boolean true hoặc 1 cho giá trị true, false hoặc 0 cho kết quả sai
Số nguyên số nguyên 64 bit có dấu
Số nguyên chưa ký số nguyên 64 bit chưa ký
Đôi dấu phẩy động có độ chính xác kép
Chuỗi mọi chuỗi UTF-8 hợp lệ
enum các giá trị có thể là chuỗi UTF-8 hợp lệ không có khoảng trắng
Danh sách ở trên Dấu phẩy (,) được dùng làm dấu phân cách
Danh sách số nguyên [1, 2, 3] được lưu trữ dưới dạng 1,2,3

Trong nội bộ, tất cả các thuộc tính đều được lưu trữ dưới dạng chuỗi. Bạn có thể thực thi loại này bằng cách chỉ định loại này là tệp property_contexts. Để biết thêm thông tin, hãy xem property_contexts trong Bước 3.

Bước 2: Xác định các mức độ hỗ trợ người khuyết tật cần thiết

Có bốn macro trợ giúp xác định một thuộc tính.

Loại hỗ trợ tiếp cận Ý nghĩa
system_internal_prop Những thuộc tính chỉ được dùng trong /system
system_restricted_prop Những thuộc tính được đọc bên ngoài /system nhưng không được ghi
system_vendor_config_prop Các thuộc tính được đọc bên ngoài /system và chỉ do vendor_init viết
system_public_prop Các thuộc tính được đọc và ghi bên ngoài /system

Giới hạn quyền truy cập vào các thuộc tính hệ thống trong phạm vi hẹp nhất có thể. Trước đây, việc truy cập rộng rãi đã dẫn đến các sự cố ngắt ứng dụng và lỗ hổng bảo mật. Hãy cân nhắc các câu hỏi sau đây khi xác định phạm vi:

  • Thuộc tính hệ thống này có cần được duy trì không? (nếu có, tại sao?)
  • Quy trình nào cần có quyền đọc đối với tài sản này?
  • Quy trình nào có quyền ghi đối với tài sản này?

Sử dụng các câu hỏi trước và cây quyết định sau đây làm công cụ để xác định phạm vi truy cập thích hợp.

Cây quyết định để xác định phạm vi truy cập

Hình 1. Cây quyết định để xác định phạm vi truy cập vào các thuộc tính của hệ thống

Bước 3: Thêm vào hệ thống/sepolicy

Khi truy cập vào sysprop, SELinux sẽ kiểm soát khả năng hỗ trợ tiếp cận của các quy trình. Sau khi bạn xác định mức độ hỗ trợ tiếp cận cần thiết, hãy xác định ngữ cảnh thuộc tính trong system/sepolicy, cùng với các quy tắc allow (cho phép) và nevercho phép bổ sung về các quy trình được phép (và không được phép) đọc hoặc ghi.

Trước tiên, hãy xác định ngữ cảnh thuộc tính trong tệp system/sepolicy/public/property.te. Nếu thuộc tính là thuộc tính nội bộ của hệ thống, hãy xác định thuộc tính đó trong tệp system/sepolicy/private/property.te. Sử dụng một trong các macro system_[accessibility]_prop([context]) cung cấp khả năng hỗ trợ tiếp cận cần thiết cho thuộc tính hệ thống của bạn. Đây là ví dụ về tệp system/sepolicy/public/property.te:

system_public_prop(audio_foo_prop)
system_vendor_config_prop(audio_bar_prop)

Ví dụ về cách thêm vào tệp system/sepolicy/private/property.te:

system_internal_prop(audio_baz_prop)

Thứ hai, cấp quyền đọc và (hoặc) ghi cho ngữ cảnh thuộc tính. Sử dụng các macro set_propget_prop để cấp quyền truy cập, trong tệp system/sepolicy/public/{domain}.te hoặc system/sepolicy/private/{domain}.te. Sử dụng private bất cứ khi nào có thể; public chỉ phù hợp nếu macro set_prop hoặc get_prop ảnh hưởng đến bất kỳ miền nào ngoài miền chính.

Ví dụ: trong tệp system/sepolicy/private/audio.te:

set_prop(audio, audio_foo_prop)
set_prop(audio, audio_bar_prop)

Ví dụ: trong tệp system/sepolicy/public/domain.te:

get_prop(domain, audio_bar_prop)

Thứ ba, thêm một số quy tắc không bao giờ cho phép để giảm thêm khả năng hỗ trợ tiếp cận nằm trong phạm vi của macro. Ví dụ: giả sử bạn đã sử dụng system_restricted_prop vì các thuộc tính hệ thống của bạn phải được đọc bằng quy trình của nhà cung cấp. Nếu tất cả các quy trình của nhà cung cấp không yêu cầu quyền đọc và chỉ cần một nhóm quy trình nhất định (chẳng hạn như vendor_init), hãy cấm các quy trình của nhà cung cấp không cần quyền đọc.

Sử dụng cú pháp sau để hạn chế quyền ghi và đọc:

Cách hạn chế quyền ghi:

neverallow [domain] [context]:property_service set;

Cách hạn chế quyền đọc:

neverallow [domain] [context]:file no_rw_file_perms;

Đặt quy tắc Neverallow trong tệp system/sepolicy/private/{domain}.te nếu quy tắc giá bao giờ cho phép bị liên kết với một miền cụ thể. Đối với các quy tắc không bao giờ cho phép rộng hơn, hãy sử dụng các miền chung như sau khi thích hợp:

  • system/sepolicy/private/property.te
  • system/sepolicy/private/coredomain.te
  • system/sepolicy/private/domain.te

Trong tệp system/sepolicy/private/audio.te, hãy đặt như sau:

neverallow {
    domain -init -audio
} {audio_foo_prop audio_bar_prop}:property_service set;

Trong tệp system/sepolicy/private/property.te, hãy đặt như sau:

neverallow {
    domain -coredomain -vendor_init
} audio_prop:file no_rw_file_perms;

Lưu ý rằng {domain -coredomain} ghi lại mọi quy trình của nhà cung cấp. Vì vậy, {domain -coredomain -vendor_init} có nghĩa là "tất cả quy trình của nhà cung cấp ngoại trừ vendor_init".

Cuối cùng, hãy liên kết một thuộc tính hệ thống với ngữ cảnh thuộc tính. Điều này đảm bảo rằng quyền truy cập đã cấp và các quy tắc không bao giờ cho phép áp dụng cho ngữ cảnh thuộc tính sẽ được áp dụng cho các thuộc tính thực tế. Để thực hiện việc này, hãy thêm một mục vào tệp property_contexts. Tệp này mô tả mối liên kết giữa các thuộc tính của hệ thống và ngữ cảnh thuộc tính. Trong tệp này, bạn có thể chỉ định một thuộc tính duy nhất hoặc một tiền tố cho các thuộc tính cần liên kết vào ngữ cảnh.

Đây là cú pháp để liên kết một tài sản:

[property_name] u:object_r:[context_name]:s0 exact [type]

Đây là cú pháp để liên kết một tiền tố:

[property_name_prefix] u:object_r:[context_name]:s0 prefix [type]

Bạn có thể tuỳ ý chỉ định loại thuộc tính, có thể là một trong các loại sau:

  • bool
  • int
  • uint
  • double
  • enum [list of possible values...]
  • string (Sử dụng string để liệt kê các cơ sở lưu trú.)

Đảm bảo rằng mọi mục nhập đều có loại được chỉ định bất cứ khi nào có thể, vì type được thực thi khi đặt property. Ví dụ sau đây cho thấy cách viết một mối liên kết:

# binds a boolean property "ro.audio.status.enabled"
# to the context "audio_foo_prop"
ro.audio.status.enabled u:object_r:audio_foo_prop:s0 exact bool

# binds a boolean property "vold.decrypt.status"
# to the context "vold_foo_prop"
# The property can only be set to one of these: on, off, unknown
vold.decrypt.status u:object_r:vold_foo_prop:s0 exact enum on off unknown

# binds any properties starting with "ro.audio.status."
# to the context "audio_bar_prop", such as
# "ro.audio.status.foo", or "ro.audio.status.bar.baz", and so on.
ro.audio.status. u:object_r:audio_bar_prop:s0 prefix

Khi một mục nhập chính xác và một mục nhập có tiền tố xung đột, thì mục nhập chính xác sẽ được ưu tiên. Để xem thêm ví dụ, hãy xem system/sepolicy/private/property_contexts.

Bước 4: Xác định các yêu cầu về độ ổn định

Độ ổn định là một khía cạnh khác của các thuộc tính hệ thống và khác với khả năng hỗ trợ tiếp cận. Độ ổn định thể hiện việc một thuộc tính hệ thống có thể được thay đổi hay không (ví dụ: đổi tên hoặc thậm chí là xoá) trong tương lai. Điều này đặc biệt quan trọng khi hệ điều hành Android trở thành mô-đun. Với Treble, các phân vùng hệ thống, nhà cung cấp và sản phẩm có thể được cập nhật độc lập với nhau. Với Mainline, một số phần của hệ điều hành được mô-đun hoá dưới dạng mô-đun có thể cập nhật (trong APEX hoặc APK).

Nếu một thuộc tính hệ thống được dùng trên các phần mềm có thể cập nhật, chẳng hạn như trên các phân vùng của hệ thống và nhà cung cấp, thì thuộc tính đó phải ổn định. Tuy nhiên, nếu chỉ được dùng trong một mô-đun Mainline cụ thể, thì bạn có thể thay đổi bối cảnh tên, loại hoặc thuộc tính của mô-đun đó và thậm chí là xoá mô-đun đó.

Hãy đặt những câu hỏi sau đây để xác định độ ổn định của một thuộc tính hệ thống:

  • Có phải thuộc tính hệ thống này sẽ do các đối tác định cấu hình (hoặc được định cấu hình khác nhau cho từng thiết bị) không? Nếu có, thì mã đó phải ổn định.
  • Thuộc tính hệ thống do AOSP xác định này có phải được ghi hoặc đọc từ mã (không phải quy trình) tồn tại trong các phân vùng không phải hệ thống như vendor.img hoặc product.img không? Nếu có, thì mã đó phải ổn định.
  • Thuộc tính hệ thống này có được truy cập qua các mô-đun Mainline hoặc qua mô-đun Mainline và phần không thể cập nhật của nền tảng không? Nếu có, thì mã đó phải ổn định.

Đối với các thuộc tính hệ thống ổn định, hãy chính thức định nghĩa từng thuộc tính dưới dạng API và sử dụng API để truy cập vào thuộc tính hệ thống, như đã giải thích trong Bước 6.

Bước 5: Đặt thuộc tính tại thời điểm xây dựng

Đặt thuộc tính tại thời điểm xây dựng bằng các biến makefile. Về mặt kỹ thuật, các giá trị được tích hợp vào {partition}/build.prop. Sau đó, init đọc {partition}/build.prop để đặt các thuộc tính. Có 2 bộ biến như vậy: PRODUCT_{PARTITION}_PROPERTIESTARGET_{PARTITION}_PROP.

PRODUCT_{PARTITION}_PROPERTIES chứa danh sách các giá trị thuộc tính. Cú pháp là {prop}={value} hoặc {prop}?={value}.

{prop}={value} là một thao tác chỉ định thông thường đảm bảo rằng {prop} được đặt thành {value}; chỉ một thao tác chỉ định như vậy là có thể thực hiện cho mỗi thuộc tính.

{prop}?={value} là một bài tập không bắt buộc; {prop} chỉ đặt thành {value} nếu không có bài tập nào được chỉ định {prop}={value}. Nếu có nhiều mục chỉ định không bắt buộc, thì mục đầu tiên sẽ thắng.

# sets persist.traced.enable to 1 with system/build.prop
PRODUCT_SYSTEM_PROPERTIES += persist.traced.enable=1

# sets ro.zygote to zygote32 with system/build.prop
# but only when there are no other assignments to ro.zygote
# optional are useful when giving a default value to a property
PRODUCT_SYSTEM_PROPERTIES += ro.zygote?=zygote32

# sets ro.config.low_ram to true with vendor/build.prop
PRODUCT_VENDOR_PROPERTIES += ro.config.low_ram=true

TARGET_{PARTITION}_PROP chứa danh sách các tệp được phát trực tiếp vào {partition}/build.prop. Mỗi tệp chứa một danh sách các cặp {prop}={value}.

# example.prop

ro.cp_system_other_odex=0
ro.adb.secure=0
ro.control_privapp_permissions=disable

# emits example.prop to system/build.prop
TARGET_SYSTEM_PROP += example.prop

Để biết thêm thông tin chi tiết, hãy xem build/make/core/sysprop.mk.

Bước 6: Truy cập vào các thuộc tính trong thời gian chạy

Thuộc tính có thể được đọc và ghi trong thời gian chạy.

Tập lệnh khởi tạo

Các tệp tập lệnh init (thường là tệp *.rc) có thể đọc một thuộc tính bằng ${prop} hoặc ${prop:-default}, có thể thiết lập một hành động sẽ chạy bất cứ khi nào một thuộc tính trở thành giá trị cụ thể, đồng thời có thể ghi các thuộc tính bằng lệnh setprop.

# when persist.device_config.global_settings.sys_traced becomes 1,
# set persist.traced.enable to 1
on property:persist.device_config.global_settings.sys_traced=1
    setprop persist.traced.enable 1

# when security.perf_harden becomes 0,
# write /proc/sys/kernel/sample_rate to the value of
# debug.sample_rate. If it's empty, write -100000 instead
on property:security.perf_harden=0
    write /proc/sys/kernel/sample_rate ${debug.sample_rate:-100000}

các lệnh shell getprop và setprop

Bạn có thể dùng các lệnh shell getprop hoặc setprop tương ứng để đọc hoặc ghi thuộc tính. Để biết thêm thông tin chi tiết, hãy gọi getprop --help hoặc setprop --help.

$ adb shell getprop ro.vndk.version
$
$ adb shell setprop security.perf_harden 0

Sysprop làm API cho C++/Java/Rust

Với sysprop dưới dạng API, bạn có thể xác định các thuộc tính hệ thống và sử dụng API được tạo tự động (cụ thể và được nhập). Việc đặt scope với Public cũng giúp các API đã tạo được cung cấp cho các mô-đun vượt qua ranh giới và đảm bảo độ ổn định của API. Dưới đây là mẫu của tệp .sysprop, mô-đun Android.bp và mã C++, Java và Rust sử dụng các mô-đun đó.

# AudioProps.sysprop
# module becomes static class (Java) / namespace (C++) for serving API
module: "android.sysprop.AudioProps"
# owner can be Platform or Vendor or Odm
owner: Platform
# one prop defines one property
prop {
    prop_name: "ro.audio.volume.level"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "volume_level"
}
…
// Android.bp
sysprop_library {
    name: "AudioProps",
    srcs: ["android/sysprop/AudioProps.sysprop"],
    property_owner: "Platform",
}

// Rust, Java and C++ modules can link against the sysprop_library
rust_binary {
    rustlibs: ["libaudioprops_rust"],
    …
}

java_library {
    static_libs: ["AudioProps"],
    …
}

cc_binary {
    static_libs: ["libAudioProps"],
    …
}
// Rust code accessing generated API.
// Get volume. Use 50 as the default value.
let vol = audioprops::volume_level()?.unwrap_or_else(50);
// Java codes accessing generated API
// get volume. use 50 as the default value.
int vol = android.sysprop.AudioProps.volume_level().orElse(50);
// add 10 to the volume level.
android.sysprop.AudioProps.volume_level(vol + 10);
// C++ codes accessing generated API
// get volume. use 50 as the default value.
int vol = android::sysprop::AudioProps::volume_level().value_or(50);
// add 10 to the volume level.
android::sysprop::AudioProps::volume_level(vol + 10);

Để biết thêm thông tin, hãy xem bài viết Triển khai thuộc tính hệ thống dưới dạng API.

Các hàm và phương thức thuộc tính cấp thấp trong C/C++, Java và Rust

Khi có thể, hãy sử dụng Sysprop làm API mặc dù các hàm C/C++ hay Rust cấp thấp hoặc các phương thức Java cấp thấp được cung cấp cho bạn.

libc, libbaselibcutils cung cấp các hàm thuộc tính hệ thống C++. libc có API cơ bản, trong khi các hàm libbaselibcutils là trình bao bọc. Nếu có thể, hãy dùng các hàm sysprop libbase. Đây là các hàm thuận tiện nhất và tệp nhị phân lưu trữ có thể sử dụng các hàm libbase. Để biết thêm thông tin chi tiết, hãy xem sys/system_properties.h (libc), android-base/properties.h (libbase) và cutils/properties.h (libcutils).

Lớp android.os.SystemProperties cung cấp các phương thức thuộc tính hệ thống Java.

Mô-đun rustutils::system_properties cung cấp các kiểu và hàm thuộc tính hệ thống Rust.

Phụ lục: Thêm tài sản theo nhà cung cấp

Các đối tác (bao gồm cả nhân viên của Google làm việc trong bối cảnh phát triển Pixel) muốn xác định các thuộc tính hệ thống dành riêng cho phần cứng (hoặc thiết bị cụ thể). Các thuộc tính dành riêng cho nhà cung cấp là các thuộc tính do đối tác sở hữu dành riêng cho phần cứng hoặc thiết bị của riêng họ, chứ không dành cho nền tảng. Vì các thành phần này phụ thuộc vào phần cứng hoặc thiết bị, nên các thành phần này được dùng trong phân vùng /vendor hoặc /odm.

Kể từ Project Treble, các thuộc tính nền tảng và thuộc tính của nhà cung cấp đã được chia tách hoàn toàn để tránh xung đột. Phần sau đây mô tả cách xác định thuộc tính của nhà cung cấp và cho biết bạn luôn phải sử dụng thuộc tính nào của nhà cung cấp.

Không gian tên trên tên thuộc tính và ngữ cảnh

Tất cả thuộc tính của nhà cung cấp phải bắt đầu bằng một trong các tiền tố sau để tránh xung đột giữa các tiền tố đó với thuộc tính của các phân vùng khác.

  • ctl.odm.
  • ctl.vendor.
  • ctl.start$odm.
  • ctl.start$vendor.
  • ctl.stop$odm.
  • ctl.stop$vendor.
  • init.svc.odm.
  • init.svc.vendor.
  • ro.odm.
  • ro.vendor.
  • odm.
  • persist.odm.
  • persist.vendor.
  • vendor.

Xin lưu ý rằng ro.hardware. được phép dùng làm tiền tố, nhưng chỉ để tương thích. Không sử dụng thuộc tính này cho các thuộc tính thông thường.

Các ví dụ sau đây đều sử dụng một trong các tiền tố được liệt kê trước đó:

  • vendor.display.primary_red
  • persist.vendor.faceauth.use_disk_cache
  • ro.odm.hardware.platform

Tất cả ngữ cảnh thuộc tính nhà cung cấp phải bắt đầu bằng vendor_. Điều này cũng nhằm đảm bảo khả năng tương thích. Sau đây là các ví dụ:

  • vendor_radio_prop.
  • vendor_faceauth_prop.
  • vendor_usb_prop.

Nhà cung cấp có trách nhiệm đặt tên và duy trì các thuộc tính. Vì vậy, hãy làm theo định dạng được đề xuất ở Bước 2, ngoài các yêu cầu về không gian tên của nhà cung cấp.

Các quy tắc SEPolicy và thuộc tính property_contexts dành riêng cho nhà cung cấp

Bạn có thể xác định thuộc tính của nhà cung cấp bằng macro vendor_internal_prop. Đặt các quy tắc dành riêng cho nhà cung cấp mà bạn xác định trong thư mục BOARD_VENDOR_SEPOLICY_DIRS. Ví dụ: giả sử bạn đang xác định thuộc tính Faceauth của nhà cung cấp ở san hô.

Trong tệp BoardConfig.mk (hoặc trong bất kỳ BoardConfig.mk nào bao gồm), hãy đặt nội dung sau:

BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy

Trong tệp device/google/coral-sepolicy/private/property.te, hãy đặt nội dung sau:

vendor_internal_prop(vendor_faceauth_prop)

Trong tệp device/google/coral-sepolicy/private/property_contexts, hãy đặt nội dung sau:

vendor.faceauth.trace u:object_r:vendor_faceauth_prop:s0 exact bool

Hạn chế của thuộc tính của nhà cung cấp

Vì phân vùng sản phẩm và hệ thống không thể phụ thuộc vào nhà cung cấp, nên đừng bao giờ cho phép truy cập vào các thuộc tính của nhà cung cấp từ phân vùng system, system-ext hoặc product.

Phụ lục: Đổi tên tài sản hiện có

Khi bạn phải ngừng sử dụng một thuộc tính và chuyển sang một thuộc tính mới, hãy sử dụng Sysprop dưới dạng API để đổi tên các thuộc tính hiện có. Việc này giúp duy trì khả năng tương thích ngược bằng cách chỉ định cả tên cũ và tên thuộc tính mới. Cụ thể, bạn có thể đặt tên cũ bằng trường legacy_prop_name trong tệp .sysprop. API được tạo sẽ cố đọc prop_name và sử dụng legacy_prop_name nếu prop_name không tồn tại.

Ví dụ: các bước sau đây đổi tên awesome_feature_foo_enabled thành foo.awesome_feature.enabled.

Trong tệp foo.sysprop

module: "android.sysprop.foo"
owner: Platform
prop {
    api_name: "is_awesome_feature_enabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "foo.awesome_feature.enabled"
    legacy_prop_name: "awesome_feature_foo_enabled"
}

Trong mã C++

// is_awesome_feature_enabled() reads "foo.awesome_feature.enabled".
// If it doesn't exist, reads "awesome_feature_foo_enabled" instead
using android::sysprop::foo;

bool enabled = foo::is_awesome_feature_enabled().value_or(false);

Xin lưu ý những điểm cần lưu ý sau đây:

  • Trước tiên, bạn không thể thay đổi loại sysprop. Ví dụ: bạn không thể tạo thuộc tính int thành thuộc tính string. Bạn chỉ có thể thay đổi tên.

  • Thứ hai, chỉ API đọc mới chuyển về tên cũ. API ghi sẽ không dừng lại ở đó. Nếu sysprop là một thuộc tính có thể ghi, thì bạn không thể đổi tên nó.