1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hitrace_invoker.h"
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <cinttypes>
21 
22 #include "hilog/log_c.h"
23 #include "hilog/log_cpp.h"
24 #include "hitrace/trace.h"
25 #include "ipc_debug.h"
26 #include "log_tags.h"
27 #include "message_parcel.h"
28 #include "process_skeleton.h"
29 #include "sys_binder.h"
30 
31 namespace OHOS {
32 // the value should be equal to the set of parcel
33 using namespace OHOS::HiviewDFX;
34 static const HiLogLabel TRACE_LABEL = { LOG_CORE, LOG_ID_IPC_BINDER_INVOKER, "BinderHiTrace" };
35 
IsClientTraced(int32_t handle,uint32_t flags,const HiTraceId & traceId)36 bool HitraceInvoker::IsClientTraced(int32_t handle, uint32_t flags, const HiTraceId &traceId)
37 {
38     return (traceId.IsValid() && (handle != 0) &&
39         ((flags & TF_ONE_WAY) ? traceId.IsFlagEnabled(HITRACE_FLAG_INCLUDE_ASYNC) : true));
40 }
41 
TraceClientSend(int32_t handle,uint32_t code,MessageParcel & data,uint32_t & flags,const HiTraceId & traceId)42 HiTraceId HitraceInvoker::TraceClientSend(int32_t handle, uint32_t code, MessageParcel &data, uint32_t &flags,
43     const HiTraceId &traceId)
44 {
45     HiTraceId childId = traceId;
46     bool isClientTraced = IsClientTraced(handle, flags, traceId);
47     if (isClientTraced) {
48         childId = HiTraceChain::CreateSpan();
49         // add childid to parcel data
50         uint8_t idBytes[HITRACE_ID_LEN];
51         size_t idLen = (size_t)(childId.ToBytes(idBytes, HITRACE_ID_LEN));
52         if (idLen != HITRACE_ID_LEN) {
53             ZLOGE(TRACE_LABEL, "idLen not correct");
54             return childId;
55         }
56 
57         size_t oldWritePosition = data.GetWritePosition();
58         if (!data.WriteBuffer(idBytes, idLen)) {
59             ZLOGE(TRACE_LABEL, "Write idBytes fail");
60             // restore Parcel data
61             data.RewindWrite(oldWritePosition);
62             return childId;
63         }
64 
65         // padded size of traceid
66         if (!data.WriteUint8(data.GetWritePosition() - oldWritePosition)) {
67             ZLOGE(TRACE_LABEL, "Write idLen fail");
68             // restore Parcel data
69             data.RewindWrite(oldWritePosition);
70             return childId;
71         }
72         // tracepoint: CS(Client Send)
73         std::u16string desc = data.GetInterfaceToken();
74         HiTraceChain::Tracepoint(HITRACE_TP_CS, childId, "%{public}s handle=%{public}d,code=%{public}u,desc=%{public}s",
75             (flags & TF_ONE_WAY) ? "ASYNC" : "SYNC", handle, code,
76             ProcessSkeleton::ConvertToSecureDesc(Str16ToStr8(desc)).c_str());
77         flags |= TF_HITRACE;
78     } else {
79         if (flags & TF_HITRACE) {
80             ZLOGW(TRACE_LABEL, "business set the error flags, traceid is invalid ");
81             flags &= ~(uint32_t)TF_HITRACE;
82         }
83     }
84     return childId;
85 }
86 
TraceClientReceieve(int32_t handle,uint32_t code,uint32_t flags,const HiTraceId & traceId,const HiTraceId & childId)87 void HitraceInvoker::TraceClientReceieve(int32_t handle, uint32_t code, uint32_t flags, const HiTraceId &traceId,
88     const HiTraceId &childId)
89 {
90     if (!(flags & TF_HITRACE)) {
91         return;
92     }
93     bool isClientTraced = IsClientTraced(handle, flags, traceId);
94     if (isClientTraced) {
95         if (!(flags & TF_ONE_WAY)) {
96             // restore thread trace id
97             HiTraceChain::SetId(traceId);
98             // tracepoint: CR(Client Receive)
99             HiTraceChain::Tracepoint(HITRACE_TP_CR, childId,
100                 "%{public}s handle=%{public}d,code=%{public}u", "SYNC", handle, code);
101         }
102     }
103 }
104 
RecoveryDataAndFlag(Parcel & data,uint32_t & flags,size_t oldReadPosition,uint8_t idLen)105 void HitraceInvoker::RecoveryDataAndFlag(Parcel &data, uint32_t &flags, size_t oldReadPosition, uint8_t idLen)
106 {
107     if (data.GetDataSize() < (idLen + PADDED_SIZE_OF_PARCEL)) {
108         return;
109     }
110     // restore data
111     data.RewindRead(oldReadPosition);
112     // padded size(4 bytes) of uint8_t
113     data.SetDataSize(data.GetDataSize() - PADDED_SIZE_OF_PARCEL - idLen);
114     flags &= ~(uint32_t)TF_HITRACE;
115 }
116 
TraceServerReceieve(uint64_t handle,uint32_t code,MessageParcel & data,uint32_t & flags)117 bool HitraceInvoker::TraceServerReceieve(uint64_t handle, uint32_t code, MessageParcel &data, uint32_t &flags)
118 {
119     bool isServerTraced = (flags & TF_HITRACE) != 0;
120     if (!isServerTraced) {
121         return isServerTraced;
122     }
123     size_t oldReadPosition = data.GetReadPosition();
124     // padded size(4 bytes) of uint8_t
125     if (data.GetDataSize() < PADDED_SIZE_OF_PARCEL) {
126         ZLOGE(TRACE_LABEL, "The size of the data packet is less than 4");
127         return false;
128     }
129     data.RewindRead(data.GetDataSize() - PADDED_SIZE_OF_PARCEL);
130     // the padded size of traceid
131     uint8_t idLen = data.ReadUint8();
132     if ((idLen >= sizeof(HiTraceIdStruct)) && (idLen <= (data.GetDataSize() - PADDED_SIZE_OF_PARCEL))) {
133         // padded size(4 bytes) of uint8_t
134         data.RewindRead(data.GetDataSize() - PADDED_SIZE_OF_PARCEL - idLen);
135         const uint8_t *idBytes = data.ReadUnpadBuffer(sizeof(HiTraceIdStruct));
136         if (idBytes == nullptr) {
137             ZLOGE(TRACE_LABEL, "idBytes is null");
138             isServerTraced = false;
139             RecoveryDataAndFlag(data, flags, oldReadPosition, idLen);
140             return isServerTraced;
141         }
142         HiTraceId traceId(idBytes, sizeof(HiTraceIdStruct));
143         HiTraceChain::SetId(traceId);
144         // tracepoint: SR(Server Receive)
145         data.RewindRead(oldReadPosition);
146         std::u16string desc = data.ReadInterfaceToken();
147         HiTraceChain::Tracepoint(HITRACE_TP_SR, traceId,
148             "%{public}s handle=%{public}" PRIu64 ",code=%{public}u,desc=%{public}s",
149             (flags & TF_ONE_WAY) ? "ASYNC" : "SYNC", handle, code,
150             ProcessSkeleton::ConvertToSecureDesc(Str16ToStr8(desc)).c_str());
151     }
152     RecoveryDataAndFlag(data, flags, oldReadPosition, idLen);
153 
154     return isServerTraced;
155 }
156 
TraceServerSend(uint64_t handle,uint32_t code,bool isServerTraced,uint32_t flags)157 void HitraceInvoker::TraceServerSend(uint64_t handle, uint32_t code, bool isServerTraced, uint32_t flags)
158 {
159     if (isServerTraced) {
160         // tracepoint: SS(Server Send)
161         HiTraceChain::Tracepoint(HITRACE_TP_SS, HiTraceChain::GetId(),
162             "%{public}s handle=%{public}" PRIu64 ",code=%{public}u",
163             (flags & TF_ONE_WAY) ? "ASYNC" : "SYNC", handle, code);
164     }
165     HiTraceChain::ClearId();
166 }
167 } // namespace OHOS
168