प्रोफ़ाइलें वापस पाना और अपलोड करना

चाहे आपने ऐप्लिकेशन से ट्रिगर होने वाली प्रोफ़ाइल कैप्चर की हो या ट्रिगर पर आधारित प्रोफ़ाइल, 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
    • Java के हीप डंप के लिए .perfetto-java-heap-dump
    • हीप प्रोफ़ाइल के लिए .perfetto-heap-profile
    • स्टैक सैंपलिंग प्रोफ़ाइलों के लिए .perfetto-stack-sample

डिवाइस का स्टोरेज और उसे खाली करने की सुविधा

डिवाइस का स्टोरेज तुरंत खाली करने के लिए, अपलोड पूरा होने के तुरंत बाद, अपलोड वर्कर में मौजूद हर प्रोफ़ाइल फ़ाइल को मिटा दें. ऐसा इसलिए, क्योंकि अपने-आप क्लीनअप होने की सुविधा सिर्फ़ तब काम करती है, जब ProfilingManager आपके ऐप्लिकेशन को नतीजे डिलीवर करता है. अगर आपका ऐप्लिकेशन, कैंपेन खत्म होने के बाद कॉलबैक रजिस्टर करना बंद कर देता है, तो अपलोड न की गई फ़ाइलें डिस्क पर रह सकती हैं. Profiling मॉड्यूल के हाल ही के वर्शन पर फ़ॉलबैक के तौर पर, ProfilingManager आपके ऐप्लिकेशन के लिए खास स्टोरेज डायरेक्ट्री में मौजूद, डिलीवर की गई उन फ़ाइलों को भी अपने-आप मिटा देता है जो पांच दिन से ज़्यादा पुरानी हैं. ऐसा तब होता है, जब नए नतीजे डिलीवर किए जाते हैं.

WorkManager की मदद से, प्रोडक्शन में प्रोफ़ाइलें अपलोड करना

प्रोफ़ाइल फ़ाइलों का साइज़ कई मेगाबाइट हो सकता है. इसलिए, प्रोडक्शन अपलोड को बैकग्राउंड में शेड्यूल करें. ऐसा तब करें, जब डिवाइस किसी ऐसे नेटवर्क (वाई-फ़ाई) से कनेक्ट हो जिसमें डेटा इस्तेमाल की कोई सीमा न हो, डिवाइस चार्ज हो रहा हो, और उसका इस्तेमाल न किया जा रहा हो.

अपलोड करने से पहले, प्रोफ़ाइल फ़ाइल को कंप्रेस करें. उदाहरण के लिए, GZIPOutputStream या ZipOutputStream का इस्तेमाल करके. Perfetto protobuf प्रोफ़ाइल और Java हीप डंप को काफ़ी हद तक कंप्रेस किया जा सकता है. इससे नेटवर्क बैंडविड्थ और बैकएंड स्टोरेज की लागत कम हो जाती है.

WorkManager डिपेंडेंसी जोड़ना

ProfilingManager, क्लाउड-एग्नोस्टिक है. इसलिए, WorkManager का इस्तेमाल करके, किसी भी बैकएंड पर प्रोफ़ाइल अपलोड करने का शेड्यूल सेट किया जा सकता है. WorkManager लाइब्रेरी को अपनी build.gradle.kts फ़ाइल में जोड़ें:

Kotlin

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

Groovy

   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());
}

कोड के बारे में सिलसिलेवार तरीके से जानकारी

पिछले उदाहरण में, ये चरण पूरे किए गए हैं:

  • वर्कर तय करना: Worker को एक्सटेंड करने वाली TraceUploadWorker क्लास बनाएं. doWork को लागू करें, ताकि यह पुष्टि की जा सके कि प्रोफ़ाइल फ़ाइल अब भी मौजूद है. इसके बाद, अपने बैकएंड एसडीके या एचटीटीपी क्लाइंट का इस्तेमाल करके, इसे कंप्रेस और अपलोड करें. अपलोड हो जाने के बाद, लोकल फ़ाइल को मिटा दें.
  • काम शेड्यूल करना:
    • अपने वर्कर के लिए OneTimeWorkRequest बनाएं.
    • शर्तें सेट करना: setRequiredNetworkType(NetworkType.UNMETERED), setRequiresDeviceIdle(true), और setRequiresCharging(true) का इस्तेमाल करें, ताकि अपलोड सिर्फ़ तब हो, जब डिवाइस वाई-फ़ाई से कनेक्ट हो, चार्ज हो रहा हो, और इस्तेमाल में न हो.
    • डेटा पास करना: getResultFilePath से वर्कर को प्रोफ़ाइल पाथ पास करने के लिए, setInputData का इस्तेमाल करें.
    • सूची में शामिल करें: WorkManager को अनुरोध सबमिट करने के लिए, WorkManager.enqueue पर कॉल करें.

अगले चरण

प्रोफ़ाइलें वापस पाने या अपलोड करने के बाद, उन्हें Perfetto के यूज़र इंटरफ़ेस (यूआई) में देखें, PerfettoSQL की मदद से अलग-अलग प्रोफ़ाइलों के बारे में क्वेरी करें, एक साथ कई ट्रेस का विश्लेषण करें या एआई की मदद से प्रोफ़ाइलों का विश्लेषण करें. सर्वर-साइड पर विश्लेषण करने वाली ऐसी पाइपलाइन सेट अप करने के लिए जिसमें ज़रूरत के हिसाब से बदलाव किया जा सके, Kubernetes पर Bigtrace को डिप्लॉय करना लेख पढ़ें.