ProfilingManager hỗ trợ ghi lại các hồ sơ dựa trên các trình kích hoạt hệ thống. Hệ thống quản lý quy trình ghi và cung cấp hồ sơ kết quả cho ứng dụng của bạn.
Các trình kích hoạt được liên kết với các sự kiện quan trọng về hiệu suất. Hồ sơ do hệ thống ghi lại cung cấp thông tin gỡ lỗi chi tiết cho các hành trình trọng yếu của người dùng (CUJ) liên kết với những điều kiện kích hoạt này.
Ghi lại dữ liệu trong quá khứ
Nhiều điều kiện kích hoạt yêu cầu phân tích dữ liệu trước đây dẫn đến sự kiện. Bản thân sự kiện kích hoạt thường là hậu quả của một vấn đề chứ không phải nguyên nhân gốc rễ. Nếu bạn chỉ bắt đầu một hồ sơ sau khi sự kiện kích hoạt xảy ra, thì nguyên nhân cốt lõi có thể đã bị mất.
Ví dụ: một thao tác chạy trong thời gian dài trên luồng giao diện người dùng sẽ gây ra lỗi Ứng dụng không phản hồi (ANR). Khi hệ thống phát hiện thấy lỗi ANR và báo hiệu cho ứng dụng, thao tác có thể đã hoàn tất. Việc bắt đầu lập hồ sơ tại thời điểm đó sẽ bỏ lỡ công việc chặn thực tế.
Không thể dự đoán chính xác thời điểm xảy ra một số điều kiện kích hoạt, khiến bạn không thể bắt đầu hồ sơ theo cách thủ công trước.
Tại sao nên sử dụng tính năng chụp dựa trên điều kiện kích hoạt?
Lý do chính để sử dụng trình kích hoạt lập hồ sơ là thu thập dữ liệu cho các sự kiện không thể dự đoán được. Trong trường hợp này, ứng dụng không thể bắt đầu ghi lại theo cách thủ công trước khi các sự kiện này xảy ra. Bạn có thể sử dụng các trình kích hoạt lập hồ sơ để:
- Gỡ lỗi các vấn đề về hiệu suất: Chẩn đoán lỗi ANR, rò rỉ bộ nhớ và các vấn đề khác về độ ổn định.
- Tối ưu hoá hành trình trọng yếu của người dùng: Phân tích và cải thiện các luồng, ví dụ: khởi động ứng dụng.
- Tìm hiểu hành vi của người dùng: Nhận thông tin chi tiết về các sự kiện, ví dụ: người dùng tự ý thoát ứng dụng.
Thiết lập điều kiện kích hoạt
Đoạn mã sau đây minh hoạ cách đăng ký trình kích hoạt TRIGGER_TYPE_APP_FULLY_DRAWN và áp dụng giới hạn tốc độ cho trình kích hoạt đó.
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);
Mã này thực hiện các bước sau:
- Get the manager: Truy xuất dịch vụ
ProfilingManager. - Xác định một trình kích hoạt: Tạo một
ProfilingTriggerchoTRIGGER_TYPE_APP_FULLY_DRAWN. Sự kiện này xảy ra khi ứng dụng báo cáo rằng ứng dụng đã khởi động xong và có thể tương tác. - Đặt giới hạn tốc độ: Áp dụng giới hạn tốc độ 1 giờ cho trình kích hoạt cụ thể này (
setRateLimitingPeriodHours(1)). Điều này ngăn ứng dụng ghi lại nhiều hồ sơ khởi động hơn một lần mỗi giờ. - Đăng ký trình nghe: Gọi
registerForAllProfilingResultsđể xác định lệnh gọi lại xử lý kết quả. Lệnh gọi lại này nhận được đường dẫn của hồ sơ đã lưu thông quagetResultFilePath(). - Thêm trình kích hoạt: Đăng ký danh sách trình kích hoạt bằng
ProfilingManagerbằng cách sử dụngaddProfilingTriggers. - Sự kiện Fire: Gọi
reportFullyDrawn(), phát ra sự kiệnTRIGGER_TYPE_APP_FULLY_DRAWNcho hệ thống, kích hoạt một quy trình thu thập hồ sơ giả định rằng một dấu vết nền hệ thống đang chạy và có hạn ngạch bộ hạn chế tốc độ. Bước không bắt buộc này minh hoạ một quy trình từ đầu đến cuối vì ứng dụng của bạn phải gọireportFullyDrawn()cho trình kích hoạt này.
Truy xuất dấu vết
Hệ thống lưu các hồ sơ dựa trên điều kiện kích hoạt trong cùng thư mục với các hồ sơ khác. Tên tệp cho các dấu vết được kích hoạt tuân theo định dạng sau:
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>
Bạn có thể kéo tệp bằng ADB. Ví dụ: để kéo dấu vết hệ thống được ghi lại bằng mã ví dụ bằng ADB, dấu vết hệ thống có thể trông như sau:
adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace
Để biết thông tin chi tiết về cách trực quan hoá các dấu vết này, hãy xem phần Truy xuất và phân tích dữ liệu lập hồ sơ.
Cách hoạt động của tính năng theo dõi trong nền
Để thu thập dữ liệu từ trước một sự kiện kích hoạt, hệ điều hành sẽ định kỳ bắt đầu một dấu vết trong nền. Nếu một điều kiện kích hoạt xảy ra trong khi dấu vết nền này đang hoạt động và ứng dụng của bạn đã đăng ký cho điều kiện kích hoạt đó, thì hệ thống sẽ lưu hồ sơ dấu vết vào thư mục của ứng dụng. Sau đó, hồ sơ sẽ bao gồm thông tin dẫn đến sự kiện kích hoạt.
Sau khi hồ sơ được lưu, hệ thống sẽ thông báo cho ứng dụng của bạn bằng lệnh gọi lại được cung cấp cho registerForAllProfilingResults. Phương thức gọi lại này cung cấp đường dẫn đến hồ sơ đã chụp mà bạn có thể truy cập bằng cách gọi ProfilingResult#getResultFilePath().
Để giảm tác động đến hiệu suất thiết bị và thời lượng pin, hệ thống không chạy các dấu vết ở chế độ nền liên tục. Thay vào đó, nó sử dụng phương pháp lấy mẫu. Hệ thống sẽ bắt đầu một dấu vết trong nền một cách ngẫu nhiên trong một khung thời gian nhất định (với thời lượng tối thiểu và tối đa). Việc tạo khoảng cách ngẫu nhiên cho các dấu vết này sẽ cải thiện phạm vi kích hoạt.
Hồ sơ do hệ thống kích hoạt có kích thước tối đa do hệ thống xác định, vì vậy, chúng sử dụng bộ nhớ đệm vòng. Sau khi bộ nhớ đệm đầy, dữ liệu dấu vết mới sẽ ghi đè dữ liệu cũ nhất. Như minh hoạ trong Hình 1, một dấu vết được ghi lại có thể không bao gồm toàn bộ thời lượng ghi ở chế độ nền nếu bộ nhớ đệm đầy; thay vào đó, dấu vết này thể hiện hoạt động gần đây nhất dẫn đến sự kiện kích hoạt.
Triển khai giới hạn tốc độ theo điều kiện kích hoạt
Các điều kiện kích hoạt tần suất cao có thể nhanh chóng tiêu thụ hạn mức bộ giới hạn tốc độ của ứng dụng. Để hiểu rõ hơn về bộ hạn chế tốc độ, bạn nên xem bài viết Cách bộ hạn chế tốc độ hoạt động. Để ngăn một loại điều kiện kích hoạt duy nhất sử dụng hết hạn mức của bạn, bạn có thể triển khai tính năng giới hạn tốc độ theo điều kiện kích hoạt.
ProfilingManager hỗ trợ tính năng giới hạn số lần gọi theo từng điều kiện kích hoạt do ứng dụng xác định. Điều này cho phép bạn thêm một lớp điều tiết dựa trên thời gian khác ngoài bộ giới hạn tốc độ hiện có. Dùng API setRateLimitingPeriodHours để đặt thời gian tạm ngưng cụ thể cho một điều kiện kích hoạt. Sau khi thời gian chờ kết thúc, bạn có thể kích hoạt lại tính năng này.
Gỡ lỗi các điều kiện kích hoạt cục bộ
Vì các dấu vết trong nền chạy vào những thời điểm ngẫu nhiên, nên việc gỡ lỗi các sự kiện kích hoạt cục bộ là rất khó. Để buộc một dấu vết trong nền cho mục đích kiểm thử, hãy sử dụng lệnh ADB sau:
adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>
Lệnh này buộc hệ thống bắt đầu một dấu vết liên tục ở chế độ nền cho gói được chỉ định, cho phép mọi trình kích hoạt có thể thu thập một hồ sơ nếu bộ giới hạn tốc độ cho phép.
Bạn cũng có thể bật các lựa chọn gỡ lỗi khác, chẳng hạn như vô hiệu hoá bộ giới hạn tốc độ khi gỡ lỗi cục bộ. Để biết thêm thông tin, hãy xem phần Lệnh gỡ lỗi để lập hồ sơ cục bộ.