目录

HiDebug接口使用示例(C/C++)

HiDebug C/C++接口功能独立,需要获取调试信息时直接调用。具体调用示例请参考下文。

通用开发示例

下文展示如何在应用内使用HiDebug NDK接口以进行线程栈回溯,且获取进程内线程的CPU使用率:

步骤一:创建项目

  1. 使用DevEco Studio新建一个Native C++工程,并新增文件“test_backtrace.cpp”与“test_backtrace.h”,目录结构如下:

    entry:
      src:
        main:
          cpp:
            - types:
              - libentry:
                - index.d.ts
            - CMakeLists.txt
            - napi_init.cpp
            - test_backtrace.cpp
            - test_backtrace.h
          ets:
            pages:
              - Index.ets
  2. 编辑“test_backtrace.h”文件,内容如下:

    #ifndef MYAPPLICATION_TESTBACKTRACE_H
    #define MYAPPLICATION_TESTBACKTRACE_H
    
    void BacktraceCurrentThread();
    
    #endif // MYAPPLICATION_TESTBACKTRACE_H
  3. 编辑“test_backtrace.cpp”文件,内容如下:

    #include "test_backtrace.h"
    #include <condition_variable>
    #include <csignal>
    #include <unistd.h>
    #include <sys/syscall.h>
    #include "hidebug/hidebug.h"
    #include "hilog/log.h"
    
    #define MAX_FRAME_SIZE 256 // 最大栈回溯深度,应根据业务场景调整该值。
    
    namespace {
        constexpr auto LOG_PRINT_DOMAIN = 0xFF00;
    }
    
    class BackTraceObject { // 封装了抓栈过程中需要使用的资源,在使用过程中请注意线程安全和异步信号安全。
    public:
        static BackTraceObject& GetInstance();
        BackTraceObject(const BackTraceObject&) = delete;
        BackTraceObject& operator=(const BackTraceObject&) = delete;
        BackTraceObject(BackTraceObject&&) = delete;
        BackTraceObject& operator=(BackTraceObject&&) = delete;
        bool Init(uint32_t size);
        void Release();
        int BackTraceFromFp(void* startFp, int size); // 该函数异步信号安全。
        void SymbolicAddress(int index); // 该函数耗费性能,请避免频繁调用。
        void PrintStackFrame(void* pc, const HiDebug_StackFrame& frame);
    private:
        BackTraceObject() = default;
        ~BackTraceObject() = default;
        HiDebug_Backtrace_Object backtraceObject_ = nullptr;
        void** pcs_ = nullptr;
    };
    
    BackTraceObject& BackTraceObject::GetInstance() // 单例模式,用于信号处理和请求抓栈线程的数据交互。注意该类非异步信号安全,业务逻辑应确保同一时刻仅单个线程访问。
    {
        static BackTraceObject instance;
        return instance;
    }
    
    bool BackTraceObject::Init(uint32_t size) // 初始化资源。
    {
        backtraceObject_ = OH_HiDebug_CreateBacktraceObject();
        if (backtraceObject_ == nullptr || size > MAX_FRAME_SIZE) {
            return false;
        }
        pcs_ = new (std::nothrow) void* [size]{nullptr};
        if (pcs_ == nullptr) {
            return false;
        }
        return true;
    }
    
    void BackTraceObject::Release() // 释放资源。
    {
        OH_HiDebug_DestroyBacktraceObject(backtraceObject_);
        backtraceObject_ = nullptr;
        delete[] pcs_;
        pcs_ = nullptr;
    }
    
    int BackTraceObject::BackTraceFromFp(void* startFp, int size) // 栈回溯获取pc地址。
    {
        if (size <= MAX_FRAME_SIZE) {
            return OH_HiDebug_BacktraceFromFp(backtraceObject_, startFp, pcs_, size); // OH_HiDebug_BacktraceFromFp接口调用示例。
        }
        return 0;
    }
    
    void BackTraceObject::PrintStackFrame(void* pc, const HiDebug_StackFrame& frame) // 输出栈内容。
    {
        if (frame.type == HIDEBUG_STACK_FRAME_TYPE_JS) { // 根据栈帧的类型,区分不同的栈帧输出方式。
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "testTag",
                "js stack frame info for pc: %{public}p is "
                "relativePc: %{public}p "
                "line: %{public}d "
                "column: %{public}d "
                "mapName: %{public}s "
                "functionName: %{public}s "
                "url: %{public}s "
                "packageName: %{public}s.",
                pc,
                reinterpret_cast<void*>(frame.frame.js.relativePc),
                frame.frame.js.line,
                frame.frame.js.column,
                frame.frame.js.mapName,
                frame.frame.js.functionName,
                frame.frame.js.url,
                frame.frame.js.packageName);
        } else {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "testTag",
                "native stack frame info for pc: %{public}p is "
                "relativePc: %{public}p "
                "funcOffset: %{public}p "
                "mapName: %{public}s "
                "functionName: %{public}s "
                "buildId: %{public}s "
                "reserved: %{public}s.",
                pc,
                reinterpret_cast<void*>(frame.frame.native.relativePc),
                reinterpret_cast<void*>(frame.frame.native.funcOffset),
                frame.frame.native.mapName,
                frame.frame.native.functionName,
                frame.frame.native.buildId,
                frame.frame.native.reserved);
        }
    }
    
    void BackTraceObject::SymbolicAddress(int index)  // 栈解析接口。
    {
        if (index < 0 || index >= MAX_FRAME_SIZE) {
            return;
        }
        OH_HiDebug_SymbolicAddress(backtraceObject_, pcs_[index], this,
            [] (void* pc, void* arg, const HiDebug_StackFrame* frame) {
                reinterpret_cast<BackTraceObject*>(arg)->PrintStackFrame(pc, *frame);
            }); // 调用OH_HiDebug_SymbolicAddress接口解析栈。
    }
    
    void BacktraceCurrentThread() // 该接口非线程安全,同一时刻只能由一个线程使用。
    {
        if (!BackTraceObject::GetInstance().Init(MAX_FRAME_SIZE)) { // 注意:在调用栈回溯函数之前,需申请资源,且不可重复初始化。
            BackTraceObject::GetInstance().Release();
            OH_LOG_Print(LOG_APP, LOG_WARN, LOG_PRINT_DOMAIN, "testTag", "failed init backtrace object.");
            return;
        }
        int pcSize = BackTraceObject::GetInstance().BackTraceFromFp(__builtin_frame_address(0), MAX_FRAME_SIZE);
        for (int i = 0; i < pcSize; i++) {
            BackTraceObject::GetInstance().SymbolicAddress(i); // 主线程获取pc后,对pc值进行栈解析。
        }
        BackTraceObject::GetInstance().Release(); // 栈回溯并且解析结束后,及时释放资源。
    }
  4. 编辑“CMakeLists.txt”文件,添加库依赖:

    # 新增动态库依赖libohhidebug.so和libhilog_ndk.z.so(日志输出)
    add_library(entry SHARED napi_init.cpp test_backtrace.cpp test_async_context.cpp)
    target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libohhidebug.so)
  5. 编辑“napi_init.cpp”文件,导入依赖文件并定义测试方法:

    #include <thread>
    #include "hidebug/hidebug.h"
    #include "hilog/log.h"
    #include "test_backtrace.h"
    #include "test_async_context.h"
    
    #undef LOG_TAG
    #define LOG_TAG "testTag"
    
    __attribute((noinline)) __attribute((optnone)) void TestNativeFrames(int i)
    {
        if (i > 0) {
            TestNativeFrames(i - 1);
            return;
        }
        BacktraceCurrentThread();
    }
    
    __attribute((noinline)) __attribute((optnone)) napi_value TestBackTrace(napi_env env, napi_callback_info info)
    {
        TestNativeFrames(1);
        return nullptr;
    }
    
    napi_value TestGetThreadCpuUsage(napi_env env, napi_callback_info info)
    {
        HiDebug_ThreadCpuUsagePtr cpuUsage = OH_HiDebug_GetAppThreadCpuUsage();
        while (cpuUsage != nullptr) {
            OH_LOG_INFO(LogType::LOG_APP,
                "GetAppThreadCpuUsage: threadId %{public}d, cpuUsage: %{public}f", cpuUsage->threadId, cpuUsage->cpuUsage);
            cpuUsage = cpuUsage->next; // 获取下一个线程的cpu使用率对象指针。
        }
        OH_HiDebug_FreeThreadCpuUsage(&cpuUsage); // 释放内存,防止内存泄漏。
        return nullptr;
    }
    
    napi_value TestAsyncContext(napi_env env, napi_callback_info info)
    {
        TestAsyncContextChain();
        return nullptr;
    }

    注册“TestHiDebugNdk”为ArkTS接口并初始化主线程的信号处理函数:

    napi_property_descriptor desc[] = {
        { "testGetThreadCpuUsage", nullptr, TestGetThreadCpuUsage, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "testBackTrace", nullptr, TestBackTrace, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "testAsyncContext", nullptr, TestAsyncContext, nullptr, nullptr, nullptr, napi_default, nullptr },
    };
  6. 编辑“index.d.ts”文件,声明ArkTS接口:

    export const testGetThreadCpuUsage: () => void;
    export const testBackTrace: () => void;
    export const testAsyncContext: () => void;
  7. 编辑“Index.ets”文件,添加触发接口调用的按钮,示例代码如下:

    导入依赖:

    import testNapi from 'libentry.so';

    定义测试方法:

    function testBackTraceJsFrame(i : number) : void {
      if (i > 0) {
        return testBackTraceJsFrame(i-1);
      }
      return testNapi.testBackTrace();
    }
    
    function testBackTrace() : void {
      testBackTraceJsFrame(3);
    }
    
    function testGetThreadCpuUsage() : void {
      testNapi.testGetThreadCpuUsage();
    }
    
    function testAsyncContext() : void {
      testNapi.testAsyncContext();
    }

    添加按钮以触发接口调用:

    Button('testGetThreadCpuUsage')
      .type(ButtonType.Capsule)
      .margin({
        top: 20
      })
      .backgroundColor('#0D9FFB')
      .width('60%')
      .height('5%')
      // 添加点击事件
      .onClick(testGetThreadCpuUsage);
    
    Button('testHiDebugBackTrace')
      .type(ButtonType.Capsule)
      .margin({
        top: 20
      })
      .backgroundColor('#0D9FFB')
      .width('60%')
      .height('5%')
      // 添加点击事件
      .onClick(testBackTrace);
    
    Button('testAsyncContext')
      .type(ButtonType.Capsule)
      .margin({
        top: 20
      })
      .backgroundColor('#0D9FFB')
      .width('60%')
      .height('5%')
      // 添加点击事件
      .onClick(testAsyncContext);

步骤二:运行工程

  1. 点击DevEco Studio界面中的运行按钮,然后分别单击应用界面上的“testGetThreadCpuUsage”和“testHiDebugBackTrace”按钮。

  2. 在DevEco Studio底部切换到“Log”窗口,设置日志过滤条件为“testTag”,即可查看相关日志:

    ...
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19261, cpuUsage: 0.000104
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19381, cpuUsage: 0.000000
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19382, cpuUsage: 0.000040
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19383, cpuUsage: 0.000010
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19384, cpuUsage: 0.000001
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19386, cpuUsage: 0.000038
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19387, cpuUsage: 0.000000
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19388, cpuUsage: 0.000007
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19389, cpuUsage: 0.000004
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19390, cpuUsage: 0.000007
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19391, cpuUsage: 0.000006
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19393, cpuUsage: 0.000001
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19394, cpuUsage: 0.000004
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19397, cpuUsage: 0.000002
    10-22 15:46:05.933   19261-19261   A00000/com.sam...gtool/testTag  com.sampl...ebugtool  I     GetAppThreadCpuUsage: threadId 19401, cpuUsage: 0.000001
    ...
    10-22 15:46:13.351   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     native stack frame info for pc: ************ is relativePc: ****** funcOffset: 0x38 mapName: /data/storage/el1/bundle/libs/arm64/libentry.so functionName: TestNativeFrames(int) buildId: b6d3429f6e2e594b1c696e13049dae7e51694099 reserved: (null).
    10-22 15:46:13.351   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     native stack frame info for pc: ************ is relativePc: ****** funcOffset: 0x30 mapName: /data/storage/el1/bundle/libs/arm64/libentry.so functionName: TestNativeFrames(int) buildId: b6d3429f6e2e594b1c696e13049dae7e51694099 reserved: (null).
    10-22 15:46:13.351   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     native stack frame info for pc: ************ is relativePc: ****** funcOffset: 0x1c mapName: /data/storage/el1/bundle/libs/arm64/libentry.so functionName: TestBackTrace(napi_env__*, napi_callback_info__*) buildId: b6d3429f6e2e594b1c696e13049dae7e51694099 reserved: (null).
    ...
    10-22 15:46:13.354   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     js stack frame info for pc: ************ is relativePc: ****** line: 27 column: 21 mapName: /data/storage/el1/bundle/entry.hap functionName: testBackTraceJsFrame url: entry|entry|1.0.0|src/main/ets/pages/Index.ts packageName: .
    10-22 15:46:13.354   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     js stack frame info for pc: ************ is relativePc: ****** line: 25 column: 16 mapName: /data/storage/el1/bundle/entry.hap functionName: testBackTraceJsFrame url: entry|entry|1.0.0|src/main/ets/pages/Index.ts packageName: .
    10-22 15:46:13.354   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     js stack frame info for pc: ************ is relativePc: ****** line: 25 column: 16 mapName: /data/storage/el1/bundle/entry.hap functionName: testBackTraceJsFrame url: entry|entry|1.0.0|src/main/ets/pages/Index.ts packageName: .
    10-22 15:46:13.354   19261-19261   A0FF00/com.sam...gtool/testTag  com.sampl...ebugtool  I     js stack frame info for pc: ************ is relativePc: ****** line: 25 column: 16 mapName: /data/storage/el1/bundle/entry.hap functionName: testBackTraceJsFrame url: entry|entry|1.0.0|src/main/ets/pages/Index.ts packageName: ....
    ...

管理异步上下文示例

从API版本26.0.0开始提供管理异步上下文功能。下文展示如何在应用内使用HiDebug C/C++异步上下文管理接口,构造A->B单层异步调用链,在异步任务提交和完成时分别压入和弹出异步上下文,建立和解除异步调用链关系。

该功能仅支持ARM64架构,且仅可在debug版本应用中使用,需配合hiprofiler调优组件追踪完整的异步调用栈。

[h2]步骤一:新增异步上下文管理接口示例代码

  1. 编辑“test_async_context.h”文件,声明异步上下文调用链入口函数:

    #ifndef MYAPPLICATION_TESTASYNCCONTEXT_H
    #define MYAPPLICATION_TESTASYNCCONTEXT_H
    
    // 测试异步上下文管理接口,构造A->B最小三方异步调用。
    void TestAsyncContextChain();
    
    #endif // MYAPPLICATION_TESTASYNCCONTEXT_H
  2. 编辑“test_async_context.cpp”文件,构造A->B单层异步调用链,演示四个接口的调用时序(A:Acquire/Release;B:Push/Pop):

    #include "test_async_context.h"
    #include "hidebug/hidebug.h"
    #include "hilog/log.h"
    #include <cstdlib>
    #include <thread>
    #include <chrono>
    
    #undef LOG_TAG
    #define LOG_TAG "testTag"
    
    // IsDebuggableHap()与DfxInvokeHiDebugCallback均检查。
    // 环境变量 HAP_DEBUGGABLE;setenv 须早于注入,故用 constructor 在 libentry.so 加载时设置。
    __attribute__((constructor)) static void SetHapDebuggableEnv()
    {
        setenv("HAP_DEBUGGABLE", "true", 1);
    }
    
    // 模拟异步任务耗时(ms)。
    static constexpr int ASYNC_TASK_DURATION_MS = 500;
    
    // 三方异步任务上下文,用于在线程间透传异步上下文句柄
    struct AsyncTaskCtx {
        uint64_t asyncCtx;
    };
    
    // B:三方异步任务,使用std::thread模拟三方异步框架。
    static void ThirdPartyAsyncTask(AsyncTaskCtx *ctx)
    {
        if (ctx == nullptr) {
            return;
        }
        // 异步任务执行时,将异步上下文压入当前线程运行上下文,建立异步调用链。
        OH_HiDebug_PushAsyncContext(ctx->asyncCtx);
        OH_LOG_INFO(LogType::LOG_APP, "[Async-B] Third-party async task start, push context %{public}llu",
            (unsigned long long)ctx->asyncCtx);
        std::this_thread::sleep_for(std::chrono::milliseconds(ASYNC_TASK_DURATION_MS)); // 模拟三方异步耗时。
        OH_LOG_INFO(LogType::LOG_APP, "[Async-B] Third-party async task done");
        // 异步任务完成时,将异步上下文弹出,解除异步调用链。
        OH_HiDebug_PopAsyncContext(ctx->asyncCtx);
        delete ctx;
    }
    
    // A:提交方,在独立线程执行以避免阻塞napi调用线程。
    static void OuterTaskFunc()
    {
        // 异步任务提交前,获取一个异步上下文。
        uint64_t asyncCtx = OH_HiDebug_AcquireAsyncContext();
        OH_LOG_INFO(LogType::LOG_APP, "[Async-A] Acquired context: %{public}llu", (unsigned long long)asyncCtx);
    
        // 提交三方异步任务B,透传异步上下文句柄。
        OH_LOG_INFO(LogType::LOG_APP, "[Async-A] Submit third-party async task B");
        auto *ctx = new (std::nothrow) AsyncTaskCtx{asyncCtx};
        if (ctx == nullptr) {
            OH_HiDebug_ReleaseAsyncContext(asyncCtx);
            return;
        }
        std::thread worker(ThirdPartyAsyncTask, ctx);
        worker.join(); // 等待B完成,保证Release在Push/Pop之后
    
        // 异步任务结束后,释放异步上下文资源,防止资源泄漏。
        OH_HiDebug_ReleaseAsyncContext(asyncCtx);
        OH_LOG_INFO(LogType::LOG_APP, "[Async-A] Released context");
    }
    
    // 构造A->B最小三方异步调用,演示管理异步上下文的四个接口。
    void TestAsyncContextChain()
    {
        // 在独立线程执行A,避免阻塞napi调用线程。
        std::thread(OuterTaskFunc).detach();
    }
  3. 编辑“CMakeLists.txt”文件,将新增源文件test_async_context.cpp加入add_library编译目标。

  4. 编辑“napi_init.cpp”文件,导入“test_async_context.h”并新增napi包装方法TestAsyncContext:

    #include <thread>
    #include "hidebug/hidebug.h"
    #include "hilog/log.h"
    #include "test_backtrace.h"
    #include "test_async_context.h"
    
    #undef LOG_TAG
    #define LOG_TAG "testTag"
    
    __attribute((noinline)) __attribute((optnone)) void TestNativeFrames(int i)
    {
        if (i > 0) {
            TestNativeFrames(i - 1);
            return;
        }
        BacktraceCurrentThread();
    }
    
    __attribute((noinline)) __attribute((optnone)) napi_value TestBackTrace(napi_env env, napi_callback_info info)
    {
        TestNativeFrames(1);
        return nullptr;
    }
    
    napi_value TestGetThreadCpuUsage(napi_env env, napi_callback_info info)
    {
        HiDebug_ThreadCpuUsagePtr cpuUsage = OH_HiDebug_GetAppThreadCpuUsage();
        while (cpuUsage != nullptr) {
            OH_LOG_INFO(LogType::LOG_APP,
                "GetAppThreadCpuUsage: threadId %{public}d, cpuUsage: %{public}f", cpuUsage->threadId, cpuUsage->cpuUsage);
            cpuUsage = cpuUsage->next; // 获取下一个线程的cpu使用率对象指针。
        }
        OH_HiDebug_FreeThreadCpuUsage(&cpuUsage); // 释放内存,防止内存泄漏。
        return nullptr;
    }
    
    napi_value TestAsyncContext(napi_env env, napi_callback_info info)
    {
        TestAsyncContextChain();
        return nullptr;
    }
  5. 注册“testAsyncContext”为ArkTS接口:

    napi_property_descriptor desc[] = {
        { "testGetThreadCpuUsage", nullptr, TestGetThreadCpuUsage, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "testBackTrace", nullptr, TestBackTrace, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "testAsyncContext", nullptr, TestAsyncContext, nullptr, nullptr, nullptr, napi_default, nullptr },
    };
  6. 编辑“index.d.ts”文件,声明ArkTS接口testAsyncContext:

    export const testGetThreadCpuUsage: () => void;
    export const testBackTrace: () => void;
    export const testAsyncContext: () => void;
  7. 编辑“Index.ets”文件,定义测试方法:

    function testBackTraceJsFrame(i : number) : void {
      if (i > 0) {
        return testBackTraceJsFrame(i-1);
      }
      return testNapi.testBackTrace();
    }
    
    function testBackTrace() : void {
      testBackTraceJsFrame(3);
    }
    
    function testGetThreadCpuUsage() : void {
      testNapi.testGetThreadCpuUsage();
    }
    
    function testAsyncContext() : void {
      testNapi.testAsyncContext();
    }
  8. 编辑“Index.ets”文件,添加按钮以触发接口调用:

    Button('testGetThreadCpuUsage')
      .type(ButtonType.Capsule)
      .margin({
        top: 20
      })
      .backgroundColor('#0D9FFB')
      .width('60%')
      .height('5%')
      // 添加点击事件
      .onClick(testGetThreadCpuUsage);
    
    Button('testHiDebugBackTrace')
      .type(ButtonType.Capsule)
      .margin({
        top: 20
      })
      .backgroundColor('#0D9FFB')
      .width('60%')
      .height('5%')
      // 添加点击事件
      .onClick(testBackTrace);
    
    Button('testAsyncContext')
      .type(ButtonType.Capsule)
      .margin({
        top: 20
      })
      .backgroundColor('#0D9FFB')
      .width('60%')
      .height('5%')
      // 添加点击事件
      .onClick(testAsyncContext);

[h2]步骤二:运行工程

  1. 启动hiprofiler采集任务,使能异步上下文追踪。

    hdc shell
    hiprofiler_cmd -c - -o /data/local/tmp/hiprofiler_data.htrace -t 60 -s -k <<CONFIG
    request_id: 1
    session_config {
      buffers {
        pages: 16384
      }
    }
    plugin_configs {
      plugin_name: "nativehook"
      sample_interval: 5000
      config_data {
        save_file: false
        smb_pages: 16384
        max_stack_depth: 20
        process_name: "com.samples.hidebugtool"
        fp_unwind: true
        blocked: true
        callframe_compress: true
        record_accurately: true
        offline_symbolization: true
        startup_mode: false
        async_stack_enable: true
        async_type: CUSTOMIZE
      }
    }
    CONFIG
  2. 点击DevEco Studio界面中的运行按钮,然后单击应用界面上的“testAsyncContext”按钮。

  3. 在DevEco Studio底部切换到“Log”窗口,设置日志过滤条件为“testTag”,即可查看异步调用链日志。