1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ciimport { SpSystemTrace } from '../SpSystemTrace';
17fb726d48Sopenharmony_ciimport { TraceRow } from '../trace/base/TraceRow';
18fb726d48Sopenharmony_ciimport { info } from '../../../log/Log';
19fb726d48Sopenharmony_ciimport { procedurePool } from '../../database/Procedure';
20fb726d48Sopenharmony_ciimport { type NativeEventHeap } from '../../bean/NativeHook';
21fb726d48Sopenharmony_ciimport { HeapRender, HeapStruct } from '../../database/ui-worker/ProcedureWorkerHeap';
22fb726d48Sopenharmony_ciimport { Utils } from '../trace/base/Utils';
23fb726d48Sopenharmony_ciimport { renders } from '../../database/ui-worker/ProcedureWorker';
24fb726d48Sopenharmony_ciimport { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
25fb726d48Sopenharmony_ciimport { type BaseStruct } from '../../bean/BaseStruct';
26fb726d48Sopenharmony_ciimport {
27fb726d48Sopenharmony_ci  nativeMemoryChartDataCacheSender,
28fb726d48Sopenharmony_ci  nativeMemoryChartDataSender,
29fb726d48Sopenharmony_ci} from '../../database/data-trafic/NativeMemoryDataSender';
30fb726d48Sopenharmony_ciimport { queryNativeHookProcess, queryNativeHookStatisticsCount } from '../../database/sql/NativeHook.sql';
31fb726d48Sopenharmony_ciimport { queryHeapGroupByEvent } from '../../database/sql/SqlLite.sql';
32fb726d48Sopenharmony_ciimport { queryNativeMemoryRealTime } from '../../database/sql/Memory.sql';
33fb726d48Sopenharmony_ciimport { queryBootTime } from '../../database/sql/Clock.sql';
34fb726d48Sopenharmony_ciimport { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil';
35fb726d48Sopenharmony_ci
36fb726d48Sopenharmony_ciexport class SpNativeMemoryChart {
37fb726d48Sopenharmony_ci  static EVENT_HEAP: Array<NativeEventHeap> = [];
38fb726d48Sopenharmony_ci  static REAL_TIME_DIF: number = 0;
39fb726d48Sopenharmony_ci  private trace: SpSystemTrace;
40fb726d48Sopenharmony_ci
41fb726d48Sopenharmony_ci  constructor(trace: SpSystemTrace) {
42fb726d48Sopenharmony_ci    this.trace = trace;
43fb726d48Sopenharmony_ci  }
44fb726d48Sopenharmony_ci
45fb726d48Sopenharmony_ci  folderThreadHandler(row: TraceRow<BaseStruct>): void {
46fb726d48Sopenharmony_ci    row.onThreadHandler = (useCache): void => {
47fb726d48Sopenharmony_ci      row.canvasSave(this.trace.canvasPanelCtx!);
48fb726d48Sopenharmony_ci      if (row.expansion) {
49fb726d48Sopenharmony_ci        // @ts-ignore
50fb726d48Sopenharmony_ci        this.trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
51fb726d48Sopenharmony_ci      } else {
52fb726d48Sopenharmony_ci        (renders.empty as EmptyRender).renderMainThread(
53fb726d48Sopenharmony_ci          {
54fb726d48Sopenharmony_ci            context: this.trace.canvasPanelCtx,
55fb726d48Sopenharmony_ci            useCache: useCache,
56fb726d48Sopenharmony_ci            type: '',
57fb726d48Sopenharmony_ci          },
58fb726d48Sopenharmony_ci          row
59fb726d48Sopenharmony_ci        );
60fb726d48Sopenharmony_ci      }
61fb726d48Sopenharmony_ci      row.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
62fb726d48Sopenharmony_ci    };
63fb726d48Sopenharmony_ci  }
64fb726d48Sopenharmony_ci
65fb726d48Sopenharmony_ci  chartThreadHandler(row: TraceRow<HeapStruct>): void {
66fb726d48Sopenharmony_ci    row.onThreadHandler = (useCache): void => {
67fb726d48Sopenharmony_ci      let context: CanvasRenderingContext2D;
68fb726d48Sopenharmony_ci      if (row.currentContext) {
69fb726d48Sopenharmony_ci        context = row.currentContext;
70fb726d48Sopenharmony_ci      } else {
71fb726d48Sopenharmony_ci        context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
72fb726d48Sopenharmony_ci      }
73fb726d48Sopenharmony_ci      row.canvasSave(context);
74fb726d48Sopenharmony_ci      (renders.heap as HeapRender).renderMainThread(
75fb726d48Sopenharmony_ci        {
76fb726d48Sopenharmony_ci          context: context,
77fb726d48Sopenharmony_ci          useCache: useCache,
78fb726d48Sopenharmony_ci          type: 'heap',
79fb726d48Sopenharmony_ci        },
80fb726d48Sopenharmony_ci        row
81fb726d48Sopenharmony_ci      );
82fb726d48Sopenharmony_ci      row.canvasRestore(context, this.trace);
83fb726d48Sopenharmony_ci    };
84fb726d48Sopenharmony_ci  }
85fb726d48Sopenharmony_ci
86fb726d48Sopenharmony_ci  initNativeMemoryFolder(process: number, ipid: number): TraceRow<BaseStruct> {
87fb726d48Sopenharmony_ci    const nativeRow = TraceRow.skeleton();
88fb726d48Sopenharmony_ci    nativeRow.rowId = `native-memory ${process} ${ipid}`;
89fb726d48Sopenharmony_ci    nativeRow.index = 0;
90fb726d48Sopenharmony_ci    nativeRow.rowType = TraceRow.ROW_TYPE_NATIVE_MEMORY;
91fb726d48Sopenharmony_ci    nativeRow.drawType = 0;
92fb726d48Sopenharmony_ci    nativeRow.style.height = '40px';
93fb726d48Sopenharmony_ci    nativeRow.rowParentId = '';
94fb726d48Sopenharmony_ci    nativeRow.folder = true;
95fb726d48Sopenharmony_ci    nativeRow.addTemplateTypes('NativeMemory', 'Memory');
96fb726d48Sopenharmony_ci    nativeRow.name = `Native Memory (${process})`;
97fb726d48Sopenharmony_ci    nativeRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
98fb726d48Sopenharmony_ci    nativeRow.selectChangeHandler = this.trace.selectChangeHandler;
99fb726d48Sopenharmony_ci    nativeRow.addRowSettingPop();
100fb726d48Sopenharmony_ci    nativeRow.rowSetting = 'enable';
101fb726d48Sopenharmony_ci    nativeRow.rowSettingPopoverDirection = 'bottomLeft';
102fb726d48Sopenharmony_ci    nativeRow.rowSettingList = [
103fb726d48Sopenharmony_ci      {
104fb726d48Sopenharmony_ci        key: '0',
105fb726d48Sopenharmony_ci        title: 'Current Bytes',
106fb726d48Sopenharmony_ci        checked: true,
107fb726d48Sopenharmony_ci      },
108fb726d48Sopenharmony_ci      {
109fb726d48Sopenharmony_ci        key: '1',
110fb726d48Sopenharmony_ci        title: 'Native Memory Density',
111fb726d48Sopenharmony_ci      },
112fb726d48Sopenharmony_ci    ];
113fb726d48Sopenharmony_ci    nativeRow.onRowSettingChangeHandler = (value): void => {
114fb726d48Sopenharmony_ci      nativeRow.childrenList.forEach((row) => (row.drawType = parseInt(value[0])));
115fb726d48Sopenharmony_ci      this.trace
116fb726d48Sopenharmony_ci        .getCollectRows((row) => row.rowType === 'heap')
117fb726d48Sopenharmony_ci        .forEach((it) => {
118fb726d48Sopenharmony_ci          it.drawType = parseInt(value[0]);
119fb726d48Sopenharmony_ci        });
120fb726d48Sopenharmony_ci      this.trace.refreshCanvas(false);
121fb726d48Sopenharmony_ci    };
122fb726d48Sopenharmony_ci    nativeRow.supplier = (): Promise<BaseStruct[]> => new Promise<Array<BaseStruct>>((resolve) => resolve([]));
123fb726d48Sopenharmony_ci    this.folderThreadHandler(nativeRow);
124fb726d48Sopenharmony_ci    this.trace.rowsEL?.appendChild(nativeRow);
125fb726d48Sopenharmony_ci    return nativeRow;
126fb726d48Sopenharmony_ci  }
127fb726d48Sopenharmony_ci
128fb726d48Sopenharmony_ci  initAllocMapChart(folder: TraceRow<BaseStruct>, type: string, process: { pid: number; ipid: number }): void {
129fb726d48Sopenharmony_ci    const chartList = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
130fb726d48Sopenharmony_ci    for (let i = 0; i < chartList.length; i++) {
131fb726d48Sopenharmony_ci      const nm = chartList[i];
132fb726d48Sopenharmony_ci      const allHeapRow = TraceRow.skeleton<HeapStruct>();
133fb726d48Sopenharmony_ci      allHeapRow.index = i;
134fb726d48Sopenharmony_ci      allHeapRow.rowParentId = `native-memory ${process.pid} ${process.ipid}`;
135fb726d48Sopenharmony_ci      allHeapRow.rowHidden = !folder.expansion;
136fb726d48Sopenharmony_ci      allHeapRow.style.height = '40px';
137fb726d48Sopenharmony_ci      allHeapRow.name = nm;
138fb726d48Sopenharmony_ci      allHeapRow.rowId = nm;
139fb726d48Sopenharmony_ci      allHeapRow.drawType = 0;
140fb726d48Sopenharmony_ci      allHeapRow.isHover = true;
141fb726d48Sopenharmony_ci      allHeapRow.folder = false;
142fb726d48Sopenharmony_ci      allHeapRow.rowType = TraceRow.ROW_TYPE_HEAP;
143fb726d48Sopenharmony_ci      allHeapRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
144fb726d48Sopenharmony_ci      allHeapRow.selectChangeHandler = this.trace.selectChangeHandler;
145fb726d48Sopenharmony_ci      allHeapRow.setAttribute('heap-type', type);
146fb726d48Sopenharmony_ci      allHeapRow.setAttribute('children', '');
147fb726d48Sopenharmony_ci      allHeapRow.focusHandler = (): void => {
148fb726d48Sopenharmony_ci        let tip = '';
149fb726d48Sopenharmony_ci        if (HeapStruct.hoverHeapStruct) {
150fb726d48Sopenharmony_ci          if (allHeapRow.drawType === 1) {
151fb726d48Sopenharmony_ci            tip = `<span>${HeapStruct.hoverHeapStruct.density}</span>`;
152fb726d48Sopenharmony_ci          } else {
153fb726d48Sopenharmony_ci            tip = `<span>${Utils.getByteWithUnit(HeapStruct.hoverHeapStruct.heapsize!)}</span>`;
154fb726d48Sopenharmony_ci          }
155fb726d48Sopenharmony_ci        }
156fb726d48Sopenharmony_ci        this.trace?.displayTip(allHeapRow, HeapStruct.hoverHeapStruct, tip);
157fb726d48Sopenharmony_ci      };
158fb726d48Sopenharmony_ci      allHeapRow.findHoverStruct = (): void => {
159fb726d48Sopenharmony_ci        HeapStruct.hoverHeapStruct = allHeapRow.getHoverStruct();
160fb726d48Sopenharmony_ci      }; //@ts-ignore
161fb726d48Sopenharmony_ci      allHeapRow.supplierFrame = (): Promise<unknown> =>
162fb726d48Sopenharmony_ci        nativeMemoryChartDataSender(allHeapRow, {
163fb726d48Sopenharmony_ci          eventType: i,
164fb726d48Sopenharmony_ci          ipid: process.ipid,
165fb726d48Sopenharmony_ci          model: type,
166fb726d48Sopenharmony_ci          drawType: allHeapRow.drawType,
167fb726d48Sopenharmony_ci        });
168fb726d48Sopenharmony_ci      this.chartThreadHandler(allHeapRow);
169fb726d48Sopenharmony_ci      folder.addChildTraceRow(allHeapRow);
170fb726d48Sopenharmony_ci    }
171fb726d48Sopenharmony_ci  }
172fb726d48Sopenharmony_ci
173fb726d48Sopenharmony_ci  initChart = async (): Promise<void> => {
174fb726d48Sopenharmony_ci    let time = new Date().getTime();
175fb726d48Sopenharmony_ci    let nativeMemoryType = 'native_hook';
176fb726d48Sopenharmony_ci    let nmsCount = await queryNativeHookStatisticsCount();
177fb726d48Sopenharmony_ci    if (nmsCount && nmsCount[0] && nmsCount[0].num > 0) {
178fb726d48Sopenharmony_ci      nativeMemoryType = 'native_hook_statistic';
179fb726d48Sopenharmony_ci    }
180fb726d48Sopenharmony_ci    let nativeProcess = await queryNativeHookProcess(nativeMemoryType);
181fb726d48Sopenharmony_ci    info('NativeHook Process data size is: ', nativeProcess!.length);
182fb726d48Sopenharmony_ci    if (nativeProcess.length === 0) {
183fb726d48Sopenharmony_ci      return;
184fb726d48Sopenharmony_ci    }
185fb726d48Sopenharmony_ci    // 有native_memory进程,统计nativehook插件
186fb726d48Sopenharmony_ci    let requestBody = {
187fb726d48Sopenharmony_ci      eventData: {
188fb726d48Sopenharmony_ci        plugin: ['nativehook']
189fb726d48Sopenharmony_ci      }
190fb726d48Sopenharmony_ci    };
191fb726d48Sopenharmony_ci    SpStatisticsHttpUtil.recordPluginUsage(requestBody);
192fb726d48Sopenharmony_ci    await this.initNativeMemory();
193fb726d48Sopenharmony_ci    await nativeMemoryChartDataCacheSender(
194fb726d48Sopenharmony_ci      nativeProcess.map((it) => it.ipid),
195fb726d48Sopenharmony_ci      nativeMemoryType
196fb726d48Sopenharmony_ci    );
197fb726d48Sopenharmony_ci    SpNativeMemoryChart.EVENT_HEAP = await queryHeapGroupByEvent(nativeMemoryType);
198fb726d48Sopenharmony_ci    for (const process of nativeProcess) {
199fb726d48Sopenharmony_ci      const nativeRow = this.initNativeMemoryFolder(process.pid, process.ipid);
200fb726d48Sopenharmony_ci      this.initAllocMapChart(nativeRow, nativeMemoryType, process);
201fb726d48Sopenharmony_ci    }
202fb726d48Sopenharmony_ci    let durTime = new Date().getTime() - time;
203fb726d48Sopenharmony_ci    info('The time to load the Native Memory data is: ', durTime);
204fb726d48Sopenharmony_ci  };
205fb726d48Sopenharmony_ci
206fb726d48Sopenharmony_ci  initNativeMemory = async (): Promise<void> => {
207fb726d48Sopenharmony_ci    let time = new Date().getTime();
208fb726d48Sopenharmony_ci    let isRealtime = false;
209fb726d48Sopenharmony_ci    let realTimeDif = 0;
210fb726d48Sopenharmony_ci    SpNativeMemoryChart.REAL_TIME_DIF = 0;
211fb726d48Sopenharmony_ci    let queryTime = await queryNativeMemoryRealTime();
212fb726d48Sopenharmony_ci    let bootTime = await queryBootTime();
213fb726d48Sopenharmony_ci    if (queryTime.length > 0) {
214fb726d48Sopenharmony_ci      //@ts-ignore
215fb726d48Sopenharmony_ci      isRealtime = queryTime[0].clock_name === 'realtime';
216fb726d48Sopenharmony_ci    }
217fb726d48Sopenharmony_ci    if (bootTime.length > 0 && isRealtime) {
218fb726d48Sopenharmony_ci      //@ts-ignore
219fb726d48Sopenharmony_ci      realTimeDif = queryTime[0].ts - bootTime[0].ts;
220fb726d48Sopenharmony_ci      SpNativeMemoryChart.REAL_TIME_DIF = realTimeDif;
221fb726d48Sopenharmony_ci    }
222fb726d48Sopenharmony_ci    await new Promise<unknown>((resolve) => {
223fb726d48Sopenharmony_ci      procedurePool.submitWithName(
224fb726d48Sopenharmony_ci        'logic0',
225fb726d48Sopenharmony_ci        'native-memory-init',
226fb726d48Sopenharmony_ci        { isRealtime, realTimeDif },
227fb726d48Sopenharmony_ci        undefined,
228fb726d48Sopenharmony_ci        (res: unknown) => {
229fb726d48Sopenharmony_ci          resolve(res);
230fb726d48Sopenharmony_ci        }
231fb726d48Sopenharmony_ci      );
232fb726d48Sopenharmony_ci    });
233fb726d48Sopenharmony_ci    let durTime = new Date().getTime() - time;
234fb726d48Sopenharmony_ci    info('The time to init the native memory data is: ', durTime);
235fb726d48Sopenharmony_ci  };
236fb726d48Sopenharmony_ci}
237