พัฒนาโค้ดเคอร์เนลสําหรับ GKI

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

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

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

    • แสดงหลักฐานว่าส่งแพตช์ไปยัง LKML แล้วและได้รับความคิดเห็นเกี่ยวกับแพตช์ หรือเวลาโดยประมาณที่ส่งแพตช์ไปยัง upstream
    • ตัดสินใจเลือกแนวทางในการเผยแพร่แพตช์ใน 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 รุ่นถัดไป ข้อยกเว้นรวมถึงกรณีที่มีการพอร์ตแพตช์จากเวอร์ชันหลักไปยัง android12-5.4 (เนื่องจากแพตช์มีแนวโน้มที่จะอยู่ใน android-mainline อยู่แล้ว)

แพตช์จากฝั่งที่ส่งข้อมูล

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

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

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

หากทําการเปลี่ยนแปลงที่จําเป็นในอัปสตรีมไม่ได้ ให้ลองส่งแพตช์ที่ไม่ใช่ของต้นไม้ไปยัง ACK โดยตรง การส่งแพตช์ที่ไม่ใช่ในต้นไม้กำหนดให้คุณต้องสร้างปัญหาในทีมไอทีซึ่งระบุแพตช์และเหตุผลที่ส่งแพตช์ไปยัง upstream ไม่ได้ (ดูตัวอย่างในรายการก่อนหน้า) อย่างไรก็ตาม อาจมีบางกรณีที่ส่งโค้ดไปยัง upstream ไม่ได้ กรณีเหล่านี้จะครอบคลุมดังต่อไปนี้ และต้องเป็นไปตามหลักเกณฑ์การมีส่วนร่วมสำหรับแพตช์เฉพาะ 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 แต่ไม่ยอมรับสำหรับช่องทางขึ้นต้น

ตัวอย่างเช่น ให้พิจารณาแพตช์ที่เพิ่มมาโคร 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 อย่างชัดแจ้งหรือเป็นข้อกำหนดเบื้องต้น

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

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

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

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

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

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

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

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

หมายเหตุ: โครงสร้างข้อมูลที่ใช้ในประกาศฮุกต้องได้รับการกําหนดอย่างสมบูรณ์เพื่อรับประกันความเสถียรของ 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.

หากต้องการแก้ไขข้อผิดพลาดเกี่ยวกับบิลด์ประเภทนี้ ให้ใช้การแก้ไขที่เทียบเท่ากับฮุกของผู้ให้บริการในไฟล์ส่วนหัวที่คุณรวมอยู่ ดูข้อมูลเพิ่มเติมได้ที่ 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 ในระหว่างการทํางานปกติของอุปกรณ์)