ネイティブ コード内のカスタム トレース イベント
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
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()
を呼び出して、別のスレッドから終了することはできません。1 つのスレッド内で両方の関数を呼び出す必要があります。
ヒント
以下のヒントは必須ではありませんが、ネイティブ コードの分析が容易になる場合があります。
関数全体をトレースする
コールスタックや関数のタイミングをインストルメント化する場合は、関数全体をトレースすると便利です。ATRACE_CALL()
マクロを使用すると、この種のトレースを簡単にセットアップできます。また、このようなマクロを使用すると、トレース対象関数が例外をスローしたり、早期に return
を呼び出したりする可能性のあるケースにおいて、try
ブロックや catch
ブロックの作成をスキップできます。
関数全体をトレースするマクロを作成する手順は次のとおりです。
マクロを定義します。
#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");
}
あなたへのおすすめ
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2025-07-27 UTC。
[[["わかりやすい","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-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)"]]