• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 "transaction/rs_unmarshal_thread.h"
17 
18 #include "app_mgr_client.h"
19 #include "hisysevent.h"
20 #include "pipeline/render_thread/rs_base_render_util.h"
21 #include "pipeline/main_thread/rs_main_thread.h"
22 #include "pipeline/rs_unmarshal_task_manager.h"
23 #include "platform/common/rs_log.h"
24 #include "platform/common/rs_system_properties.h"
25 #include "transaction/rs_transaction_data.h"
26 #include "res_sched_client.h"
27 #include "res_type.h"
28 #include "rs_frame_report.h"
29 #include "rs_profiler.h"
30 #include "command/rs_node_command.h"
31 #include "command/rs_canvas_node_command.h"
32 #include "recording/draw_cmd_list.h"
33 #include "rs_trace.h"
34 #include "platform/common/rs_hisysevent.h"
35 
36 #ifdef RES_SCHED_ENABLE
37 #include "qos.h"
38 #endif
39 
40 namespace OHOS::Rosen {
41 namespace {
42 constexpr int REQUEST_FRAME_AWARE_ID = 100001;
43 constexpr int REQUEST_SET_FRAME_LOAD_ID = 100006;
44 constexpr int REQUEST_FRAME_AWARE_LOAD = 85;
45 constexpr int REQUEST_FRAME_AWARE_NUM = 4;
46 constexpr int REQUEST_FRAME_STANDARD_LOAD = 50;
47 constexpr size_t TRANSACTION_DATA_ALARM_COUNT = 10000;
48 constexpr size_t TRANSACTION_DATA_KILL_COUNT = 20000;
49 const char* TRANSACTION_REPORT_NAME = "IPC_DATA_OVER_ERROR";
50 
GetAppMgrClient()51 const std::shared_ptr<AppExecFwk::AppMgrClient> GetAppMgrClient()
52 {
53     static std::shared_ptr<AppExecFwk::AppMgrClient> appMgrClient =
54         std::make_shared<AppExecFwk::AppMgrClient>();
55     return appMgrClient;
56 }
57 }
58 
Instance()59 RSUnmarshalThread& RSUnmarshalThread::Instance()
60 {
61     static RSUnmarshalThread instance;
62     return instance;
63 }
64 
Start()65 void RSUnmarshalThread::Start()
66 {
67     runner_ = AppExecFwk::EventRunner::Create("RSUnmarshalThread");
68     handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
69 #ifdef RES_SCHED_ENABLE
70     PostTask([this]() {
71         auto ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
72         unmarshalTid_ = gettid();
73         RS_LOGI("RSUnmarshalThread: SetThreadQos retcode = %{public}d", ret);
74     });
75 #endif
76 }
77 
PostTask(const std::function<void ()> & task,const std::string & name)78 void RSUnmarshalThread::PostTask(const std::function<void()>& task, const std::string& name)
79 {
80     if (handler_) {
81         handler_->PostTask(
82             [task, taskName = name]() mutable {
83                 auto handle = RSUnmarshalTaskManager::Instance().BeginTask(std::move(taskName));
84                 std::invoke(task);
85                 RSUnmarshalTaskManager::Instance().EndTask(handle);
86             }, name, 0, AppExecFwk::EventQueue::Priority::IMMEDIATE);
87     }
88 }
89 
RemoveTask(const std::string & name)90 void RSUnmarshalThread::RemoveTask(const std::string& name)
91 {
92     if (handler_) {
93         handler_->RemoveTask(name);
94     }
95 }
96 
RecvParcel(std::shared_ptr<MessageParcel> & parcel,bool isNonSystemAppCalling,pid_t callingPid,std::unique_ptr<AshmemFdWorker> ashmemFdWorker,std::shared_ptr<AshmemFlowControlUnit> ashmemFlowControlUnit,uint32_t parcelNumber)97 void RSUnmarshalThread::RecvParcel(std::shared_ptr<MessageParcel>& parcel, bool isNonSystemAppCalling, pid_t callingPid,
98     std::unique_ptr<AshmemFdWorker> ashmemFdWorker, std::shared_ptr<AshmemFlowControlUnit> ashmemFlowControlUnit,
99     uint32_t parcelNumber)
100 {
101     if (!handler_ || !parcel) {
102         RS_LOGE("RSUnmarshalThread::RecvParcel has nullptr, handler: %{public}d, parcel: %{public}d",
103             (!handler_), (!parcel));
104         return;
105     }
106     bool isPendingUnmarshal = (parcel->GetDataSize() > MIN_PENDING_REQUEST_SYNC_DATA_SIZE);
107     RSTaskMessage::RSTask task = [this, parcel = parcel, isPendingUnmarshal, isNonSystemAppCalling, callingPid,
108         ashmemFdWorker = std::shared_ptr(std::move(ashmemFdWorker)), ashmemFlowControlUnit, parcelNumber]() {
109         RSMarshallingHelper::SetCallingPid(callingPid);
110         AshmemFdContainer::SetIsUnmarshalThread(true);
111         if (ashmemFdWorker) {
112             ashmemFdWorker->PushFdsToContainer();
113         }
114         SetFrameParam(REQUEST_FRAME_AWARE_ID, REQUEST_FRAME_AWARE_LOAD, REQUEST_FRAME_AWARE_NUM, 0);
115         SetFrameLoad(REQUEST_FRAME_AWARE_LOAD);
116         auto transData = RSBaseRenderUtil::ParseTransactionData(*parcel, parcelNumber);
117         SetFrameLoad(REQUEST_FRAME_STANDARD_LOAD);
118         if (ashmemFdWorker) {
119             // ashmem parcel fds will be closed in ~AshmemFdWorker() instead of ~MessageParcel()
120             parcel->FlushBuffer();
121             ashmemFdWorker->EnableManualCloseFds();
122         }
123         if (!transData) {
124             return;
125         }
126         if (isNonSystemAppCalling) {
127             const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
128             if (!transData->IsCallingPidValid(callingPid, nodeMap)) {
129                 RS_LOGE("RSUnmarshalThread::RecvParcel IsCallingPidValid check failed");
130             }
131             bool shouldDrop = ReportTransactionDataStatistics(callingPid, transData.get(), isNonSystemAppCalling);
132             if (shouldDrop) {
133                 RS_LOGW("RSUnmarshalThread::RecvParcel data droped");
134                 return;
135             }
136         }
137         RS_PROFILER_ON_PARCEL_RECEIVE(parcel.get(), transData.get());
138         int64_t time = transData == nullptr ? 0 : transData->GetTimestamp();
139         {
140             std::lock_guard<std::mutex> lock(transactionDataMutex_);
141             cachedTransactionDataMap_[transData->GetSendingPid()].emplace_back(std::move(transData));
142         }
143         if (isPendingUnmarshal) {
144             RSMainThread::Instance()->RequestNextVSync("UI", time);
145         } else {
146             const auto &now = std::chrono::steady_clock::now().time_since_epoch();
147             int64_t currentTime = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
148             constexpr int64_t ONE_PERIOD = 8000000;
149             if (currentTime - time > ONE_PERIOD && time != 0) {
150                 RSMainThread::Instance()->RequestNextVSync("UI", time);
151             }
152         }
153         RSMainThread::Instance()->NotifyUnmarshalTask(time);
154         // ashmem parcel flow control ends in the destructor of ashmemFlowControlUnit
155     };
156     {
157         ffrt::task_handle handle;
158         if (RSSystemProperties::GetUnmarshParallelFlag()) {
159             handle = ffrt::submit_h(task, {}, {}, ffrt::task_attr().qos(ffrt::qos_user_interactive));
160         } else {
161             PostTask(task, std::to_string(callingPid));
162         }
163         /* a task has been posted, it means cachedTransactionDataMap_ will not been empty.
164          * so set willHaveCachedData_ to true
165          */
166         std::lock_guard<std::mutex> lock(transactionDataMutex_);
167         willHaveCachedData_ = true;
168         if (RSSystemProperties::GetUnmarshParallelFlag()) {
169             cachedDeps_.push_back(std::move(handle));
170         }
171     }
172     if (!isPendingUnmarshal) {
173         RSMainThread::Instance()->RequestNextVSync();
174     }
175 }
176 
GetCachedTransactionData()177 TransactionDataMap RSUnmarshalThread::GetCachedTransactionData()
178 {
179     TransactionDataMap transactionData;
180     {
181         std::lock_guard<std::mutex> lock(transactionDataMutex_);
182         std::swap(transactionData, cachedTransactionDataMap_);
183         willHaveCachedData_ = false;
184     }
185     return transactionData;
186 }
187 
CachedTransactionDataEmpty()188 bool RSUnmarshalThread::CachedTransactionDataEmpty()
189 {
190     std::lock_guard<std::mutex> lock(transactionDataMutex_);
191     /* we need consider both whether cachedTransactionDataMap_ is empty now
192      * and whether cachedTransactionDataMap_ will be empty later
193      */
194     return cachedTransactionDataMap_.empty() && !willHaveCachedData_;
195 }
SetFrameParam(int requestId,int load,int frameNum,int value)196 void RSUnmarshalThread::SetFrameParam(int requestId, int load, int frameNum, int value)
197 {
198     if (RsFrameReport::GetInstance().GetEnable()) {
199         RsFrameReport::GetInstance().SetFrameParam(requestId, load, frameNum, value);
200     }
201 }
SetFrameLoad(int load)202 void RSUnmarshalThread::SetFrameLoad(int load)
203 {
204     if (load == REQUEST_FRAME_STANDARD_LOAD && unmarshalLoad_ > REQUEST_FRAME_STANDARD_LOAD) {
205         unmarshalLoad_ = load;
206         SetFrameParam(REQUEST_SET_FRAME_LOAD_ID, load, 0, unmarshalTid_);
207         return;
208     }
209     SetFrameParam(REQUEST_SET_FRAME_LOAD_ID, load, 0, unmarshalTid_);
210     unmarshalLoad_ = load;
211 }
212 
Wait()213 void RSUnmarshalThread::Wait()
214 {
215     std::vector<ffrt::dependence> deps;
216     {
217         std::lock_guard<std::mutex> lock(transactionDataMutex_);
218         std::swap(deps, cachedDeps_);
219     }
220     ffrt::wait(deps);
221 }
222 
IsHaveCmdList(const std::unique_ptr<RSCommand> & cmd) const223 bool RSUnmarshalThread::IsHaveCmdList(const std::unique_ptr<RSCommand>& cmd) const
224 {
225     if (!cmd) {
226         return false;
227     }
228     bool haveCmdList = false;
229     switch (cmd->GetType()) {
230         case RSCommandType::RS_NODE:
231             if (cmd->GetSubType() == RSNodeCommandType::UPDATE_MODIFIER_DRAW_CMD_LIST ||
232                 cmd->GetSubType() == RSNodeCommandType::ADD_MODIFIER) {
233                 haveCmdList = true;
234             }
235             break;
236         case RSCommandType::CANVAS_NODE:
237             if (cmd->GetSubType() == RSCanvasNodeCommandType::CANVAS_NODE_UPDATE_RECORDING) {
238                 haveCmdList = true;
239             }
240             break;
241         default:
242             break;
243     }
244     return haveCmdList;
245 }
246 
ReportTransactionDataStatistics(pid_t pid,RSTransactionData * transactionData,bool isNonSystemAppCalling)247 bool RSUnmarshalThread::ReportTransactionDataStatistics(pid_t pid,
248                                                         RSTransactionData* transactionData,
249                                                         bool isNonSystemAppCalling)
250 {
251     size_t preCount = 0;
252     size_t totalCount = 0;
253     size_t opCount = 0;
254     if (!transactionData) {
255         return false;
256     }
257     opCount = transactionData->GetCommandCount();
258     auto& payload_temp = transactionData->GetPayload();
259     for (auto& item_temp : payload_temp) {
260         auto& cmd = std::get<2>(item_temp);
261         if (!cmd) {
262             continue;
263         }
264         if (IsHaveCmdList(cmd)) {
265             auto drawCmdList = cmd->GetDrawCmdList();
266             if (drawCmdList) {
267                 opCount += drawCmdList->GetOpItemSize();
268             }
269         }
270     }
271     {
272         std::unique_lock<std::mutex> lock(statisticsMutex_);
273         preCount = transactionDataStatistics_[pid];
274         totalCount = preCount + opCount;
275         transactionDataStatistics_[pid] = totalCount;
276 
277         if (totalCount < TRANSACTION_DATA_ALARM_COUNT) {
278             return false;
279         }
280     }
281     const auto appMgrClient = GetAppMgrClient();
282     if (!appMgrClient) {
283         RS_LOGW("Get global variable AppMgrClient failed");
284         return false;
285     }
286     int32_t uid = 0;
287     std::string bundleName;
288     appMgrClient->GetBundleNameByPid(pid, bundleName, uid);
289 
290     RS_TRACE_NAME_FMT("RSUnmarshalThread::ReportTransactionDataStatistics HiSysEventWrite pid[%d] uid[%d]"
291         " bundleName[%s] opCount[%zu] exceeded[%d]",
292         pid, uid, bundleName.c_str(), totalCount, totalCount > TRANSACTION_DATA_KILL_COUNT);
293     RSHiSysEvent::EventWrite(RSEventName::IPC_DATA_OVER_ERROR, RSEventType::RS_STATISTIC, "PID", pid, "UID", uid,
294         "BUNDLE_NAME", bundleName, "TRANSACTION_DATA_SIZE", totalCount);
295     RS_LOGW("TransactionDataStatistics pid[%{public}d] uid[%{public}d]"
296             " bundleName[%{public}s] opCount[%{public}zu] exceeded[%{public}d]",
297         pid, uid, bundleName.c_str(), totalCount, totalCount > TRANSACTION_DATA_KILL_COUNT);
298 
299     bool terminateEnabled = RSSystemProperties::GetTransactionTerminateEnabled();
300     if (!isNonSystemAppCalling || !terminateEnabled) {
301         return false;
302     }
303     if (totalCount > TRANSACTION_DATA_KILL_COUNT && preCount <= TRANSACTION_DATA_KILL_COUNT) {
304         int res = appMgrClient->KillApplicationByUid(bundleName, uid);
305         return res == AppExecFwk::RESULT_OK;
306     }
307     return false;
308 }
309 
ClearTransactionDataStatistics()310 void RSUnmarshalThread::ClearTransactionDataStatistics()
311 {
312     std::unique_lock<std::mutex> lock(statisticsMutex_);
313     transactionDataStatistics_.clear();
314 }
315 }
316