เพิ่มพร็อพเพอร์ตี้ของระบบ

หน้านี้มีวิธี Canonical สำหรับการเพิ่มหรือกำหนดพร็อพเพอร์ตี้ระบบใน Android พร้อมด้วยหลักเกณฑ์ในการเปลี่ยนโครงสร้างภายในพร็อพเพอร์ตี้ของระบบที่มีอยู่ ตรวจสอบว่าคุณใช้หลักเกณฑ์เมื่อเปลี่ยนโครงสร้างภายในโค้ด เว้นแต่ว่าคุณจะมีปัญหาด้านความเข้ากันได้ที่รุนแรงซึ่งจะระบุไว้เป็นอย่างอื่น

ขั้นตอนที่ 1: กำหนดพร็อพเพอร์ตี้ของระบบ

เมื่อเพิ่มพร็อพเพอร์ตี้ของระบบ ให้เลือกชื่อพร็อพเพอร์ตี้ แล้วเชื่อมโยงกับบริบทของพร็อพเพอร์ตี้ SELinux หากไม่มีบริบทที่มีอยู่ที่เหมาะสม ให้สร้างบริบทใหม่ ชื่อนี้จะใช้เมื่อเข้าถึงพร็อพเพอร์ตี้ ส่วนบริบทของพร็อพเพอร์ตี้จะใช้เพื่อควบคุมการช่วยเหลือพิเศษใน SELinux ชื่ออาจเป็นสตริงใดก็ได้ แต่ AOSP แนะนำให้ใช้รูปแบบที่มีโครงสร้างเพื่อความชัดเจน

ชื่อพร็อพเพอร์ตี้

ใช้รูปแบบนี้ร่วมกับตัวพิมพ์เล็ก/ใหญ่ snake_case:

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

ใช้ "" (ละเว้น), ro (สำหรับพร็อพเพอร์ตี้ที่ตั้งไว้เพียงครั้งเดียว) หรือ persist (สำหรับพร็อพเพอร์ตี้ที่ยังคงอยู่ในช่วงรีบูต) สำหรับองค์ประกอบ prefix

ข้อควรระวัง

ใช้ ro เฉพาะเมื่อคุณมั่นใจว่าไม่จำเป็นต้องใช้ prefix สำหรับการเขียนในอนาคต ** ไม่ต้องระบุคำนำหน้า ro** แต่ให้ใช้ sepolicy เพื่อทำให้ prefix เป็นแบบอ่านอย่างเดียวแทน (กล่าวคือ เขียนได้ด้วย init เท่านั้น)

ใช้ persist เฉพาะเมื่อคุณมั่นใจว่าค่าดังกล่าวต้องคงอยู่ในการรีบูต และคุณต้องใช้พร็อพเพอร์ตี้ของระบบเท่านั้น

Google จะตรวจสอบพร็อพเพอร์ตี้ของระบบที่มีพร็อพเพอร์ตี้ ro หรือ persist อย่างเคร่งครัด

คำว่า group ใช้เพื่อรวบรวมพร็อพเพอร์ตี้ที่เกี่ยวข้อง แต่มีไว้เพื่อเป็นชื่อระบบย่อยที่คล้ายกับ audio หรือ telephony อย่าใช้คำที่กำกวมหรือมากเกินไป เช่น sys, system, dev, default หรือ config

โดยทั่วไปแล้วมักจะใช้ชื่อประเภทโดเมนของกระบวนการที่มีสิทธิ์เข้าถึงแบบอ่านหรือเขียนพิเศษในพร็อพเพอร์ตี้ระบบ ตัวอย่างเช่น สำหรับพร็อพเพอร์ตี้ระบบที่กระบวนการ vold มีสิทธิ์เขียน โดยทั่วไปแล้วจะใช้ vold (ชื่อของประเภทโดเมนสำหรับกระบวนการ) เป็นชื่อกลุ่ม

หากจำเป็น ให้เพิ่ม subgroup เพื่อจัดหมวดหมู่พร็อพเพอร์ตี้เพิ่มเติม แต่หลีกเลี่ยงการใช้คำที่กำกวมหรือมากเกินไปเพื่ออธิบายองค์ประกอบนี้ (นอกจากนี้ คุณยังมี subgroup ได้มากกว่า 1 รายการ)

ชื่อกลุ่มหลายชื่อได้รับการกำหนดแล้ว ตรวจสอบไฟล์ system/sepolicy/private/property_contexts และใช้ชื่อกลุ่มที่มีอยู่หากเป็นไปได้ แทนการสร้างใหม่ ตารางต่อไปนี้แสดงตัวอย่างชื่อกลุ่มที่ใช้บ่อย

โดเมน กลุ่ม (และกลุ่มย่อย)
เกี่ยวกับบลูทูธ bluetooth
sysprops จากเคอร์เนล cmdline boot
sysprops ที่ระบุบิลด์ build
เกี่ยวกับโทรศัพท์ telephony
เกี่ยวกับเสียง audio
เกี่ยวกับกราฟิก graphics
เกี่ยวข้องกับ vold vold

ต่อไปนี้จะกำหนดการใช้ name และ type ในตัวอย่างนิพจน์ทั่วไปก่อนหน้า

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

  • name ระบุพร็อพเพอร์ตี้ของระบบภายในกลุ่ม

  • type เป็นองค์ประกอบที่ไม่บังคับซึ่งชี้แจงประเภทหรือ Intent ของพร็อพเพอร์ตี้ระบบ เช่น แทนที่จะตั้งชื่อ sysprop เป็น audio.awesome_feature_enabled หรือ audio.awesome_feature ให้เปลี่ยนชื่อเป็น audio.awesome_feature.enabled เพื่อแสดงประเภทพร็อพเพอร์ตี้ของระบบและ Intent

ไม่มีกฎที่เจาะจงเกี่ยวกับประเภท คำแนะนำการใช้งานมีดังต่อไปนี้

  • enabled: ใช้ในกรณีที่ประเภทเป็นพร็อพเพอร์ตี้ระบบบูลีนที่ใช้เปิดหรือปิดฟีเจอร์
  • config: ใช้ในกรณีที่ Intent เป็นการชี้แจงว่าพร็อพเพอร์ตี้ของระบบไม่ได้หมายถึงสถานะแบบไดนามิกของระบบ แต่แสดงถึงค่าที่กำหนดค่าไว้ล่วงหน้า (เช่น แบบอ่านอย่างเดียว)
  • List: ใช้ในกรณีที่เป็นพร็อพเพอร์ตี้ระบบที่มีค่าเป็นรายการ
  • Timeoutmillis: ใช้ในกรณีที่เป็นพร็อพเพอร์ตี้ระบบสำหรับค่าระยะหมดเวลาในหน่วยมิลลิวินาที

ตัวอย่าง

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

บริบทพร็อพเพอร์ตี้

รูปแบบบริบทของพร็อพเพอร์ตี้ SELinux ใหม่ช่วยให้สามารถตั้งชื่ออย่างละเอียดและสื่อความหมายได้มากขึ้น เช่นเดียวกับที่ใช้สำหรับชื่อพร็อพเพอร์ตี้ AOSP แนะนำให้ใช้รูปแบบต่อไปนี้

{group}[_{subgroup}]*_prop

ข้อกำหนดมีคำจำกัดความดังต่อไปนี้

group และ subgroup มีความหมายเดียวกับที่กำหนดไว้สำหรับ regex ตัวอย่างก่อนหน้า ตัวอย่างเช่น vold_config_prop จะบ่งบอกพร็อพเพอร์ตี้ซึ่งเป็นการกำหนดค่าจากผู้ให้บริการและควรกำหนดโดย vendor_init ขณะที่ vold_status_prop หรือ vold_prop เพียงอย่างเดียวหมายถึงพร็อพเพอร์ตี้ที่แสดงสถานะปัจจุบันของ vold

เมื่อตั้งชื่อบริบทพร็อพเพอร์ตี้ ให้เลือกชื่อที่สื่อถึงการใช้งานทั่วไปของพร็อพเพอร์ตี้ โดยเฉพาะอย่างยิ่ง ให้หลีกเลี่ยงคำประเภทต่อไปนี้

  • คำที่ดูกว้างและกำกวมเกินไป เช่น sys, system, default
  • ข้อกำหนดที่เข้ารหัสการช่วยเหลือพิเศษโดยตรง เช่น exported, apponly, ro, public, private

คุณต้องการใช้ชื่ออย่างเช่น vold_config_prop เป็น exported_vold_prop หรือ vold_vendor_writable_prop

ประเภท

ประเภทพร็อพเพอร์ตี้อาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้ตามที่แสดงในตาราง

ประเภท คำจำกัดความ
บูลีน true หรือ 1 สำหรับจริง, false หรือ 0 สำหรับเท็จ
จำนวนเต็ม จำนวนเต็ม 64 บิตแบบมีเครื่องหมาย
จำนวนเต็มที่ไม่ได้ลงชื่อ จำนวนเต็ม 64 บิตที่ไม่มีเครื่องหมาย
ดับเบิล ทศนิยมแบบสองจุด
สตริง สตริง UTF-8 ที่ถูกต้อง
Enum ค่าเป็นสตริง UTF-8 ที่ถูกต้องใดก็ได้โดยไม่มีช่องว่าง
รายการด้านบน คอมมา (,) ใช้เป็นตัวคั่น
รายการจำนวนเต็ม [1, 2, 3] จะจัดเก็บเป็น 1,2,3

ระบบเก็บข้อมูลพร็อพเพอร์ตี้ทั้งหมดเป็นสตริงเป็นการภายใน คุณบังคับใช้ประเภทได้โดยการระบุเป็นไฟล์ property_contexts ดูข้อมูลเพิ่มเติมได้ที่ property_contexts ในขั้นตอนที่ 3

ขั้นตอนที่ 2: ระบุระดับการช่วยเหลือพิเศษที่จำเป็น

มีมาโครตัวช่วยระบุพร็อพเพอร์ตี้อยู่ 4 แบบ

ประเภทการช่วยเหลือพิเศษ ความหมาย
system_internal_prop พร็อพเพอร์ตี้ที่ใช้ใน /system เท่านั้น
system_restricted_prop พร็อพเพอร์ตี้ที่อ่านนอก /system แต่ไม่ได้เขียน
system_vendor_config_prop พร็อพเพอร์ตี้ที่อ่านนอก /system และเขียนโดย vendor_init เท่านั้น
system_public_prop พร็อพเพอร์ตี้ที่อ่านและเขียนภายนอก /system

กำหนดขอบเขตการเข้าถึงพร็อพเพอร์ตี้ของระบบให้แคบที่สุดเท่าที่จะทำได้ ในอดีต การเข้าถึงในวงกว้างส่งผลให้แอปหยุดทำงานและมีช่องโหว่ด้านความปลอดภัย พิจารณาคำถามต่อไปนี้เมื่อกำหนดขอบเขต

  • จำเป็นต้องเก็บพร็อพเพอร์ตี้ของระบบนี้ไว้หรือไม่ (หากใช่ เพราะเหตุใด)
  • กระบวนการใดควรมีสิทธิ์การเข้าถึงระดับอ่านในพร็อพเพอร์ตี้นี้
  • กระบวนการใดควรมีสิทธิ์การเขียนพร็อพเพอร์ตี้นี้

ใช้คำถามก่อนหน้าและแผนผังการตัดสินใจต่อไปนี้เป็นเครื่องมือในการกำหนดขอบเขตที่เหมาะสมสำหรับการเข้าถึง

แผนผังการตัดสินใจสำหรับการกำหนดขอบเขตการเข้าถึง

รูปที่ 1 แผนผังการตัดสินใจสำหรับการกำหนดขอบเขตการเข้าถึงพร็อพเพอร์ตี้ของระบบ

ขั้นตอนที่ 3: เพิ่มลงในระบบ/นโยบาย

เมื่อเข้าถึง sysprop แล้ว SELinux จะควบคุมความสามารถในการเข้าถึงของกระบวนการ หลังจากที่ระบุระดับความสามารถเข้าถึงได้ง่ายที่ต้องการแล้ว ให้กำหนดบริบทของพร็อพเพอร์ตี้ใน system/sepolicy พร้อมกับกฎ allow และ neverallow เพิ่มเติมเกี่ยวกับกระบวนการ (และไม่ได้รับอนุญาต) ให้อ่านหรือเขียน

ก่อนอื่นให้กำหนดบริบทของพร็อพเพอร์ตี้ในไฟล์ system/sepolicy/public/property.te หากพร็อพเพอร์ตี้เป็นระบบภายใน ให้กำหนดในไฟล์ system/sepolicy/private/property.te ใช้มาโคร system_[accessibility]_prop([context]) ตัวใดตัวหนึ่งที่ให้การช่วยเหลือพิเศษที่จำเป็นสำหรับพร็อพเพอร์ตี้ระบบของคุณ นี่คือตัวอย่างสำหรับไฟล์ system/sepolicy/public/property.te

system_public_prop(audio_foo_prop)
system_vendor_config_prop(audio_bar_prop)

ตัวอย่างที่จะเพิ่มในไฟล์ system/sepolicy/private/property.te

system_internal_prop(audio_baz_prop)

ขั้นที่สอง ให้สิทธิ์อ่านและ (หรือ) เขียนบริบทของพร็อพเพอร์ตี้ ใช้มาโคร set_prop และ get_prop เพื่อให้สิทธิ์เข้าถึงในไฟล์ system/sepolicy/public/{domain}.te หรือ system/sepolicy/private/{domain}.te ใช้ private เมื่อใดก็ตามที่เป็นไปได้ public จะเหมาะสมก็ต่อเมื่อมาโคร set_prop หรือ get_prop มีผลกับโดเมนใดๆ ที่อยู่นอกโดเมนหลัก

ตัวอย่างเช่น ในไฟล์ system/sepolicy/private/audio.te

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

ตัวอย่างเช่น ในไฟล์ system/sepolicy/public/domain.te

get_prop(domain, audio_bar_prop)

ขั้นตอนที่ 3 เพิ่มกฎ "ไม่อนุญาต" บางส่วนเพื่อลดการช่วยเหลือพิเศษที่มาโครกำหนดขอบเขตลงไปอีก เช่น สมมติว่าคุณใช้ system_restricted_prop เพราะกระบวนการของผู้ให้บริการจะต้องอ่านพร็อพเพอร์ตี้ระบบ หากกระบวนการของผู้ให้บริการทั้งหมดไม่จำเป็นต้องใช้สิทธิ์การอ่าน และจำเป็นต้องใช้สิทธิ์ระดับอ่านในบางกระบวนการเท่านั้น (เช่น vendor_init) จะห้ามไม่ให้กระบวนการของผู้ให้บริการที่ไม่จำเป็นต้องใช้สิทธิ์การอ่าน

ใช้ไวยากรณ์ต่อไปนี้เพื่อจำกัดการเข้าถึงการเขียนและการอ่าน

หากต้องการจำกัดการเข้าถึงการเขียน ให้ทำดังนี้

neverallow [domain] [context]:property_service set;

หากต้องการจำกัดการเข้าถึงการอ่าน ให้ทำดังนี้

neverallow [domain] [context]:file no_rw_file_perms;

วางกฎ Neverallow ในไฟล์ system/sepolicy/private/{domain}.te หากกฎ neverallow เชื่อมโยงกับโดเมนที่เฉพาะเจาะจง สำหรับกฎ Neverallow ที่กว้างขึ้น ให้ใช้โดเมนทั่วไปดังตัวอย่างต่อไปนี้ตามความเหมาะสม

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

วางข้อมูลต่อไปนี้ในไฟล์ system/sepolicy/private/audio.te

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

วางข้อมูลต่อไปนี้ในไฟล์ system/sepolicy/private/property.te

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

โปรดทราบว่า {domain -coredomain} จะบันทึกกระบวนการของผู้ให้บริการทั้งหมด ดังนั้น {domain -coredomain -vendor_init} หมายถึง "กระบวนการของผู้ให้บริการทั้งหมด ยกเว้น vendor_init"

สุดท้าย ให้เชื่อมโยงพร็อพเพอร์ตี้ของระบบกับบริบทของพร็อพเพอร์ตี้ วิธีนี้ช่วยให้มั่นใจได้ว่าสิทธิ์เข้าถึงที่ได้รับอนุญาตและกฎที่ไม่เคยอนุญาตที่ใช้กับบริบทพร็อพเพอร์ตี้จะใช้กับพร็อพเพอร์ตี้จริง โดยให้เพิ่มรายการลงในไฟล์ property_contexts ซึ่งเป็นไฟล์ที่อธิบายการแมประหว่างพร็อพเพอร์ตี้ระบบกับบริบทพร็อพเพอร์ตี้ ในไฟล์นี้ คุณสามารถระบุพร็อพเพอร์ตี้เดี่ยวหรือคำนำหน้าสำหรับพร็อพเพอร์ตี้ที่จะแมปลงในบริบท

ไวยากรณ์สำหรับการแมปพร็อพเพอร์ตี้เดียวมีดังนี้

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

นี่คือไวยากรณ์สำหรับการจับคู่คำนำหน้า:

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

คุณเลือกระบุประเภทของพร็อพเพอร์ตี้ได้ ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้

  • bool
  • int
  • uint
  • double
  • enum [list of possible values...]
  • string (ใช้ string สำหรับรายการพร็อพเพอร์ตี้)

ตรวจสอบว่ารายการทั้งหมดเป็นประเภทที่กำหนดเมื่อเป็นไปได้ เนื่องจากมีการบังคับใช้ type เมื่อตั้งค่า property ตัวอย่างต่อไปนี้แสดงวิธีเขียนการแมป

# 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

เมื่อรายการที่ตรงกันทุกประการกับรายการคำนำหน้าขัดแย้งกัน รายการนั้นๆ จะมีลำดับความสำคัญเหนือกว่า ดูตัวอย่างเพิ่มเติมได้ที่ system/sepolicy/private/property_contexts

ขั้นตอนที่ 4: ระบุข้อกำหนดด้านความเสถียร

ความเสถียรเป็นอีกแง่มุมหนึ่งของพร็อพเพอร์ตี้ของระบบ และแตกต่างจากการช่วยเหลือพิเศษ ความเสถียรคือการตัดสินใจว่าจะเปลี่ยนพร็อพเพอร์ตี้ของระบบ (เช่น เปลี่ยนชื่อ หรือแม้กระทั่งนำออก) ในอนาคตได้หรือไม่ ซึ่งมีความสำคัญมากเป็นพิเศษเมื่อระบบปฏิบัติการ Android กลายเป็นโมดูลต่างๆ เมื่อใช้ Treble คุณจะอัปเดตพาร์ติชันระบบ ผู้ให้บริการ และผลิตภัณฑ์แยกกันได้ เมื่อใช้เมนไลน์ ระบบปฏิบัติการบางส่วนจะแยกส่วนเป็นโมดูลที่อัปเดตได้ (ใน APEXes หรือ APK)

หากพร็อพเพอร์ตี้ของระบบใช้ในซอฟต์แวร์หลายรายการที่อัปเดตได้ เช่น ในพาร์ติชันระบบและผู้ให้บริการ พร็อพเพอร์ตี้ดังกล่าวต้องมีความเสถียร อย่างไรก็ตาม หากมีการใช้เฉพาะภายในโมดูลเมนไลน์ที่เฉพาะเจาะจงเท่านั้น คุณสามารถเปลี่ยนชื่อ ประเภท หรือบริบทพร็อพเพอร์ตี้ หรือแม้กระทั่งนำออกก็ได้

ถามคำถามต่อไปนี้เพื่อระบุความเสถียรของพร็อพเพอร์ตี้ระบบ

  • พร็อพเพอร์ตี้ของระบบนี้มีไว้เพื่อกำหนดค่าโดยพาร์ทเนอร์ (หรือกำหนดค่าต่างกันตามอุปกรณ์) ใช่หรือไม่ หากใช่ ไฟล์ต้องเสถียร
  • พร็อพเพอร์ตี้ระบบที่กำหนดโดย AOSP นี้มีขึ้นเพื่อเขียนหรืออ่านจากโค้ด (ไม่ใช่กระบวนการ) ที่มีอยู่ในพาร์ติชันที่ไม่ใช่ระบบ เช่น vendor.img หรือ product.img ใช่ไหม หากใช่ ไฟล์ต้องเสถียร
  • มีการเข้าถึงพร็อพเพอร์ตี้ของระบบนี้ในโมดูลเมนไลน์หรือโมดูลเมนไลน์และส่วนที่ไม่สามารถอัปเดตได้ของแพลตฟอร์มไหม หากใช่ ไฟล์ต้องเสถียร

สำหรับพร็อพเพอร์ตี้ระบบที่เสถียร ให้กำหนดแต่ละรายการเป็น API อย่างเป็นทางการและใช้ API เพื่อเข้าถึงพร็อพเพอร์ตี้ระบบตามที่อธิบายไว้ในขั้นตอนที่ 6

ขั้นตอนที่ 5: ตั้งค่าพร็อพเพอร์ตี้ในเวลาบิลด์

ตั้งค่าพร็อพเพอร์ตี้ในเวลาบิลด์ด้วยตัวแปร Makefile โดยในทางเทคนิค ค่าต่างๆ จะมีอยู่ใน {partition}/build.prop จากนั้น init จะอ่าน {partition}/build.prop เพื่อตั้งค่าพร็อพเพอร์ตี้ ตัวแปรดังกล่าวมี 2 ชุด คือ PRODUCT_{PARTITION}_PROPERTIES และ TARGET_{PARTITION}_PROP

PRODUCT_{PARTITION}_PROPERTIES มีรายการค่าของพร็อพเพอร์ตี้ ไวยากรณ์คือ {prop}={value} หรือ {prop}?={value}

{prop}={value} เป็นการมอบหมายทั่วไปซึ่งช่วยให้มั่นใจว่ามีการตั้งค่า {prop} เป็น {value} โดยจะกำหนดได้เพียง 1 รายการต่อพร็อพเพอร์ตี้ 1 รายการเท่านั้น

{prop}?={value} เป็นงานที่ไม่บังคับ {prop} จะตั้งค่าเป็น {value} เฉพาะเมื่อไม่มีงาน {prop}={value} เท่านั้น หากมีการมอบหมายที่ไม่บังคับหลายรายการ ตัวเลือกแรกจะชนะ

# 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 มีรายการไฟล์ซึ่งส่งไปยัง {partition}/build.prop โดยตรง แต่ละไฟล์จะมีรายชื่อคู่กัน {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

ดูรายละเอียดเพิ่มเติมได้ที่ build/make/core/sysprop.mk

ขั้นตอนที่ 6: เข้าถึงพร็อพเพอร์ตี้ขณะรันไทม์

อ่านและเขียนพร็อพเพอร์ตี้ขณะรันไทม์ได้

สคริปต์เริ่มต้น

ไฟล์สคริปต์ Init (โดยทั่วไปคือไฟล์ *.rc) จะอ่านพร็อพเพอร์ตี้โดยใช้ ${prop} หรือ ${prop:-default} ได้ รวมถึงตั้งค่าการดำเนินการที่จะทำงานเมื่อพร็อพเพอร์ตี้เป็นค่าที่เจาะจง และเขียนพร็อพเพอร์ตี้ได้โดยใช้คำสั่ง 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}

คำสั่ง Shell getprop และ setprop

คุณใช้คำสั่ง Shell getprop หรือ setprop ตามลำดับเพื่ออ่านหรือเขียนพร็อพเพอร์ตี้ได้ โปรดเรียกใช้ getprop --help หรือ setprop --help เพื่อดูรายละเอียดเพิ่มเติม

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

Sysprop เป็น API สำหรับ C++/Java/Rust

เมื่อใช้ sysprop เป็น API คุณสามารถกำหนดพร็อพเพอร์ตี้ของระบบและใช้ API ที่สร้างขึ้นโดยอัตโนมัติซึ่งเป็นรูปธรรมและพิมพ์ได้ การตั้งค่า scope ด้วย Public ยังทำให้ API ที่สร้างขึ้นพร้อมใช้งานสำหรับโมดูลต่างๆ ในทุกขอบเขต และทำให้ API มีความเสถียรด้วย ต่อไปนี้คือตัวอย่างของไฟล์ .sysprop, โมดูล Android.bp รวมถึง C++, Java และโค้ด Rust

# 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);

ดูข้อมูลเพิ่มเติมได้ที่ใช้พร็อพเพอร์ตี้ระบบเป็น API

ฟังก์ชันและวิธีการของพร็อพเพอร์ตี้ระดับ C/C++, Java และ Rust

เมื่อเป็นไปได้ ให้ใช้ Sysprop เป็น API แม้ว่าฟังก์ชัน Rust หรือ C/C++ ระดับต่ำหรือเมธอด Java ระดับต่ำจะใช้ได้ก็ตาม

libc, libbase และ libcutils เสนอฟังก์ชันพร็อพเพอร์ตี้ของระบบ C++ libc มี API ที่สำคัญ ส่วนฟังก์ชัน libbase และ libcutils จะเป็น Wrapper หากเป็นไปได้ ให้ใช้ฟังก์ชัน sysprop ของ libbase ซึ่งสะดวกที่สุด และไบนารีของโฮสต์สามารถใช้ฟังก์ชัน libbase ดูรายละเอียดเพิ่มเติมได้ที่ sys/system_properties.h (libc), android-base/properties.h (libbase) และ cutils/properties.h (libcutils)

คลาส android.os.SystemProperties มีวิธีพร็อพเพอร์ตี้ระบบ Java

โมดูล rustutils::system_properties มีฟังก์ชันและประเภทพร็อพเพอร์ตี้ของระบบ Rust

ภาคผนวก: เพิ่มพร็อพเพอร์ตี้เฉพาะผู้ให้บริการ

พาร์ทเนอร์ (รวมถึง Googler ที่ทำงานในบริบทของการพัฒนา Pixel) ต้องการกำหนดพร็อพเพอร์ตี้ของระบบเฉพาะฮาร์ดแวร์ (หรือเฉพาะอุปกรณ์) พร็อพเพอร์ตี้เฉพาะผู้ให้บริการคือพร็อพเพอร์ตี้ที่พาร์ทเนอร์เป็นเจ้าของซึ่งไม่ซ้ำกันสำหรับฮาร์ดแวร์หรืออุปกรณ์ของพาร์ทเนอร์ ไม่ใช่แพลตฟอร์ม เนื่องจากทรัพยากรเหล่านี้ขึ้นอยู่กับฮาร์ดแวร์หรืออุปกรณ์ ดังนั้นจึงควรใช้ภายในพาร์ติชัน /vendor หรือ /odm

นับตั้งแต่ Project Treble ได้แยกพร็อพเพอร์ตี้แพลตฟอร์มและพร็อพเพอร์ตี้ของผู้ให้บริการเข้าด้วยกันโดยสมบูรณ์เพื่อไม่ให้มีความขัดแย้งกัน เนื้อหาต่อไปนี้อธิบายวิธีกำหนดพร็อพเพอร์ตี้ของผู้ให้บริการ และบอกพร็อพเพอร์ตี้ของผู้ให้บริการที่ต้องใช้เสมอ

เนมสเปซในชื่อพร็อพเพอร์ตี้และชื่อบริบท

พร็อพเพอร์ตี้ของผู้ให้บริการทั้งหมดต้องขึ้นต้นด้วยคำนำหน้าอย่างใดอย่างหนึ่งต่อไปนี้เพื่อป้องกันการขัดแย้งระหว่างพร็อพเพอร์ตี้กับพร็อพเพอร์ตี้ของพาร์ติชันอื่นๆ

  • 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.

โปรดทราบว่าอนุญาตให้ใช้ ro.hardware. เป็นคํานําหน้าได้ แต่ใช้สําหรับความเข้ากันได้เท่านั้น อย่าใช้สำหรับพร็อพเพอร์ตี้ปกติ

ตัวอย่างต่อไปนี้ทั้งหมดใช้คำนำหน้าอย่างใดอย่างหนึ่งที่แสดงอยู่ก่อนหน้า

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

บริบทพร็อพเพอร์ตี้ของผู้ให้บริการทั้งหมดต้องขึ้นต้นด้วย vendor_ วิธีนี้ยังใช้กับ การใช้งานร่วมกันด้วย ตัวอย่างมีดังต่อไปนี้

  • vendor_radio_prop
  • vendor_faceauth_prop
  • vendor_usb_prop

ผู้ให้บริการมีหน้าที่รับผิดชอบในการตั้งชื่อและดูแลรักษาพร็อพเพอร์ตี้ ดังนั้นทำตามรูปแบบที่แนะนำในขั้นตอนที่ 2 นอกเหนือจากข้อกำหนดเนมสเปซของผู้ให้บริการ

กฎ SEPolicy เฉพาะผู้ให้บริการและ property_contexts

มาโคร vendor_internal_prop จะกำหนดพร็อพเพอร์ตี้ผู้ให้บริการได้ ใส่กฎเฉพาะผู้ให้บริการที่คุณกำหนดในไดเรกทอรี BOARD_VENDOR_SEPOLICY_DIRS เช่น สมมติว่าคุณกำหนดพร็อพเพอร์ตี้ Faceauth ของผู้ให้บริการในปะการัง

ในไฟล์ BoardConfig.mk (หรือใน BoardConfig.mk ใดก็ตาม) ให้ใส่ข้อมูลต่อไปนี้

BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy

ในไฟล์ device/google/coral-sepolicy/private/property.te ให้ใส่ข้อมูลต่อไปนี้

vendor_internal_prop(vendor_faceauth_prop)

ในไฟล์ device/google/coral-sepolicy/private/property_contexts ให้ใส่ข้อมูลต่อไปนี้

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

ข้อจำกัดของพร็อพเพอร์ตี้ผู้ให้บริการ

เนื่องจากพาร์ติชันระบบและพาร์ติชันผลิตภัณฑ์พึ่งพาผู้ให้บริการไม่ได้ จึงไม่อนุญาตให้เข้าถึงพร็อพเพอร์ตี้ของผู้ให้บริการจากพาร์ติชัน system, system-ext หรือ product

ภาคผนวก: เปลี่ยนชื่อพร็อพเพอร์ตี้ที่มีอยู่

เมื่อต้องเลิกใช้งานพร็อพเพอร์ตี้และย้ายไปยังพร็อพเพอร์ตี้ใหม่ ให้ใช้ Sysprop เป็น API เพื่อเปลี่ยนชื่อพร็อพเพอร์ตี้ที่มีอยู่ ซึ่งช่วยรักษาความเข้ากันได้แบบย้อนหลังโดยการระบุทั้งชื่อเดิมและชื่อพร็อพเพอร์ตี้ใหม่ กล่าวคือ คุณตั้งชื่อเดิมตามช่อง legacy_prop_name ในไฟล์ .sysprop ได้ API ที่สร้างขึ้นจะพยายามอ่าน prop_name และใช้ legacy_prop_name หากไม่มี prop_name

เช่น ขั้นตอนต่อไปนี้เปลี่ยนชื่อ awesome_feature_foo_enabled เป็น foo.awesome_feature.enabled

ในไฟล์ 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"
}

ในโค้ด 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);

โปรดทราบข้อควรระวังต่อไปนี้

  • อย่างแรกคือไม่สามารถเปลี่ยนประเภทของ sysprop ได้ ตัวอย่างเช่น คุณไม่สามารถสร้างพร็อพเพอร์ตี้ int เป็นพร็อพเพอร์ตี้ string โดยเปลี่ยนได้เฉพาะชื่อเท่านั้น

  • ประการที่ 2 เฉพาะ API การอ่านเท่านั้นที่กลับไปใช้ชื่อเดิม Write API จะไม่หายไป หาก sysprop เป็น เขียนได้ คุณจะเปลี่ยนชื่อไม่ได้