استرداد الملفات الشخصية وتحميلها

سواء كنت تلتقط ملفًا شخصيًا مستندًا إلى التطبيق أو ملفًا شخصيًا مستندًا إلى عامل تشغيل، يحفظ ProfilingManager الملف المكتمل على الجهاز ويقدّم ProfilingResult إلى معاودة الاتصال المسجّلة. استخدِم الدالة ProfilingResult.getResultFilePath للحصول على مسار الملف الشخصي المحفوظ:

استرداد الملفات الشخصية من جهاز

يوضّح هذا القسم مكان تخزين ProfilingManager للملفات الشخصية على الجهاز، وكيفية عمل ميزة التنظيف التلقائي للملفات، وكيفية سحب الملفات محليًا باستخدام adb.

مواقع الملفات وتنسيقات التسمية

يحفظ ProfilingManager الملفات الشخصية التي تم تنقيحها في دليل التخزين الخاص بالتطبيق في /data/user/0/<app>/files/profiling/. يعتمد تنسيق اسم الملف على طريقة تسجيل الملف الشخصي:

  • الملفات الشخصية المستندة إلى التطبيقات:

    profile_<tag>_<datetime>_uid-<uid>.<profile-type-ext>
    

    في حال عدم تقديم أي علامة عند طلب الملف الشخصي، يتم حذف <tag>_: profile_<datetime>_uid-<uid>.<profile-type-ext>.

  • الملفات الشخصية المستندة إلى تفاعلات الجمهور:

    profile_trigger-type-<trigger_type>_<datetime>_uid-<uid>.<profile-type-ext>
    

المكان:

  • ‫<app> هو اسم حزمة تطبيقك.
  • ‫<tag> هو أول 20 حرفًا أبجديًا رقميًا (وواصلات) من العلامة التي يوفّرها المتصل والتي تم ضبطها باستخدام setTag أو تم تمريرها إلى requestProfiling، وتم تحويلها إلى أحرف صغيرة مع إزالة أي أحرف خارج a-z و0-9 و-.
  • ‫<trigger_type> هو رمز العدد الصحيح الثابت للمشغّل من ProfilingTrigger. يجب دائمًا استدعاء ProfilingResult.getTriggerType في الرمز بدلاً من تحليل اسم الملف.
  • ‫<datetime> هو تاريخ ووقت تسجيل الملف الشخصي (yyyy-MM-dd-HH-mm-ss-SSS).
  • ‫<uid> هو رقم تعريف مستخدم Linux في تطبيقك (مضمَّن في إصدارات وحدة Profiling الأخيرة).
  • <profile-type-ext> هو امتداد الملف لنوع الملف الشخصي الذي تم تسجيله:
    • ‫.perfetto-trace لسجلّات تتبُّع النظام
    • ‫.perfetto-java-heap-dump للقطات أجزاء من الذاكرة في Java
    • ‫.perfetto-heap-profile للقطات لعناصر متعدّدة
    • ‫.perfetto-stack-sample لقطة لعناصر متعدّدة من عينات عشوائية

مساحة التخزين على الجهاز فقط وعملية إخلاء المساحة

لإخلاء مساحة التخزين على الجهاز على الفور، احذف كل ملف شخصي في أداة التحميل بعد تحميله بنجاح (لأنّ عملية التنظيف التلقائي لا تتم إلا عندما يرسل ProfilingManager النتائج إلى تطبيقك، وقد تظل الملفات غير المحمَّلة على القرص إذا توقّف تطبيقك عن تسجيل عمليات الاستدعاء بعد إنهاء حملة). كحل احتياطي في إصدارات وحدة Profiling الأخيرة، يحذف ProfilingManager أيضًا تلقائيًا الملفات التي تم تسليمها في دليل التخزين الخاص بالتطبيق والتي مرّ عليها أكثر من 5 أيام عند تسليم نتائج جديدة.

تحميل ملفات التعريف في قناة الإصدار العلني باستخدام WorkManager

بما أنّ حجم ملفات الملفات الشخصية قد يبلغ عدة ميغابايت، ننصحك بجدولة عمليات تحميل ملفات الإصدارات في الخلفية عندما يكون الجهاز متصلاً بشبكة لا تفرض تكلفة استخدام (Wi-Fi) وأثناء شحنه وعدم استخدامه.

قبل التحميل، اضغط ملف الملف الشخصي (على سبيل المثال، باستخدام GZIPOutputStream أو ZipOutputStream). يتم ضغط ملفات Perfetto protobuf الشخصية ولقطات أجزاء من الذاكرة في Java بشكل كبير، ما يقلل من معدل نقل البيانات في الشبكة وتكاليف التخزين في الخلفية.

إضافة تبعيات WorkManager

لا يعتمد ProfilingManager على السحابة الإلكترونية، لذا يمكنك جدولة تحميل الملفات الشخصية إلى أي واجهة خلفية باستخدام WorkManager. أضِف مكتبة WorkManager إلى ملف build.gradle.kts:

Kotlin

   dependencies {
       implementation("androidx.work:work-runtime:2.12.0")
   }
   

أنيق

   dependencies {
       implementation 'androidx.work:work-runtime:2.12.0'
   }
   

جدولة مهمة تحميل

عندما يتلقّى تطبيقك ProfilingResult، عليك جدولة مهمة التحميل. يستبعد المثال التالي طلب تحليل الأداء الأولي. للحصول على مثال كامل للطلب، يُرجى الاطّلاع على تسجيل تتبُّع النظام.

Kotlin

class TraceUploadWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        // Perform your uploading work here
        Log.d("ProfileTest", "Uploading trace: " + inputData.getString("PROFILE_PATH"))

        return Result.success()
    }
}

fun setupProfileUploadWorker(profileFilepath: String?) {
    val workMgr = WorkManager.getInstance(applicationContext)
    val workRequestBuilder = OneTimeWorkRequest.Builder(TraceUploadWorker::class)

    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresDeviceIdle(true)
        .setRequiresCharging(true)
        .build()
    workRequestBuilder.setConstraints(constraints)

    val inputDataBuilder = Data.Builder()
    inputDataBuilder.putString("PROFILE_PATH", profileFilepath)
    workRequestBuilder.setInputData(inputDataBuilder.build())

    workMgr.enqueue(workRequestBuilder.build())
}

Java

public static class TraceUploadWorker extends Worker {

  public TraceUploadWorker(
      @androidx.annotation.NonNull Context context,
      @androidx.annotation.NonNull WorkerParameters workerParams) {
    super(context, workerParams);
  }

  @androidx.annotation.NonNull
  @Override
  public Result doWork() {
    // Perform your uploading work here
    Log.d("ProfileTest", "Uploading trace: " + getInputData().getString("PROFILE_PATH"));

    return Result.success();
  }
}

public void setupProfileUploadWorker(String profileFilepath) {
  WorkManager workMgr = WorkManager.getInstance(getApplicationContext());
  OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(
      TraceUploadWorker.class);

  Constraints constraints = new Constraints.Builder()
      .setRequiredNetworkType(NetworkType.UNMETERED)
      .setRequiresDeviceIdle(true)
      .setRequiresCharging(true)
      .build();
  workRequestBuilder.setConstraints(constraints);

  Data.Builder inputDataBuilder = new Data.Builder();
  inputDataBuilder.putString("PROFILE_PATH", profileFilepath);
  workRequestBuilder.setInputData(inputDataBuilder.build());

  workMgr.enqueue(workRequestBuilder.build());
}

جولة تفصيلية في الرمز البرمجي

ينفّذ المثال السابق الخطوات التالية:

  • تحديد العامل: أنشئ فئة TraceUploadWorker تمدّد Worker. يجب تنفيذ doWork للتحقّق من أنّ ملف الملف الشخصي لا يزال موجودًا، وضغطه وتحميله باستخدام حزمة تطوير البرامج (SDK) في الخلفية أو عميل HTTP، وحذف الملف المحلي بعد نجاح عملية التحميل.
  • جدولة العمل:
    • أنشِئ OneTimeWorkRequest للعامل.
    • ضبط القيود: استخدِم setRequiredNetworkType(NetworkType.UNMETERED) وsetRequiresDeviceIdle(true) وsetRequiresCharging(true) لكي يتم التحميل فقط عندما يكون الجهاز متصلاً بشبكة Wi-Fi وقيد الشحن وفي وضع عدم النشاط.
    • تمرير البيانات: استخدِم setInputData لتمرير مسار الملف الشخصي من getResultFilePath إلى العامل.
    • Enqueue: لإرسال الطلب إلى WorkManager من خلال استدعاء WorkManager.enqueue.

الخطوات التالية

بعد استرداد الملفات الشخصية أو تحميلها، يمكنك عرضها في واجهة مستخدم Perfetto، أو الاستعلام عن الملفات الشخصية الفردية باستخدام PerfettoSQL، أو تحليل عمليات التتبّع بشكل مجمّع، أو تحليل الملفات الشخصية باستخدام الذكاء الاصطناعي. للحصول على إرشادات حول إعداد مسار تحليل قابل للتوسّع من جهة الخادم، يُرجى الاطّلاع على نشر Bigtrace على Kubernetes.