เครื่องมือการรับส่งข้อมูลเครือข่าย 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 ขึ้นไปและมาพร้อมกับรุ่น P ต้องใช้การบัญชีการตรวจสอบการรับส่งข้อมูลเครือข่ายที่ใช้ eBPF แทน xt_qtaguid
โครงสร้างพื้นฐานใหม่มีความยืดหยุ่นมากขึ้นและบำรุงรักษาได้มากขึ้น และไม่ต้องใช้โค้ดเคอร์เนลที่อยู่นอกแผนผัง
ความแตกต่างในการออกแบบที่สำคัญระหว่างการตรวจสอบการรับส่งข้อมูลแบบเดิมและ eBPF แสดงไว้ในรูปที่ 1
รูปที่ 1. ความแตกต่างในการออกแบบการมอนิเตอร์ทราฟฟิกแบบดั้งเดิม (ซ้าย) และ eBPF (ขวา)
การออกแบบ trafficController
ใหม่นั้นใช้ตัวกรอง eBPF ของกลุ่ม cgroup
และโมดูล netfilter xt_bpf
ภายในเคอร์เนล ตัวกรอง eBPF เหล่านี้จะใช้กับแพ็กเก็ต tx/rx เมื่อผ่านตัวกรอง ตัวกรอง cgroup
eBPF อยู่ที่เลเยอร์การขนส่ง และมีหน้าที่รับผิดชอบในการนับการรับส่งข้อมูลกับ UID ที่ถูกต้อง ขึ้นอยู่กับ UID ของซ็อกเก็ตตลอดจนการตั้งค่าพื้นที่ผู้ใช้ xt_bpf
netfilter เชื่อมต่ออยู่ที่เชน bw_raw_PREROUTING
และ bw_mangle_POSTROUTING
และมีหน้าที่รับผิดชอบในการนับการรับส่งข้อมูลกับอินเทอร์เฟซที่ถูกต้อง
ในเวลาบูต กระบวนการ trafficController
ของ userspace จะสร้างแมป 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=y
-
CONFIG_BPF=y
-
CONFIG_BPF_SYSCALL=y
-
CONFIG_NETFILTER_XT_MATCH_BPF=y
-
CONFIG_INET_UDP_DIAG=y
การทดสอบการกำหนดค่าเคอร์เนล VTS จะมีประโยชน์เมื่อตรวจสอบว่าได้เปิดใช้งานการกำหนดค่าที่ถูกต้องแล้ว
-
กระบวนการเลิกใช้ xt_qtaguid แบบเดิม
เครื่องมือ eBPF ใหม่กำลังแทนที่โมดูล xt_qtaguid
และโมดูล xt_owner
ที่ใช้อยู่ เราจะเริ่มลบโมดูล xt_qtaguid
ออกจากเคอร์เนล Android และปิดการใช้งานการกำหนดค่าที่ไม่จำเป็น
ในรุ่น Android 9 โมดูล xt_qtaguid
จะเปิดอยู่ในอุปกรณ์ทั้งหมด แต่ API สาธารณะทั้งหมดที่อ่านไฟล์ proc โมดูล xt_qtaguid
โดยตรงจะถูกย้ายไปยัง NetworkManagement
Service ขึ้นอยู่กับเวอร์ชันเคอร์เนลของอุปกรณ์และระดับ API แรก NetworkManagement
Service จะทราบว่าเครื่องมือ eBPF เปิดอยู่หรือไม่ และเลือกโมดูลที่เหมาะสมสำหรับสถิติการใช้งานเครือข่ายแอปแต่ละรายการ แอปที่มี SDK ระดับ 28 ขึ้นไปจะถูกบล็อกไม่ให้เข้าถึงไฟล์ xt_qtaguid
proc โดย sepolicy
ใน 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
เนื่องจากโมดูลการตรวจสอบการรับส่งข้อมูลทั้งสองได้รับการรองรับในรุ่น 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/+/main/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
- https://android.googlesource.com/platform/cts/+/main/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
- https://android.googlesource.com/platform/system/netd/+/main/tests/bpf_base_test.cpp
การทดสอบ VTS อยู่ที่ https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py
การทดสอบหน่วยอยู่ที่:
- https://android.googlesource.com/platform/system/netd/+/main/libbpf/BpfNetworkStatsTest.cpp
- https://android.googlesource.com/platform/system/netd/+/main/server/TrafficControllerTest.cpp