พัฒนารหัสเคอร์เนลสำหรับ GKI

รูปภาพเคอร์เนลทั่วไป (GKI) จะลดการกระจัดกระจายของเคิร์นัลโดยการปรับให้สอดคล้องกับเคอร์เนล Linux เวอร์ชันที่พัฒนาขึ้น อย่างไรก็ตาม มีเหตุผลหลายประการที่ทำให้แพตช์เหล่านี้ไม่ได้รับการยอมรับจากอัปสตรีม รวมถึงมีกำหนดการของผลิตภัณฑ์ที่ต้องปฏิบัติตาม ดังนั้นจึงมีการบำรุงรักษาแพตช์บางแพตช์ในแหล่งที่มา Kernel Common (ACK) ของ Android ที่สร้าง GKI

นักพัฒนาซอฟต์แวร์ต้องส่งการเปลี่ยนแปลงโค้ดไปยัง upstream โดยใช้ Linux Kernel Mailing List (LKML) เป็นตัวเลือกแรก และส่งการเปลี่ยนแปลงโค้ดไปยังสาขา ACKandroid-mainline เฉพาะในกรณีที่มีเหตุผลอันสมควรที่ upstream ไม่เหมาะ ตัวอย่างสาเหตุที่เป็นไปได้และวิธีจัดการมีดังนี้

  • ส่งแพตช์ไปยัง LKML แล้ว แต่ไม่ได้รับการยอมรับภายในเวลาเปิดตัวผลิตภัณฑ์ วิธีจัดการแพตช์นี้

    • แสดงหลักฐานว่ามีการส่งแพตช์ไปยัง LKML และความคิดเห็นที่ได้รับสำหรับแพตช์ หรือเวลาโดยประมาณที่ระบบส่งแพตช์ไปยังอัปสตรีม
    • ตัดสินใจเลือกแนวทางในการเผยแพร่แพตช์ใน ACK, ขออนุมัติจากฝั่งอัปสตรีม แล้วนำแพตช์ออกจาก ACK เมื่อผสานเวอร์ชันอัปสตรีมขั้นสุดท้ายลงใน ACK
  • แพตช์กำหนด EXPORT_SYMBOLS_GPL() สำหรับโมดูลของผู้ให้บริการ แต่ส่งไปยังอัปสตรีมไม่ได้เนื่องจากไม่มีโมดูลในต้นไม้ที่ใช้สัญลักษณ์ดังกล่าว หากต้องการจัดการกับแพตช์นี้ โปรดระบุรายละเอียดว่าเหตุใดโมดูลของคุณจึงส่งไปยังระบบส่วนกลางไม่ได้ และทางเลือกอื่นๆ ที่คุณพิจารณาก่อนที่จะส่งคำขอนี้

  • แพตช์ไม่เหมาะสําหรับเวอร์ชันที่อัปเดตจากเวอร์ชันหลักมากพอและไม่มีเวลาที่จะเขียนโค้ดใหม่ก่อนการเปิดตัวผลิตภัณฑ์ ในการจัดการแพตช์นี้ โปรดระบุเวลาโดยประมาณในการส่งอัปสตรีมของแพตช์แบบเปลี่ยนโครงสร้างภายในโค้ด (จะไม่ยอมรับแพตช์ใน ACK หากไม่มีแผนที่จะส่งอัปสตรีมของแพตช์ที่ปรับเปลี่ยนโครงสร้างใหม่เพื่อรับการตรวจสอบ)

  • อัปสตรีมไม่ยอมรับแพตช์เนื่องจาก... <insert reason here> หากต้องการจัดการกับแพตช์นี้ โปรดติดต่อทีมเคอร์เนล Android และทำงานร่วมกับเราเกี่ยวกับตัวเลือกในการรีแฟกทอเรียลแพตช์เพื่อให้ส่งเข้ารับการตรวจสอบและยอมรับในอัปสตรีมได้

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

ข้อกำหนดแพตช์

แพตช์ต้องเป็นไปตามมาตรฐานการเขียนโค้ดเคอร์เนล Linux ที่อธิบายไว้ในซอร์สทรี Linux ไม่ว่าจะส่งไปยัง upstream หรือ ACK ระบบจะเรียกใช้สคริปต์ scripts/checkpatch.pl เป็นส่วนหนึ่งของการทดสอบก่อนส่งของ Gerrit ดังนั้นให้เรียกใช้ล่วงหน้าเพื่อให้แน่ใจว่าสคริปต์ทำงานได้ หากต้องการเรียกใช้สคริปต์ checkpatch ที่มีการกำหนดค่าเดียวกับการทดสอบก่อนส่ง ให้ใช้ //build/kernel/static_analysis:checkpatch_presubmit ดูรายละเอียดได้ที่ build/kernel/kleaf/docs/checkpatch.md

แพตช์ ACK

แพตช์ที่ส่งไปยัง ACK ต้องเป็นไปตามมาตรฐานการเขียนโค้ดเคอร์เนล Linux และหลักเกณฑ์การมีส่วนร่วม คุณต้องใส่แท็ก Change-Id ในข้อความคอมมิต หากคุณส่งแพตช์ไปยังหลายสาขา (เช่น android-mainline และ android12-5.4) คุณต้องใช้ Change-Id เดียวกันกับอินสแตนซ์ทั้งหมดของแพตช์

ส่งแพตช์ไปยัง LKML ก่อนเพื่อรับการตรวจสอบจาก upstream หากแพตช์มีลักษณะดังต่อไปนี้

  • อัปสตรีมที่ยอมรับ ระบบจะผสานรวมเป็น android-mainline โดยอัตโนมัติ
  • ไม่ยอมรับใน upstream ให้ส่งไปยัง android-mainline พร้อมการอ้างอิงถึงการส่งใน upstream หรือคำอธิบายสาเหตุที่ไม่ได้ส่งไปยัง LKML

หลังจากยอมรับแพตช์ในอัปสตรีมหรือใน android-mainline แล้ว คุณสามารถพอร์ตแพตช์ไปยัง ACK ที่ใช้ LTS ที่เหมาะสม (เช่น android12-5.4 และ android11-5.4 สำหรับแพตช์ที่แก้ไขโค้ดเฉพาะ Android) การส่งไปยัง android-mainline จะช่วยให้ทดสอบกับรุ่นที่พร้อมใช้งานใหม่ในอัปสตรีมได้ และรับประกันว่าแพตช์จะอยู่ใน ACK ที่ใช้ LTS รุ่นถัดไป ข้อยกเว้นรวมถึงกรณีที่มีการพอร์ตแพตช์จาก upstream ไปยัง android12-5.4 (เนื่องจากแพตช์มีแนวโน้มที่จะอยู่ใน android-mainline อยู่แล้ว)

แพตช์อัปสตรีม

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

  • UPSTREAM: - แพตช์ที่คัดสรรมาอย่างดีจาก "android-mainline" มีแนวโน้มที่จะได้รับยอมรับใน ACK หากมี Use Case ที่สมเหตุสมผล
  • BACKPORT: - แพตช์จากอัปสตรีมที่ไม่ได้เลือกเฉพาะบางรายการอย่างเรียบร้อยและจำเป็นต้องมีการแก้ไขก็อาจได้รับการยอมรับเช่นกันหากมีกรณีการใช้งานที่เหมาะสม
  • FROMGIT: - เราอาจยอมรับการแก้ไขที่คัดสรรมาจากสาขาของผู้ดูแลเพื่อเตรียมส่งไปยังสาขาหลักของ Linux หากมีกำหนดเวลาที่จะถึง ทั้ง 2 อย่างนี้ต้องรองรับทั้งเนื้อหาและกำหนดการ
  • FROMLIST: - แพตช์ที่ส่งไปยัง LKML แต่ยังไม่ได้รับการยอมรับในสาขาของผู้ดูแลระบบมีแนวโน้มที่จะไม่ได้รับการยอมรับ เว้นแต่จะมีเหตุผลที่น่าสนใจมากพอที่จะทำให้แพตช์ได้รับการยอมรับ ไม่ว่าจะนำไปใช้ใน Linux เวอร์ชันที่พัฒนาขึ้นร่วมกันหรือไม่ก็ตาม (เราถือว่าจะไม่นำไปใช้) ปัญหาต้องเกี่ยวข้องกับแพตช์ FROMLIST เพื่อให้เราพูดคุยกับทีมเคอร์เนล Android ได้

แพตช์สำหรับ Android โดยเฉพาะ

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

การเปลี่ยนแปลง gki_defconfig

การเปลี่ยนแปลง CONFIG ทั้งหมดใน gki_defconfig มีผลกับทั้งเวอร์ชัน arm64 และ x86 เว้นแต่ว่า CONFIG จะเป็นเฉพาะสำหรับสถาปัตยกรรม หากต้องการขอเปลี่ยนแปลงการตั้งค่า CONFIG ให้สร้างปัญหาในทีมไอทีเพื่อพูดคุยเกี่ยวกับการเปลี่ยนแปลง ระบบจะปฏิเสธCONFIGการเปลี่ยนแปลงที่ส่งผลต่ออินเทอร์เฟซของโมดูลเคอร์เนล (KMI) หลังจากที่มีการหยุด ในกรณีที่พาร์ทเนอร์ขอการตั้งค่าที่ขัดแย้งกันสำหรับการกำหนดค่าเดียว เราจะแก้ไขข้อขัดแย้งผ่านการพูดคุยถึงข้อบกพร่องที่เกี่ยวข้อง

โค้ดที่ไม่มีอยู่ในส่วนที่ส่งผ่านข้อมูล

คุณจะส่งการแก้ไขโค้ดที่เจาะจง Android อยู่แล้วไปยัง upstream ไม่ได้ ตัวอย่างเช่น แม้ว่าจะมีการบำรุงรักษาไดรเวอร์ Binder ในอัปสตรีม แต่คุณจะส่งการแก้ไขฟีเจอร์การสืบทอดลําดับความสําคัญของไดรเวอร์ Binder ไปยังอัปสตรีมไม่ได้เนื่องจากฟีเจอร์ดังกล่าวมีไว้สําหรับ Android โดยเฉพาะ ระบุข้อบกพร่องและแพตช์อย่างชัดเจนว่าเหตุใดจึงส่งโค้ดไปยัง upstream ไม่ได้ หากเป็นไปได้ ให้แยกแพตช์ออกเป็นส่วนๆ ที่ส่งไปยัง upstream ได้ และส่วนสำหรับ Android โดยเฉพาะที่ส่งไปยัง upstream ไม่ได้ เพื่อลดจำนวนโค้ดนอกต้นไม้ที่ดูแลรักษาใน ACK

การเปลี่ยนแปลงอื่นๆ ในหมวดหมู่นี้ ได้แก่ การอัปเดตไฟล์การนำเสนอ KMI, รายการสัญลักษณ์ KMI, gki_defconfig, สคริปต์การสร้างหรือการกำหนดค่า หรือสคริปต์อื่นๆ ที่ไม่มีอยู่ในส่วนต้น

โมดูลนอกโครงสร้าง

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

ตัวอย่างเช่น ลองพิจารณาแพตช์ที่เพิ่มมาโคร EXPORT_SYMBOL_GPL() ในกรณีที่โมดูลที่ใช้การส่งออกไม่ได้อยู่ในสคีมาต้นทาง แม้ว่าคุณจะต้องพยายามขออัปสตรีม EXPORT_SYMBOL_GPL() และจัดหาโมดูลที่ใช้สัญลักษณ์ที่ส่งออกใหม่ แต่หากมีเหตุผลที่ชัดเจนว่าเหตุใดจึงไม่ส่งโมดูลดังกล่าวไปยังอัปสตรีม คุณส่งแพตช์ไปยัง ACK แทนได้ คุณต้องระบุเหตุผลที่อัปสตรีมโมดูลไม่ได้ในปัญหา (อย่าขอตัวแปรที่ไม่ใช่ GPL EXPORT_SYMBOL())

การกําหนดค่าที่ซ่อนอยู่

โมดูลในแผนผังบางโมดูลจะเลือกการกำหนดค่าที่ซ่อนอยู่ซึ่งไม่สามารถระบุได้ใน gki_defconfig โดยอัตโนมัติ เช่น ระบบจะเลือก CONFIG_SND_SOC_TOPOLOGY โดยอัตโนมัติเมื่อกําหนดค่า CONFIG_SND_SOC_SOF=y GKI มีกลไกในการเปิดใช้การกำหนดค่าที่ซ่อนอยู่เพื่อรองรับการสร้างโมดูลนอกต้นไม้

หากต้องการเปิดใช้การกำหนดค่าที่ซ่อนอยู่ ให้เพิ่มคำสั่ง select ใน init/Kconfig.gki เพื่อให้ระบบเลือกการกำหนดค่าดังกล่าวโดยอัตโนมัติตามการกำหนดค่าเคอร์เนลของ CONFIG_GKI_HACKS_TO_FIX ซึ่งเปิดใช้อยู่ใน gki_defconfig ใช้กลไกนี้สำหรับการกำหนดค่าที่ซ่อนอยู่เท่านั้น หากไม่ได้ซ่อนการกำหนดค่าไว้ คุณจะต้องระบุการกำหนดค่าใน gki_defconfig อย่างชัดแจ้งหรือเป็นทรัพยากร Dependency

ตัวควบคุมที่สามารถโหลดได้

สำหรับเฟรมเวิร์กเคอร์เนล (เช่น cpufreq) ที่รองรับตัวควบคุมโหลดได้ คุณสามารถลบล้างตัวควบคุมเริ่มต้น (เช่น ตัวควบคุม schedutil ของ cpufreq) สำหรับเฟรมเวิร์ก (เช่น เฟรมเวิร์กด้านความร้อน) ที่ไม่รองรับตัวควบคุมหรือไดรเวอร์ที่โหลดได้ แต่ยังคงต้องใช้การติดตั้งเฉพาะของผู้ให้บริการ ให้สร้างปัญหาในทีมไอทีและปรึกษากับทีมเคอร์เนล Android

เราจะทำงานร่วมกับคุณและผู้ดูแลระบบในอัปสตรีมเพื่อเพิ่มการสนับสนุนที่จำเป็น

ฮุกของผู้ให้บริการ

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

Hook ของผู้ให้บริการมี 2 ตัวแปร (ปกติและแบบจำกัด) ที่อิงตามจุดติดตาม (ไม่ใช่ติดตามเหตุการณ์) ซึ่งโมดูลของผู้ให้บริการจะต่อเชื่อมได้ ตัวอย่างเช่น แทนที่จะเพิ่มฟังก์ชัน sched_exit() ใหม่เพื่อทำการบัญชีเมื่อสิ้นสุดการทำงานของงาน ผู้ให้บริการสามารถเพิ่มฮุกใน do_exit() ที่โมดูลของผู้ให้บริการจะแนบไว้เพื่อประมวลผลได้ ตัวอย่างการติดตั้งใช้งานมีฮุกของผู้ให้บริการต่อไปนี้

  • ฮุกของผู้ให้บริการทั่วไปใช้ DECLARE_HOOK() เพื่อสร้างฟังก์ชันการติดตามที่มีชื่อ trace_name โดยที่ name คือตัวระบุที่ไม่ซ้ำกันสำหรับการติดตาม ตามธรรมเนียมแล้ว ชื่อฮุกของผู้ให้บริการปกติจะขึ้นต้นด้วย android_vh ดังนั้นชื่อฮุก sched_exit() จะเป็น android_vh_sched_exit
  • ต้องใช้ฮุกของผู้ให้บริการที่ถูกจำกัดสำหรับกรณีต่างๆ เช่น ฮุกเครื่องจัดตารางเวลาที่ต้องเรียกใช้ฟังก์ชันที่แนบแม้ว่า CPU จะออฟไลน์อยู่หรือต้องใช้บริบทที่ไม่ใช่แบบอะตอมก็ตาม คุณไม่สามารถถอดฮุกของผู้ให้บริการที่จํากัดออกได้ ดังนั้นโมดูลที่แนบกับฮุกที่จํากัดจะยกเลิกการโหลดไม่ได้ ชื่อฮุกของผู้ให้บริการที่จำกัดจะขึ้นต้นด้วย android_rvh

หากต้องการเพิ่มฮุกของผู้ให้บริการ ให้ยื่นปัญหาด้านไอทีและส่งแพตช์ (เช่นเดียวกับแพตช์ทั้งหมดเฉพาะสำหรับ Android จะต้องมีปัญหาอยู่และต้องระบุเหตุผล) การรองรับฮุกของผู้ให้บริการมีอยู่ใน ACK เท่านั้น ดังนั้นอย่าส่งแพตช์เหล่านี้ไปยัง Linux เวอร์ชันที่พัฒนาขึ้น

เพิ่มช่องผู้ให้บริการลงในโครงสร้าง

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

OEM ต้องไม่ใช้ช่องที่ประกาศโดยใช้มาโคร ANDROID_VENDOR_DATA() เพื่อหลีกเลี่ยงความขัดแย้งที่อาจเกิดขึ้นระหว่างช่องที่นักพัฒนาแอปต้องการกับช่องที่ OEM ต้องการ แต่ OEM ต้องใช้ ANDROID_OEM_DATA() เพื่อประกาศฟิลด์ android_oem_data แทน

#include <linux/android_vendor.h>
...
struct important_kernel_data {
  [all the standard fields];
  /* Create vendor data for use by hook implementations. The
   * size of vendor data is based on vendor input. Vendor data
   * can be defined as single u64 fields like the following that
   * declares a single u64 field named "android_vendor_data1" :
   */
  ANDROID_VENDOR_DATA(1);

  /*
   * ...or an array can be declared. The following is equivalent to
   * u64 android_vendor_data2[20]:
   */
  ANDROID_VENDOR_DATA_ARRAY(2, 20);

  /*
   * SoC vendors must not use fields declared for OEMs and
   * OEMs must not use fields declared for SoC vendors.
   */
  ANDROID_OEM_DATA(1);

  /* no further fields */
}

กำหนดฮุกของผู้ให้บริการ

เพิ่มฮุกของผู้ให้บริการลงในโค้ดเคอร์เนลเป็นจุดการติดตามโดยการประกาศโดยใช้ DECLARE_HOOK() หรือ DECLARE_RESTRICTED_HOOK() แล้วเพิ่มลงในโค้ดเป็นจุดติดตาม เช่น หากต้องการเพิ่ม trace_android_vh_sched_exit() ลงในฟังก์ชันเคอร์เนล do_exit() ที่มีอยู่ ให้ทำดังนี้

#include <trace/hooks/exit.h>
void do_exit(long code)
{
    struct task_struct *tsk = current;
    ...
    trace_android_vh_sched_exit(tsk);
    ...
}

ฟังก์ชัน trace_android_vh_sched_exit() จะตรวจสอบเพียงว่ามีสิ่งที่แนบอยู่หรือไม่ในตอนแรก อย่างไรก็ตาม หากโมดูลของผู้ให้บริการลงทะเบียนตัวแฮนเดิลโดยใช้ register_trace_android_vh_sched_exit() ระบบจะเรียกใช้ฟังก์ชันที่ลงทะเบียนไว้ ตัวแฮนเดิลต้องทราบบริบทเกี่ยวกับล็อกที่ถืออยู่ สถานะ RCS และปัจจัยอื่นๆ คุณต้องกำหนดฮุกในไฟล์ส่วนหัวในไดเรกทอรี include/trace/hooks

ตัวอย่างเช่น โค้ดต่อไปนี้แสดงประกาศที่เป็นไปได้สำหรับ trace_android_vh_sched_exit() ในไฟล์ include/trace/hooks/exit.h

/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM sched
#define TRACE_INCLUDE_PATH trace/hooks

#if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_SCHED_H
#include <trace/hooks/vendor_hooks.h>
/*
 * Following tracepoints are not exported in tracefs and provide a
 * mechanism for vendor modules to hook and extend functionality
 */

struct task_struct;

DECLARE_HOOK(android_vh_sched_exit,
             TP_PROTO(struct task_struct *p),
             TP_ARGS(p));

#endif /* _TRACE_HOOK_SCHED_H */

/* This part must be outside protection */
#include <trace/define_trace.h>

หากต้องการสร้างอินเทอร์เฟซที่จําเป็นสําหรับฮุกของผู้ให้บริการ ให้เพิ่มไฟล์ส่วนหัวที่มีการประกาศฮุกลงใน drivers/android/vendor_hooks.c และส่งออกสัญลักษณ์ ตัวอย่างเช่น โค้ดต่อไปนี้จะประกาศ android_vh_sched_exit() hook ให้เสร็จสมบูรณ์

#ifndef __GENKSYMS__
/* struct task_struct */
#include <linux/sched.h>
#endif

#define CREATE_TRACE_POINTS
#include <trace/hooks/vendor_hooks.h>
#include <trace/hooks/exit.h>
/*
 * Export tracepoints that act as a bare tracehook (i.e. have no trace
 * event associated with them) to allow external modules to probe
 * them.
 */
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_exit);

หมายเหตุ: โครงสร้างข้อมูลที่ใช้ภายในการประกาศ Hook ต้องได้รับการกำหนดอย่างสมบูรณ์เพื่อรับประกันความเสถียรของ ABI มิฉะนั้น ไม่ปลอดภัยที่จะปิดใช้งานตัวชี้แบบทึบหรือใช้โครงสร้างในบริบทที่มีขนาด ส่วน include ที่ระบุคำจำกัดความของโครงสร้างข้อมูลดังกล่าวอย่างเต็มรูปแบบควรอยู่ภายในส่วน #ifndef __GENKSYMS__ ของ drivers/android/vendor_hooks.c ไฟล์ส่วนหัวใน include/trace/hooks ไม่ควรรวมไฟล์ส่วนหัวของเคอร์เนลที่มีคำจำกัดความของประเภทเพื่อหลีกเลี่ยงการเปลี่ยนแปลง CRC ซึ่งจะทำให้ KMI ใช้งานไม่ได้ แต่ให้ประกาศประเภทแบบส่งต่อแทน

แนบกับฮุกของผู้ให้บริการ

หากต้องการใช้ฮุกของผู้ให้บริการ โมดูลผู้ให้บริการจะต้องลงทะเบียนเครื่องจัดการสำหรับฮุก (โดยปกติจะทำระหว่างการเริ่มต้นโมดูล) เช่น โค้ดต่อไปนี้แสดงเครื่องจัดการ foo.ko ของโมดูลสำหรับ trace_android_vh_sched_exit()

#include <trace/hooks/sched.h>
...
static void foo_sched_exit_handler(void *data, struct task_struct *p)
{
    foo_do_exit_accounting(p);
}
...
static int foo_probe(..)
{
    ...
    rc = register_trace_android_vh_sched_exit(foo_sched_exit_handler, NULL);
    ...
}

ใช้ฮุกของผู้ให้บริการจากไฟล์ส่วนหัว

หากต้องการใช้ฮุกของผู้ให้บริการจากไฟล์ส่วนหัว คุณอาจต้องอัปเดตไฟล์ส่วนหัวของฮุกของผู้ให้บริการเพื่อยกเลิกการกําหนดค่า TRACE_INCLUDE_PATH เพื่อหลีกเลี่ยงข้อผิดพลาดในการสร้างที่ระบุว่าไม่พบไฟล์ส่วนหัวของจุดติดตาม ตัวอย่างเช่น

In file included from .../common/init/main.c:111:
In file included from .../common/include/trace/events/initcall.h:74:
.../common/include/trace/define_trace.h:95:10: fatal error: 'trace/hooks/initcall.h' file not found
   95 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:90:32: note: expanded from macro 'TRACE_INCLUDE'
   90 | # define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)
      |                                ^~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:87:34: note: expanded from macro '__TRACE_INCLUDE'
   87 | # define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:10:27: note: expanded from macro '__stringify'
   10 | #define __stringify(x...)       __stringify_1(x)
      |                                 ^~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:9:29: note: expanded from macro '__stringify_1'
    9 | #define __stringify_1(x...)     #x
      |                                 ^~
<scratch space>:14:1: note: expanded from here
   14 | "trace/hooks/initcall.h"
      | ^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

ในการแก้ไขข้อผิดพลาดของบิลด์ประเภทนี้ ให้ใช้การแก้ไขที่เทียบเท่ากับไฟล์ส่วนหัว Hook ของผู้ให้บริการที่คุณกำลังรวม ดูข้อมูลเพิ่มเติมได้ที่ https://r.android.com/3066703

diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h
index bc6de7e53d66..039926f7701d 100644
--- a/include/trace/hooks/mm.h
+++ b/include/trace/hooks/mm.h
@@ -2,7 +2,10 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mm

+#ifdef CREATE_TRACE_POINTS
 #define TRACE_INCLUDE_PATH trace/hooks
+#define UNDEF_TRACE_INCLUDE_PATH
+#endif

การกําหนด UNDEF_TRACE_INCLUDE_PATH บอก include/trace/define_trace.h ให้ยกเลิกการกําหนด TRACE_INCLUDE_PATH หลังจากสร้างจุดติดตาม

ฟีเจอร์หลักของเคิร์นัล

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

User Application Programming Interface (UAPI)

  • ไฟล์ส่วนหัว UAPI การเปลี่ยนแปลงไฟล์ส่วนหัว UAPI ต้องเกิดขึ้นที่ต้นทาง เว้นแต่การเปลี่ยนแปลงจะเป็นอินเทอร์เฟซเฉพาะ Android ใช้ไฟล์ส่วนหัวเฉพาะของผู้ให้บริการเพื่อกำหนดอินเทอร์เฟซระหว่างโมดูลของผู้ให้บริการกับโค้ดพื้นที่ผู้ใช้ของผู้ให้บริการ
  • โหนด sysfs อย่าเพิ่มโหนด sysfs ใหม่ลงในเคอร์เนล GKI (การเพิ่มดังกล่าวใช้ได้เฉพาะในโมดูลของผู้ให้บริการ) โหนด sysfs ที่ใช้โดยไลบรารีที่ไม่เจาะจง SoC และอุปกรณ์ รวมถึงโค้ด Java ที่ประกอบเฟรมเวิร์ก Android จะเปลี่ยนแปลงได้เฉพาะในลักษณะที่เข้ากันได้ และต้องเปลี่ยนแปลงในฝั่งที่ส่งออกหากไม่ใช่โหนด sysfs สำหรับ Android โดยเฉพาะ คุณสามารถสร้างโหนด sysfs เฉพาะของผู้ให้บริการเพื่อใช้โดยพื้นที่ผู้ใช้ของผู้ให้บริการ โดยค่าเริ่มต้น การเข้าถึงโหนด sysfs ตามพื้นที่ผู้ใช้จะถูกปฏิเสธโดยใช้ SELinux ขึ้นอยู่กับผู้ให้บริการที่จะเพิ่มป้ายกำกับ SELinux ที่เหมาะสมเพื่ออนุญาตให้ซอฟต์แวร์ของผู้ให้บริการที่ได้รับอนุญาตเข้าถึง
  • โหนด DebugFS โมดูลของผู้ให้บริการจะกำหนดโหนดใน debugfs สำหรับการแก้ไขข้อบกพร่องเท่านั้น (เนื่องจากระบบไม่ได้เมานต์ debugfs ในระหว่างการทํางานปกติของอุปกรณ์)