Niestandardowe zdarzenia śledzenia w kodzie natywnym
Zadbaj o dobrą organizację dzięki kolekcji
Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.
Android 6.0 (poziom interfejsu API 23) i nowsze wersje obsługują natywny interfejs API śledzenia trace.h
,
do zapisywania zdarzeń śledzenia w buforze systemowym, które można następnie przeanalizować za pomocą
Perfetto lub systrace. Typowe przypadki użycia tego interfejsu API obejmują obserwację czasu
konkretnego bloku kodu do wykonania,
wiążącego blok kodu,
przy niepożądanemu działaniu systemu.
Uwaga: na urządzeniach i emulatorach z interfejsem API na poziomie 27 lub niższym, o ile jest dostępny
za mało dostępnej pamięci lub jest ona zbyt pofragmentowana,
ta wiadomość: Atrace could not allocate enough memory to record a trace
.
Jeśli tak się stanie i przechwytywanie nie ma pełnego zestawu danych,
powinien zamknąć procesy w tle albo ponownie uruchomić urządzenie lub emulator.
Aby zdefiniować zdarzenia niestandardowe występujące w kodzie natywnym w aplikacji lub grze:
wykonaj te czynności:
Zdefiniuj wskaźniki funkcji dla funkcji ATrace, których używasz do
rejestruje zdarzenia niestandardowe w aplikacji lub grze, zgodnie z tym kodem
snippet:
#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);
Wczytywanie symboli ATrace w czasie działania, jak pokazano w tym kodzie
. Zwykle ten proces wykonuje się w konstruktorze obiektów.
// 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"));
}
Uwaga: ze względów bezpieczeństwa uwzględnij połączenia z
dlopen()
tylko w wersji do debugowania aplikacji lub gry.
Uwaga: aby zapewnić pomoc w śledzeniu, od
Androida 4.3 (poziom interfejsu API 18), możesz używać JNI do wywoływania metod
kodu zarządzanego wokół kodu widocznego w sekcji
poprzedzający fragment kodu.
Zadzwoń pod numer ATrace_beginSection()
i
ATrace_endSection()
odpowiednio na początku i na końcu,
Twoje zdarzenie niestandardowe:
#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();
Uwaga: gdy dzwonisz do: ATrace_beginSection()
pod wiele
dzwonienia pod numer ATrace_endSection()
kończy się najczęściej
nazywanej ostatnio metodą ATrace_beginSection()
. Zagnieżdżony
upewnij się, że każde wywołanie jest odpowiednio dopasowane do
ATrace_beginSection()
z połączeniem do
ATrace_endSection()
Nie możesz też zadzwonić do ATrace_beginSection()
na jeden
i zakończyć od innego. Obie funkcje musisz wywoływać z tego samego
w wątku.
Wskazówki wygodne
Podane niżej wskazówki są opcjonalne, ale mogą ułatwić analizę reklam natywnych
w kodzie.
Śledzenie całej funkcji
Może Ci się to przydać przy instrumentowaniu stosu wywołań lub czasu funkcji
do śledzenia całych funkcji. Aby to zrobić, możesz użyć makra ATRACE_CALL()
jest łatwiejszy do skonfigurowania. Poza tym takie makro pozwala pominąć
tworząc bloki try
i catch
w przypadkach, gdy funkcja śledzona może
zgłosić wyjątek lub wywołać return
wcześniej.
Aby utworzyć makro do śledzenia całej funkcji, wykonaj te czynności:
Zdefiniuj makro:
#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();
}
};
Wywołaj makro w ramach funkcji, którą chcesz śledzić:
void myExpensiveFunction() {
ATRACE_CALL();
// Code that you want to trace.
}
Nadawanie nazw wątkom
Każdy wątek, w którym występują zdarzenia, możesz nazwać zgodnie z przykładem
w tym fragmencie kodu. Ten krok ułatwia rozpoznawanie wątków
które należą do konkretnych działań w grze.
#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");
}
Polecane dla Ciebie
.
Treść strony i umieszczone na niej fragmenty kodu podlegają licencjom opisanym w Licencji na treści. Java i OpenJDK są znakami towarowymi lub zastrzeżonymi znakami towarowymi należącymi do firmy Oracle lub jej podmiotów stowarzyszonych.
Ostatnia aktualizacja: 2025-07-27 UTC.
[[["Łatwo zrozumieć","easyToUnderstand","thumb-up"],["Rozwiązało to mój problem","solvedMyProblem","thumb-up"],["Inne","otherUp","thumb-up"]],[["Brak potrzebnych mi informacji","missingTheInformationINeed","thumb-down"],["Zbyt skomplikowane / zbyt wiele czynności do wykonania","tooComplicatedTooManySteps","thumb-down"],["Nieaktualne treści","outOfDate","thumb-down"],["Problem z tłumaczeniem","translationIssue","thumb-down"],["Problem z przykładami/kodem","samplesCodeIssue","thumb-down"],["Inne","otherDown","thumb-down"]],["Ostatnia aktualizacja: 2025-07-27 UTC."],[],[],null,["# Custom trace events in native code\n\nAndroid 6.0 (API level 23) and higher support a native tracing API, `trace.h`,\nto write trace events to the system buffer that you can then analyze using\nPerfetto or systrace. Common use cases for this API include observing the time\nthat a particular block of code takes to execute and associating a block of code\nwith undesirable system behavior.\n\n**Note:** On devices and emulators running API level 27 and lower, if there\nisn't enough memory available or the memory is too fragmented, you'll get the\nfollowing message: `Atrace could not allocate enough memory to record a trace`.\nIf this happens and your capture does not have a complete set of data, then you\nshould close background processes or restart the device or emulator.\n\nTo define custom events that occur in the native code within your app or game,\ncomplete the following steps:\n\n1. Define function pointers for the ATrace functions that you use to\n capture custom events within your app or game, as shown in the following code\n snippet:\n\n ```c++\n #include \u003candroid/trace.h\u003e\n #include \u003cdlfcn.h\u003e\n\n void *(*ATrace_beginSection) (const char* sectionName);\n void *(*ATrace_endSection) (void);\n\n typedef void *(*fp_ATrace_beginSection) (const char* sectionName);\n typedef void *(*fp_ATrace_endSection) (void);\n ```\n2. Load the ATrace symbols at runtime, as shown in the following code\n snippet. Usually, you perform this process in an object constructor.\n\n ```c++\n // Retrieve a handle to libandroid.\n void *lib = dlopen(\"libandroid.so\", RTLD_NOW | RTLD_LOCAL);\n\n // Access the native tracing functions.\n if (lib != NULL) {\n // Use dlsym() to prevent crashes on devices running Android 5.1\n // (API level 22) or lower.\n ATrace_beginSection = reinterpret_cast\u003cfp_ATrace_beginSection\u003e(\n dlsym(lib, \"ATrace_beginSection\"));\n ATrace_endSection = reinterpret_cast\u003cfp_ATrace_endSection\u003e(\n dlsym(lib, \"ATrace_endSection\"));\n }\n ```\n\n **Caution:** For security reasons, include calls to\n `dlopen()` only in the debug version of your app or game.\n\n **Note:** To provide tracing support further back to\n Android 4.3 (API level 18), you can use JNI to call the methods in\n [managed code](#managed-code) around the code shown in the\n preceding snippet.\n3. Call `ATrace_beginSection()` and\n `ATrace_endSection()` at the beginning and end, respectively, of\n your custom event:\n\n ```c++\n #include \u003candroid/trace.h\u003e\n\n char *customEventName = new char[32];\n sprintf(customEventName, \"User tapped %s button\", buttonName);\n\n ATrace_beginSection(customEventName);\n // Your app or game's response to the button being pressed.\n ATrace_endSection();\n ``` \n **Note:** When you call `ATrace_beginSection()` multiple\n times, calling `ATrace_endSection()` ends only the most\n recently called `ATrace_beginSection()` method. So, for nested\n calls, make sure that you properly match each call to\n `ATrace_beginSection()` with a call to\n `ATrace_endSection()`.\n\n Additionally, you cannot call `ATrace_beginSection()` on one\n thread and end it from another. You must call both functions from the same\n thread.\n\nConvenience tips\n================\n\nThe following tips are optional but might make it easier to analyze your native\ncode.\n\nTrace an entire function\n------------------------\n\nWhen instrumenting your call stack or function timing, you might find it useful\nto trace entire functions. You can use the `ATRACE_CALL()` macro to make this\ntype of tracing easier to set up. Furthermore, such a macro allows you to skip\ncreating `try` and `catch` blocks for cases where the traced function might\nthrow an exception or call `return` early.\n\nTo create a macro for tracing an entire function, complete the following steps:\n\n1. Define the macro:\n\n ```c++\n #define ATRACE_NAME(name) ScopedTrace ___tracer(name)\n\n // ATRACE_CALL is an ATRACE_NAME that uses the current function name.\n #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)\n\n class ScopedTrace {\n public:\n inline ScopedTrace(const char *name) {\n ATrace_beginSection(name);\n }\n\n inline ~ScopedTrace() {\n ATrace_endSection();\n }\n };\n ```\n2. Call the macro within the function that you want to trace:\n\n ```c++\n void myExpensiveFunction() {\n ATRACE_CALL();\n // Code that you want to trace.\n }\n ```\n\nName your threads\n-----------------\n\nYou can give a name to each thread in which your events occur, as demonstrated\nin the following code snippet. This step makes it easier to identify the threads\nthat belong to specific actions within your game. \n\n```c++\n#include \u003cpthread.h\u003e\n\nstatic void *render_scene(void *parm) {\n // Code for preparing your app or game's visual components.\n}\n\nstatic void *load_main_menu(void *parm) {\n // Code that executes your app or game's main logic.\n}\n\nvoid init_threads() {\n pthread_t render_thread, main_thread;\n\n pthread_create(&render_thread, NULL, render_scene, NULL);\n pthread_create(&main_thread, NULL, load_main_menu, NULL);\n\n pthread_setname_np(render_thread, \"MyRenderer\");\n pthread_setname_np(main_thread, \"MyMainMenu\");\n}\n```\n\nRecommended for you\n-------------------\n\n- Note: link text is displayed when JavaScript is off\n- [Best practices for SQLite performance](/topic/performance/sqlite-performance-best-practices)\n- [Create and measure Baseline Profiles without Macrobenchmark](/topic/performance/baselineprofiles/manually-create-measure)"]]