• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }