ट्रिगर के आधार पर प्रोफ़ाइलिंग

Android 16 (एपीआई लेवल 36) और इसके बाद के वर्शन पर, ProfilingManager सिस्टम ट्रिगर के जवाब में प्रोफ़ाइलों को अपने-आप कैप्चर करने की सुविधा देता है. जैसे, ऐप्लिकेशन काम नहीं कर रहा है (ANR) गड़बड़ियां, आउट ऑफ़ मेमोरी (OutOfMemoryError) की वजह से क्रैश होना या ऐप्लिकेशन के स्टार्टअप इवेंट. इनमें से कई इवेंट कब होंगे, इसका अंदाज़ा नहीं लगाया जा सकता. इसलिए, रिकॉर्डिंग को पहले से मैन्युअल तरीके से शुरू करना मुमकिन नहीं है. ट्रिगर पर आधारित प्रोफ़ाइलिंग की मदद से, सिस्टम कैप्चर को मैनेज करता है और नतीजे के तौर पर मिली प्रोफ़ाइल को आपके ऐप्लिकेशन पर डिलीवर करता है. इससे ये काम किए जा सकते हैं:

  • स्थिरता से जुड़ी समस्याओं को डीबग करना: एएनआर की गड़बड़ियों और मेमोरी लीक का पता लगाएं.
  • क्रिटिकल यूज़र जर्नी (सीयूजे) को ऑप्टिमाइज़ करना: ऐप्लिकेशन के स्टार्टअप (TRIGGER_TYPE_COLD_START और TRIGGER_TYPE_APP_FULLY_DRAWN) जैसे फ़्लो का विश्लेषण करें.
  • उपयोगकर्ताओं के व्यवहार को समझना: उपयोगकर्ता की ओर से ऐप्लिकेशन से बाहर निकलने जैसे इवेंट की जांच करें.

उपलब्ध ट्रिगर की पूरी सूची देखने के लिए, ProfilingTrigger पर जाएं.

ट्रिगर के टाइप

इवेंट होने पर सिस्टम, प्रोफ़ाइल को कैसे कैप्चर करता है, इसके आधार पर ट्रिगर अलग-अलग होते हैं.

बैकग्राउंड ट्रेस का इस्तेमाल करने वाले ट्रिगर

कई ट्रिगर, जैसे कि एएनआर, किसी पिछली समस्या की वजह से होते हैं. सिस्टम से ANR की गड़बड़ी का पता चलने के बाद ही ट्रेस शुरू करने से, उस ब्लॉक करने वाले काम का पता नहीं चलता जिसकी वजह से यह गड़बड़ी हुई थी. इवेंट से पहले की गतिविधि को कैप्चर करने के लिए, ये ट्रिगर सिस्टम के चालू बैकग्राउंड ट्रेस का स्नैपशॉट सेव करते हैं. अगर इवेंट होने के दौरान बैकग्राउंड में कोई ट्रेस नहीं चल रहा है, तो कोई प्रोफ़ाइल इकट्ठा नहीं की जाती:

नया कैप्चर शुरू करने वाले ट्रिगर

यहां दिए गए ट्रिगर, बैकग्राउंड ट्रेस पर निर्भर नहीं करते. इसके बजाय, इवेंट होने पर सिस्टम एक नई प्रोफ़ाइल कैप्चर करना शुरू करता है:

ऐसे ट्रिगर जहां कैप्चर करने का तरीका, अनॉमली के हिसाब से अलग-अलग होता है

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

ट्रिगर सेट अप करना

यहां दिए गए कोड में, TRIGGER_TYPE_APP_FULLY_DRAWN ट्रिगर के लिए रजिस्टर करने और उस पर कूलडाउन पीरियड सेट करने का तरीका बताया गया है.

Kotlin

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun recordWithTrigger() {
    val profilingManager =
        applicationContext.getSystemService(ProfilingManager::class.java) ?: return

    val triggers = ArrayList<ProfilingTrigger>()

    val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN)
        .setRateLimitingPeriodHours(1)

    triggers.add(triggerBuilder.build())

    val callbackExecutor: 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(callbackExecutor, resultCallback)
    profilingManager.addProfilingTriggers(triggers)

    Choreographer.getInstance().postFrameCallback { frameTimeNanos ->
        // This will cause the TRIGGER_TYPE_APP_FULLY_DRAWN to be emitted.
        reportFullyDrawn()
    }
}

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 callbackExecutor = 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(callbackExecutor, resultCallback);
  profilingManager.addProfilingTriggers(triggers);

  Choreographer.getInstance().postFrameCallback((f) -> {
    // This will cause the TRIGGER_TYPE_APP_FULLY_DRAWN to be emitted.
    reportFullyDrawn();
  });
}

कोड ये चरण पूरे करता है:

  1. मैनेजर वापस लाएं: ProfilingManager सेवा को वापस लाता है.
  2. ट्रिगर तय करना: TRIGGER_TYPE_APP_FULLY_DRAWN के लिए ProfilingTrigger बनाता है. यह इवेंट तब होता है, जब ऐप्लिकेशन किसी गतिविधि से शुरू होने वाले कोल्ड स्टार्ट के दौरान reportFullyDrawn() को कॉल करता है. इससे यह रिपोर्ट किया जाता है कि ऐप्लिकेशन शुरू हो गया है और इंटरैक्टिव है.
  3. ट्रिगर कूलडाउन सेट करें: सिस्टम अनुरोध संख्या सीमित करने के अलावा, setRateLimitingPeriodHours का इस्तेमाल करके, इस खास ट्रिगर पर एक घंटे का कूलडाउन पीरियड लागू करता है. इस कूलडाउन की वजह से, ऐप्लिकेशन हर घंटे एक से ज़्यादा स्टार्टअप प्रोफ़ाइल रिकॉर्ड नहीं कर पाता.
  4. लिसनर को रजिस्टर करें: यह registerForAllProfilingResults को कॉल करता है, ताकि नतीजे को हैंडल करने वाले कॉलबैक को तय किया जा सके. इस कॉलबैक को, getResultFilePath() के ज़रिए सेव की गई प्रोफ़ाइल का पाथ मिलता है.
  5. ट्रिगर जोड़ें: addProfilingTriggers का इस्तेमाल करके, ProfilingManager के साथ ट्रिगर की सूची को रजिस्टर करता है.
  6. फ़ायर इवेंट: यह Choreographer फ़्रेम कॉलबैक पोस्ट करता है, जो अगला फ़्रेम बनने के बाद reportFullyDrawn() को कॉल करता है. इससे सिस्टम में TRIGGER_TYPE_APP_FULLY_DRAWN इवेंट ट्रिगर होता है. साथ ही, प्रोफ़ाइल कलेक्शन ट्रिगर होता है. इसके लिए, यह माना जाता है कि सिस्टम बैकग्राउंड ट्रेस चल रहा था और अनुरोध संख्या सीमित करने का कोटा उपलब्ध है. इस ट्रिगर के होने के लिए, पक्का करें कि आपका ऐप्लिकेशन reportFullyDrawn() को कॉल करे.

ट्रिगर लाइफ़साइकल

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

ट्रिगर का रजिस्ट्रेशन कब रद्द करना चाहिए

रजिस्टर किए गए ट्रिगर, ऐप्लिकेशन के रीस्टार्ट होने और सिस्टम के रीबूट होने के बाद भी बने रहते हैं. इसलिए, बाद में लॉन्च होने पर addProfilingTriggers को छोड़ने से, पिछले सेशन में रजिस्टर किए गए ट्रिगर नहीं रुकते. किसी खास इवेंट या सभी इवेंट के लिए प्रोफ़ाइल कैप्चर करना बंद करने के लिए, removeProfilingTriggersByType या clearProfilingTriggers को साफ़ तौर पर कॉल करें.

इन स्थितियों में ट्रिगर का रजिस्ट्रेशन रद्द करें:

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

कॉलबैक लाइफ़साइकल

डायरेक्ट प्रोफ़ाइलिंग अनुरोधों के उलट, ट्रिगर पर आधारित प्रोफ़ाइलें सिर्फ़ registerForAllProfilingResults के साथ रजिस्टर किए गए ग्लोबल लिसनर को नतीजे डिलीवर करती हैं. अपने कॉलबैक में, ProfilingResult.getTriggerType को कॉल करें, ताकि यह पता लगाया जा सके कि किस ट्रिगर ने कैप्चर शुरू किया. साथ ही, सेव की गई प्रोफ़ाइल फ़ाइल का पता लगाने के लिए, ProfilingResult.getResultFilePath को कॉल करें. ट्रिगर प्रोफ़ाइल के फ़ाइल नामों, adb की मदद से फ़ाइलें पुल करने, और बैकग्राउंड में नतीजे अपलोड करने के बारे में ज़्यादा जानने के लिए, प्रोफ़ाइलें वापस पाना और अपलोड करना लेख पढ़ें.

ऐप्लिकेशन को रीस्टार्ट करने और सिस्टम को रीबूट करने के बाद भी ट्रिगर बने रहते हैं. हालांकि, आपका नतीजा कॉलबैक नहीं होता. ऐप्लिकेशन के स्टार्टअप के बाद, बैकग्राउंड Executor पर अपना कॉलबैक रजिस्टर करें. इससे, कोल्ड स्टार्ट की प्रोसेस धीमी नहीं होती. साथ ही, इन दोनों स्थितियों में प्रोफ़ाइलें मिलती हैं:

  • ऐप्लिकेशन के चलने के दौरान: ऐसे ट्रिगर जो आपके ऐप्लिकेशन को बंद या क्रैश नहीं करते हैं उनके लिए, सिस्टम आपके कॉलबैक को दिए गए Executor पर ट्रिगर होने और प्रोफ़ाइल सेव होने पर शुरू करता है.
  • ऐप्लिकेशन बंद होने के बाद: ऐसे ट्रिगर जो अक्सर ऐप्लिकेशन बंद होने से पहले या बाद में होते हैं (जैसे, TRIGGER_TYPE_ANR, TRIGGER_TYPE_OOM या TRIGGER_TYPE_KILL_RECENTS) या अगर कैप्चर पूरा होने से पहले आपका ऐप्लिकेशन बंद हो जाता है, तो सिस्टम बैकग्राउंड में प्रोफ़ाइल को सेव कर लेता है. साथ ही, ऐप्लिकेशन के रीस्टार्ट होने और सिस्टम के रीबूट होने पर, नतीजे को सूची में जोड़ देता है. सिस्टम, डिलीवर नहीं किए गए नतीजों को सात दिनों तक सेव रखता है. अगली बार जब आपका ऐप्लिकेशन चलता है और registerForAllProfilingResults को कॉल करता है, तो सिस्टम उन्हें डिलीवर कर देता है.

बैकग्राउंड ट्रेसिंग की सुविधा कैसे काम करती है

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

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

बैकग्राउंड ट्रेस स्नैपशॉट के काम करने का तरीका दिखाने वाला डायग्राम. इसमें रिंग बफ़र, ट्रिगर इवेंट से पहले डेटा कैप्चर करता है.
पहली इमेज. बैकग्राउंड ट्रेस स्नैपशॉट कैसे काम करते हैं.

किसी ट्रिगर के लिए कूलडाउन सेट करना

ज़्यादा फ़्रीक्वेंसी वाले ट्रिगर, आपके ऐप्लिकेशन के अनुरोध संख्या सीमित करने वाले कोटे को तेज़ी से इस्तेमाल कर सकते हैं. किसी एक ट्रिगर टाइप की वजह से आपका कोटा खत्म न हो, इसके लिए setRateLimitingPeriodHours का इस्तेमाल करें. इससे, सिस्टम रेट लिमिटर के अलावा, हर ट्रिगर के लिए कम से कम कूलडाउन पीरियड जोड़ा जा सकता है.

लोकल लेवल पर ट्रिगर को डीबग करना

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

बैकग्राउंड ट्रेस को हमेशा चालू रखने, कमांड लाइन से ट्रिगर को सिम्युलेट करने, और सेवा की स्थिति की जांच करने के लिए, adb कमांड का इस्तेमाल करें. इसके लिए, लोकल प्रोफ़ाइलिंग के लिए डीबग कमांड में जाकर, ट्रिगर टेस्टिंग के लिए बैकग्राउंड ट्रेस को हमेशा चालू करें देखें.