Yerel kodda özel iz etkinlikleri

Android 6.0 (API düzeyi 23) ve sonraki sürümler, izleme etkinliklerini sistem arabelleğine yazmak için yerel bir izleme API'sini (trace.h) destekler. Daha sonra Perfetto veya systrace kullanarak analiz edebilirsiniz. Bu API'nin yaygın kullanım alanları, belirli bir kod bloğunun yürütülmesi için geçen süreyi gözlemlemek ve bir kod bloğunu istenmeyen sistem davranışıyla ilişkilendirmektir.

Not: API düzeyi 27 ve altını çalıştıran cihazlarda ve emülatörlerde yeterli bellek yoksa veya bellek çok parçalanmışsa şu mesajı alırsınız: Atrace could not allocate enough memory to record a trace. Bu durumda yakalamanız tam bir veri grubuna sahip değilse arka plan işlemlerini kapatmanız veya cihazı ya da emülatörü yeniden başlatmanız gerekir.

Uygulamanızın veya oyununuzun yerel kodda meydana gelen özel etkinlikleri tanımlamak için aşağıdaki adımları tamamlayın:

  1. Aşağıdaki kod snippet'inde gösterildiği gibi, uygulama veya oyununuzdaki özel etkinlikleri yakalamak amacıyla kullandığınız ATrace işlevleri için işlev işaretçileri tanımlayın:

    #include <android/trace.h>
    #include <dlfcn.h>
    
    void *(*ATrace_beginSection) (const char* sectionName);
    void *(*ATrace_endSection) (void);
    
    typedef void *(*fp_ATrace_beginSection) (const char* sectionName);
    typedef void *(*fp_ATrace_endSection) (void);
    
  2. Aşağıdaki kod snippet'inde gösterildiği gibi, çalışma zamanında ATrace simgelerini yükleyin. Genellikle bu işlemi bir nesne oluşturucuda gerçekleştirirsiniz.

    // Retrieve a handle to libandroid.
    void *lib = dlopen("libandroid.so", RTLD_NOW || RTLD_LOCAL);
    
    // Access the native tracing functions.
    if (lib != NULL) {
        // Use dlsym() to prevent crashes on devices running Android 5.1
        // (API level 22) or lower.
        ATrace_beginSection = reinterpret_cast<fp_ATrace_beginSection>(
            dlsym(lib, "ATrace_beginSection"));
        ATrace_endSection = reinterpret_cast<fp_ATrace_endSection>(
            dlsym(lib, "ATrace_endSection"));
    }
    

    Dikkat: Güvenlik nedeniyle, dlopen() numaralı telefona yapılan aramaları yalnızca uygulama veya oyununuzun hata ayıklama sürümüne dahil edin.

    Not: Android 4.3'e (API düzeyi 18) kadar uzanan izleme desteği sağlamak için JNI'yi kullanarak, yönetilen kod bölümünde önceki snippet'te gösterilen kodun çevresinde bulunan yöntemleri çağırabilirsiniz.

  3. Özel etkinliğinizin başında ve sonunda sırasıyla ATrace_beginSection() ve ATrace_endSection() yöntemini çağırın:

    #include <android/trace.h>
    
    char *customEventName = new char[32];
    sprintf(customEventName, "User tapped %s button", buttonName);
    
    ATrace_beginSection(customEventName);
    // Your app or game's response to the button being pressed.
    ATrace_endSection();
    

    Not: ATrace_beginSection() yöntemini birden çok kez çağırdığınızda ATrace_endSection() yöntemini çağırmak yalnızca en son çağrılan ATrace_beginSection() yöntemini sonlandırır. Bu nedenle, iç içe yerleştirilmiş çağrılarda her bir ATrace_beginSection() çağrısını ATrace_endSection() çağrısıyla düzgün şekilde eşleştirdiğinizden emin olun.

    Ayrıca, bir ileti dizisinde ATrace_beginSection() çağırıp başka bir ileti dizisinden sonlandıramazsınız. Her iki işlevi de aynı iş parçacığından çağırmanız gerekir.

Kolaylık ipuçları

Aşağıdaki ipuçları isteğe bağlıdır ancak yerel kodunuzu analiz etmeyi kolaylaştırabilir.

Bir fonksiyonun tamamını izleme

Çağrı yığınınızı veya işlev zamanlamasını enstrümantasyonla uygularken tüm işlevleri izlemek yararlı olabilir. Bu tür izlemeyi ayarlamayı kolaylaştırmak için ATRACE_CALL() makrosunu kullanabilirsiniz. Ayrıca bu tür bir makro, izlenen fonksiyonun istisna oluşturduğu veya return'yi erken çağırdığı durumlar için try ve catch blokları oluşturmayı atlamanıza olanak tanır.

Bir işlevin tamamını izlemek amacıyla makro oluşturmak için aşağıdaki adımları tamamlayın:

  1. Makroyu tanımlayın:

    #define ATRACE_NAME(name) ScopedTrace ___tracer(name)
    
    // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
    #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
    
    class ScopedTrace {
      public:
        inline ScopedTrace(const char *name) {
          ATrace_beginSection(name);
        }
    
        inline ~ScopedTrace() {
          ATrace_endSection();
        }
    };
    
  2. İzlemek istediğiniz işlevde makroyu çağırın:

    void myExpensiveFunction() {
      ATRACE_CALL();
      // Code that you want to trace.
    }
    

İleti dizilerinizi adlandırın

Aşağıdaki kod snippet'inde gösterildiği gibi, etkinliklerinizin gerçekleştiği her iş parçacığına bir ad verebilirsiniz. Bu adım, oyununuzda belirli işlemlere ait ileti dizilerini tanımlamayı kolaylaştırır.

#include <pthread.h>

static void *render_scene(void *parm) {
    // Code for preparing your app or game's visual components.
}

static void *load_main_menu(void *parm) {
    // Code that executes your app or game's main logic.
}

void init_threads() {
    pthread_t render_thread, main_thread;

    pthread_create(&render_thread, NULL, render_scene, NULL);
    pthread_create(&main_thread, NULL, load_main_menu, NULL);

    pthread_setname_np(render_thread, "MyRenderer");
    pthread_setname_np(main_thread, "MyMainMenu");
}