• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "uc_telemetry_listener.h"
16 
17 #include "cjson_util.h"
18 #include "hiview_logger.h"
19 #include "time_util.h"
20 #include "hisysevent.h"
21 #include "uc_telemetry_callback.h"
22 
23 namespace OHOS::HiviewDFX {
24 DEFINE_LOG_TAG("HiView-UnifiedCollector");
25 namespace {
26 const int64_t DURATION_DEFAULT = 3600 * SECONDS_TO_MS; // ms
27 const int64_t MAX_DURATION = 7 * 24 * 3600 * SECONDS_TO_MS; // ms
28 const uint32_t BT_M_UNIT = 1024 * 1024;
29 const int64_t MAX_BUFFER_SIZE = 500 * 1024; // 500M
30 constexpr char TELEMETRY_DOMAIN[] = "TELEMETRY";
31 constexpr char TAGS[] = "tags";
32 constexpr char BUFFER_SIZE[] = "bufferSize";
33 
34 constexpr char SWITCH_ON[] = "on";
35 constexpr char SWITCH_OFF[] = "off";
36 constexpr char POLICY_POWER[] = "power";
37 constexpr char POLICY_MANUAL[] = "manual";
38 
39 // Default quota of flow control
40 const int64_t DEFAULT_XPERF_SIZE = 20 * 1024 * 1024;
41 const int64_t DEFAULT_XPOWER_SIZE = 20 * 1024 * 1024;
42 const int64_t DEFAULT_RELIABILITY_SIZE = 20 * 1024 * 1024;
43 const int64_t DEFAULT_TOTAL_SIZE = 50 * 1024 * 1024;
44 const int64_t MAX_TOTAL_SIZE = 1024; // 1G
45 
46 constexpr char KEY_ID[] = "telemetryId";
47 constexpr char KEY_FILTER_NAME[] = "appFilterName";
48 constexpr char KEY_SA_NAMES[] = "saNames";
49 constexpr char KEY_SWITCH_STATUS[] = "telemetryStatus";
50 constexpr char KEY_TRACE_POLICY[] = "tracePolicy";
51 constexpr char KEY_TRACE_TAG[] = "traceArgs";
52 constexpr char KEY_TOTAL_QUOTA[] = "traceQuota";
53 constexpr char KEY_OPEN_TIME[] = "traceOpenTime";
54 constexpr char KEY_DURATION[] = "traceDuration";
55 constexpr char KEY_XPERF_QUOTA[] = "xperfTraceQuota";
56 constexpr char KEY_XPOWER_QUOTA[] = "xpowerTraceQuota";
57 constexpr char KEY_RELIABILITY_QUOTA[] = "reliabilityTraceQuota";
58 constexpr char TOTAL[] = "Total";
59 
60 const std::unordered_set<std::string> TRACE_TAG_FILTER_LIST {
61     "sched", "freq", "disk", "sync", "binder", "mmc", "membus", "load", "pagecache", "workq", "net", "dsched",
62     "graphic", "multimodalinput", "dinput", "ark", "ace", "window", "zaudio", "daudio", "zmedia", "dcamera",
63     "zcamera", "dhfwk", "app", "ability", "power", "samgr", "nweb"
64 };
65 
66 const std::unordered_set<std::string> TRACE_SA_FILTER_LIST {
67     "render_service", "foundation"
68 };
69 
ParseAndFilterTraceArgs(const std::unordered_set<std::string> & filterList,cJSON * root,const std::string & key)70 std::vector<std::string> ParseAndFilterTraceArgs(const std::unordered_set<std::string> &filterList,
71     cJSON* root, const std::string &key)
72 {
73     if (!cJSON_IsObject(root)) {
74         HIVIEW_LOGE("trace jsonArgs parse error");
75         return {};
76     }
77     std::vector<std::string> traceArgs;
78     CJsonUtil::GetStringArray(root, key, traceArgs);
79     auto new_end = std::remove_if(traceArgs.begin(), traceArgs.end(), [&filterList](const std::string& tag) {
80         return filterList.find(tag) == filterList.end();
81     });
82     traceArgs.erase(new_end, traceArgs.end());
83     return traceArgs;
84 }
85 }
86 
OnUnorderedEvent(const Event & msg)87 void TelemetryListener::OnUnorderedEvent(const Event &msg)
88 {
89     bool isCloseMsg = false;
90     TelemetryParams params;
91     std::string errorMsg = CheckValidParam(msg, params, isCloseMsg);
92     HIVIEW_LOGI("isClose:%{public}d", isCloseMsg);
93     if (!errorMsg.empty()) {
94         return WriteErrorEvent(errorMsg, params);
95     }
96     if (isCloseMsg) {
97         HandleStop();
98         return;
99     }
100     params.appFilterName = msg.GetValue(KEY_FILTER_NAME);
101     params.traceDuration = msg.GetInt64Value(KEY_DURATION) * SECONDS_TO_MS;
102     if (params.traceDuration <= 0) {
103         params.traceDuration = DURATION_DEFAULT;
104     } else if (params.traceDuration > MAX_DURATION) {
105         params.traceDuration = MAX_DURATION;
106     }
107     GetSaNames(msg, params);
108 
109     bool isTimeOut = false;
110     if (!InitTelemetryDbData(msg, isTimeOut, params)) {
111         return WriteErrorEvent("init telemetry time table fail", params);
112     }
113     if (isTimeOut) {
114         HIVIEW_LOGE("%{public}s", "trace already time out");
115         return;
116     }
117     auto delaySeconds = params.beginTime - TimeUtil::GetSeconds();
118     if (delaySeconds <= 0) {
119         HandleStart(params);
120     } else {
121         if (taskQueue_ == nullptr) {
122             taskQueue_ = std::make_unique<ffrt::queue>("telemetry_queue");
123         }
124         startTaskHandle_ = taskQueue_->submit_h([this, params] { this->HandleStart(params); },
125             ffrt::task_attr().delay(delaySeconds * SECONDS_TO_MS * MS_TO_US));
126     }
127 }
128 
CheckValidParam(const Event & msg,TelemetryParams & params,bool & isCloseMsg)129 std::string TelemetryListener::CheckValidParam(const Event &msg, TelemetryParams &params, bool &isCloseMsg)
130 {
131     std::string errorMsg;
132     if (!CheckTelemetryId(msg, params, errorMsg)) {
133         return errorMsg;
134     }
135     if (!CheckTraceTags(msg, params, errorMsg)) {
136         return errorMsg;
137     }
138     if (!CheckTracePolicy(msg, params, errorMsg)) {
139         return errorMsg;
140     }
141     if (!CheckSwitchValid(msg, isCloseMsg, errorMsg)) {
142         return errorMsg;
143     }
144     if (!CheckBeginTime(msg, params, errorMsg)) {
145         return errorMsg;
146     }
147     return errorMsg;
148 }
149 
InitTelemetryDbData(const Event & msg,bool & isTimeOut,const TelemetryParams & params)150 bool TelemetryListener::InitTelemetryDbData(const Event &msg, bool &isTimeOut, const TelemetryParams &params)
151 {
152     std::map<std::string, int64_t> flowControlQuotas {
153         {CallerName::XPERF, DEFAULT_XPERF_SIZE },
154         {CallerName::XPOWER, DEFAULT_XPOWER_SIZE},
155         {CallerName::RELIABILITY, DEFAULT_RELIABILITY_SIZE},
156         {TOTAL, DEFAULT_TOTAL_SIZE}
157     };
158     auto xperfTraceQuota = msg.GetInt64Value(KEY_XPERF_QUOTA);
159     if (xperfTraceQuota > 0) {
160         flowControlQuotas[CallerName::XPERF] = xperfTraceQuota * BT_M_UNIT;
161     }
162     auto xpowerTraceQuota = msg.GetInt64Value(KEY_XPOWER_QUOTA);
163     if (xpowerTraceQuota > 0) {
164         flowControlQuotas[CallerName::XPOWER] = xpowerTraceQuota * BT_M_UNIT;
165     }
166     auto reliabilityTraceQuota = msg.GetInt64Value(KEY_RELIABILITY_QUOTA);
167     if (reliabilityTraceQuota > 0) {
168         flowControlQuotas[CallerName::RELIABILITY] = reliabilityTraceQuota * BT_M_UNIT;
169     }
170     auto totalTraceQuota = msg.GetInt64Value(KEY_TOTAL_QUOTA);
171     if (totalTraceQuota > 0 && totalTraceQuota <= MAX_TOTAL_SIZE) {
172         flowControlQuotas[TOTAL] = totalTraceQuota * BT_M_UNIT;
173     } else if (totalTraceQuota > MAX_TOTAL_SIZE) {
174         flowControlQuotas[TOTAL] = MAX_TOTAL_SIZE * BT_M_UNIT;
175     } else {
176         HIVIEW_LOGI("default total quota size");
177     }
178 
179     int64_t running_time = 0;
180     auto ret = TraceFlowController(BusinessName::TELEMETRY).InitTelemetryData(params.telemetryId, running_time,
181         flowControlQuotas);
182     if (ret == TelemetryRet::EXIT) {
183         return false;
184     }
185     isTimeOut = running_time >= params.traceDuration;
186     return true;
187 }
188 
HandleStart(const TelemetryParams & params)189 void TelemetryListener::HandleStart(const TelemetryParams &params)
190 {
191     auto ret = TraceStateMachine::GetInstance().OpenTelemetryTrace(params.traceTag, params.tracePolicy);
192     if (ret.IsSuccess()) {
193         std::shared_ptr<TelemetryCallback> callback;
194         switch (params.tracePolicy) {
195             case TelemetryPolicy::POWER:
196                 callback = std::make_shared<PowerCallback>(params);
197                 break;
198             case TelemetryPolicy::MANUAL:
199                 callback = std::make_shared<ManualCallback>(params);
200                 break;
201             default:
202                 callback = std::make_shared<UcTelemetryCallback>(params);
203                 break;
204         }
205         bool isSuccess = TraceStateMachine::GetInstance().RegisterTelemetryCallback(callback);
206         HIVIEW_LOGI("register callback result:%{public}d, traceDuration%{public}" PRId64 "", isSuccess,
207             params.traceDuration);
208     } else {
209         WriteErrorEvent("trace state error", params);
210     }
211 }
212 
HandleStop()213 void TelemetryListener::HandleStop()
214 {
215     TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_TELEMETRY);
216     TraceFlowController controller(BusinessName::TELEMETRY);
217     controller.ClearTelemetryData();
218     if (taskQueue_ != nullptr && taskQueue_->cancel(startTaskHandle_) < 0) {
219         HIVIEW_LOGW("%{public}s", "telemetstartTaskHandle_ry trace already start");
220     }
221 }
222 
WriteErrorEvent(const std::string & error,const TelemetryParams & params)223 void TelemetryListener::WriteErrorEvent(const std::string &error, const TelemetryParams &params)
224 {
225     HIVIEW_LOGE("%{public}s", error.c_str());
226     HiSysEventWrite(TELEMETRY_DOMAIN, "TASK_INFO", HiSysEvent::EventType::STATISTIC,
227         "ID", params.telemetryId,
228         "STAGE", "TRACE_BEGIN",
229         "ERROR", error);
230 }
231 
ProcessTraceTag(std::string & traceTag)232 bool TelemetryListener::ProcessTraceTag(std::string &traceTag)
233 {
234     cJSON* root = cJSON_Parse(traceTag.c_str());
235     if (root == nullptr) {
236         return false;
237     }
238     auto tags = ParseAndFilterTraceArgs(TRACE_TAG_FILTER_LIST, root, TAGS);
239     if (tags.empty()) {
240         cJSON_Delete(root);
241         return false;
242     }
243     auto bufferSize = CJsonUtil::GetIntValue(root, BUFFER_SIZE);
244     cJSON_Delete(root);
245     if (bufferSize <= 0) {
246         HIVIEW_LOGE("jsonArgs parse trace bufferSize error");
247         return false;
248     }
249     if (bufferSize > MAX_BUFFER_SIZE) {
250         bufferSize = MAX_BUFFER_SIZE;
251     }
252     bool isFirst = true;
253     std::string result("tags:");
254     for (const auto &tag: tags) {
255         if (!isFirst) {
256             result.append(", ").append(tag);
257             continue;
258         }
259         result.append(tag);
260         isFirst = false;
261     }
262     result.append(" bufferSize:").append(std::to_string(bufferSize));
263     traceTag = std::move(result);
264     return true;
265 }
266 
CheckTelemetryId(const Event & msg,TelemetryParams & params,std::string & errorMsg)267 bool TelemetryListener::CheckTelemetryId(const Event &msg, TelemetryParams &params, std::string &errorMsg)
268 {
269     std::string telemetryId = msg.GetValue(KEY_ID);
270     if (telemetryId.empty()) {
271         errorMsg.append("telemetryId get empty");
272         return false;
273     }
274     params.telemetryId = telemetryId;
275     return true;
276 }
277 
GetSaNames(const Event & msg,TelemetryParams & params)278 void TelemetryListener::GetSaNames(const Event &msg, TelemetryParams &params)
279 {
280     std::string saJsonNames = msg.GetValue(KEY_SA_NAMES);
281     if (!saJsonNames.empty()) {
282         cJSON* root = cJSON_Parse(saJsonNames.c_str());
283         if (root == nullptr) {
284             return;
285         }
286         auto saNames = ParseAndFilterTraceArgs(TRACE_SA_FILTER_LIST, root, KEY_SA_NAMES);
287         for (const auto &saName : saNames) {
288             auto param = "startup.service.ctl." + saName + ".pid";
289             params.saParams.emplace_back(param);
290         }
291         cJSON_Delete(root);
292     }
293 }
294 
CheckTraceTags(const Event & msg,TelemetryParams & params,std::string & errorMsg)295 bool TelemetryListener::CheckTraceTags(const Event &msg, TelemetryParams &params, std::string &errorMsg)
296 {
297     auto traceTag = msg.GetValue(KEY_TRACE_TAG);
298     if (!traceTag.empty() && !ProcessTraceTag(traceTag)) {
299         errorMsg.append("process trace tag fail");
300         return false;
301     }
302     params.traceTag = traceTag;
303     return true;
304 }
305 
CheckTracePolicy(const Event & msg,TelemetryParams & params,std::string & errorMsg)306 bool TelemetryListener::CheckTracePolicy(const Event &msg, TelemetryParams &params, std::string &errorMsg)
307 {
308     auto tracePolicy = msg.GetValue(KEY_TRACE_POLICY);
309     if (tracePolicy.empty()) {
310         params.tracePolicy = TelemetryPolicy::DEFAULT;
311         return true;
312     }
313     if (tracePolicy == POLICY_POWER) {
314         params.tracePolicy = TelemetryPolicy::POWER;
315     } else if (tracePolicy == POLICY_MANUAL) {
316         params.tracePolicy = TelemetryPolicy::MANUAL;
317     } else {
318         errorMsg.append("trace policy get empty");
319         return false;
320     }
321     return true;
322 }
323 
CheckSwitchValid(const Event & msg,bool & isCloseMsg,std::string & errorMsg)324 bool TelemetryListener::CheckSwitchValid(const Event &msg, bool &isCloseMsg, std::string &errorMsg)
325 {
326     auto switchStatus = msg.GetValue(KEY_SWITCH_STATUS);
327     if (switchStatus.empty()) {
328         errorMsg.append("switchStatus get empty");
329         return false;
330     }
331     if (switchStatus == SWITCH_OFF) {
332         isCloseMsg = true;
333         return false;
334     }
335     if (switchStatus != SWITCH_ON) {
336         errorMsg.append("switchStatus param get error");
337         return false;
338     }
339     return true;
340 }
341 
CheckBeginTime(const Event & msg,TelemetryParams & params,std::string & errorMsg)342 bool TelemetryListener::CheckBeginTime(const Event &msg, TelemetryParams &params, std::string &errorMsg)
343 {
344     // Get begin time of telemetry trace unit seconds
345     int64_t beginTime = msg.GetInt64Value(KEY_OPEN_TIME);
346     if (beginTime < 0) {
347         errorMsg.append("begin time get failed");
348         return false;
349     }
350     params.beginTime = beginTime;
351     return true;
352 }
353 }
354