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