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