#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2) 原创 精华

碼磚民工
发布于 2022-7-1 11:26
浏览
5收藏

「本文正在参加星光计划3.0–夏日挑战赛」

@toc

简介

HiTrace主要是对于跨设备/跨进程/跨线程的业务流程,通过相同的traceid在整个业务流程中传递,将流程处理过程中的调用关系、各种输出信息关联和展现出来,帮助使用者分析、定位问题和系统调优。此文章以OpenHarmony 3.1代码基础, 以IPC进程通信中的HiTrace应用介绍HiTrace的使用和数据流转。

  • HiTrace在IPC通信中的应用介绍。
  • HiTrace在IPC通信中应用示例。
  • HiTrace在IPC中的数据流介绍。
  • 本用例开发板(3516开发板:HiSpark_AI_Hi3516D_One_Light_VER.B开发板上测试)

HiTrace在IPC通信中的应用介绍。

IPC通信的框架代码中:
客户端的发送接收数据地方已经有 tranceId发送到服务端以及发送和接收数据的跟踪日志代码。
服务端的接收回复数据地方已经有 获取传递过来的tranceId以及接收和发送数据的跟踪日志代码。
我们只需要在要跟踪的代码块前添加HiTrace::Begin, 代码块后添加HiTrace::End即可。
抓取跟踪日志:hilog | grep HiTraceC查看数据的发送和接收日志。

  1. 源代码开发 在类定义头文件或者类实现源文件中,包含hitrace头文件:
#include "hitrace/trace.h"
  1. 在业务类实现源文件中使用(启动/结束跟踪):
using namespace OHOS::HiviewDFX;
HiTraceId traceId = HiTrace::Begin("MyServiceFlow", HITRACE_FLAG_DEFAULT);
......
HiTrace::End(traceId);
  1. 跟踪日志(IPC框架中已经实现,不用实现)
HiTraceId id = HiTrace::GetId(); // 在Begin和End之间的id是有效的,其他阶段id无效。id无效,则Tracepoint的日志不会输出。
HiTrace::Tracepoint(HITRACE_TP_CS, id, "client send msg content"); // hilog | grep HiTraceC 抓取跟踪日志
  1. 编译设置,在BUILD.gn里增加子系统SDK依赖:
external_deps = [ "hiviewdfx:libhitrace" ]

HiTrace在IPC通信中应用示例。

子系统配置

build\subsystem_config.json

 "myapp": {
    "path":"myapptest",
    "name": "myapp"
  }

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区

产品配置

productdefine\common\products\Hi3516DV300.json

"myapp:myappservice_test":{}

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区

代码

代码目录结构

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区
myapptest放在代码根目录,代码见附件

服务ID的添加

服务ID有统一的头文件
foundation\distributedschedule\samgr\interfaces\innerkits\samgr_proxy\include\system_ability_definition.h

MY_APP_SERVICE_ID                                = 9000,
...
{ MY_APP_SERVICE_ID, "MyAppService"},

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区
#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区

编译

编译和把编译结果文件发送到开发板修改权限参考OpenHarmony 实现的一个IPC的客户端和服务端, 代码基于这个文档的代码修改添加。

测试

终端1:抓取日志

hilog | grep HiTraceC

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区
图中白色部分是一次完整的客户端和服务端交互流程, 每一个begin和end之间tranceid相同,每一次完整的交互spanid一样。CS:客户端发送数据,CR:客户端接收数据,SR:服务端接收数据,SS:服务端发送数据。
终端2:启动服务

sa_main /system/profile/myappservice_sa.xml

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区
终端3:启动客户端

 /data/test/myappclient

#夏日挑战赛# OpenHarmony HiTrace在IPC通信中的应用(L2)-鸿蒙开发者社区

HiTrace在IPC中的数据流介绍

入口函数文件:
foundation\communication\ipc\ipc\native\src\mock\source\binder_invoker.cpp
IPC客户端发收数据入口:

int BinderInvoker::SendRequest(int handle, uint32_t code, MessageParcel &data, MessageParcel &reply,
    MessageOption &option)
{
    int error = ERR_NONE;
    uint32_t flags = (uint32_t)option.GetFlags();
    ZLOGI(LABEL, "%{public}s: handle=%d ,flags:%u, code:%u", __func__, handle, flags, code);
    MessageParcel &newData = const_cast<MessageParcel &>(data);
    size_t oldWritePosition = newData.GetWritePosition();
    // ####### 1.获取tranceId
    HiTraceId traceId = HiTrace::GetId();
    // set client send trace point if trace is enabled
    // ####### 2.客户端数据发送跟踪记录,并把tranceid打包到发送数据中去。
    HiTraceId childId = HitraceInvoker::TraceClientSend(handle, code, newData, flags, traceId);
    if (!WriteTransaction(BC_TRANSACTION, flags, handle, code, data, nullptr)) {
        newData.RewindWrite(oldWritePosition);
        ZLOGE(LABEL, "WriteTransaction ERROR");
#ifndef BUILD_PUBLIC_VERSION
        ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE,
            DbinderErrorCode::IPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::TRANSACT_DATA_FAILURE);
#endif
        return IPC_INVOKER_WRITE_TRANS_ERR;
    }

    if ((flags & TF_ONE_WAY) != 0) {
        error = WaitForCompletion(nullptr);
    } else {
        error = WaitForCompletion(&reply);
    }
    // ####### 3.客户端数据接收跟踪记录。
    HitraceInvoker::TraceClientReceieve(handle, code, flags, traceId, childId);
    // restore Parcel data
    newData.RewindWrite(oldWritePosition);
    ZLOGI(LABEL, "%{public}s: handle=%d result = %{public}d", __func__, handle, error);
    return error;
}

服务端收发数据入口:

void BinderInvoker::OnTransaction(const uint8_t *buffer)
{
    const binder_transaction_data *tr = reinterpret_cast<const binder_transaction_data *>(buffer);
    auto data = std::make_unique<MessageParcel>(new BinderAllocator());
    data->ParseFrom(tr->data.ptr.buffer, tr->data_size);
    if (tr->offsets_size > 0) {
        data->InjectOffsets(tr->data.ptr.offsets, tr->offsets_size / sizeof(binder_size_t));
    }
    uint32_t &newflags = const_cast<uint32_t &>(tr->flags);
    // ####### 1.服务端数据接收数据,解析tranceid,记录接收数据的跟踪信息。
    int isServerTraced = HitraceInvoker::TraceServerReceieve(tr->target.handle, tr->code, *data, newflags);
    const pid_t oldPid = callerPid_;
    const auto oldUid = static_cast<const uid_t>(callerUid_);
    const uint32_t oldToken = callerTokenID_;
    const uint32_t oldFirstToken = firstTokenID_;
    uint32_t oldStatus = status_;
    callerPid_ = tr->sender_pid;
    callerUid_ = tr->sender_euid;
    if (binderConnector_->IsAccessTokenSupported()) {
        struct access_token tmp;
        int error = binderConnector_->WriteBinder(BINDER_GET_ACCESS_TOKEN, &tmp);
        if (error != ERR_NONE) {
            callerTokenID_ = 0;
            firstTokenID_ = 0;
        } else {
            callerTokenID_ = tmp.sender_tokenid;
            firstTokenID_ = tmp.first_tokenid;
        }
    } else {
        callerTokenID_ = 0;
        firstTokenID_ = 0;
    }
    SetStatus(IRemoteInvoker::ACTIVE_INVOKER);
    int error = ERR_DEAD_OBJECT;
    sptr<IRemoteObject> targetObject;
    if (tr->target.ptr != 0) {
        auto *refs = reinterpret_cast<IRemoteObject *>(tr->target.ptr);
        if ((refs != nullptr) && (tr->cookie) && (refs->AttemptIncStrongRef(this))) {
            targetObject = reinterpret_cast<IPCObjectStub *>(tr->cookie);
            targetObject->DecStrongRef(this);
        }
    } else {
        targetObject = IPCProcessSkeleton::GetCurrent()->GetRegistryObject();
    }
    MessageParcel reply;
    MessageOption option;
    uint32_t flagValue = static_cast<uint32_t>(tr->flags) & ~static_cast<uint32_t>(MessageOption::TF_ACCEPT_FDS);
    if (targetObject != nullptr) {
        option.SetFlags(static_cast<int>(flagValue));
        error = targetObject->SendRequest(tr->code, *data, reply, option);
    }
    // ####### 2.服务端数据回复记录接发送数据的跟踪信息。
    HitraceInvoker::TraceServerSend(tr->target.handle, tr->code, isServerTraced, newflags);
    if (!(flagValue & TF_ONE_WAY)) {
        SendReply(reply, 0, error);
    }
    callerPid_ = oldPid;
    callerUid_ = oldUid;
    callerTokenID_ = oldToken;
    firstTokenID_ = oldFirstToken;
    SetStatus(oldStatus);
}

这里只对IPC数据交互的客户端和服务端总入口进行简单注释。要对IPC框架了解,需要结合OpenHarmony IPC通信(L2)进行代码分析学习。

官网文档

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
myapptest.rar 8.14K 51次下载
已于2022-11-18 10:49:54修改
7
收藏 5
回复
举报
6条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

很详细的讲解!

2
回复
2022-7-1 13:46:09
挖墙脚的农民工
挖墙脚的农民工

虽然看不懂,但还是感觉很牛的样子。

2
回复
2022-7-1 13:48:49
科技维度
科技维度

大佬优秀啊

1
回复
2022-7-4 10:31:34
民之码农
民之码农

666

1
回复
2022-7-5 10:35:18
民之码农
民之码农

大佬优秀啊

2
回复
2022-7-5 10:35:37
民之码农
民之码农

很不错,赞起!

2
回复
2022-7-5 10:36:01
回复
    相关推荐