OpenHarmony HiTrace在IPC通信中的应用(L2)

系统教程10个月前发布 lipeichen
9 0 0

OpenHarmony HiTrace在IPC通信中的应用(L2)

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

简介

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查看数据的发送和接收日志。

源代码开发 在类定义头文件或者类实现源文件中,包含hitrace头文件:

#include "hitrace/trace.h"

在业务类实现源文件中使用(启动/结束跟踪):

using namespace OHOS::HiviewDFX;
HiTraceId traceId = HiTrace::Begin("MyServiceFlow", HITRACE_FLAG_DEFAULT);
......
HiTrace::End(traceId);

跟踪日志(IPC框架中已经实现,不用实现):

HiTraceId id = HiTrace::GetId(); // 在Begin和End之间的id是有效的,其他阶段id无效。id无效,则Tracepoint的日志不会输出。
HiTrace::Tracepoint(HITRACE_TP_CS, id, "client send msg content"); // hilog | grep HiTraceC 抓取跟踪日志

编译设置,在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\include\dbinder_base_invoker.h。

IPC客户端发收数据入口:

int DBinderBaseInvoker<T>::SendRequest(int32_t handle, uint32_t code, MessageParcel &data, MessageParcel &reply,
MessageOption &option)
{
uint64_t seqNumber = 0;
int ret;
uint32_t flags = (uint32_t)option.GetFlags();
int userWaitTime = option.GetWaitTime();
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);
std::shared_ptr<T> session = WriteTransaction(BC_TRANSACTION, flags, handle, 0, code, data, seqNumber, 0);
if (session == nullptr) {
newData.RewindWrite(oldWritePosition);
DBINDER_BASE_LOGE("seqNumber can not be zero,handle=%d", handle);
#ifndef BUILD_PUBLIC_VERSION
ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE,
DbinderErrorCode::RPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::TRANSACT_DATA_FAILURE);
#endif
return RPC_BASE_INVOKER_WRITE_TRANS_ERR;
}

if (flags & TF_ONE_WAY) {
ret = SendOrWaitForCompletion(userWaitTime, seqNumber, session, nullptr);
} else {
ret = SendOrWaitForCompletion(userWaitTime, seqNumber, session, &reply);
}
// ####### 3.客户端数据接收跟踪记录。
HitraceInvoker::TraceClientReceieve(handle, code, flags, traceId, childId);
// restore Parcel data
newData.RewindWrite(oldWritePosition);
return ret;
}

服务端收发数据入口:

template <class T> void DBinderBaseInvoker<T>::OnTransaction(std::shared_ptr<ThreadProcessInfo> processInfo)
{
if (processInfo == nullptr) {
DBINDER_BASE_LOGE("processInfo is error!");
return;
}
uint32_t listenFd = processInfo->listenFd;
char *package = processInfo->buffer.get();

if (package == nullptr || listenFd == 0) {
DBINDER_BASE_LOGE("package is null or listenFd invalid!");
return;
}
dbinder_transaction_data *tr = reinterpret_cast<dbinder_transaction_data *>(package);
if (tr->sizeOfSelf < sizeof(dbinder_transaction_data)) {
DBINDER_BASE_LOGE("package is invalid");
return;
}
if (tr->cmd == BC_TRANSACTION) {
// ####### 服务端数据处理函数
ProcessTransaction(tr, listenFd);
} else if (tr->cmd == BC_REPLY) {
ProcessReply(tr, listenFd);
}
return;
}
template <class T> void DBinderBaseInvoker<T>::ProcessTransaction(dbinder_transaction_data *tr, uint32_t listenFd)
{
int error;
MessageParcel data, reply;
IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
if (current == nullptr) {
DBINDER_BASE_LOGE("current ipc process skeleton is nullptr");
return;
}
auto allocator = new DBinderSendAllocator();
if (!data.SetAllocator(allocator)) {
DBINDER_BASE_LOGE("SetAllocator failed");
delete allocator;
return;
}
data.ParseFrom(reinterpret_cast<uintptr_t>(tr->buffer), tr->buffer_size);
if (!(tr->flags & MessageOption::TF_STATUS_CODE) && tr->offsets_size > 0) {
data.InjectOffsets(reinterpret_cast<binder_uintptr_t>(reinterpret_cast<char *>(tr->buffer) + tr->offsets),
tr->offsets_size / sizeof(binder_size_t));
}
uint32_t &newflags = const_cast<uint32_t &>(tr->flags);
// ####### 1.服务端数据接收数据,解析tranceid,记录接收数据的跟踪信息。
int isServerTraced = HitraceInvoker::TraceServerReceieve(tr->cookie, tr->code, data, newflags);

const pid_t oldPid = GetCallerPid();
const auto oldUid = static_cast<const uid_t>(GetCallerUid());
const std::string oldDeviceId = GetCallerDeviceID();
uint32_t oldStatus = GetStatus();
if (CheckAndSetCallerInfo(listenFd, tr->cookie) != ERR_NONE) {
DBINDER_BASE_LOGE("set user info error, maybe cookie is NOT belong to current caller");
return;
}
SetStatus(IRemoteInvoker::ACTIVE_INVOKER);
const uint32_t flags = tr->flags;
uint64_t senderSeqNumber = tr->seqNumber;
if (tr->cookie == 0) {
// maybe cookie is zero, discard this package
return;
}
auto *stub = current->QueryStubByIndex(tr->cookie);
if (stub == nullptr) {
DBINDER_BASE_LOGE("stubIndex is invalid");
return;
}
if (!IRemoteObjectTranslate(reinterpret_cast<char *>(tr->buffer), tr->buffer_size, data, listenFd, nullptr)) {
DBINDER_BASE_LOGE("translate object failed");
return;
}
auto *stubObject = reinterpret_cast<IPCObjectStub *>(stub);
MessageOption option;
option.SetFlags(flags);
error = stubObject->SendRequest(tr->code, data, reply, option);
if (error != ERR_NONE) {
DBINDER_BASE_LOGE("stub is invalid, has not OnReceive or Request");
// can not return;
}
if (data.GetRawData() != nullptr) {
DBINDER_BASE_LOGE("delete raw data in process skeleton");
current->DetachRawData(listenFd);
}
// ####### 2.服务端数据回复记录接发送数据的跟踪信息。
HitraceInvoker::TraceServerSend(tr->cookie, tr->code, isServerTraced, newflags);
if (!(flags & MessageOption::TF_ASYNC)) {
SetClientFd(listenFd);
SetSeqNum(senderSeqNumber);
SendReply(reply, 0, error);
SetClientFd(0);
SetSeqNum(0);
}
SetCallerPid(oldPid);
SetCallerUid(oldUid);
SetCallerDeviceID(oldDeviceId);
SetStatus(oldStatus);
}

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

​官网文档​​。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

© 版权声明

相关文章