• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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
17/*  UINodeRegisterProxy singeleton class
18
19Acts on behave on ElementRegister to hold elmtIds of deleted UINodes
20until these get unregistered from a ViewPU.
21
22Two flows inside the framework that involve UINodeRegisterProxy:
23
24Flow A:
251. UINode Destructor calls ElementRegister.RemoveItem(UINode's elmtId) - processing stops:
26
272. Some time later on next re-render of a ViewPU:
283. ViewPU.purgeDeletedElmtIds calls C+++ UINodeRegisterProxy.obtainElementIds(),
294. UINodeRegisterProxy.obtainElementIds() calls C++  ElementRegister::MoveRemovedItems to move elmtIds of deleted UINodes UINodeRegisterProxy
30   (those added by RemoveItems(elmtId) in step 1).
315. UINodeRegisterProxy.unregisterElmtIdsFromIViews: unregister the removedElementIds from the all the viewpus:
32  1) purge the update function in viewpu
33  2) purge the dependent element if from statevariable
34
35Flow B:
361. CustomNode destructor calls deleteFunction calls ViewPU.aboutToBeDeleted
37   note that CustomNode destructor may get called before child UINodes' destructor.
38  1) unregister its own element ids
39  2) call UINodeRegisterProxy.obtainElementIds() to get the removed elementIds from cpp and unregister from all the viewpus.
40     it may make the first viewpu aboutToBeDeleted execution time longer than before, but for rest viewpu may be faster.
41     It's function equals with purgeDeletedElmtIdsRecursively, so it is not necessary to execute purgeDeletedElmtIds for all its child recursively.
42
432. some time later or when idle: PipelineContext::OnIdle will CallJSCleanUpIdleTaskFunc to do the clean up for the removed elements which have not unregisted
44   from the stateMgmt side.
45*/
46
47type RemovedElementInfo = { elmtId : number, tag : string };
48// defined a globle function to clean up the removeItems when idle
49function uiNodeCleanUpIdleTask(maxTimeInMs: number): void {
50    stateMgmtConsole.debug(`UINodeRegisterProxy. static uiNodeCleanUpIdleTask(${maxTimeInMs}):`);
51    const deadline = Date.now() + maxTimeInMs;
52    UINodeRegisterProxy.obtainDeletedElmtIds();
53    UINodeRegisterProxy.unregisterElmtIdsFromIViews();
54    ObserveV2.getObserve().runIdleTasks(deadline);
55}
56
57class UINodeRegisterProxy {
58    public static readonly notRecordingDependencies : number = -1;
59    public static readonly monitorIllegalV1V2StateAccess : number = -2;
60
61    public static obtainDeletedElmtIds(): void {
62        stateMgmtConsole.debug(`UINodeRegisterProxy. static obtainDeletedElmtIds:`);
63        if ((!UINodeRegisterProxy.instance_.obtainDeletedElmtIds) || typeof UINodeRegisterProxy.instance_.obtainDeletedElmtIds !== 'function') {
64            stateMgmtConsole.error(`UINodeRegisterProxy obtainDeletedElmtIds is not a function: ${UINodeRegisterProxy.instance_.obtainDeletedElmtIds}.` );
65        } else {
66            UINodeRegisterProxy.instance_.obtainDeletedElmtIds();
67        }
68    }
69
70    // FIXME unregisterElmtIdsFromIViews needs adaptation
71    public static unregisterElmtIdsFromIViews(): void {
72        stateMgmtConsole.debug('UINodeRegisterProxy.unregisterElmtIdsFromIViews elmtIds');
73        UINodeRegisterProxy.instance_.unregisterElmtIdsFromIViews();
74    }
75
76    // unregisters all the received removedElements in func parameter
77    public static unregisterRemovedElmtsFromViewPUs(removedElements: Array<number>): void {
78        stateMgmtConsole.debug(`UINodeRegisterProxy.unregisterRemovedElmtsFromViewPUs elmtIds ${removedElements}`);
79        UINodeRegisterProxy.instance_.populateRemoveElementInfo(removedElements);
80        UINodeRegisterProxy.instance_.unregisterElmtIdsFromIViews();
81    }
82
83    private populateRemoveElementInfo(removedElements: Array<number>) {
84        for (const elmtId of removedElements) {
85            this.removeElementsInfo_.push(elmtId);
86        }
87    }
88
89    /* just get the remove items from the native side
90    */
91    private obtainDeletedElmtIds(): void {
92        stateMgmtConsole.debug('UINodeRegisterProxy.obtainDeletedElmtIds: ');
93        let removedElementsInfo = new Array<number>();
94        ViewStackProcessor.moveDeletedElmtIds(removedElementsInfo);
95        stateMgmtConsole.debug(`   ... ${removedElementsInfo.length} elmtIds newly obtained from ElementRegister: ${JSON.stringify(removedElementsInfo)} .`);
96        this.removeElementsInfo_ = removedElementsInfo;
97    }
98
99    public unregisterElmtIdsFromIViews(): void {
100        stateMgmtConsole.debug(`${this.removeElementsInfo_.length} elmtIds newly obtained from ElementRegister: ${JSON.stringify(this.removeElementsInfo_)} .`);
101
102        if (this.removeElementsInfo_.length === 0) {
103            stateMgmtConsole.debug(`${this.removeElementsInfo_.length} elmtIds needs to purgeDelete. } .`);
104            return;
105        }
106        let owningView : ViewBuildNodeBase | undefined;
107        this.removeElementsInfo_.forEach((elmtId: number) => {
108            const owningViewPUWeak : WeakRef<ViewBuildNodeBase> | undefined = UINodeRegisterProxy.ElementIdToOwningViewPU_.get(elmtId);
109            if (owningViewPUWeak !== undefined) {
110                owningView = owningViewPUWeak.deref();
111                if (owningView) {
112                    owningView.purgeDeleteElmtId(elmtId);
113                } else {
114                    stateMgmtConsole.debug(`elmtIds ${elmtId} has not been removed because of failure of updating the weakptr of viewpu. Internal error!.`);
115                }
116            } else {
117                stateMgmtConsole.debug(`elmtIds ${elmtId} cannot find its owning ViewPU, maybe this ViewPu has already been aboutToBeDeleted. Internal error!`);
118            }
119
120            ObserveV2.getObserve().clearBinding(elmtId);
121            delete ObserveV2.getObserve().id2cmp_[elmtId];
122        })
123
124        this.removeElementsInfo_.length = 0;
125    }
126
127    /**
128     * Retrieves the ViewBuildNodeBase instance that owns the element identified by the given elmtId
129     * @param elmtId - Unique ID of the element
130     * @returns The owning view (ViewPU/ViewV2) or undefined if not found
131     */
132    public static GetView(elmtId: number): ViewBuildNodeBase | undefined {
133        const viewWeakRef = this.ElementIdToOwningViewPU_.get(elmtId);
134        if (viewWeakRef) {
135            const view = viewWeakRef.deref();
136            if (view && ((view instanceof ViewPU || view instanceof ViewV2))) {
137                return view;
138            }
139        }
140        stateMgmtConsole.warn(`fail to get view for elmtIds ${elmtId}`);
141        return undefined;
142    }
143
144    /**
145     * Retrieves the ViewBuildNodeBase instance that owns the element identified by the given elmtId
146     * @param elmtId - Unique ID of the element
147     * @returns The owning ViewBuildNodeBase or undefined if not found
148     */
149    public static GetViewBuildNodeBase(elmtId: number): ViewBuildNodeBase | undefined {
150        const viewWeakRef = this.ElementIdToOwningViewPU_.get(elmtId);
151        if (viewWeakRef && 'deref' in viewWeakRef) {
152            const view = viewWeakRef.deref();
153            if (view) {
154                return view;
155            }
156        }
157        stateMgmtConsole.warn(`fail to get view for elmtIds ${elmtId}`);
158        return undefined;
159    }
160
161    public static instance_: UINodeRegisterProxy = new UINodeRegisterProxy();
162    public removeElementsInfo_: Array<number> = new Array<number>();
163    public static ElementIdToOwningViewPU_: Map<number, WeakRef<ViewBuildNodeBase>> = new Map<number, WeakRef<ViewBuildNodeBase>>();
164}
165