Peristiwa rekaman aktivitas kustom dalam kode native
Tetap teratur dengan koleksi
Simpan dan kategorikan konten berdasarkan preferensi Anda.
Android 6.0 (level API 23) dan yang lebih tinggi mendukung API pelacakan native, trace.h
,
untuk menulis peristiwa rekaman aktivitas ke buffer sistem yang kemudian dapat Anda analisis menggunakan
Perfetto atau systrace. Contoh kasus penggunaan umum untuk API ini mencakup pengamatan waktu
yang diperlukan blok kode tertentu untuk menjalankan dan mengaitkan blok kode
dengan perilaku sistem yang tidak diinginkan.
Catatan: Pada perangkat dan emulator yang menjalankan API level 27 dan yang lebih rendah, jika
memori yang tersedia tidak mencukupi atau memori terlalu terfragmen, Anda akan mendapatkan
pesan berikut: Atrace could not allocate enough memory to record a trace
.
Jika hal ini terjadi dan rekaman Anda tidak memiliki kumpulan data yang lengkap, Anda
harus menutup proses latar belakang atau memulai ulang perangkat atau emulator.
Untuk menentukan peristiwa kustom yang terjadi pada kode native dalam aplikasi atau game Anda,
selesaikan langkah-langkah berikut:
Tentukan pointer fungsi untuk fungsi ATrace yang Anda gunakan untuk
mengambil peristiwa kustom dalam aplikasi atau game Anda, seperti yang ditampilkan pada cuplikan kode
berikut:
#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);
Muat simbol ATrace saat waktu proses, seperti yang ditampilkan pada cuplikan kode
berikut. Biasanya, Anda menjalankan proses ini pada pembuat objek.
// 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"));
}
Perhatian: Untuk alasan keamanan, sertakan panggilan ke
dlopen()
hanya dalam versi debug aplikasi atau game Anda.
Catatan: Untuk memberikan dukungan pelacakan hingga pada
Android 4.3 (level API 18), Anda dapat menggunakan JNI guna memanggil metode dalam
kode terkelola di sekitar kode yang ditampilkan pada
cuplikan sebelumnya.
Panggil ATrace_beginSection()
dan
ATrace_endSection()
di awal dan akhir
peristiwa kustom Anda:
#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();
Catatan: Saat Anda memanggil ATrace_beginSection()
beberapa
kali, memanggil ATrace_endSection()
hanya akan mengakhiri
metode ATrace_beginSection()
yang terakhir dipanggil. Jadi, untuk panggilan
bertingkat, pastikan Anda mencocokkan dengan tepat setiap panggilan ke
ATrace_beginSection()
dengan panggilan ke
ATrace_endSection()
.
Selain itu, Anda tidak dapat memanggil ATrace_beginSection()
di satu
thread dan mengakhirinya di thread lain. Anda harus memanggil kedua fungsi dari thread yang
sama.
Tips untuk memudahkan
Tips berikut dapat Anda lakukan untuk memudahkan proses analisis kode native
Anda.
Melacak seluruh fungsi
Saat melakukan instrumentasi stack panggilan atau pengaturan waktu fungsi, melacak seluruh
fungsi mungkin akan bermanfaat. Anda dapat menggunakan makro ATRACE_CALL()
untuk menjadikan jenis
pelacakan ini lebih mudah disiapkan. Selain itu, makro semacam itu memungkinkan Anda melewati
pembuatan blok try
dan catch
dalam berbagai kasus yang mana fungsi yang dilacak mungkin
memberikan pengecualian atau panggilan return
lebih awal.
Untuk membuat makro guna melacak seluruh fungsi, selesaikan langkah-langkah berikut:
Tentukan 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();
}
};
Panggil makro pada fungsi yang ingin Anda lacak:
void myExpensiveFunction() {
ATRACE_CALL();
// Code that you want to trace.
}
Memberi nama thread Anda
Anda dapat memberi nama untuk setiap thread di tempat peristiwa terjadi, seperti yang diperlihatkan
pada cuplikan kode berikut. Langkah ini memudahkan identifikasi thread
yang termasuk dalam tindakan spesifik dalam game Anda.
#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");
}
Direkomendasikan untuk Anda
Konten dan contoh kode di halaman ini tunduk kepada lisensi yang dijelaskan dalam Lisensi Konten. Java dan OpenJDK adalah merek dagang atau merek dagang terdaftar dari Oracle dan/atau afiliasinya.
Terakhir diperbarui pada 2025-07-27 UTC.
[[["Mudah dipahami","easyToUnderstand","thumb-up"],["Memecahkan masalah saya","solvedMyProblem","thumb-up"],["Lainnya","otherUp","thumb-up"]],[["Informasi yang saya butuhkan tidak ada","missingTheInformationINeed","thumb-down"],["Terlalu rumit/langkahnya terlalu banyak","tooComplicatedTooManySteps","thumb-down"],["Sudah usang","outOfDate","thumb-down"],["Masalah terjemahan","translationIssue","thumb-down"],["Masalah kode / contoh","samplesCodeIssue","thumb-down"],["Lainnya","otherDown","thumb-down"]],["Terakhir diperbarui pada 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)"]]