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 #include <atomic>
16 #include <cinttypes>
17 #include <climits>
18 #include <fcntl.h>
19 #include <fstream>
20 #include <mutex>
21 #include <unistd.h>
22 #include <vector>
23 #include "bytrace.h"
24 #include "hilog/log.h"
25 #include "parameter.h"
26 #include "parameters.h"
27
28 using namespace std;
29 using namespace OHOS::HiviewDFX;
30
31 #define EXPECTANTLY(exp) (__builtin_expect(!!(exp), true))
32 #define UNEXPECTANTLY(exp) (__builtin_expect(!!(exp), false))
33
34 namespace {
35 int g_markerFd = -1;
36 std::once_flag g_onceFlag;
37
38 std::atomic<bool> g_isBytraceInit(false);
39 std::atomic<uint64_t> g_tagsProperty(BYTRACE_TAG_NOT_READY);
40
41 const std::string KEY_TRACE_TAG = "debug.bytrace.tags.enableflags";
42 const std::string KEY_APP_NUMBER = "debug.bytrace.app_number";
43 const std::string KEY_RO_DEBUGGABLE = "ro.debuggable";
44
45 constexpr int NAME_MAX_SIZE = 1000;
46 static std::vector<std::string> g_markTypes = {"B", "E", "S", "F", "C"};
47 enum MarkerType { MARKER_BEGIN, MARKER_END, MARKER_ASYNC_BEGIN, MARKER_ASYNC_END, MARKER_INT, MARKER_MAX };
48
49 constexpr uint64_t BYTRACE_TAG = 0xd03301;
50 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, BYTRACE_TAG, "BytraceCore"};
51
ParameterChange(const char * key,const char * value,void * context)52 static void ParameterChange(const char* key, const char* value, void* context)
53 {
54 HiLog::Info(LABEL, "ParameterChange %{public}s", key);
55 UpdateTraceLabel();
56 }
57
IsAppValid()58 bool IsAppValid()
59 {
60 // Judge if application-level tracing is enabled.
61 if (OHOS::system::GetBoolParameter(KEY_RO_DEBUGGABLE, 0)) {
62 std::ifstream fs;
63 fs.open("/proc/self/cmdline");
64 if (!fs.is_open()) {
65 fprintf(stderr, "IsAppValid, open /proc/self/cmdline failed.\n");
66 return false;
67 }
68
69 std::string lineStr;
70 std::getline(fs, lineStr);
71 std::string keyPrefix = "debug.bytrace.app_";
72 int nums = OHOS::system::GetIntParameter<int>(KEY_APP_NUMBER, 0);
73 for (int i = 0; i < nums; i++) {
74 std::string keyStr = keyPrefix + std::to_string(i);
75 std::string val = OHOS::system::GetParameter(keyStr, "");
76 if (val == "*" || val == lineStr) {
77 fs.close();
78 return true;
79 }
80 }
81 }
82 return false;
83 }
84
GetSysParamTags()85 uint64_t GetSysParamTags()
86 {
87 // Get the system parameters of KEY_TRACE_TAG.
88 uint64_t tags = OHOS::system::GetUintParameter<uint64_t>(KEY_TRACE_TAG, 0);
89 if (tags == 0) {
90 // HiLog::Error(LABEL, "GetUintParameter %s error.\n", KEY_TRACE_TAG.c_str());
91 return 0;
92 }
93
94 IsAppValid();
95 return (tags | BYTRACE_TAG_ALWAYS) & BYTRACE_TAG_VALID_MASK;
96 }
97
98 // open file "trace_marker".
OpenTraceMarkerFile()99 void OpenTraceMarkerFile()
100 {
101 const std::string debugFile = "/sys/kernel/debug/tracing/trace_marker";
102 const std::string traceFile = "/sys/kernel/tracing/trace_marker";
103 g_markerFd = open(debugFile.c_str(), O_WRONLY | O_CLOEXEC);
104 if (g_markerFd == -1) {
105 g_markerFd = open(traceFile.c_str(), O_WRONLY | O_CLOEXEC);
106 if (g_markerFd == -1) {
107 HiLog::Error(LABEL, "open trace file %{public}s failed: %{public}s", traceFile.c_str(), strerror(errno));
108 g_tagsProperty = 0;
109 return;
110 }
111 }
112 g_tagsProperty = GetSysParamTags();
113
114 if (WatchParameter(KEY_TRACE_TAG.c_str(), ParameterChange, nullptr) != 0) {
115 HiLog::Error(LABEL, "WatchParameter %{public}s failed", KEY_TRACE_TAG.c_str());
116 return;
117 }
118 g_isBytraceInit = true;
119 }
120 }; // namespace
121
AddBytraceMarker(MarkerType type,uint64_t tag,const std::string & name,const std::string & value)122 void AddBytraceMarker(MarkerType type, uint64_t tag, const std::string& name, const std::string& value)
123 {
124 if (UNEXPECTANTLY(!g_isBytraceInit)) {
125 std::call_once(g_onceFlag, OpenTraceMarkerFile);
126 }
127 if (UNEXPECTANTLY(g_tagsProperty & tag)) {
128 // record fomart: "type|pid|name value".
129 std::string record = g_markTypes[type] + "|";
130 record += std::to_string(getpid()) + "|";
131 record += (name.size() < NAME_MAX_SIZE) ? name : name.substr(0, NAME_MAX_SIZE);
132 record += " " + value;
133 if (write(g_markerFd, record.c_str(), record.size()) < 0) {
134 HiLog::Error(LABEL, "write trace_marker failed, %{public}s", strerror(errno));
135 }
136 }
137 }
138
UpdateTraceLabel()139 void UpdateTraceLabel()
140 {
141 if (!g_isBytraceInit) {
142 return;
143 }
144 g_tagsProperty = GetSysParamTags();
145 }
146
StartTrace(uint64_t label,const string & value,float limit)147 void StartTrace(uint64_t label, const string& value, float limit)
148 {
149 string traceName = "H:" + value;
150 AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
151 }
152
StartTraceDebug(uint64_t label,const string & value,float limit)153 void StartTraceDebug(uint64_t label, const string& value, float limit)
154 {
155 #if (TRACE_LEVEL >= DEBUG_LEVEL)
156 string traceName = "H:" + value + GetHiTraceInfo();
157 AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
158 #endif
159 }
160
FinishTrace(uint64_t label)161 void FinishTrace(uint64_t label)
162 {
163 AddBytraceMarker(MARKER_END, label, "", "");
164 }
165
FinishTraceDebug(uint64_t label)166 void FinishTraceDebug(uint64_t label)
167 {
168 #if (TRACE_LEVEL >= DEBUG_LEVEL)
169 AddBytraceMarker(MARKER_END, label, "", "");
170 #endif
171 }
172
StartAsyncTrace(uint64_t label,const string & value,int32_t taskId,float limit)173 void StartAsyncTrace(uint64_t label, const string& value, int32_t taskId, float limit)
174 {
175 string traceName = "H:" + value;
176 AddBytraceMarker(MARKER_ASYNC_BEGIN, label, traceName, std::to_string(taskId));
177 }
178
StartAsyncTraceDebug(uint64_t label,const string & value,int32_t taskId,float limit)179 void StartAsyncTraceDebug(uint64_t label, const string& value, int32_t taskId, float limit)
180 {
181 #if (TRACE_LEVEL >= DEBUG_LEVEL)
182 string traceName = "H:" + value;
183 AddBytraceMarker(MARKER_ASYNC_BEGIN, label, traceName, std::to_string(taskId));
184 #endif
185 }
186
FinishAsyncTrace(uint64_t label,const string & value,int32_t taskId)187 void FinishAsyncTrace(uint64_t label, const string& value, int32_t taskId)
188 {
189 string traceName = "H:" + value;
190 AddBytraceMarker(MARKER_ASYNC_END, label, traceName, std::to_string(taskId));
191 }
192
FinishAsyncTraceDebug(uint64_t label,const string & value,int32_t taskId)193 void FinishAsyncTraceDebug(uint64_t label, const string& value, int32_t taskId)
194 {
195 #if (TRACE_LEVEL >= DEBUG_LEVEL)
196 string traceName = "H:" + value;
197 AddBytraceMarker(MARKER_ASYNC_END, label, traceName, std::to_string(taskId));
198 #endif
199 }
200
MiddleTrace(uint64_t label,const string & beforeValue,const std::string & afterValue)201 void MiddleTrace(uint64_t label, const string& beforeValue, const std::string& afterValue)
202 {
203 string traceName = "H:" + afterValue;
204 AddBytraceMarker(MARKER_END, label, "", "");
205 AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
206 }
207
MiddleTraceDebug(uint64_t label,const string & beforeValue,const std::string & afterValue)208 void MiddleTraceDebug(uint64_t label, const string& beforeValue, const std::string& afterValue)
209 {
210 #if (TRACE_LEVEL >= DEBUG_LEVEL)
211 string traceName = "H:" + afterValue + GetTraceInfo();
212 AddBytraceMarker(MARKER_END, label, "", "");
213 AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
214 #endif
215 }
216
CountTrace(uint64_t label,const string & name,int64_t count)217 void CountTrace(uint64_t label, const string& name, int64_t count)
218 {
219 string traceName = "H:" + name;
220 AddBytraceMarker(MARKER_INT, label, traceName, std::to_string(count));
221 }
222
CountTraceDebug(uint64_t label,const string & name,int64_t count)223 void CountTraceDebug(uint64_t label, const string& name, int64_t count)
224 {
225 #if (TRACE_LEVEL >= DEBUG_LEVEL)
226 string traceName = "H:" + name;
227 AddBytraceMarker(MARKER_INT, label, traceName, std::to_string(count));
228 #endif
229 }
230