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

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

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

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

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

ใช้รูปแบบนี้โดยใช้ตัวพิมพ์เล็กและคั่นด้วยขีดล่าง

[{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 จากบรรทัดคำสั่งของเคอร์เนล boot
sysprops ที่ระบุบิลด์ build
ที่เกี่ยวข้องกับโทรศัพท์ telephony
ที่เกี่ยวข้องกับเสียง audio
กราฟิกที่เกี่ยวข้อง graphics
เกี่ยวกับ vold vold

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

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

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

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

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

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

ตัวอย่าง

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

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

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

{group}[_{subgroup}]*_prop

คำจำกัดความของคำศัพท์มีดังนี้

group และ subgroup มีความหมายเหมือนกับที่กำหนดไว้สำหรับนิพจน์ทั่วไปตัวอย่างก่อนหน้า เช่น 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: เพิ่มลงใน system/sepolicy

เมื่อเข้าถึง 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)

ประการที่ 2 ให้สิทธิ์การอ่านและ (หรือ) การเขียนบริบทพร็อพเพอร์ตี้ ใช้มาโคร 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)

ประการที่สาม เพิ่มกฎ neverallow เพื่อลดการเข้าถึงที่ กำหนดขอบเขตโดยมาโครเพิ่มเติม ตัวอย่างเช่น สมมติว่าคุณใช้ 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"

สุดท้าย ให้เชื่อมโยงพร็อพเพอร์ตี้ของระบบกับบริบทของพร็อพเพอร์ตี้ ซึ่งจะช่วยให้มั่นใจได้ว่าสิทธิ์เข้าถึงที่ได้รับและกฎ neverallow ที่ใช้กับบริบทของพร็อพเพอร์ตี้จะใช้กับพร็อพเพอร์ตี้จริง โดยเพิ่มรายการลงในไฟล์ 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 ช่วยให้สามารถอัปเดตพาร์ติชันระบบ ผู้ให้บริการ และผลิตภัณฑ์แยกกันได้ Mainline จะแยกส่วนบางส่วนของระบบปฏิบัติการเป็นโมดูลที่อัปเดตได้ (ใน APEX หรือ APK)

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

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

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

สำหรับพร็อพเพอร์ตี้ของระบบที่เสถียร ให้กำหนดแต่ละรายการอย่างเป็นทางการเป็น 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 รายการต่อพร็อพเพอร์ตี้เดียว

{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: เข้าถึงพร็อพเพอร์ตี้ที่รันไทม์

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

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

ไฟล์สคริปต์เริ่มต้น (โดยปกติคือไฟล์ *.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}

คำสั่งเชลล์ getprop และ setprop

คุณใช้คำสั่งเชลล์ 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 ที่สร้างขึ้นโดยอัตโนมัติได้ ซึ่งเป็น 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 แม้ว่าคุณจะใช้ฟังก์ชัน C/C++ หรือ Rust ระดับต่ำ หรือเมธอด Java ระดับต่ำได้ก็ตาม

libc, libbase และ libcutils มีฟังก์ชันพร็อพเพอร์ตี้ของระบบ C++ libc มี API พื้นฐาน ขณะที่ฟังก์ชัน libbase และ libcutils เป็น Wrapper หากเป็นไปได้ ให้ใช้ฟังก์ชัน libbase sysprop เนื่องจากเป็นฟังก์ชันที่สะดวกที่สุด และไบนารีของโฮสต์สามารถใช้ฟังก์ชัน 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 ของผู้ให้บริการใน Coral

ในไฟล์ 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 การอ่านเท่านั้นที่จะเปลี่ยนไปใช้ชื่อเดิม API การเขียนจะไม่ ย้อนกลับ หาก sysprop เป็นแบบเขียนได้ คุณจะเปลี่ยนชื่อไม่ได้