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

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

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

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

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

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

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

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

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

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

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

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

แพตช์ต้นทาง

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

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

แพตช์เฉพาะ Android

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

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

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

โค้ดที่ไม่มีในต้นทาง

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

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

โมดูลนอกทรี

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 ไม่ว่าจะ โดยชัดแจ้งหรือเป็นทรัพยากร Dependency

ผู้ว่าการที่โหลดได้

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

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

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

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

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

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

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

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

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

เพื่อหลีกเลี่ยงความขัดแย้งที่อาจเกิดขึ้นระหว่างฟิลด์ที่ผู้ให้บริการต้องการกับฟิลด์ที่ OEM ต้องการ OEM ต้องไม่ใช้ฟิลด์ที่ประกาศโดยใช้มาโคร ANDROID_VENDOR_DATA() แต่ 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 */
}

กำหนดเวนเดอร์ฮุก

เพิ่ม Hook ของผู้ให้บริการลงในโค้ดเคอร์เนลเป็นจุดติดตามโดยประกาศโดยใช้ 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 และ ปัจจัยอื่นๆ ต้องกำหนด Hook ในไฟล์ส่วนหัวในไดเรกทอรี 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>

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

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

หากต้องการใช้ Hook ของผู้ให้บริการ โมดูลของผู้ให้บริการจะต้องลงทะเบียนตัวแฮนเดิลสำหรับ Hook (โดยปกติจะทำในระหว่างการเริ่มต้นโมดูล) ตัวอย่างเช่น โค้ดต่อไปนี้ แสดงแฮนเดิลโมดูล 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);
    ...
}

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

หากต้องการใช้ Hook ของผู้ให้บริการจากไฟล์ส่วนหัว คุณอาจต้องอัปเดตไฟล์ส่วนหัวของ Hook ของผู้ให้บริการ เพื่อยกเลิกการกำหนด 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.

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

Application Programming Interface (API) ของผู้ใช้

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