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