رویدادهای ردیابی سفارشی در کد بومی
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
Android 6.0 (سطح API 23) و بالاتر از API ردیابی بومی، trace.h
پشتیبانی می کند تا رویدادهای ردیابی را در بافر سیستم بنویسد که سپس می توانید با استفاده از Perfetto یا systrace آن را تجزیه و تحلیل کنید. موارد استفاده رایج برای این API شامل مشاهده زمانی است که یک بلوک کد خاص برای اجرا طول می کشد و ارتباط یک بلوک کد با رفتار نامطلوب سیستم.
توجه: در دستگاهها و شبیهسازهایی که API سطح 27 و پایینتر دارند، اگر حافظه کافی در دسترس نباشد یا حافظه بیش از حد تکهتکه باشد، پیام زیر را دریافت خواهید کرد: Atrace could not allocate enough memory to record a trace
. اگر این اتفاق افتاد و ضبط شما مجموعه کاملی از داده ها را نداشت، باید فرآیندهای پس زمینه را ببندید یا دستگاه یا شبیه ساز را مجددا راه اندازی کنید.
برای تعریف رویدادهای سفارشی که در کد بومی در برنامه یا بازی شما رخ می دهد، مراحل زیر را کامل کنید:
همانطور که در قطعه کد زیر نشان داده شده است، نشانگرهای تابع را برای توابع ATrace تعریف کنید که برای ثبت رویدادهای سفارشی در برنامه یا بازی خود استفاده می کنید:
#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);
همانطور که در قطعه کد زیر نشان داده شده است، نمادهای ATrace را در زمان اجرا بارگذاری کنید. معمولاً این فرآیند را در یک سازنده شی انجام می دهید.
// 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"));
}
احتیاط: به دلایل امنیتی، تماسهای dlopen()
را فقط در نسخه اشکالزدایی برنامه یا بازی خود وارد کنید.
توجه: برای ارائه پشتیبانی ردیابی بیشتر به Android 4.3 (سطح API 18)، میتوانید از JNI برای فراخوانی متدهای موجود در کد مدیریت شده در اطراف کد نشان داده شده در قطعه قبلی استفاده کنید.
ATrace_beginSection()
و ATrace_endSection()
را به ترتیب در ابتدا و انتهای رویداد سفارشی خود فراخوانی کنید:
#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();
توجه: هنگامی که ATrace_beginSection()
چندین بار فراخوانی می کنید، فراخوانی ATrace_endSection()
تنها به متد اخیر ATrace_beginSection()
پایان می دهد. بنابراین، برای تماسهای تودرتو، مطمئن شوید که هر تماس را با ATrace_beginSection()
با فراخوانی به ATrace_endSection()
مطابقت دهید.
علاوه بر این، نمیتوانید ATrace_beginSection()
در یک رشته فراخوانی کنید و آن را از یک رشته دیگر پایان دهید. شما باید هر دو تابع را از یک رشته فراخوانی کنید.
نکات راحتی
نکات زیر اختیاری هستند، اما ممکن است تجزیه و تحلیل کد بومی شما را آسانتر کنند.
ردیابی کل یک تابع
هنگام تنظیم زمان بندی پشته تماس یا عملکرد، ممکن است ردیابی کل عملکردها مفید باشد. میتوانید از ماکرو ATRACE_CALL()
برای تنظیم آسانتر این نوع ردیابی استفاده کنید. علاوه بر این، چنین ماکرویی به شما امکان میدهد از ایجاد بلوکهای try
and catch
برای مواردی که تابع ردیابی شده ممکن است استثنا ایجاد کند یا تماس زودهنگام return
، صرفنظر کنید.
برای ایجاد یک ماکرو برای ردیابی کل یک تابع، مراحل زیر را انجام دهید:
ماکرو را تعریف کنید:
#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();
}
};
ماکرو را در تابعی که می خواهید ردیابی کنید فراخوانی کنید:
void myExpensiveFunction() {
ATRACE_CALL();
// Code that you want to trace.
}
تاپیک های خود را نام ببرید
همانطور که در قطعه کد زیر نشان داده شده است، می توانید برای هر رشته ای که رویدادهای شما در آن اتفاق می افتد یک نام بدهید. این مرحله شناسایی رشتههایی را که به اقدامات خاصی در بازی شما تعلق دارند، آسانتر میکند.
#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");
}
{% کلمه به کلمه %}
{% آخر کلمه %} برای شما توصیه می شود
{% کلمه به کلمه %} {% آخر کلمه %}
محتوا و نمونه کدها در این صفحه مشمول پروانههای توصیفشده در پروانه محتوا هستند. جاوا و OpenJDK علامتهای تجاری یا علامتهای تجاری ثبتشده Oracle و/یا وابستههای آن هستند.
تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی.
[[["درک آسان","easyToUnderstand","thumb-up"],["مشکلم را برطرف کرد","solvedMyProblem","thumb-up"],["غیره","otherUp","thumb-up"]],[["اطلاعاتی که نیاز دارم وجود ندارد","missingTheInformationINeed","thumb-down"],["بیشازحد پیچیده/ مراحل بسیار زیاد","tooComplicatedTooManySteps","thumb-down"],["قدیمی","outOfDate","thumb-down"],["مشکل ترجمه","translationIssue","thumb-down"],["مشکل کد / نمونهها","samplesCodeIssue","thumb-down"],["غیره","otherDown","thumb-down"]],["تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی."],[],[],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)"]]