เครื่องมือการจราจรของข้อมูลในเครือข่าย eBPF ใช้การใช้งานในเคอร์เนลและพื้นที่ผู้ใช้ร่วมกันเพื่อตรวจสอบการใช้งานเครือข่ายในอุปกรณ์ตั้งแต่การเปิดเครื่องอุปกรณ์ครั้งล่าสุด โดยมีฟังก์ชันการทำงานเพิ่มเติม เช่น การติดแท็กซ็อกเก็ต การแยกการรับส่งข้อมูลเบื้องหน้า/เบื้องหลัง และไฟร์วอลล์ต่อ UID เพื่อบล็อกไม่ให้แอปเข้าถึงเครือข่ายได้โดยขึ้นอยู่กับสถานะโทรศัพท์ ระบบจะจัดเก็บสถิติที่รวบรวมจากเครื่องมือไว้ในโครงสร้างข้อมูลเคอร์เนลที่เรียกว่า eBPF maps และบริการต่างๆ เช่น NetworkStatsService จะใช้ผลลัพธ์เพื่อแสดงสถิติการรับส่งข้อมูลแบบถาวรตั้งแต่การบูตครั้งล่าสุด
ตัวอย่างและแหล่งที่มา
การเปลี่ยนแปลงในพื้นที่ผู้ใช้ส่วนใหญ่อยู่ในโปรเจ็กต์ system/netd และ framework/base การพัฒนาจะดำเนินการใน AOSP ดังนั้นโค้ด AOSP จะเป็นเวอร์ชันล่าสุดเสมอ แหล่งที่มาส่วนใหญ่อยู่ที่
system/netd/server/TrafficController*,
system/netd/bpfloader,
และ
system/netd/libbpf/
นอกจากนี้ การเปลี่ยนแปลงเฟรมเวิร์กที่จำเป็นบางอย่างยังอยู่ใน framework/base/ และ system/core ด้วย
การใช้งาน
ตั้งแต่ Android 9 เป็นต้นไป อุปกรณ์ Android ที่ใช้เคอร์เนล 4.9 ขึ้นไปและเปิดตัวพร้อมกับ Android เวอร์ชัน P จะต้องใช้การบัญชีการตรวจสอบการจราจรของข้อมูลในเครือข่ายที่อิงตาม eBPF แทน xt_qtaguid โครงสร้างพื้นฐานใหม่มีความยืดหยุ่นและดูแลรักษาง่ายกว่า และไม่จำเป็นต้องใช้โค้ดเคอร์เนลนอกโครงสร้าง
ความแตกต่างที่สำคัญในการออกแบบระหว่างการตรวจสอบการรับส่งข้อมูลแบบเดิมกับ eBPF แสดงไว้ในรูปที่ 1
รูปที่ 1 ความแตกต่างในการออกแบบการตรวจสอบการรับส่งข้อมูลแบบเดิม (ซ้าย) กับ eBPF (ขวา)
การออกแบบ trafficController ใหม่จะอิงตามตัวกรอง eBPF ต่อ cgroup รวมถึงโมดูล xt_bpf netfilter ภายในเคอร์เนล ระบบจะใช้ตัวกรอง eBPF เหล่านี้กับการรับส่งแพ็กเก็ตเมื่อแพ็กเก็ตผ่านตัวกรอง ตัวกรอง eBPF cgroup อยู่ที่เลเยอร์การขนส่งและมีหน้าที่นับการรับส่งข้อมูลเทียบกับ UID ที่ถูกต้องโดยขึ้นอยู่กับ UID ของซ็อกเก็ตและการตั้งค่าพื้นที่ผู้ใช้
netfilter xt_bpf เชื่อมต่อกับเชน bw_raw_PREROUTING และ bw_mangle_POSTROUTING และมีหน้าที่นับการรับส่งข้อมูลเทียบกับอินเทอร์เฟซที่ถูกต้อง
เมื่อบูตเครื่อง กระบวนการพื้นที่ผู้ใช้ trafficController จะสร้างแผนที่ eBPF ที่ใช้สำหรับการเก็บรวบรวมข้อมูลและปักหมุดแผนที่ทั้งหมดเป็นไฟล์เสมือนที่ sys/fs/bpf
จากนั้นกระบวนการที่มีสิทธิ์ bpfloader จะโหลดโปรแกรม eBPF ที่คอมไพล์ไว้ล่วงหน้าลงในเคอร์เนลและแนบโปรแกรมดังกล่าวเข้ากับ cgroup ที่ถูกต้อง มี cgroup รูทเดียวสำหรับการรับส่งข้อมูลทั้งหมด ดังนั้นกระบวนการทั้งหมดควรอยู่ใน cgroup นั้นโดยค่าเริ่มต้น
ในรันไทม์ trafficController สามารถติดแท็ก/นำแท็กออกจากซ็อกเก็ตได้โดยการเขียนไปยัง traffic_cookie_tag_map และ traffic_uid_counterSet_map NetworkStatsService สามารถอ่านข้อมูลสถิติการรับส่งข้อมูลจาก traffic_tag_stats_map, traffic_uid_stats_map และ traffic_iface_stats_map
นอกจากฟังก์ชันการรวบรวมสถิติการรับส่งข้อมูลแล้ว trafficController และตัวกรอง eBPF cgroup ยังมีหน้าที่บล็อกการรับส่งข้อมูลจาก UID บางรายการโดยขึ้นอยู่กับการตั้งค่าโทรศัพท์ด้วย ฟีเจอร์การบล็อกการรับส่งข้อมูลเครือข่ายตาม UID เป็นการแทนที่โมดูล xt_owner ภายในเคอร์เนล และคุณสามารถกำหนดค่าโหมดรายละเอียดได้โดยการเขียนไปยัง traffic_powersave_uid_map, traffic_standby_uid_map และ traffic_dozable_uid_map
การใช้งานใหม่นี้เป็นไปตามการใช้งานโมดูล xt_qtaguid แบบเดิม ดังนั้น TrafficController และ NetworkStatsService จะทำงานกับการใช้งานแบบเดิมหรือแบบใหม่ก็ได้ หากแอปใช้ API สาธารณะ แอปไม่ควรพบความแตกต่างใดๆ ไม่ว่าจะใช้เครื่องมือ xt_qtaguid หรือ eBPF ในเบื้องหลัง
หากเคอร์เนลของอุปกรณ์อิงตามเคอร์เนลทั่วไปของ Android 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 ขึ้นไป) คุณไม่จำเป็นต้องแก้ไข HAL, ไดรเวอร์ หรือโค้ดเคอร์เนลเพื่อใช้งานเครื่องมือ eBPF ใหม่
ข้อกำหนด
การกำหนดค่าเคอร์เนลต้องเปิดการกำหนดค่าต่อไปนี้
CONFIG_CGROUP_BPF=yCONFIG_BPF=yCONFIG_BPF_SYSCALL=yCONFIG_NETFILTER_XT_MATCH_BPF=yCONFIG_INET_UDP_DIAG=y
การทดสอบการกำหนดค่าเคอร์เนล VTS มีประโยชน์เมื่อตรวจสอบว่าได้เปิดการกำหนดค่าที่ถูกต้องแล้ว
กระบวนการเลิกใช้งาน xt_qtaguid แบบเดิม
เครื่องมือ eBPF ใหม่จะแทนที่โมดูล xt_qtaguid และโมดูล xt_owner ที่เครื่องมือดังกล่าวอิงอยู่ เราจะเริ่มนำโมดูล xt_qtaguid ออกจากเคอร์เนลของ Android และปิดใช้การกำหนดค่าที่ไม่จำเป็น
ใน Android เวอร์ชัน 9 โมดูล xt_qtaguid จะเปิดอยู่ในอุปกรณ์ทั้งหมด แต่ API สาธารณะทั้งหมดที่อ่านไฟล์ proc ของโมดูล xt_qtaguid โดยตรงจะย้ายไปอยู่ในบริการ NetworkManagement
บริการ NetworkManagement จะทราบว่าได้เปิดเครื่องมือ eBPF ไว้หรือไม่ และเลือกโมดูลที่เหมาะสมเพื่อรับสถิติการใช้งานเครือข่ายของแต่ละแอป โดยขึ้นอยู่กับเวอร์ชันเคอร์เนลของอุปกรณ์และระดับ API แรก แอปที่มี SDK ระดับ 28 ขึ้นไปจะถูก sepolicy บล็อกไม่ให้เข้าถึงไฟล์ proc ของ xt_qtaguid
ใน Android เวอร์ชันถัดไปหลังจากเวอร์ชัน 9 การเข้าถึงไฟล์ proc ของ xt_qtaguid เหล่านั้นจะถูกบล็อกอย่างสมบูรณ์ และเราจะเริ่มนำโมดูล xt_qtaguid ออกจากเคอร์เนลทั่วไปของ Android เวอร์ชันใหม่ หลังจากนำออกแล้ว เราจะอัปเดตการกำหนดค่าพื้นฐานของ Android สำหรับเคอร์เนลเวอร์ชันนั้นเพื่อปิดโมดูล xt_qtaguid อย่างชัดเจน โมดูล xt_qtaguid จะเลิกใช้งานอย่างสมบูรณ์เมื่อข้อกำหนดเวอร์ชันเคอร์เนลขั้นต่ำสำหรับ Android เวอร์ชันหนึ่งๆ คือ 4.9 ขึ้นไป
ใน Android เวอร์ชัน 9 เฉพาะอุปกรณ์ที่เปิดตัวพร้อมกับ Android เวอร์ชัน 9 เท่านั้นที่ต้องมีฟีเจอร์ eBPF ใหม่ สำหรับอุปกรณ์ที่เปิดตัวพร้อมกับเคอร์เนลที่รองรับเครื่องมือ eBPF เราขอแนะนำให้อัปเดตเป็นฟีเจอร์ eBPF ใหม่เมื่ออัปเกรดเป็น Android เวอร์ชัน 9 ไม่มีการทดสอบ CTS เพื่อบังคับให้อัปเดต
การตรวจสอบ
คุณควรรับแพตช์จากเคอร์เนลทั่วไปของ Android และ Android AOSP หลักเป็นประจำ ตรวจสอบว่าการใช้งานของคุณผ่านการทดสอบ VTS และ CTS ที่เกี่ยวข้อง รวมถึง netd_unit_test และ libbpf_test
การทดสอบ
มีการทดสอบ
net_tests ของเคอร์เนล
เพื่อให้แน่ใจว่าคุณได้เปิดฟีเจอร์ที่จำเป็นและย้อนกลับแพตช์เคอร์เนลที่จำเป็น
แล้ว การทดสอบจะผสานรวมเป็นส่วนหนึ่งของการทดสอบ VTS ของ Android เวอร์ชัน 9 มีการทดสอบหน่วยบางรายการใน system/netd/
(netd_unit_test
และ
libbpf_test)
และมีการทดสอบบางรายการใน netd_integration_test เพื่อตรวจสอบลักษณะการทำงานโดยรวม
ของเครื่องมือใหม่
CTS และ CTS Verifier
เนื่องจาก Android เวอร์ชัน 9 รองรับทั้งโมดูลการตรวจสอบการรับส่งข้อมูล จึงไม่มีการทดสอบ CTS เพื่อบังคับให้ใช้งานโมดูลใหม่ในอุปกรณ์ทั้งหมด แต่สำหรับอุปกรณ์ที่มีเคอร์เนลเวอร์ชันสูงกว่า 4.9 ซึ่งเปิดตัวพร้อมกับ Android เวอร์ชัน 9 (เช่น ระดับ API แรก >= 28) จะมีการทดสอบ CTS ใน GSI เพื่อตรวจสอบว่าได้กำหนดค่าโมดูลใหม่อย่างถูกต้อง คุณสามารถใช้การทดสอบ CTS แบบเก่า เช่น TrafficStatsTest, NetworkUsageStatsTest และ CtsNativeNetTestCases เพื่อตรวจสอบว่าลักษณะการทำงานสอดคล้องกับโมดูล UID แบบเก่า
การทดสอบด้วยตนเอง
มีการทดสอบหน่วยบางรายการใน system/netd/
(netd_unit_test,
netd_integration_test
และ
libbpf_test)
และมีการรองรับ dumpsys สำหรับการตรวจสอบสถานะด้วยตนเอง คำสั่ง dumpsys netd จะแสดงสถานะพื้นฐานของโมดูล trafficController และแสดงว่าได้เปิด eBPF อย่างถูกต้องหรือไม่ หากเปิด eBPF ไว้ คำสั่ง dumpsys netd trafficcontroller จะแสดงเนื้อหาโดยละเอียดของแผนที่ eBPF แต่ละรายการ ซึ่งรวมถึงข้อมูลซ็อกเก็ตที่ติดแท็ก สถิติต่อแท็ก, UID และ iface รวมถึงการจับคู่ UID ของเจ้าของ
ตำแหน่งการทดสอบ
การทดสอบ CTS อยู่ที่
- https://android.googlesource.com/platform/cts/+/android17-release/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
- https://android.googlesource.com/platform/cts/+/android17-release/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
- https://android.googlesource.com/platform/system/netd/+/android17-release/tests/bpf_base_test.cpp
การทดสอบ VTS อยู่ที่ https://android.googlesource.com/kernel/tests/+/android17-release/net/test/bpf_test.py
การทดสอบหน่วยอยู่ที่