1 /**
2 * Copyright (c) 2025 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 "ui_decorator.h"
17
18 #include "function.h"
19 #include "graph_analyzer.h"
20 #include "program.h"
21 #include "configs/guard_context.h"
22 #include "util/assert_util.h"
23 #include "util/string_util.h"
24
25 namespace {
26 using OpcodeList = std::vector<panda::pandasm::Opcode>;
27
28 constexpr std::string_view TAG = "[UI_Decorator]";
29
30 constexpr std::string_view UI_DECORATOR_PREFIX = "__";
31 constexpr std::string_view MONITOR_UI_DECORATOR_DELIMITER = ".";
32
33 constexpr std::string_view UI_DECORATOR_FUNC_NAME_UPDATE_STATE_VARS = "updateStateVars";
34 constexpr std::string_view UI_DECORATOR_FUNC_NAME_RESET_STATE_VARS_ON_REUSE = "resetStateVarsOnReuse";
35 constexpr std::string_view UI_DECORATOR_FUNC_NAME_GET_REUSE_ID = "getReuseId";
36
37 // defined in constructor
38 std::unordered_map<panda::guard::UiDecoratorType, std::vector<std::string>> g_uiDecoratorByNewTable {
39 {panda::guard::UiDecoratorType::LINK, {"SynchedPropertySimpleTwoWayPU", "SynchedPropertyObjectTwoWayPU"}},
40 {panda::guard::UiDecoratorType::PROP, {"SynchedPropertySimpleOneWayPU", "SynchedPropertyObjectOneWayPU"}},
41 {panda::guard::UiDecoratorType::OBJECT_LINK, {"SynchedPropertyNesedObjectPU"}},
42 {panda::guard::UiDecoratorType::PROVIDE, {"ObservedPropertySimplePU", "ObservedPropertyObjectPU"}},
43 };
44
45 // defined in constructor
46 std::unordered_map<panda::guard::UiDecoratorType, std::vector<std::string>> g_uiDecoratorByMethodMemberTable {
47 {panda::guard::UiDecoratorType::LOCAL_STORAGE_LINK, {"createLocalStorageLink"}},
48 {panda::guard::UiDecoratorType::LOCAL_STORAGE_PROP, {"createLocalStorageProp"}},
49 {panda::guard::UiDecoratorType::STORAGE_LINK, {"createStorageLink"}},
50 {panda::guard::UiDecoratorType::STORAGE_PROP, {"createStorageProp"}},
51 {panda::guard::UiDecoratorType::CONSUME, {"initializeConsume"}},
52 };
53
54 // defined in class constructor: PARAM(initParam)
55 // defined in ui class method or in toplevel function: BUILDER
56 // defined in ui class method updateStateVars: PARAM(updateParam)
57 // defined in ui class method resetStateVarsOnReuse: COMPUTED, CONSUMER, PARAM(resetParam)
58 // defined in toplevel function: ANIMATABLE_EXTEND
59 std::unordered_map<panda::guard::UiDecoratorType, std::vector<std::string>> g_uiDecoratorByMethodFieldTable {
60 {panda::guard::UiDecoratorType::PARAM, {"initParam", "updateParam", "resetParam"}},
61 {panda::guard::UiDecoratorType::COMPUTED, {"resetComputed"}},
62 {panda::guard::UiDecoratorType::CONSUMER, {"resetConsumer"}},
63 {panda::guard::UiDecoratorType::BUILDER, {"makeBuilderParameterProxy"}},
64 {panda::guard::UiDecoratorType::EXTERNAL_API, {"addProvidedVar", "declareWatch"}},
65 {panda::guard::UiDecoratorType::ANIMATABLE_EXTEND, {"createAnimatableProperty", "updateAnimatableProperty"}},
66 {panda::guard::UiDecoratorType::REUSABLE_V2, {"reuseOrCreateNewComponent"}},
67 };
68
69 // defined in func_main0
70 std::unordered_map<panda::guard::UiDecoratorType, std::vector<std::string>> g_uiDecoratorInFuncMain0Table {
71 {panda::guard::UiDecoratorType::LOCAL, {"Local"}}, {panda::guard::UiDecoratorType::EVENT, {"Event"}},
72 {panda::guard::UiDecoratorType::ONCE, {"Once"}}, {panda::guard::UiDecoratorType::PARAM, {"Param"}},
73 {panda::guard::UiDecoratorType::MONITOR, {"Monitor"}}, {panda::guard::UiDecoratorType::TRACK, {"Track"}},
74 {panda::guard::UiDecoratorType::TRACE, {"Trace"}}, {panda::guard::UiDecoratorType::COMPUTED, {"Computed"}},
75 {panda::guard::UiDecoratorType::PROVIDER, {"Provider"}}, {panda::guard::UiDecoratorType::CONSUMER, {"Consumer"}},
76 };
77
GetUiDecoratorType(const std::string & name,const std::unordered_map<panda::guard::UiDecoratorType,std::vector<std::string>> & table)78 panda::guard::UiDecoratorType GetUiDecoratorType(
79 const std::string &name, const std::unordered_map<panda::guard::UiDecoratorType, std::vector<std::string>> &table)
80 {
81 if (name.empty()) {
82 return panda::guard::UiDecoratorType::NONE;
83 }
84
85 for (const auto &[type, methodList] : table) {
86 for (const auto &methodName : methodList) {
87 if (methodName == name) {
88 return type;
89 }
90 }
91 }
92
93 return panda::guard::UiDecoratorType::NONE;
94 }
95
GetNewUiDecoratorType(const std::string & name)96 panda::guard::UiDecoratorType GetNewUiDecoratorType(const std::string &name)
97 {
98 return GetUiDecoratorType(name, g_uiDecoratorByNewTable);
99 }
100
GetMemberUiDecoratorType(const std::string & name)101 panda::guard::UiDecoratorType GetMemberUiDecoratorType(const std::string &name)
102 {
103 return GetUiDecoratorType(name, g_uiDecoratorByMethodMemberTable);
104 }
105
GetFieldUiDecoratorType(const std::string & name)106 panda::guard::UiDecoratorType GetFieldUiDecoratorType(const std::string &name)
107 {
108 return GetUiDecoratorType(name, g_uiDecoratorByMethodFieldTable);
109 }
110
GetFuncMain0UiDecoratorType(const std::string & name)111 panda::guard::UiDecoratorType GetFuncMain0UiDecoratorType(const std::string &name)
112 {
113 return GetUiDecoratorType(name, g_uiDecoratorInFuncMain0Table);
114 }
115
IsParamUiDecoratorValid(const panda::guard::InstructionInfo & info)116 bool IsParamUiDecoratorValid(const panda::guard::InstructionInfo &info)
117 {
118 if (info.ins_->opcode != panda::pandasm::Opcode::CALLTHIS2) {
119 return false;
120 }
121
122 if (!info.function_->component_ && (info.function_->name_ != UI_DECORATOR_FUNC_NAME_UPDATE_STATE_VARS) &&
123 (info.function_->name_ != UI_DECORATOR_FUNC_NAME_RESET_STATE_VARS_ON_REUSE)) {
124 return false;
125 }
126 return true;
127 }
128
129 const OpcodeList UI_DECORATOR_LIST_IN_FUNCTION = {
130 panda::pandasm::Opcode::STOBJBYNAME, panda::pandasm::Opcode::CALLTHIS1, panda::pandasm::Opcode::CALLTHIS2,
131 panda::pandasm::Opcode::CALLTHIS3, panda::pandasm::Opcode::CALLARGS2, panda::pandasm::Opcode::ISIN};
132
133 const OpcodeList UI_DECORATOR_LIST_IN_FUNC_MAIN0 = {
134 panda::pandasm::Opcode::CALLARG1, panda::pandasm::Opcode::CALLARGS2, panda::pandasm::Opcode::CALLARGS3,
135 panda::pandasm::Opcode::CALLRANGE, panda::pandasm::Opcode::CALLTHIS2, panda::pandasm::Opcode::CALLTHIS3,
136 };
137
138 } // namespace
139
IsUiDecoratorIns(const InstructionInfo & info,Scope scope)140 bool panda::guard::UiDecorator::IsUiDecoratorIns(const InstructionInfo &info, Scope scope)
141 {
142 const auto &uiDecoratorInsList =
143 (scope == TOP_LEVEL) ? UI_DECORATOR_LIST_IN_FUNC_MAIN0 : UI_DECORATOR_LIST_IN_FUNCTION;
144 return std::any_of(uiDecoratorInsList.begin(), uiDecoratorInsList.end(),
145 [&](const panda::pandasm::Opcode opcode) -> bool { return info.ins_->opcode == opcode; });
146 }
147
ExtractNames(std::set<std::string> & strings) const148 void panda::guard::UiDecorator::ExtractNames(std::set<std::string> &strings) const
149 {
150 strings.emplace(this->name_);
151 }
152
Build()153 void panda::guard::UiDecorator::Build()
154 {
155 if (scope_ == TOP_LEVEL) {
156 HandleInstInFuncMain0();
157 return;
158 }
159 HandleInstInFunction();
160 }
161
AddDefineInsList(const std::vector<InstructionInfo> & instLIst)162 void panda::guard::UiDecorator::AddDefineInsList(const std::vector<InstructionInfo> &instLIst)
163 {
164 for (const auto &inst : instLIst) {
165 AddDefineInsList(inst);
166 }
167 }
168
IsValidUiDecoratorType() const169 bool panda::guard::UiDecorator::IsValidUiDecoratorType() const
170 {
171 return (this->type_ != UiDecoratorType::NONE);
172 }
173
Update()174 void panda::guard::UiDecorator::Update()
175 {
176 if (!IsValidUiDecoratorType()) {
177 return;
178 }
179
180 if (IsMonitorUiDecoratorType()) {
181 UpdateMonitorDecorator();
182 return;
183 }
184
185 this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
186 for (auto &inst : defineInsList_) {
187 inst.ins_->GetId(INDEX_0) = this->obfName_;
188 }
189 this->program_->prog_->strings.emplace(this->obfName_);
190 }
191
HandleInstInFuncMain0()192 void panda::guard::UiDecorator::HandleInstInFuncMain0()
193 {
194 std::string callName = GraphAnalyzer::GetCallName(baseInst_);
195 this->type_ = GetFuncMain0UiDecoratorType(callName);
196 if (!IsValidUiDecoratorType()) {
197 return;
198 }
199
200 if (IsMonitorUiDecoratorType()) {
201 BuildMonitorDecorator(); // CALLARG1 CALLARGS2 CALLARGS3 CALLRANGE
202 return;
203 }
204
205 uint32_t paramIndex;
206 if (baseInst_.equalToOpcode(pandasm::Opcode::CALLARG1)) {
207 paramIndex = INDEX_0;
208 } else if (baseInst_.equalToOpcode(pandasm::Opcode::CALLARGS2) ||
209 baseInst_.equalToOpcode(pandasm::Opcode::CALLARGS3)) { // CALLARGS3 COMPUTED
210 paramIndex = INDEX_1;
211 } else {
212 PANDA_GUARD_ABORT_PRINT(TAG, ErrorCode::GENERIC_ERROR, "unsupported ui decorator call scene");
213 }
214
215 InstructionInfo param;
216 GraphAnalyzer::GetCallLdaStrParam(baseInst_, paramIndex, param);
217 if (!param.IsValid()) {
218 this->type_ = UiDecoratorType::NONE;
219 return;
220 }
221
222 this->name_ = param.ins_->GetId(INDEX_0);
223 this->AddDefineInsList(param);
224
225 LOG(INFO, PANDAGUARD) << TAG << "func_main0 found ui decorator property name:" << this->name_
226 << ", type:" << static_cast<int>(this->type_);
227 }
228
HandleInstInFunction()229 void panda::guard::UiDecorator::HandleInstInFunction()
230 {
231 switch (baseInst_.ins_->opcode) {
232 case pandasm::Opcode::STOBJBYNAME:
233 HandleStObjByNameIns();
234 break;
235 case pandasm::Opcode::CALLTHIS1:
236 case pandasm::Opcode::CALLTHIS2:
237 case pandasm::Opcode::CALLTHIS3:
238 case pandasm::Opcode::CALLARGS2:
239 BuildCreatedByMemberFieldDecorator();
240 break;
241 case pandasm::Opcode::ISIN:
242 BuildEventDecorator();
243 break;
244 default:
245 break;
246 }
247
248 if (IsValidUiDecoratorType()) {
249 LOG(INFO, PANDAGUARD) << TAG << "function found ui decorator property name:" << this->name_
250 << ", type:" << static_cast<int>(this->type_);
251 }
252 }
253
HandleStObjByNameIns()254 void panda::guard::UiDecorator::HandleStObjByNameIns()
255 {
256 if (!baseInst_.function_->component_) {
257 return;
258 }
259 if (!StringUtil::IsPrefixMatched(baseInst_.ins_->GetId(INDEX_0), UI_DECORATOR_PREFIX.data())) {
260 return;
261 }
262 this->name_ = baseInst_.ins_->GetId(INDEX_0).substr(UI_DECORATOR_PREFIX.size());
263
264 InstructionInfo input;
265 GraphAnalyzer::GetStObjByNameInput(baseInst_, input);
266 if (!input.IsValid()) {
267 return;
268 }
269 switch (input.ins_->opcode) {
270 case pandasm::Opcode::NEWOBJRANGE:
271 HandleNewObjRangeIns(input);
272 break;
273 case pandasm::Opcode::CALLTHIS2:
274 BuildCreatedByMemberMethodDecorator(input, INDEX_2);
275 break;
276 case pandasm::Opcode::CALLTHIS3:
277 BuildCreatedByMemberMethodDecorator(input, INDEX_3);
278 break;
279 default:
280 break;
281 }
282 }
283
HandleNewObjRangeIns(const InstructionInfo & info)284 void panda::guard::UiDecorator::HandleNewObjRangeIns(const InstructionInfo &info)
285 {
286 std::string callName;
287 InstructionInfo out;
288 GraphAnalyzer::GetNewObjRangeInfo(info, callName, out);
289 if (callName.empty() || !out.IsValid()) {
290 return;
291 }
292
293 this->type_ = GetNewUiDecoratorType(callName);
294 if (!IsValidUiDecoratorType()) {
295 this->type_ = UiDecoratorType::NONE;
296 return;
297 }
298
299 this->AddDefineInsList(out);
300 }
301
BuildCreatedByMemberMethodDecorator(const InstructionInfo & info,uint32_t paramIndex)302 void panda::guard::UiDecorator::BuildCreatedByMemberMethodDecorator(const InstructionInfo &info, uint32_t paramIndex)
303 {
304 std::string callName = GraphAnalyzer::GetCallName(info);
305 this->type_ = GetMemberUiDecoratorType(callName);
306 if (!IsValidUiDecoratorType()) {
307 return;
308 }
309
310 InstructionInfo param;
311 GraphAnalyzer::GetCallLdaStrParam(info, paramIndex, param);
312 if (!param.IsValid()) {
313 this->type_ = UiDecoratorType::NONE;
314 return;
315 }
316 this->AddDefineInsList(param);
317
318 if (this->type_ == UiDecoratorType::CONSUME) {
319 InstructionInfo aliasParam;
320 GraphAnalyzer::GetCallLdaStrParam(info, INDEX_1, aliasParam);
321 if (!aliasParam.IsValid()) {
322 this->type_ = UiDecoratorType::NONE;
323 return;
324 }
325 this->AddDefineInsList(aliasParam);
326 }
327 }
328
BuildMonitorDecorator()329 void panda::guard::UiDecorator::BuildMonitorDecorator()
330 {
331 uint32_t maxParamCnt = baseInst_.ins_->Regs().size();
332 if (baseInst_.ins_->opcode == pandasm::Opcode::CALLRANGE) {
333 maxParamCnt = std::get<int64_t>(baseInst_.ins_->GetImm(INDEX_1));
334 }
335 for (uint32_t index = 0; index < maxParamCnt; index++) {
336 InstructionInfo param;
337 GraphAnalyzer::GetCallLdaStrParam(baseInst_, index, param);
338 if (!param.IsValid()) {
339 this->type_ = UiDecoratorType::NONE;
340 return;
341 }
342 LOG(INFO, PANDAGUARD) << TAG << "found monitor ui decorator: " << param.ins_->GetId(INDEX_0);
343 this->AddDefineInsList(param);
344 }
345 }
346
BuildCreatedByMemberFieldDecorator()347 void panda::guard::UiDecorator::BuildCreatedByMemberFieldDecorator()
348 {
349 if (baseInst_.equalToOpcode(pandasm::Opcode::CALLTHIS1) && !baseInst_.function_->component_) {
350 return;
351 }
352
353 std::string callName = GraphAnalyzer::GetCallName(baseInst_);
354 this->type_ = GetFieldUiDecoratorType(callName);
355 if (!IsValidUiDecoratorType()) {
356 return;
357 }
358
359 if ((this->type_ == UiDecoratorType::PARAM) && !IsParamUiDecoratorValid(baseInst_)) {
360 this->type_ = UiDecoratorType::NONE;
361 return;
362 }
363
364 if (IsReusableV2UiDecoratorType()) {
365 BuildReusableV2Decorator();
366 return;
367 }
368
369 uint32_t paramIndex = INDEX_1;
370 InstructionInfo param;
371 if (this->type_ == UiDecoratorType::BUILDER) {
372 paramIndex = INDEX_0;
373 }
374 GraphAnalyzer::GetCallLdaStrParam(baseInst_, paramIndex, param);
375 if (!param.IsValid()) {
376 this->type_ = UiDecoratorType::NONE;
377 return;
378 }
379
380 this->name_ = param.ins_->GetId(INDEX_0);
381 this->AddDefineInsList(param);
382 }
383
BuildEventDecorator()384 void panda::guard::UiDecorator::BuildEventDecorator()
385 {
386 if (!baseInst_.function_->component_) {
387 return;
388 }
389
390 std::vector<InstructionInfo> out;
391 GraphAnalyzer::GetIsInInfo(baseInst_, out);
392 if (out.empty()) {
393 return;
394 }
395
396 this->name_ = out[INDEX_0].ins_->GetId(INDEX_0);
397 this->type_ = UiDecoratorType::EVENT;
398 this->AddDefineInsList(out);
399 }
400
UpdateMonitorDecorator()401 void panda::guard::UiDecorator::UpdateMonitorDecorator()
402 {
403 for (auto &inst : defineInsList_) {
404 auto nameList = StringUtil::Split(inst.ins_->GetId(INDEX_0), MONITOR_UI_DECORATOR_DELIMITER.data());
405 if (nameList.empty()) {
406 continue;
407 }
408 std::string obfName;
409 for (const auto &name : nameList) {
410 obfName += GuardContext::GetInstance()->GetNameMapping()->GetName(name);
411 obfName += MONITOR_UI_DECORATOR_DELIMITER;
412 }
413 obfName = obfName.substr(0, obfName.length() - 1);
414 LOG(INFO, PANDAGUARD) << TAG << "update monitor ui decorator: " << inst.ins_->GetId(INDEX_0) << " --> "
415 << obfName;
416 inst.ins_->GetId(INDEX_0) = obfName;
417 this->program_->prog_->strings.emplace(obfName);
418 }
419 }
420
IsMonitorUiDecoratorType() const421 bool panda::guard::UiDecorator::IsMonitorUiDecoratorType() const
422 {
423 return this->type_ == UiDecoratorType::MONITOR;
424 }
425
AddDefineInsList(const InstructionInfo & ins)426 void panda::guard::UiDecorator::AddDefineInsList(const InstructionInfo &ins)
427 {
428 LOG(INFO, PANDAGUARD) << TAG << "ui decorator add instList:" << ins.ins_->ToString();
429 this->defineInsList_.emplace_back(ins);
430 }
431
BuildReusableV2Decorator()432 void panda::guard::UiDecorator::BuildReusableV2Decorator()
433 {
434 this->type_ = UiDecoratorType::NONE;
435 if (baseInst_.notEqualToOpcode(pandasm::Opcode::CALLTHIS1)) {
436 return;
437 }
438
439 InstructionInfo createObjectInst;
440 GraphAnalyzer::GetCallCreateObjectWithBufferParam(baseInst_, INDEX_1, createObjectInst);
441 if (!createObjectInst.IsValid()) {
442 LOG(DEBUG, PANDAGUARD) << TAG << "callthi1 inst index 1 not match createobjectwithbuffer inst";
443 return;
444 }
445
446 const std::string &literalArrayIdx = createObjectInst.ins_->GetId(0);
447 auto outerProperty = GetObjectOuterProperty(literalArrayIdx);
448 if (!outerProperty) {
449 LOG(DEBUG, PANDAGUARD) << TAG << "object not find outer property:" << literalArrayIdx;
450 return;
451 }
452
453 InstructionInfo defineFuncInst;
454 GraphAnalyzer::GetDefinePropertyByNameFunction(outerProperty->defineInsList_[0], defineFuncInst);
455 if (!defineFuncInst.IsValid()) {
456 LOG(DEBUG, PANDAGUARD) << TAG << "definepropertybyname inst index 1 not match definefunc inst";
457 return;
458 }
459
460 auto func = Function(this->program_, defineFuncInst.ins_->GetId(0));
461 func.EnumerateIns([&](const InstructionInfo &inst) -> void { EnumerateIns(inst); });
462 }
463
IsReusableV2UiDecoratorType() const464 bool panda::guard::UiDecorator::IsReusableV2UiDecoratorType() const
465 {
466 return this->type_ == UiDecoratorType::REUSABLE_V2;
467 }
468
GetObjectOuterProperty(const std::string & literalArrayIdx) const469 std::shared_ptr<panda::guard::Property> panda::guard::UiDecorator::GetObjectOuterProperty(
470 const std::string &literalArrayIdx) const
471 {
472 auto it = this->objectTableRef_.find(literalArrayIdx);
473 if (it == this->objectTableRef_.end()) {
474 return nullptr;
475 }
476
477 for (const auto &property : it->second->outerProperties_) {
478 if (property->name_ == UI_DECORATOR_FUNC_NAME_GET_REUSE_ID) {
479 return property;
480 }
481 }
482 return nullptr;
483 }
484
EnumerateIns(const panda::guard::InstructionInfo & inst)485 void panda::guard::UiDecorator::EnumerateIns(const panda::guard::InstructionInfo &inst)
486 {
487 if (inst.notEqualToOpcode(pandasm::Opcode::LDA_STR)) {
488 return;
489 }
490
491 this->name_ = inst.ins_->GetId(INDEX_0);
492 this->type_ = UiDecoratorType::REUSABLE_V2;
493 this->AddDefineInsList(inst);
494 }