1 /*
2  * Copyright (c) 2021-2023 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_transaction_data.h"
17 
18 #include "command/rs_canvas_node_command.h"
19 #include "command/rs_command.h"
20 #include "command/rs_command_factory.h"
21 #include "platform/common/rs_log.h"
22 #include "platform/common/rs_system_properties.h"
23 #include "rs_profiler.h"
24 
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 static constexpr size_t PARCEL_MAX_CPACITY = 4000 * 1024; // upper bound of parcel capacity
29 static constexpr size_t PARCEL_SPLIT_THRESHOLD = 1800 * 1024; // should be < PARCEL_MAX_CPACITY
30 static constexpr uint64_t MAX_ADVANCE_TIME = 1000000000; // one second advance most
31 }
32 
__anoneaa21ccd0202(uint64_t nodeId, int count, int num) 33 std::function<void(uint64_t, int, int)> RSTransactionData::alarmLogFunc = [](uint64_t nodeId, int count, int num) {
34     ROSEN_LOGW("rsNode:%{public}" PRId64 " send %{public}d commands, "
35                 "total num of rsNode is %{public}d", nodeId, count, num);
36 };
37 
Unmarshalling(Parcel & parcel)38 RSTransactionData* RSTransactionData::Unmarshalling(Parcel& parcel)
39 {
40     auto transactionData = new RSTransactionData();
41     if (transactionData->UnmarshallingCommand(parcel)) {
42         // Do not process future data, limit data timestamps to a maximum of 1 second in advance
43         uint64_t now = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
44             std::chrono::steady_clock::now().time_since_epoch()).count());
45         if (transactionData->timestamp_ > now + MAX_ADVANCE_TIME) {
46             ROSEN_LOGW("RSTransactionData Unmarshalling limit timestamps from %{public}" PRIu64 " to "
47                 "%{public}" PRIu64 " ", transactionData->timestamp_, now + MAX_ADVANCE_TIME);
48         }
49         transactionData->timestamp_ = std::min(now + MAX_ADVANCE_TIME, transactionData->timestamp_);
50         return transactionData;
51     }
52     ROSEN_LOGE("RSTransactionData Unmarshalling Failed");
53     delete transactionData;
54     return nullptr;
55 }
56 
AddAlarmLog(std::function<void (uint64_t,int,int)> func)57 void RSTransactionData::AddAlarmLog(std::function<void(uint64_t, int, int)> func)
58 {
59     alarmLogFunc = func;
60 }
61 
~RSTransactionData()62 RSTransactionData::~RSTransactionData()
63 {
64     Clear();
65 }
66 
AlarmRsNodeLog() const67 void RSTransactionData::AlarmRsNodeLog() const
68 {
69     std::unordered_map<NodeId, int> commandNodeIdCount;
70     for (size_t countIndex = 0; countIndex < payload_.size();countIndex++) {
71         auto nodeId = std::get<0>(payload_[countIndex]);
72 
73         if (commandNodeIdCount.count(nodeId)) {
74             commandNodeIdCount[nodeId] += 1;
75         } else {
76             commandNodeIdCount[nodeId] = 1;
77         }
78     }
79 
80     int maxCount = 0;
81     NodeId maxNodeId = -1;
82     int rsNodeNum = 0;
83 
84     for (auto it = commandNodeIdCount.begin(); it != commandNodeIdCount.end(); ++it) {
85         if (it->second > maxCount) {
86             maxNodeId = it->first;
87             maxCount = it->second;
88         }
89         rsNodeNum++;
90     }
91 
92     RSTransactionData::alarmLogFunc(maxNodeId, maxCount, rsNodeNum);
93 }
94 
Marshalling(Parcel & parcel) const95 bool RSTransactionData::Marshalling(Parcel& parcel) const
96 {
97     bool success = true;
98     parcel.SetMaxCapacity(PARCEL_MAX_CPACITY);
99     // to correct actual marshaled command size later, record its position in parcel
100     size_t recordPosition = parcel.GetWritePosition();
101     std::unique_lock<std::mutex> lock(commandMutex_);
102     success = success && parcel.WriteInt32(static_cast<int32_t>(payload_.size()));
103     size_t marshaledSize = 0;
104     static bool isUniRender = RSSystemProperties::GetUniRenderEnabled();
105     success = success && parcel.WriteBool(isUniRender);
106     while (marshallingIndex_ < payload_.size()) {
107         auto& [nodeId, followType, command] = payload_[marshallingIndex_];
108 
109         if (!isUniRender) {
110             success = success && parcel.WriteUint64(nodeId);
111             success = success && parcel.WriteUint8(static_cast<uint8_t>(followType));
112         }
113         if (!command) {
114             parcel.WriteUint8(0);
115             RS_LOGW("failed RSTransactionData::Marshalling, command is nullptr");
116         } else if (command->indexVerifier_ != marshallingIndex_) {
117             parcel.WriteUint8(0);
118             RS_LOGW("failed RSTransactionData::Marshalling, indexVerifier is wrong, SIGSEGV may have occurred");
119         } else {
120             parcel.WriteUint8(1);
121             success = success && command->Marshalling(parcel);
122         }
123         if (!success) {
124             ROSEN_LOGE("failed RSTransactionData::Marshalling type:%{public}s", command->PrintType().c_str());
125             return false;
126         }
127         ++marshallingIndex_;
128         ++marshaledSize;
129         if (parcel.GetDataSize() > PARCEL_SPLIT_THRESHOLD) {
130             break;
131         }
132     }
133     if (marshaledSize < payload_.size()) {
134         // correct command size recorded in Parcel
135         *reinterpret_cast<int32_t*>(parcel.GetData() + recordPosition) = static_cast<int32_t>(marshaledSize);
136         ROSEN_LOGW("RSTransactionData::Marshalling data split to several parcels"
137                    ", marshaledSize:%{public}zu, marshallingIndex_:%{public}zu, total count:%{public}zu"
138                    ", parcel size:%{public}zu, threshold:%{public}zu.",
139             marshaledSize, marshallingIndex_, payload_.size(), parcel.GetDataSize(), PARCEL_SPLIT_THRESHOLD);
140 
141         AlarmRsNodeLog();
142     }
143     success = success && parcel.WriteBool(needSync_);
144     success = success && parcel.WriteBool(needCloseSync_);
145     success = success && parcel.WriteInt32(syncTransactionCount_);
146     success = success && parcel.WriteUint64(timestamp_);
147     success = success && parcel.WriteInt32(pid_);
148     success = success && parcel.WriteUint64(index_);
149     success = success && parcel.WriteUint64(syncId_);
150     success = success && parcel.WriteInt32(parentPid_);
151     return success;
152 }
153 
ProcessBySingleFrameComposer(RSContext & context)154 void RSTransactionData::ProcessBySingleFrameComposer(RSContext& context)
155 {
156     std::unique_lock<std::mutex> lock(commandMutex_);
157     for (auto& [nodeId, followType, command] : payload_) {
158         if (command != nullptr &&
159             command->GetType() == RSCommandType::CANVAS_NODE &&
160             command->GetSubType() == RSCanvasNodeCommandType::CANVAS_NODE_UPDATE_RECORDING) {
161             command->Process(context);
162         }
163     }
164 }
165 
Process(RSContext & context)166 void RSTransactionData::Process(RSContext& context)
167 {
168     std::unique_lock<std::mutex> lock(commandMutex_);
169     for (auto& [nodeId, followType, command] : payload_) {
170         if (command != nullptr) {
171             if (!command->IsCallingPidValid()) {
172                 continue;
173             }
174             command->Process(context);
175         }
176     }
177 }
178 
Clear()179 void RSTransactionData::Clear()
180 {
181     std::unique_lock<std::mutex> lock(commandMutex_);
182     payload_.clear();
183     payload_.shrink_to_fit();
184     timestamp_ = 0;
185 }
186 
AddCommand(std::unique_ptr<RSCommand> & command,NodeId nodeId,FollowType followType)187 void RSTransactionData::AddCommand(std::unique_ptr<RSCommand>& command, NodeId nodeId, FollowType followType)
188 {
189     std::unique_lock<std::mutex> lock(commandMutex_);
190     if (command) {
191         command->indexVerifier_ = payload_.size();
192         payload_.emplace_back(nodeId, followType, std::move(command));
193     }
194 }
195 
AddCommand(std::unique_ptr<RSCommand> && command,NodeId nodeId,FollowType followType)196 void RSTransactionData::AddCommand(std::unique_ptr<RSCommand>&& command, NodeId nodeId, FollowType followType)
197 {
198     std::unique_lock<std::mutex> lock(commandMutex_);
199     if (command) {
200         command->indexVerifier_ = payload_.size();
201         payload_.emplace_back(nodeId, followType, std::move(command));
202     }
203 }
204 
UnmarshallingCommand(Parcel & parcel)205 bool RSTransactionData::UnmarshallingCommand(Parcel& parcel)
206 {
207     Clear();
208 
209     int commandSize = 0;
210     if (!parcel.ReadInt32(commandSize)) {
211         ROSEN_LOGE("RSTransactionData::UnmarshallingCommand cannot read commandSize");
212         return false;
213     }
214     uint8_t followType = 0;
215     NodeId nodeId = 0;
216     uint8_t hasCommand = 0;
217     uint16_t commandType = 0;
218     uint16_t commandSubType = 0;
219 
220     size_t readableSize = parcel.GetReadableBytes();
221     size_t len = static_cast<size_t>(commandSize);
222     if (len > readableSize || len > payload_.max_size()) {
223         ROSEN_LOGE("RSTransactionData UnmarshallingCommand Failed read vector, size:%{public}zu,"
224             " readAbleSize:%{public}zu", len, readableSize);
225         return false;
226     }
227 
228     bool isUniRender = false;
229     if (!parcel.ReadBool(isUniRender)) {
230         ROSEN_LOGE("RSTransactionData::UnmarshallingCommand cannot read isUniRender");
231         return false;
232     }
233     std::unique_lock<std::mutex> payloadLock(commandMutex_, std::defer_lock);
234     for (size_t i = 0; i < len; i++) {
235         if (!isUniRender) {
236             if (!parcel.ReadUint64(nodeId)) {
237                 ROSEN_LOGE("RSTransactionData::UnmarshallingCommand cannot read nodeId");
238                 return false;
239             }
240             if (!parcel.ReadUint8(followType)) {
241                 ROSEN_LOGE("RSTransactionData::UnmarshallingCommand cannot read followType");
242                 return false;
243             }
244         }
245         if (!parcel.ReadUint8(hasCommand)) {
246             ROSEN_LOGE("RSTransactionData::UnmarshallingCommand cannot read hasCommand");
247             return false;
248         }
249         if (hasCommand) {
250             if (!(parcel.ReadUint16(commandType) && parcel.ReadUint16(commandSubType))) {
251                 return false;
252             }
253             auto func = RSCommandFactory::Instance().GetUnmarshallingFunc(commandType, commandSubType);
254             if (func == nullptr) {
255                 return false;
256             }
257             auto command = (*func)(parcel);
258             if (command == nullptr) {
259                 ROSEN_LOGE("failed RSTransactionData::UnmarshallingCommand, type=%{public}d subtype=%{public}d",
260                     commandType, commandSubType);
261                 return false;
262             }
263             RS_PROFILER_PATCH_COMMAND(parcel, command);
264             payloadLock.lock();
265             payload_.emplace_back(nodeId, static_cast<FollowType>(followType), std::move(command));
266             payloadLock.unlock();
267         } else {
268             continue;
269         }
270     }
271     int32_t pid;
272     return parcel.ReadBool(needSync_) && parcel.ReadBool(needCloseSync_) && parcel.ReadInt32(syncTransactionCount_) &&
273         parcel.ReadUint64(timestamp_) && ({RS_PROFILER_PATCH_TRANSACTION_TIME(parcel, timestamp_); true;}) &&
274         parcel.ReadInt32(pid) && ({RS_PROFILER_PATCH_PID(parcel, pid); pid_ = pid; true;}) &&
275         parcel.ReadUint64(index_) && parcel.ReadUint64(syncId_) && parcel.ReadInt32(parentPid_);
276 }
277 
IsCallingPidValid(pid_t callingPid,const RSRenderNodeMap & nodeMap,pid_t & conflictCommandPid,std::string & commandMapDesc) const278 bool RSTransactionData::IsCallingPidValid(pid_t callingPid, const RSRenderNodeMap& nodeMap, pid_t& conflictCommandPid,
279     std::string& commandMapDesc) const
280 {
281     // Since GetCallingPid interface always returns 0 in asynchronous binder in Linux kernel system,
282     // we temporarily add a white list to avoid abnormal functionality or abnormal display.
283     // The white list will be removed after GetCallingPid interface can return real PID.
284     if (callingPid == 0) {
285         return true;
286     }
287 
288     std::unordered_map<pid_t, std::unordered_map<NodeId, std::set<
289         std::pair<uint16_t, uint16_t>>>> conflictPidToCommandMap;
290     std::unique_lock<std::mutex> lock(commandMutex_);
291     for (auto& [_, followType, command] : payload_) {
292         if (command == nullptr) {
293             continue;
294         }
295         const NodeId nodeId = command->GetNodeId();
296         const pid_t commandPid = ExtractPid(nodeId);
297         if (command->GetType() != RSCommandType::DISPLAY_NODE) {
298             if (callingPid == commandPid) {
299                 continue;
300             }
301             if (nodeMap.IsUIExtensionSurfaceNode(nodeId)) {
302                 continue;
303             }
304         }
305         conflictPidToCommandMap[commandPid][nodeId].insert(command->GetUniqueType());
306         command->SetCallingPidValid(false);
307     }
308     lock.unlock();
309     for (const auto& [commandPid, commandTypeMap] : conflictPidToCommandMap) {
310         conflictCommandPid = commandPid;
311         commandMapDesc = PrintCommandMapDesc(commandTypeMap);
312         return false;
313     }
314     return true;
315 }
316 
PrintCommandMapDesc(const std::unordered_map<NodeId,std::set<std::pair<uint16_t,uint16_t>>> & commandTypeMap) const317 std::string RSTransactionData::PrintCommandMapDesc(
318     const std::unordered_map<NodeId, std::set<std::pair<uint16_t, uint16_t>>>& commandTypeMap) const
319 {
320     std::string commandMapDesc = "{ ";
321     for (const auto& [nodeId, commandTypeSet] : commandTypeMap) {
322         std::string commandSetDesc = std::to_string(nodeId) + ": [";
323         for (const auto& [commandType, commandSubType] : commandTypeSet) {
324             std::string commandDesc = "(" + std::to_string(commandType) + "," + std::to_string(commandSubType) + "),";
325             commandSetDesc += commandDesc;
326         }
327         commandSetDesc += "], ";
328         commandMapDesc += commandSetDesc;
329     }
330     commandMapDesc += "}";
331     return commandMapDesc;
332 }
333 
334 } // namespace Rosen
335 } // namespace OHOS
336