1/* 2 * Copyright (c) 2024 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 */ 15class stateMgmtDFX { 16 // enable profile 17 public static enableProfiler: boolean = false; 18 public static inRenderingElementId: Array<number> = new Array<number>(); 19 private static readonly DUMP_MAX_PROPERTY_COUNT: number = 50; 20 private static readonly DUMP_MAX_LENGTH: number = 10; 21 private static readonly DUMP_LAST_LENGTH: number = 3; 22 23 public static getObservedPropertyInfo<T>(observedProp: ObservedPropertyAbstractPU<T>, isProfiler: boolean, 24 changedTrackPropertyName?: string): ObservedPropertyInfo<T> { 25 return { 26 decorator: observedProp.debugInfoDecorator(), propertyName: observedProp.info(), id: observedProp.id__(), 27 changedTrackPropertyName: changedTrackPropertyName, 28 value: stateMgmtDFX.getRawValue(observedProp), 29 inRenderingElementId: stateMgmtDFX.inRenderingElementId.length === 0 ? 30 -1 : stateMgmtDFX.inRenderingElementId[stateMgmtDFX.inRenderingElementId.length - 1], 31 dependentElementIds: observedProp.dumpDependentElmtIdsObj(typeof observedProp.getUnmonitored() === 'object' ? 32 !TrackedObject.isCompatibilityMode(observedProp.getUnmonitored()) : false, isProfiler), 33 owningView: observedProp.getOwningView(), 34 length: stateMgmtDFX.getRawValueLength(observedProp), 35 syncPeers: observedProp.dumpSyncPeers(isProfiler, changedTrackPropertyName) 36 }; 37 } 38 39 private static getType(item: RawValue): string { 40 try { 41 return Object.prototype.toString.call(item); 42 } catch (e) { 43 stateMgmtConsole.warn(`Cannot get the type of current value, error message is: ${e.message}`); 44 return 'unknown type'; 45 } 46 } 47 48 /** 49 * Dump 10 items at most. 50 * If length > 10, the output will be the first 7 and last 3 items. 51 * eg: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 52 * output: [0, 1, 2, 3, 4, 5, 6, '...', 9, 10, 11] 53 * 54 */ 55 private static dumpItems(arr: Array<RawValue>): Array<DumpBuildInType> { 56 let dumpArr = arr.slice(0, stateMgmtDFX.DUMP_MAX_LENGTH); 57 if (arr.length > stateMgmtDFX.DUMP_MAX_LENGTH) { 58 dumpArr.splice(stateMgmtDFX.DUMP_MAX_LENGTH - stateMgmtDFX.DUMP_LAST_LENGTH, stateMgmtDFX.DUMP_LAST_LENGTH, '...', ...arr.slice(-stateMgmtDFX.DUMP_LAST_LENGTH)); 59 } 60 return dumpArr.map(item => typeof item === 'object' ? this.getType(item) : item); 61 } 62 63 private static dumpMap(map: Map<RawValue, RawValue>): Array<DumpBuildInType> { 64 let dumpKey = this.dumpItems(Array.from(map.keys())); 65 let dumpValue = this.dumpItems(Array.from(map.values())); 66 return dumpKey.map((item: any, index: number) => [item, dumpValue[index]]); 67 } 68 69 private static dumpObjectProperty(value: any): DumpObjectType | string { 70 let tempObj: DumpObjectType = {}; 71 try { 72 let properties: string[] = Object.getOwnPropertyNames(value); 73 properties 74 .slice(0, stateMgmtDFX.DUMP_MAX_PROPERTY_COUNT) 75 .forEach((varName: string) => { 76 const propertyValue = Reflect.get(value as Object, varName); 77 tempObj[varName] = typeof propertyValue === 'object' ? this.getType(propertyValue) : propertyValue; 78 }); 79 if (properties.length > stateMgmtDFX.DUMP_MAX_PROPERTY_COUNT) { 80 tempObj['...'] = '...'; 81 } 82 } catch (e) { 83 stateMgmtConsole.warn(`can not dump Obj, error msg ${e.message}`); 84 return 'unknown type'; 85 } 86 return tempObj; 87 } 88 89 private static getRawValue<T>(observedProp: ObservedPropertyAbstractPU<T>): DumpObjectType | Array<DumpBuildInType> | T | string { 90 let wrappedValue: T = observedProp.getUnmonitored(); 91 if (typeof wrappedValue !== 'object') { 92 return wrappedValue; 93 } 94 let rawObject: T = ObservedObject.GetRawObject(wrappedValue); 95 if (rawObject instanceof Map) { 96 return stateMgmtDFX.dumpMap(rawObject); 97 } else if (rawObject instanceof Set) { 98 return stateMgmtDFX.dumpItems(Array.from(rawObject.values())); 99 } else if (rawObject instanceof Array) { 100 return stateMgmtDFX.dumpItems(Array.from(rawObject)); 101 } else if (rawObject instanceof Date) { 102 return rawObject; 103 } else { 104 return stateMgmtDFX.dumpObjectProperty(rawObject); 105 } 106 } 107 108 private static getRawValueLength<T>(observedProp: ObservedPropertyAbstractPU<T>): number { 109 let wrappedValue: T = observedProp.getUnmonitored(); 110 if (typeof wrappedValue !== 'object') { 111 return -1; 112 } 113 let rawObject: T = ObservedObject.GetRawObject(wrappedValue); 114 if (rawObject instanceof Map || rawObject instanceof Set) { 115 return rawObject.size; 116 } else if (rawObject instanceof Array) { 117 return rawObject.length; 118 } 119 try { 120 return Object.getOwnPropertyNames(rawObject).length; 121 } catch (e) { 122 return -1; 123 } 124 } 125} 126 127function setProfilerStatus(profilerStatus: boolean): void { 128 stateMgmtConsole.warn(`${profilerStatus ? `start` : `stop`} stateMgmt Profiler`); 129 stateMgmtDFX.enableProfiler = profilerStatus; 130} 131type PropertyDependenciesInfo = { 132 mode: string, 133 trackPropertiesDependencies: MapItem<string, Array<ElementType | number | string>>[], 134 propertyDependencies: Array<ElementType> 135} 136 137type ElementType = { 138 elementId: number, 139 elementTag: string, 140 isCustomNode: boolean, 141} 142 143// Data struct send to profiler or Inspector 144type ViewPUInfo = { componentName: string, id: number }; 145type ObservedPropertyInfo<T> = { 146 decorator: string, propertyName: string, value: any, id: number, changeId?: number, inRenderingElementId?: number, 147 changedTrackPropertyName?: string | undefined, 148 dependentElementIds: PropertyDependenciesInfo, 149 length?: number 150 owningView?: ViewPUInfo, syncPeers?: ObservedPropertyInfo<T>[] 151}; 152 153type SimpleType = string | number | boolean; 154type DumpObjectType = Record<string, SimpleType>; 155type DumpBuildInType = Array<SimpleType> | Array<[SimpleType, SimpleType]>; 156type RawValue = any; 157 158class DumpInfo { 159 public viewInfo?: ViewPUInfo; 160 public observedPropertiesInfo: ObservedPropertyInfo<any>[] = [] 161} 162 163// global function used to throw error in Promise 164declare function _arkUIUncaughtPromiseError(error: any);