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

Trang này cung cấp một phương thức chính tắc để thêm hoặc xác định các thuộc tính hệ thống trong Android, kèm theo hướng dẫn về cách 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 tuân thủ các nguyên tắc khi tái cấu trúc, trừ phi bạn gặp phải vấn đề nghiêm trọng về khả năng tương thích khiến bạn không thể làm như vậy.

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 một ngữ cảnh thuộc tính SELinux. Nếu không có ngữ cảnh hiện tại phù 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 thuộc tính được dùng để kiểm soát khả năng truy cập theo SELinux. Tên có thể là bất kỳ chuỗi nào, nhưng AOSP đề xuất bạn tuân theo một định dạng có cấu trúc để giúp tên rõ ràng.

Tên thuộc tính

Hãy dùng định dạng này với kiểu viết snake_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 bạn 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ó thể đọ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 quá trình khởi động lại và 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 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.

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

Thông thường, bạn nên 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 thường dùng vold (tên của loại miền cho 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ữ mơ hồ 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ạo tên nhóm mới. Bảng sau đây cung cấp ví dụ về các tên nhóm thường dùng.

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

Sau đây xác định việc 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, giúp làm rõ loại hoặc mục đích 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 thành audio.awesome_feature.enabled để phản ánh loại và mục đích của thuộc tính hệ thống.

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

  • enabled: Sử dụng nếu loại 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 mục đích là làm rõ rằng thuộc tính hệ thống không biểu thị trạng thái động của hệ thống; thuộc tính này biểu thị một giá trị được định cấu hình trước (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à một thuộc tính hệ thống cho giá trị thời gian chờ theo đơn vị mili giây.

Ví dụ:

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

Bối cảnh của cơ sở lưu trú

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

{group}[_{subgroup}]*_prop

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

groupsubgroup có cùng ý nghĩa như được xác định 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à được vendor_init đặt, 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 một bối cảnh thuộc tính, hãy chọn tên phản ánh việc sử dụng chung các thuộc tính. Đặc biệt, hãy tránh những loại từ sau:

  • Những cụm từ có vẻ quá chung chung và mơ hồ, chẳng hạn như sys, system, default.
  • Các thuật ngữ 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 tên như vold_config_prop thay vì exported_vold_prop hoặc vold_vendor_writable_prop.

Loại

Một loại tài sản có thể là một trong những loại sau đây như được liệt kê trong bảng.

Loại Định nghĩa
Boolean true hoặc 1 cho đúng, false hoặc 0 cho sai
Số nguyên số nguyên 64 bit có dấu
Số nguyên không dấu số nguyên 64 bit chưa ký
Đôi dấu phẩy động có độ chính xác gấp đôi
Chuỗi mọi chuỗi UTF-8 hợp lệ
enum giá trị có thể là bất kỳ chuỗi UTF-8 hợp lệ nào 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

Về 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 bằng cách chỉ định loại đó làm 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 cấp độ hỗ trợ tiếp cận bắt buộc

Có 4 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 Các thuộc tính chỉ được dùng ở /system
system_restricted_prop Các 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ỉ được ghi bằng vendor_init
system_public_prop Các thuộc tính được đọc và ghi bên ngoài /system

Phạm vi truy cập vào các thuộc tính hệ thống càng hẹp càng tốt. Trước đây, quyền truy cập rộng rãi đã dẫn đến tình trạng ứng dụng bị lỗi và có lỗ hổng bảo mật. Hãy cân nhắc những câu hỏi sau 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ó thì 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ần có quyền ghi vào tài sản này?

Hã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 phù 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 hệ thống

Bước 3: Thêm vào system/sepolicy

Khi truy cập vào sysprop, SELinux sẽ kiểm soát khả năng truy cập của các quy trình. Sau khi bạn xác định cấp độ hỗ trợ tiếp cận cần thiết, hãy xác định các ngữ cảnh thuộc tính trong system/sepolicy, cùng với các quy tắc allow (cho phép) và neverallow (không bao giờ cho phép) bổ sung về những gì các quy trình được (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à nội bộ 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 bối cảnh tài sản. Sử dụng 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 bên 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, hãy thêm một số quy tắc neverallow để giảm thêm khả năng tiếp cận được xác định phạm vi theo macro. Ví dụ: giả sử bạn đã sử dụng system_restricted_prop vì các quy trình của nhà cung cấp phải đọc các thuộc tính hệ thống của bạn. Nếu không phải tất cả các quy trình của nhà cung cấp đều cần quyền đọc và chỉ một số quy trình nhất định (chẳng hạn như vendor_init) cần quyền này, 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 các quy tắc neverallow trong tệp system/sepolicy/private/{domain}.te nếu quy tắc neverallow được liên kết với một miền cụ thể. Đối với các quy tắc neverallow 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 nội dung 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 nội dung sau:

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

Xin lưu ý rằng {domain -coredomain} ghi lại tất cả các quy trình của nhà cung cấp. Vì vậy, {domain -coredomain -vendor_init} có nghĩa là "tất cả cá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 cấp và các quy tắc neverallow được á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, đây là tệp mô tả mối liên kết giữa các thuộc tính 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 sẽ được liên kết vào một ngữ cảnh.

Đây là cú pháp để liên kết một thuộc tính duy nhất:

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

Đây là cú pháp để ánh xạ 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 tài sản. Loại tài sản có thể là một trong những loại sau:

  • bool
  • int
  • uint
  • double
  • enum [list of possible values...]
  • string (Sử dụng string cho các thuộc tính danh sách.)

Đả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 ánh xạ:

# 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 tiền tố xung đột, 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

Tí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 tiếp cận. Tính ổn định là việc một thuộc tính hệ thống có thể thay đổi (ví dụ: đổi tên hoặc thậm chí xoá) trong tương lai hay không. Điều này đặc biệt quan trọng khi hệ điều hành Android trở thành hệ điều hành dạng 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 các 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 hệ thống và nhà cung cấp, thì thuộc tính đó phải ổn định. Tuy nhiên, nếu chỉ dùng trong một mô-đun Mainline cụ thể, chẳng hạn như, bạn có thể thay đổi tên, loại hoặc ngữ cảnh thuộc tính của mô-đun đó, thậm chí xoá mô-đun.

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

  • Đối tác có định cấu hình thuộc tính hệ thống này không (hoặc có định cấu hình khác nhau cho mỗi thiết bị không)? Nếu có, thì phải ổn định.
  • Liệu thuộc tính hệ thống do AOSP xác định này có được ghi vào 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ì phải ổn định.
  • Bạn có truy cập vào thuộc tính hệ thống này trên các mô-đun Mainline hay trên một 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ì phải ổn định.

Đối với các thuộc tính hệ thống ổn định, hãy chính thức xác định từng thuộc tính dưới dạng một 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 các thuộc tính tại thời điểm tạo

Đặt các thuộc tính tại thời gian 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 sẽ đọc {partition}/build.prop để thiết lập các thuộc tính. Có hai nhóm 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 phép gán thông thường, đảm bảo rằng {prop} được đặt thành {value}; chỉ có thể có một phép gán như vậy cho mỗi thuộc tính.

{prop}?={value} là một giá trị tuỳ chọn được chỉ định; {prop} chỉ đặt thành {value} nếu không có giá trị được chỉ định {prop}={value} nào. Nếu có nhiều chỉ định không bắt buộc, thì chỉ định đầu tiên sẽ được áp dụ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 đến {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, 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

Bạn có thể đọc và ghi các thuộc tính trong thời gian chạy.

Tập lệnh khởi động

Các tệp tập lệnh khởi động (thường là tệp *.rc) có thể đọc một thuộc tính bằng ${prop} hoặc ${prop:-default}, có thể đặt một thao tác chạy bất cứ khi nào một thuộc tính trở thành một giá trị cụ thể và 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}

Lệnh shell getprop và setprop

Bạn có thể dùng các lệnh shell getprop hoặc setprop để đọc hoặc ghi các thuộc tính tương ứng. Để biết thêm 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 dưới dạng API cho C++/Java/Rust

Với sysprop làm 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 thiết lập scope bằng Public cũng giúp các API được tạo có sẵn cho các mô-đun trên các ranh giới và đảm bảo tính ổn định của API. Sau đây là ví dụ về tệp .sysprop, mô-đun Android.bp và mã C++, Java và Rust bằng cách sử dụng các tệp này.

# 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 phần Triển khai các thuộc tính hệ thống dưới dạng API.

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

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

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à các trình bao bọc. Nếu có thể, hãy sử dụng các hàm sysprop libbase; đây là các hàm tiện lợi nhất và các tệp nhị phân máy chủ 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 hàm và loại thuộc tính hệ thống Rust.

Phụ lục: Thêm các thuộc tính dành riêng cho nhà cung cấp

Các đối tác (bao gồm cả nhân viên 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 dành riêng cho thiết bị). Các thuộc tính dành riêng cho nhà cung cấp là những thuộc tính thuộc sở hữu của đối tác, chỉ có trên phần cứng hoặc thiết bị của riêng họ, chứ không phải trên nền tảng. Vì đây là phần cứng hoặc phụ thuộc vào thiết bị, nên chúng được dùng trong các 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 nhà cung cấp đã được tách hoàn toàn để tránh xung đột. Phần sau đây mô tả cách xác định các thuộc tính của nhà cung cấp và cho biết bạn phải luôn sử dụng những thuộc tính nào của nhà cung cấp.

Không gian tên trên tên tài sản và bối cảnh

Tất cả cá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 để ngăn chặn xung đột giữa các thuộc tính đó và các 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. Đừng sử dụng thuộc tính này cho các tài sản thông thường.

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

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

Tất cả ngữ cảnh thuộc tính của nhà cung cấp phải bắt đầu bằng vendor_. Điều này cũng nhằm mục đích tương thích. Sau đây là một số 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 tuân theo định dạng được đề xuất trong 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à property_contexts dành riêng cho nhà cung cấp

Bạn có thể xác định các 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 một thuộc tính faceauth của nhà cung cấp trong coral.

Trong tệp BoardConfig.mk (hoặc trong bất kỳ BoardConfig.mk nào), 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

Giới hạn đối với các thuộc tính của nhà cung cấp

Vì các phân vùng hệ thống và sản phẩm không thể phụ thuộc vào nhà cung cấp, nên không bao giờ cho phép truy cập vào các thuộc tính của nhà cung cấp từ các 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 làm API để đổi tên các thuộc tính hiện có. Điều này 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ố gắng đọ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 sẽ đổ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 sau:

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

  • Thứ hai, chỉ API đọc mới quay lại tên cũ. API ghi không dự phòng. Nếu sysprop là một sysprop có thể ghi, thì bạn không thể đổi tên sysprop đó.