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