ProfilingManager รองรับการบันทึกโปรไฟล์ตามทริกเกอร์ของระบบ ระบบจะจัดการกระบวนการบันทึกและส่งโปรไฟล์ที่ได้ไปยังแอปของคุณ
ทริกเกอร์จะเชื่อมโยงกับเหตุการณ์ที่สำคัญต่อประสิทธิภาพ โปรไฟล์ที่ระบบบันทึกไว้จะให้ข้อมูลการแก้ไขข้อบกพร่องโดยละเอียดสำหรับเส้นทางของผู้ใช้ที่สำคัญ (CUJ) ที่เชื่อมโยงกับทริกเกอร์เหล่านี้
บันทึกข้อมูลย้อนหลัง
ทริกเกอร์จำนวนมากต้องวิเคราะห์ข้อมูลย้อนหลังที่นำไปสู่เหตุการณ์ ตัวทริกเกอร์เองมักเป็นผลมาจากปัญหามากกว่าที่จะเป็นสาเหตุของปัญหา หากคุณเริ่มโปรไฟล์หลังจากที่ทริกเกอร์เกิดขึ้นเท่านั้น สาเหตุของปัญหาอาจหายไปแล้ว
เช่น การดำเนินการที่ใช้เวลานานในเธรด UI จะทำให้เกิดข้อผิดพลาดแอปพลิเคชันไม่ตอบสนอง (ANR) เมื่อระบบตรวจพบ ANR และส่งสัญญาณไปยังแอป การดำเนินการอาจเสร็จสิ้นแล้ว การเริ่มโปรไฟล์ ณ ขณะนั้นจะพลาดการบล็อกที่เกิดขึ้นจริง
การคาดการณ์เวลาที่ทริกเกอร์บางอย่างจะเกิดขึ้นอย่างแม่นยำนั้นเป็นไปไม่ได้ จึงทำให้ไม่สามารถเริ่มโปรไฟล์ด้วยตนเองล่วงหน้าได้
เหตุผลที่ควรใช้การจับภาพตามทริกเกอร์
เหตุผลหลักในการใช้ทริกเกอร์การทำโปรไฟล์คือการบันทึกข้อมูลสำหรับเหตุการณ์ที่คาดเดาไม่ได้ซึ่งแอปไม่สามารถเริ่มบันทึกด้วยตนเองก่อนที่เหตุการณ์เหล่านี้จะเกิดขึ้น ทริกเกอร์การทำโปรไฟล์ใช้เพื่อทำสิ่งต่อไปนี้ได้
- แก้ไขข้อบกพร่องด้านประสิทธิภาพ: วิเคราะห์ ANR, หน่วยความจำรั่วไหล และปัญหาด้านความเสถียรอื่นๆ
- เพิ่มประสิทธิภาพเส้นทางของผู้ใช้ที่สำคัญ: วิเคราะห์และปรับปรุงขั้นตอนต่างๆ เช่น การเริ่มต้นแอป
- ทำความเข้าใจพฤติกรรมของผู้ใช้: รับข้อมูลเชิงลึกเกี่ยวกับเหตุการณ์ เช่น การออกจากแอปที่ผู้ใช้เริ่ม
ตั้งค่าทริกเกอร์
โค้ดต่อไปนี้แสดงวิธีลงทะเบียนทริกเกอร์ TRIGGER_TYPE_APP_FULLY_DRAWN และใช้การจำกัดอัตราคำขอกับทริกเกอร์ดังกล่าว
Kotlin
fun recordWithTrigger() { val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java) val triggers = ArrayList<ProfilingTrigger>() val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN) .setRateLimitingPeriodHours(1) triggers.add(triggerBuilder.build()) val mainExecutor: Executor = Executors.newSingleThreadExecutor() val resultCallback = Consumer<ProfilingResult> { profilingResult -> if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.resultFilePath ) setupProfileUploadWorker(profilingResult.resultFilePath) } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage ) } } profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback) profilingManager.addProfilingTriggers(triggers) }
Java
public void recordWithTrigger() { ProfilingManager profilingManager = getApplicationContext().getSystemService( ProfilingManager.class); List<ProfilingTrigger> triggers = new ArrayList<>(); ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN); triggerBuilder.setRateLimitingPeriodHours(1); triggers.add(triggerBuilder.build()); Executor mainExecutor = Executors.newSingleThreadExecutor(); Consumer<ProfilingResult> resultCallback = new Consumer<ProfilingResult>() { @Override public void accept(ProfilingResult profilingResult) { if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.getResultFilePath()); setupProfileUploadWorker(profilingResult.getResultFilePath()); } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.getErrorCode() + " errormsg=" + profilingResult.getErrorMessage()); } } }; profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers); }
โค้ดจะทำตามขั้นตอนต่อไปนี้
- รับผู้จัดการ: ดึงข้อมูลบริการ
ProfilingManager - กำหนดทริกเกอร์: สร้าง
ProfilingTriggerสำหรับTRIGGER_TYPE_APP_FULLY_DRAWNเหตุการณ์นี้จะเกิดขึ้นเมื่อแอปรายงานว่าได้เริ่มต้นระบบเสร็จแล้วและพร้อมให้โต้ตอบ - ตั้งค่าการจำกัดอัตราคำขอ: ใช้การจำกัดอัตราคำขอ 1 ชั่วโมงกับทริกเกอร์ที่เฉพาะเจาะจงนี้ (
setRateLimitingPeriodHours(1)) ซึ่งจะป้องกันไม่ให้แอปบันทึกโปรไฟล์การเริ่มต้นมากกว่า 1 รายการต่อชั่วโมง - ลงทะเบียน Listener: เรียกใช้
registerForAllProfilingResultsเพื่อกำหนด Callback ที่จัดการผลลัพธ์ Callback นี้จะได้รับเส้นทางของโปรไฟล์ที่บันทึกไว้ผ่านgetResultFilePath() - เพิ่มทริกเกอร์: ลงทะเบียนรายการทริกเกอร์กับ
ProfilingManagerโดยใช้addProfilingTriggers - เหตุการณ์เริ่มทำงาน: เรียกใช้
reportFullyDrawn()ซึ่งจะส่งเหตุการณ์TRIGGER_TYPE_APP_FULLY_DRAWNไปยังระบบเพื่อทริกเกอร์การรวบรวมโปรไฟล์ โดยสมมติว่ามีการติดตามเบื้องหลังของระบบทำงานอยู่และมีโควต้าตัวจำกัดอัตราคำขอพร้อมใช้งาน ขั้นตอนนี้เป็นขั้นตอนที่ไม่บังคับซึ่งแสดงให้เห็นขั้นตอนตั้งแต่ต้นจนจบ เนื่องจากแอปของคุณต้องเรียกใช้reportFullyDrawn()สำหรับทริกเกอร์นี้
ดึงข้อมูลการติดตาม
ระบบจะบันทึกโปรไฟล์ที่อิงตามทริกเกอร์ไว้ในไดเรกทอรีเดียวกับโปรไฟล์อื่นๆ ชื่อไฟล์สำหรับการติดตามที่ทริกเกอร์จะเป็นไปตามรูปแบบต่อไปนี้
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>
คุณดึงไฟล์ได้โดยใช้ ADB ตัวอย่างเช่น หากต้องการดึงการติดตามของระบบที่บันทึกไว้ด้วยโค้ดตัวอย่างโดยใช้ ADB อาจมีลักษณะดังนี้
adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace
ดูรายละเอียดเกี่ยวกับการแสดงภาพการติดตามเหล่านี้ได้ที่ดึงข้อมูลและวิเคราะห์ข้อมูลการทำโปรไฟล์
วิธีการทำงานของการติดตามในเบื้องหลัง
หากต้องการบันทึกข้อมูลจากก่อนทริกเกอร์ ระบบปฏิบัติการจะเริ่มการติดตามเบื้องหลังเป็นระยะๆ หากทริกเกอร์เกิดขึ้นขณะที่การติดตามเบื้องหลังนี้ทำงานอยู่และแอปของคุณลงทะเบียนไว้ ระบบจะบันทึกโปรไฟล์การติดตามลงในไดเรกทอรีของแอป จากนั้นโปรไฟล์จะมีข้อมูลที่นำไปสู่ทริกเกอร์
เมื่อบันทึกโปรไฟล์แล้ว ระบบจะแจ้งเตือนแอปของคุณโดยใช้ Callback ที่ระบุไว้ใน registerForAllProfilingResults Callback นี้จะระบุเส้นทางไปยังโปรไฟล์ที่บันทึกไว้ซึ่งเข้าถึงได้โดยการเรียกใช้ ProfilingResult#getResultFilePath()
ระบบจะไม่เรียกใช้การติดตามในเบื้องหลังอย่างต่อเนื่องเพื่อลดผลกระทบต่อประสิทธิภาพของอุปกรณ์และอายุการใช้งานแบตเตอรี่ แต่จะใช้วิธีการสุ่มตัวอย่างแทน ระบบจะเริ่มการติดตามเบื้องหลังแบบสุ่มภายในกรอบเวลาที่กำหนด (โดยมีระยะเวลาต่ำสุดและสูงสุด) การเว้นระยะห่างของร่องรอยเหล่านี้แบบสุ่มจะช่วยเพิ่มความครอบคลุมของทริกเกอร์
โปรไฟล์ที่ระบบทริกเกอร์มีขนาดสูงสุดที่ระบบกำหนด จึงใช้บัฟเฟอร์แบบวงแหวน เมื่อบัฟเฟอร์เต็ม ข้อมูลการติดตามใหม่จะเขียนทับข้อมูลที่เก่าที่สุด ดังที่แสดงในรูปที่ 1 การติดตามที่บันทึกไว้อาจไม่ครอบคลุมระยะเวลาทั้งหมดของการบันทึกในเบื้องหลังหากบัฟเฟอร์เต็ม แต่จะแสดงกิจกรรมล่าสุดที่นำไปสู่ทริกเกอร์แทน
ใช้การจำกัดอัตราคำขอเฉพาะทริกเกอร์
ทริกเกอร์ที่มีความถี่สูงอาจใช้โควต้าการจำกัดอัตราคำขอของแอปอย่างรวดเร็ว เพื่อให้เข้าใจตัวจำกัดอัตราได้ดียิ่งขึ้น เราขอแนะนำให้คุณดูวิธีการทำงานของตัวจำกัดอัตรา เพื่อป้องกันไม่ให้ทริกเกอร์ประเภทเดียวใช้โควต้าจนหมด คุณสามารถใช้การจำกัดอัตราคำขอเฉพาะทริกเกอร์ได้
ProfilingManager รองรับการจำกัดอัตราคำขอที่เฉพาะเจาะจงสำหรับทริกเกอร์ที่แอปกำหนด ซึ่งจะช่วยให้คุณเพิ่มการควบคุมตามเวลาอีกชั้นหนึ่งนอกเหนือจากตัวจำกัดอัตราที่มีอยู่ ใช้ setRateLimitingPeriodHours API เพื่อตั้งค่าระยะเวลาพักที่เจาะจงสำหรับทริกเกอร์ หลังจากระยะเวลาพักการใช้งานสิ้นสุดลง คุณจะเรียกใช้ได้อีกครั้ง
แก้ไขข้อบกพร่องของทริกเกอร์ในเครื่อง
เนื่องจากการติดตามในเบื้องหลังจะทำงานแบบสุ่ม การแก้ไขข้อบกพร่องของทริกเกอร์ในเครื่องจึงทำได้ยาก หากต้องการบังคับให้มีการติดตามในเบื้องหลังเพื่อทดสอบ ให้ใช้คำสั่ง ADB ต่อไปนี้
adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>
คำสั่งนี้จะบังคับให้ระบบเริ่มการติดตามเบื้องหลังอย่างต่อเนื่องสำหรับแพ็กเกจที่ระบุ ซึ่งจะช่วยให้ทริกเกอร์ทุกรายการรวบรวมโปรไฟล์ได้หากตัวจำกัดอัตราอนุญาต
นอกจากนี้ คุณยังเปิดใช้ตัวเลือกการแก้ไขข้อบกพร่องอื่นๆ ได้ด้วย เช่น การปิดใช้การจำกัดอัตราคำขอเมื่อแก้ไขข้อบกพร่องในเครื่อง ดูข้อมูลเพิ่มเติมได้ที่คำสั่งแก้ไขข้อบกพร่องสำหรับการทำโปรไฟล์ในเครื่อง