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 "pipeline/rs_unmarshal_thread.h"
17
18 #include "app_mgr_client.h"
19 #include "hisysevent.h"
20 #include "pipeline/rs_base_render_util.h"
21 #include "pipeline/rs_main_thread.h"
22 #include "platform/common/rs_log.h"
23 #include "platform/common/rs_system_properties.h"
24 #include "transaction/rs_transaction_data.h"
25 #include "res_sched_client.h"
26 #include "res_type.h"
27 #include "rs_frame_report.h"
28 #include "rs_profiler.h"
29 #include "command/rs_node_command.h"
30 #include "command/rs_canvas_node_command.h"
31 #include "recording/draw_cmd_list.h"
32
33 #ifdef RES_SCHED_ENABLE
34 #include "qos.h"
35 #endif
36
37 namespace OHOS::Rosen {
38 namespace {
39 constexpr int REQUEST_FRAME_AWARE_ID = 100001;
40 constexpr int REQUEST_SET_FRAME_LOAD_ID = 100006;
41 constexpr int REQUEST_FRAME_AWARE_LOAD = 85;
42 constexpr int REQUEST_FRAME_AWARE_NUM = 4;
43 constexpr int REQUEST_FRAME_STANDARD_LOAD = 50;
44 constexpr size_t TRANSACTION_DATA_ALARM_COUNT = 10000;
45 constexpr size_t TRANSACTION_DATA_KILL_COUNT = 20000;
46 const char* TRANSACTION_REPORT_NAME = "IPC_DATA_OVER_ERROR";
GetAppMgrClient()47 const std::unique_ptr<AppExecFwk::AppMgrClient>& GetAppMgrClient()
48 {
49 static std::unique_ptr<AppExecFwk::AppMgrClient> appMgrClient =
50 std::make_unique<AppExecFwk::AppMgrClient>();
51 return appMgrClient;
52 }
53 }
54
Instance()55 RSUnmarshalThread& RSUnmarshalThread::Instance()
56 {
57 static RSUnmarshalThread instance;
58 return instance;
59 }
60
Start()61 void RSUnmarshalThread::Start()
62 {
63 runner_ = AppExecFwk::EventRunner::Create("RSUnmarshalThread");
64 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
65 #ifdef RES_SCHED_ENABLE
66 PostTask([this]() {
67 auto ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
68 unmarshalTid_ = gettid();
69 RS_LOGI("RSUnmarshalThread: SetThreadQos retcode = %{public}d", ret);
70 });
71 #endif
72 }
73
PostTask(const std::function<void ()> & task)74 void RSUnmarshalThread::PostTask(const std::function<void()>& task)
75 {
76 if (handler_) {
77 handler_->PostTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
78 }
79 }
80
RecvParcel(std::shared_ptr<MessageParcel> & parcel,bool isNonSystemAppCalling,pid_t callingPid)81 void RSUnmarshalThread::RecvParcel(std::shared_ptr<MessageParcel>& parcel, bool isNonSystemAppCalling, pid_t callingPid)
82 {
83 if (!handler_ || !parcel) {
84 RS_LOGE("RSUnmarshalThread::RecvParcel has nullptr, handler: %{public}d, parcel: %{public}d",
85 (!handler_), (!parcel));
86 return;
87 }
88 bool isPendingUnmarshal = (parcel->GetDataSize() > MIN_PENDING_REQUEST_SYNC_DATA_SIZE);
89 RSTaskMessage::RSTask task = [this, parcel = parcel, isPendingUnmarshal, isNonSystemAppCalling, callingPid]() {
90 SetFrameParam(REQUEST_FRAME_AWARE_ID, REQUEST_FRAME_AWARE_LOAD, REQUEST_FRAME_AWARE_NUM, 0);
91 SetFrameLoad(REQUEST_FRAME_AWARE_LOAD);
92 auto transData = RSBaseRenderUtil::ParseTransactionData(*parcel);
93 SetFrameLoad(REQUEST_FRAME_STANDARD_LOAD);
94 if (!transData) {
95 return;
96 }
97 if (isNonSystemAppCalling) {
98 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
99 pid_t conflictCommandPid = 0;
100 std::string commandMapDesc = "";
101 if (!transData->IsCallingPidValid(callingPid, nodeMap, conflictCommandPid, commandMapDesc)) {
102 RS_LOGE("RSUnmarshalThread::RecvParcel non-system callingPid %{public}d"
103 " is denied to access commandPid %{public}d, commandMap = %{public}s",
104 callingPid, conflictCommandPid, commandMapDesc.c_str());
105 }
106 bool shouldDrop = ReportTransactionDataStatistics(callingPid, transData.get(), isNonSystemAppCalling);
107 if (shouldDrop) {
108 RS_LOGW("RSUnmarshalThread::RecvParcel data droped");
109 return;
110 }
111 }
112 RS_PROFILER_ON_PARCEL_RECEIVE(parcel.get(), transData.get());
113 {
114 std::lock_guard<std::mutex> lock(transactionDataMutex_);
115 cachedTransactionDataMap_[transData->GetSendingPid()].emplace_back(std::move(transData));
116 }
117 if (isPendingUnmarshal) {
118 RSMainThread::Instance()->RequestNextVSync();
119 }
120 };
121 {
122 PostTask(task);
123 /* a task has been posted, it means cachedTransactionDataMap_ will not been empty.
124 * so set willHaveCachedData_ to true
125 */
126 std::lock_guard<std::mutex> lock(transactionDataMutex_);
127 willHaveCachedData_ = true;
128 }
129
130 if (!isPendingUnmarshal) {
131 RSMainThread::Instance()->RequestNextVSync();
132 }
133 }
134
GetCachedTransactionData()135 TransactionDataMap RSUnmarshalThread::GetCachedTransactionData()
136 {
137 TransactionDataMap transactionData;
138 {
139 std::lock_guard<std::mutex> lock(transactionDataMutex_);
140 std::swap(transactionData, cachedTransactionDataMap_);
141 willHaveCachedData_ = false;
142 }
143 return transactionData;
144 }
145
CachedTransactionDataEmpty()146 bool RSUnmarshalThread::CachedTransactionDataEmpty()
147 {
148 std::lock_guard<std::mutex> lock(transactionDataMutex_);
149 /* we need consider both whether cachedTransactionDataMap_ is empty now
150 * and whether cachedTransactionDataMap_ will be empty later
151 */
152 return cachedTransactionDataMap_.empty() && !willHaveCachedData_;
153 }
SetFrameParam(int requestId,int load,int frameNum,int value)154 void RSUnmarshalThread::SetFrameParam(int requestId, int load, int frameNum, int value)
155 {
156 if (RsFrameReport::GetInstance().GetEnable()) {
157 RsFrameReport::GetInstance().SetFrameParam(requestId, load, frameNum, value);
158 }
159 }
SetFrameLoad(int load)160 void RSUnmarshalThread::SetFrameLoad(int load)
161 {
162 if (load == REQUEST_FRAME_STANDARD_LOAD && unmarshalLoad_ > REQUEST_FRAME_STANDARD_LOAD) {
163 unmarshalLoad_ = load;
164 SetFrameParam(REQUEST_SET_FRAME_LOAD_ID, load, 0, unmarshalTid_);
165 return;
166 }
167 SetFrameParam(REQUEST_SET_FRAME_LOAD_ID, load, 0, unmarshalTid_);
168 unmarshalLoad_ = load;
169 }
170
IsHaveCmdList(const std::unique_ptr<RSCommand> & cmd) const171 bool RSUnmarshalThread::IsHaveCmdList(const std::unique_ptr<RSCommand>& cmd) const
172 {
173 if (!cmd) {
174 return false;
175 }
176 bool haveCmdList = false;
177 switch (cmd->GetType()) {
178 case RSCommandType::RS_NODE:
179 if (cmd->GetSubType() == RSNodeCommandType::UPDATE_MODIFIER_DRAW_CMD_LIST ||
180 cmd->GetSubType() == RSNodeCommandType::ADD_MODIFIER) {
181 haveCmdList = true;
182 }
183 break;
184 case RSCommandType::CANVAS_NODE:
185 if (cmd->GetSubType() == RSCanvasNodeCommandType::CANVAS_NODE_UPDATE_RECORDING) {
186 haveCmdList = true;
187 }
188 break;
189 default:
190 break;
191 }
192 return haveCmdList;
193 }
194
ReportTransactionDataStatistics(pid_t pid,RSTransactionData * transactionData,bool isNonSystemAppCalling)195 bool RSUnmarshalThread::ReportTransactionDataStatistics(pid_t pid,
196 RSTransactionData* transactionData,
197 bool isNonSystemAppCalling)
198 {
199 size_t preCount = 0;
200 size_t totalCount = 0;
201 size_t opCount = 0;
202 if (!transactionData) {
203 return false;
204 }
205 opCount = transactionData->GetCommandCount();
206 auto& payload_temp = transactionData->GetPayload();
207 for (auto& item_temp : payload_temp) {
208 auto& cmd = std::get<2>(item_temp);
209 if (!cmd) {
210 continue;
211 }
212 if (IsHaveCmdList(cmd)) {
213 auto drawCmdList = cmd->GetDrawCmdList();
214 if (drawCmdList) {
215 opCount += drawCmdList->GetOpItemSize();
216 }
217 }
218 }
219 {
220 std::unique_lock<std::mutex> lock(statisticsMutex_);
221 preCount = transactionDataStatistics_[pid];
222 totalCount = preCount + opCount;
223 transactionDataStatistics_[pid] = totalCount;
224
225 if (totalCount < TRANSACTION_DATA_ALARM_COUNT) {
226 return false;
227 }
228 }
229 const auto& appMgrClient = GetAppMgrClient();
230 int32_t uid = 0;
231 std::string bundleName;
232 appMgrClient->GetBundleNameByPid(pid, bundleName, uid);
233
234 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, TRANSACTION_REPORT_NAME,
235 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "PID", pid, "UID", uid,
236 "BUNDLE_NAME", bundleName, "TRANSACTION_DATA_SIZE", totalCount);
237 RS_LOGW("TransactionDataStatistics pid[%{public}d] uid[%{public}d]"
238 " bundleName[%{public}s] opCount[%{public}zu] exceeded[%{public}d]",
239 pid, uid, bundleName.c_str(), totalCount, totalCount > TRANSACTION_DATA_KILL_COUNT);
240
241 bool terminateEnabled = RSSystemProperties::GetTransactionTerminateEnabled();
242 if (!isNonSystemAppCalling || !terminateEnabled) {
243 return false;
244 }
245 if (totalCount > TRANSACTION_DATA_KILL_COUNT && preCount <= TRANSACTION_DATA_KILL_COUNT) {
246 int res = appMgrClient->KillApplicationByUid(bundleName, uid);
247 return res == AppExecFwk::RESULT_OK;
248 }
249 return false;
250 }
251
ClearTransactionDataStatistics()252 void RSUnmarshalThread::ClearTransactionDataStatistics()
253 {
254 std::unique_lock<std::mutex> lock(statisticsMutex_);
255 transactionDataStatistics_.clear();
256 }
257 }
258