Benutzerdefinierte Trace-Ereignisse im nativen Code
Mit Sammlungen den Überblick behalten
Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.
Android 6.0 (API-Level 23) und höher unterstützen eine native Tracing API, trace.h
,
um Trace-Ereignisse in den Systempuffer zu schreiben, den Sie dann mit
Perfetto oder systrace. Häufige Anwendungsfälle für diese API sind die Beobachtung der Zeit
die ein bestimmter Codeblock zum Ausführen benötigt und
mit unerwünschtem Systemverhalten.
Hinweis:Auf Geräten und Emulatoren mit API-Level 27 und niedriger, falls vorhanden
nicht genügend Arbeitsspeicher verfügbar ist oder der Speicher zu fragmentiert ist,
folgende Nachricht: Atrace could not allocate enough memory to record a trace
.
Wenn dies passiert und Ihre Erfassung keinen vollständigen Datensatz hat,
Hintergrundprozesse schließen oder das Gerät oder den Emulator neu starten.
Um benutzerdefinierte Ereignisse zu definieren, die im nativen Code Ihrer App oder Ihres Spiels auftreten,
führen Sie die folgenden Schritte aus:
Definieren Sie Funktionszeiger für die ATrace-Funktionen, mit denen Sie
benutzerdefinierte Ereignisse in Ihrer App oder Ihrem Spiel erfassen, wie im folgenden Code gezeigt:
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);
Lädt die ATrace-Symbole zur Laufzeit, wie im folgenden Code gezeigt:
Snippet. Normalerweise führen Sie diesen Vorgang in einem Objektkonstruktor aus.
// 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"));
}
Achtung : Aus Sicherheitsgründen sollten Sie Aufrufe von
dlopen()
nur in der Debug-Version deiner App oder deines Spiels.
Hinweis : Wenn Sie Tracing-Unterstützung auch nach der
Unter Android 4.3 (API-Level 18) können Sie mit JNI die Methoden in
verwalteten Code um den im
vorige Snippets.
ATrace_beginSection()
anrufen und
ATrace_endSection()
am Anfang bzw. Ende von
Ihr benutzerdefiniertes Ereignis:
#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();
Hinweis : Wenn Sie ATrace_beginSection()
mehrere
Mal, wird ATrace_endSection()
nur am häufigsten beendet.
mit der kürzlich aufgerufenen ATrace_beginSection()
-Methode. Bei verschachtelten
-Aufrufen, stellen Sie sicher, dass Sie jeden Aufruf
ATrace_beginSection()
mit einem Anruf bei
ATrace_endSection()
.
Außerdem können Sie ATrace_beginSection()
nicht auf einem Gerät aufrufen.
und beenden sie in einem anderen Thread. Beide Funktionen müssen vom selben
Diskussions-Thread.
Praktische Tipps
Die folgenden Tipps sind optional, helfen Ihnen aber möglicherweise bei der Analyse Ihrer nativen Anzeigen.
Code.
Gesamte Funktion verfolgen
Wenn Sie Ihren Aufrufstack oder das Timing von Funktionen instrumentieren, kann es nützlich sein,
um ganze Funktionen nachzuverfolgen. Mit dem Makro ATRACE_CALL()
können Sie
Tracing-Typ einfacher einzurichten. Außerdem können Sie mit einem solchen Makro
Erstellen von try
- und catch
-Blöcken für Fälle, in denen die Traced-Funktion
eine Ausnahme auslösen oder return
vorzeitig aufrufen.
Führen Sie die folgenden Schritte aus, um ein Makro für das Tracing einer gesamten Funktion zu erstellen:
Definieren Sie das 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();
}
};
Rufen Sie das Makro innerhalb der Funktion auf, die Sie verfolgen möchten:
void myExpensiveFunction() {
ATRACE_CALL();
// Code that you want to trace.
}
Threads benennen
Sie können jeden Thread, in dem Ihre Ereignisse auftreten, benennen, wie gezeigt
im folgenden Code-Snippet auf. Mit diesem Schritt können Sie die Threads leichter identifizieren
die zu bestimmten Aktionen in deinem Spiel gehören.
#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");
}
Empfehlungen für dich
Alle Inhalte und Codebeispiele auf dieser Seite unterliegen den Lizenzen wie im Abschnitt Inhaltslizenz beschrieben. Java und OpenJDK sind Marken oder eingetragene Marken von Oracle und/oder seinen Tochtergesellschaften.
Zuletzt aktualisiert: 2025-07-27 (UTC).
[[["Leicht verständlich","easyToUnderstand","thumb-up"],["Mein Problem wurde gelöst","solvedMyProblem","thumb-up"],["Sonstiges","otherUp","thumb-up"]],[["Benötigte Informationen nicht gefunden","missingTheInformationINeed","thumb-down"],["Zu umständlich/zu viele Schritte","tooComplicatedTooManySteps","thumb-down"],["Nicht mehr aktuell","outOfDate","thumb-down"],["Problem mit der Übersetzung","translationIssue","thumb-down"],["Problem mit Beispielen/Code","samplesCodeIssue","thumb-down"],["Sonstiges","otherDown","thumb-down"]],["Zuletzt aktualisiert: 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)"]]