• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 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
16import { BaseElement, element } from '../../base-ui/BaseElement';
17import '../../base-ui/popover/LitPopover';
18import '../../base-ui/button/LitButton';
19import { LitMainMenuGroup } from '../../base-ui/menu/LitMainMenuGroup';
20import { LitMainMenuItem } from '../../base-ui/menu/LitMainMenuItem';
21import { SpRecordSetting } from './setting/SpRecordSetting';
22import { LitMainMenu, MenuGroup, MenuItem } from '../../base-ui/menu/LitMainMenu';
23import { SpProbesConfig } from './setting/SpProbesConfig';
24import { SpTraceCommand } from './setting/SpTraceCommand';
25import { FlagsConfig } from './SpFlags';
26import LitSwitch from '../../base-ui/switch/lit-switch';
27import { LitSlider } from '../../base-ui/slider/LitSlider';
28
29import {
30  CreateSessionRequest
31} from './setting/bean/ProfilerServiceTypes';
32import { PluginConvertUtils } from './setting/utils/PluginConvertUtils';
33import { SpAllocations } from './setting/SpAllocations';
34import { SpRecordPerf } from './setting/SpRecordPerf';
35import { HdcDeviceManager } from '../../hdc/HdcDeviceManager';
36import { LitButton } from '../../base-ui/button/LitButton';
37import { SpApplication } from '../SpApplication';
38import { LitSearch } from './trace/search/Search';
39import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar';
40import { log } from '../../log/Log';
41import { CmdConstant } from '../../command/CmdConstant';
42import { Cmd } from '../../command/Cmd';
43import { SpFileSystem } from './setting/SpFileSystem';
44import { SpSdkConfig } from './setting/SpSdkConfig';
45import { SpVmTracker } from './setting/SpVmTracker';
46import { SpHisysEvent } from './setting/SpHisysEvent';
47import { SpRecordTemplate } from './setting/SpRecordTemplate';
48import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil';
49import { SpArkTs } from './setting/SpArkTs';
50import { SpWebHdcShell } from './setting/SpWebHdcShell';
51import { SpHilogRecord } from './setting/SpHilogRecord';
52import { LongTraceDBUtils } from '../database/LongTraceDBUtils';
53import {
54  createFpsPluginConfig,
55  createHTracePluginConfig,
56  createHiPerfConfig,
57  createMemoryPluginConfig,
58  createMonitorPlugin,
59  createNativePluginConfig,
60  createSessionRequest,
61  createSystemConfig,
62  createSdkConfig,
63  createHiSystemEventPluginConfig,
64  createArkTsConfig,
65  createHiLogConfig,
66} from './SpRecordConfigModel';
67import { SpRecordTraceHtml } from './SpRecordTrace.html';
68
69@element('sp-record-trace')
70export class SpRecordTrace extends BaseElement {
71  public static serialNumber: string = '';
72  public static selectVersion: string | null;
73  public static isVscode = false;
74  public static cancelRecord = false;
75  static supportVersions = ['3.2', '4.0+'];
76  public deviceSelect: HTMLSelectElement | undefined;
77  public deviceVersion: HTMLSelectElement | undefined;
78  private _menuItems: Array<MenuItem> | undefined;
79  private recordButtonText: HTMLSpanElement | undefined;
80  private devicePrompt: HTMLSpanElement | undefined;
81  private recordButton: LitButton | undefined;
82  private cancelButton: LitButton | undefined;
83  private sp: SpApplication | undefined;
84  private progressEL: LitProgressBar | undefined;
85  private litSearch: LitSearch | undefined;
86  private addButton: LitButton | undefined | null;
87  private disconnectButton: LitButton | undefined | null;
88  private recordSetting: SpRecordSetting | undefined;
89  private probesConfig: SpProbesConfig | undefined;
90  private traceCommand: SpTraceCommand | undefined;
91  private spAllocations: SpAllocations | undefined;
92  private spRecordPerf: SpRecordPerf | undefined;
93  private spFileSystem: SpFileSystem | undefined;
94  private spSdkConfig: SpSdkConfig | undefined;
95  private spVmTracker: SpVmTracker | undefined;
96  private spHiSysEvent: SpHisysEvent | undefined;
97  private spRecordTemplate: SpRecordTemplate | undefined;
98  private spArkTs: SpArkTs | undefined;
99  private spHiLog: SpHilogRecord | undefined;
100  private ftraceSlider: LitSlider | undefined | null;
101  private spWebShell: SpWebHdcShell | undefined;
102  private menuGroup: LitMainMenuGroup | undefined | null;
103  private appContent: HTMLElement | undefined | null;
104  private record = 'Record';
105  private stop = 'StopRecord';
106  private nowChildItem: HTMLElement | undefined;
107  private longTraceList: Array<string> = [];
108  private refreshDeviceTimer: number | undefined;
109  private hintEl: HTMLSpanElement | undefined;
110  private selectedTemplate: Map<string, number> = new Map();
111  private hintTimeOut: number = -1;
112
113  set record_template(re: boolean) {
114    if (re) {
115      this.setAttribute('record_template', '');
116    } else {
117      this.removeAttribute('record_template');
118    }
119    if (this.recordSetting) {
120      this.recordSetting.isRecordTemplate = re;
121    }
122  }
123
124  get record_template(): boolean {
125    return this.hasAttribute('record_template');
126  }
127
128  set vs(vs: boolean) {
129    if (vs) {
130      SpRecordTrace.isVscode = true;
131      this.setAttribute('vs', '');
132    } else {
133      SpRecordTrace.isVscode = false;
134      this.removeAttribute('vs');
135    }
136  }
137
138  get vs(): boolean {
139    return this.hasAttribute('vs');
140  }
141
142  private compareArray(devs: Array<string>): boolean {
143    let clearFlag: boolean = false;
144    if (devs.length !== this.deviceSelect!.options.length) {
145      clearFlag = true;
146    } else {
147      let optionArray: string[] = [];
148      for (let index = 0; index < this.deviceSelect!.options.length; index++) {
149        optionArray.push(this.deviceSelect!.options[index].value);
150      }
151      devs.forEach((value) => {
152        if (optionArray.indexOf(value) === -1) {
153          clearFlag = true;
154        }
155      });
156    }
157    return clearFlag;
158  }
159
160  private refreshDeviceList(): void {
161    if (this.vs) {
162      this.refreshDeviceListByVs();
163    } else {
164      this.deviceSelect!.innerHTML = '';
165      // @ts-ignore
166      HdcDeviceManager.getDevices().then((devs: USBDevice[]) => {
167        if (devs.length === 0) {
168          this.recordButton!.hidden = true;
169          this.disconnectButton!.hidden = true;
170          this.devicePrompt!.innerText = 'Device not connected';
171        }
172        for (let len = 0; len < devs.length; len++) {
173          let dev = devs[len];
174          let option = document.createElement('option');
175          option.className = 'select';
176          if (typeof dev.serialNumber === 'string') {
177            option.value = dev.serialNumber;
178          }
179          option.textContent = dev!.serialNumber ? dev!.serialNumber!.toString() : 'hdc Device';
180          this.deviceSelect!.appendChild(option);
181          if (len === 0) {
182            option.selected = true;
183            this.recordButton!.hidden = false;
184            this.disconnectButton!.hidden = false;
185            this.devicePrompt!.innerText = '';
186            SpRecordTrace.serialNumber = option.value;
187            this.refreshDeviceVersion(option);
188          }
189        }
190      });
191    }
192  }
193
194  private refreshDeviceVersion(option: HTMLOptionElement): void {
195    HdcDeviceManager.connect(option.value).then((result) => {
196      if (result) {
197        HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_VERSION, false).then((version) => {
198          SpRecordTrace.selectVersion = this.getDeviceVersion(version);
199          this.setDeviceVersionSelect(SpRecordTrace.selectVersion);
200          this.nativeMemoryHideBySelectVersion();
201          this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
202            PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false),
203            this.recordSetting!.output,
204            this.recordSetting!.maxDur
205          );
206          if (this.nowChildItem === this.spWebShell) {
207            window.publish(window.SmartEvent.UI.DeviceConnect, option.value);
208          }
209        });
210      } else {
211        SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0];
212        this.setDeviceVersionSelect(SpRecordTrace.selectVersion);
213        this.nativeMemoryHideBySelectVersion();
214        let cmdTxt = PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false);
215        this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
216          cmdTxt,
217          this.recordSetting!.output,
218          this.recordSetting!.maxDur
219        );
220      }
221    });
222  }
223
224  private refreshDeviceListByVs(): void {
225    Cmd.execHdcCmd(CmdConstant.CMD_HDC_DEVICES, (res: string) => {
226      let devs: string[] = res.trim().replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/);
227      if (devs.length === 1 && devs[0].indexOf('Empty') !== -1) {
228        this.deviceSelect!.innerHTML = '';
229        return;
230      }
231      let clearFlag = this.compareArray(devs);
232      if (clearFlag) {
233        this.deviceSelect!.innerHTML = '';
234        if (devs.length === 0) {
235          this.recordButton!.hidden = true;
236          this.disconnectButton!.hidden = true;
237          this.devicePrompt!.innerText = 'Device not connected';
238        }
239        for (let i = 0; i < devs.length; i++) {
240          let dev = devs[i];
241          let option = document.createElement('option');
242          option.className = 'select';
243          option.textContent = dev;
244          this.deviceSelect!.appendChild(option);
245          if (i === 0) {
246            option.selected = true;
247            this.recordButton!.hidden = false;
248            this.disconnectButton!.hidden = false;
249            SpRecordTrace.serialNumber = option.value;
250            this.devicePrompt!.innerText = '';
251          }
252        }
253      }
254    });
255  }
256
257  private getDeviceVersion(version: string): string {
258    if (version.indexOf('3.2') !== -1) {
259      return '3.2';
260    } else if (version.indexOf('4.') !== -1) {
261      return '4.0+';
262    }
263    return '3.2';
264  }
265
266  private freshMenuDisable(disable: boolean): void {
267    let mainMenu = this.sp!.shadowRoot?.querySelector('#main-menu') as LitMainMenu;
268    mainMenu.menus?.forEach((men): void => {
269      men.children.forEach((child: HTMLElement): void => {
270        // @ts-ignore
271        child.disabled = disable;
272      });
273    });
274    mainMenu.menus = mainMenu.menus;
275  }
276
277  refreshConfig(isTraceConfig: boolean): void {
278    let recordSettingEl = this.shadowRoot?.querySelector('record-setting') as SpRecordSetting;
279    if (recordSettingEl) {
280      if (isTraceConfig) {
281        recordSettingEl.setAttribute('trace_config', '');
282      } else {
283        if (recordSettingEl.hasAttribute('trace_config')) {
284          recordSettingEl.removeAttribute('trace_config');
285        }
286      }
287    }
288  }
289
290  refreshHint(): void {
291    let flags = FlagsConfig.getAllFlagConfig();
292    let showHint = false;
293    for (let i = 0; i < flags.length; i++) {
294      let flag = flags[i];
295      if (this.selectedTemplate.has(flag.title)) {
296        let selectedOption = flag.switchOptions.filter((option) => {
297          return option.selected;
298        });
299        if (selectedOption[0].option === 'Disabled') {
300          showHint = true;
301          break;
302        }
303      }
304    }
305    this.showHint = showHint;
306  }
307
308  get showHint(): boolean {
309    return this.hasAttribute('show_hint');
310  }
311
312  set showHint(bool: boolean) {
313    if (bool) {
314      if (this.hasAttribute('show_hint')) {
315        this.removeAttribute('show_hint');
316        this.hintTimeOut = window.setTimeout(() => {
317          this.setAttribute('show_hint', '');
318        }, timeOut);
319      } else {
320        this.setAttribute('show_hint', '');
321      }
322    } else {
323      if (this.hintTimeOut !== -1) {
324        window.clearTimeout(this.hintTimeOut);
325        this.hintTimeOut = -1;
326      }
327      this.removeAttribute('show_hint');
328    }
329  }
330
331  initElements(): void {
332    let parentElement = this.parentNode as HTMLElement;
333    if (parentElement) {
334      parentElement.style.overflow = 'hidden';
335    }
336    if (!this.shadowRoot || !this.sp){
337      return;
338    }
339    this.initConfigPage();
340    this.hintEl = this.shadowRoot.querySelector('#hint') as HTMLSpanElement;
341    this.deviceSelect = this.shadowRoot.querySelector('#device-select') as HTMLSelectElement;
342    this.deviceVersion = this.shadowRoot.querySelector('#device-version') as HTMLSelectElement;
343    this.devicePrompt = this.shadowRoot.querySelector('.prompt') as HTMLSpanElement;
344    this.disconnectButton = this.shadowRoot.querySelector<LitButton>('.disconnect');
345    this.recordButton = this.shadowRoot.querySelector('.record') as LitButton;
346    this.recordButtonText = this.shadowRoot.querySelector('.record_text') as HTMLSpanElement;
347    this.cancelButton = this.shadowRoot.querySelector('.cancel') as LitButton;
348    this.sp = document.querySelector('sp-application') as SpApplication;
349    this.progressEL = this.sp.shadowRoot?.querySelector('.progress') as LitProgressBar;
350    this.litSearch = this.sp.shadowRoot?.querySelector('#lit-record-search') as LitSearch;
351    this.menuGroup = this.shadowRoot.querySelector('#menu-group') as LitMainMenuGroup;
352    this.addButton = this.shadowRoot.querySelector<LitButton>('.add');
353    if (this.record_template) {
354      this.buildTemplateTraceItem();
355    } else {
356      this.buildNormalTraceItem();
357    }
358    this.initMenuItems();
359    this.appendDeviceVersion();
360    if (this.deviceSelect.options && this.deviceSelect.options.length > 0) {
361      this.disconnectButton!.hidden = false;
362      this.recordButton.hidden = false;
363      this.devicePrompt.innerText = '';
364    } else {
365      this.disconnectButton!.hidden = true;
366      this.recordButton.hidden = true;
367      this.devicePrompt.innerText = 'Device not connected';
368    }
369  }
370
371  connectedCallback(): void {
372    super.connectedCallback();
373    this.addButton!.addEventListener('click', this.addButtonClickEvent);
374    this.deviceSelect!.addEventListener('mousedown', this.deviceSelectMouseDownEvent);
375    this.deviceSelect!.addEventListener('change', this.deviceSelectChangeEvent);
376    this.deviceVersion!.addEventListener('change', this.deviceVersionChangeEvent);
377    this.disconnectButton?.addEventListener('click', this.disconnectButtonClickEvent);
378    this.recordButton?.addEventListener('mousedown', this.recordButtonMouseDownEvent);
379    this.cancelButton?.addEventListener('click', this.cancelRecordListener);
380    this.spRecordPerf?.addEventListener('addProbe', this.recordAddProbeEvent);
381    this.spAllocations?.addEventListener('addProbe', this.recordAddProbeEvent);
382    this.probesConfig?.addEventListener('addProbe', this.recordAddProbeEvent);
383    this.spRecordTemplate?.addEventListener('addProbe', this.recordTempAddProbe);
384    this.spRecordTemplate?.addEventListener('delProbe', this.recordTempDelProbe);
385  }
386
387  disconnectedCallback(): void {
388    super.disconnectedCallback();
389    this.addButton!.removeEventListener('click', this.addButtonClickEvent);
390    this.deviceSelect!.removeEventListener('mousedown', this.deviceSelectMouseDownEvent);
391    this.deviceSelect!.removeEventListener('change', this.deviceSelectChangeEvent);
392    this.deviceVersion!.removeEventListener('change', this.deviceVersionChangeEvent);
393    this.disconnectButton?.removeEventListener('click', this.disconnectButtonClickEvent);
394    this.recordButton?.removeEventListener('mousedown', this.recordButtonMouseDownEvent);
395    this.cancelButton?.removeEventListener('click', this.cancelRecordListener);
396    this.spRecordPerf?.removeEventListener('addProbe', this.recordAddProbeEvent);
397    this.spAllocations?.removeEventListener('addProbe', this.recordAddProbeEvent);
398    this.probesConfig?.removeEventListener('addProbe', this.recordAddProbeEvent);
399    this.spRecordTemplate?.removeEventListener('addProbe', this.recordTempAddProbe);
400    this.spRecordTemplate?.removeEventListener('delProbe', this.recordTempDelProbe);
401  }
402
403  recordTempAddProbe = (ev: CustomEventInit<{ elementId: string }>): void => {
404    if (
405      FlagsConfig.DEFAULT_CONFIG.find((flagItem) => {
406        return flagItem.title === ev.detail!.elementId;
407      })
408    ) {
409      this.selectedTemplate.set(ev.detail!.elementId, 1);
410      let flagConfig = FlagsConfig.getFlagsConfig(ev.detail!.elementId);
411      if (flagConfig![ev.detail!.elementId] !== 'Enabled') {
412        this.hintEl!.textContent = 'Please open the corresponding Flags tag when parsing';
413        if (!this.showHint) {
414          this.showHint = true;
415        }
416      }
417    }
418  };
419
420  recordTempDelProbe = (ev: CustomEventInit<{ elementId: string }>): void => {
421    if (
422      FlagsConfig.DEFAULT_CONFIG.find((flagItem): boolean => {
423        return flagItem.title === ev.detail!.elementId;
424      })
425    ) {
426      this.selectedTemplate['delete'](ev.detail!.elementId);
427      if (this.selectedTemplate.size === 0) {
428        this.showHint = false;
429      }
430    }
431  };
432
433  recordAddProbeEvent = (): void => {
434    this.showHint = false;
435  };
436
437  addButtonClickEvent = (event: MouseEvent): void => {
438    if (this.vs) {
439      this.refreshDeviceList();
440    } else {
441      // @ts-ignore
442      HdcDeviceManager.findDevice().then((usbDevices): void => {
443        log(usbDevices);
444        this.refreshDeviceList();
445      });
446    }
447  };
448
449  deviceSelectMouseDownEvent = (evt: MouseEvent): void => {
450    if (this.deviceSelect!.options.length === 0) {
451      evt.preventDefault();
452    }
453  };
454
455  deviceSelectChangeEvent = (): void => {
456    if (this.deviceSelect!.options.length > 0) {
457      this.recordButton!.hidden = false;
458      this.disconnectButton!.hidden = false;
459      this.devicePrompt!.innerText = '';
460    } else {
461      this.recordButton!.hidden = true;
462      this.disconnectButton!.hidden = true;
463      this.devicePrompt!.innerText = 'Device not connected';
464    }
465    let deviceItem = this.deviceSelect!.options[this.deviceSelect!.selectedIndex];
466    let value = deviceItem.value;
467    SpRecordTrace.serialNumber = value;
468    if (this.vs) {
469      let cmd = Cmd.formatString(CmdConstant.CMD_GET_VERSION_DEVICES, [SpRecordTrace.serialNumber]);
470      Cmd.execHdcCmd(cmd, (deviceVersion: string) => {
471        this.selectedDevice(deviceVersion);
472        this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
473          PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false),
474          this.recordSetting!.output,
475          this.recordSetting!.maxDur
476        );
477      });
478    } else {
479      HdcDeviceManager.connect(value).then((result): void => {
480        if (result) {
481          HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_VERSION, true).then((deviceVersion) => {
482            this.selectedDevice(deviceVersion);
483            this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
484              PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false),
485              this.recordSetting!.output,
486              this.recordSetting!.maxDur
487            );
488            if (this.nowChildItem === this.spWebShell) {
489              window.publish(window.SmartEvent.UI.DeviceConnect, value);
490            }
491          });
492        } else {
493          SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0];
494          this.setDeviceVersionSelect(SpRecordTrace.selectVersion);
495          this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
496            PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false),
497            this.recordSetting!.output,
498            this.recordSetting!.maxDur
499          );
500        }
501      });
502    }
503  };
504
505  deviceVersionChangeEvent = (): void => {
506    let versionItem = this.deviceVersion!.options[this.deviceVersion!.selectedIndex];
507    SpRecordTrace.selectVersion = versionItem.getAttribute('device-version');
508    this.spAllocations!.startup_mode = false;
509    this.nativeMemoryHideBySelectVersion();
510    this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
511      PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false),
512      this.recordSetting!.output,
513      this.recordSetting!.maxDur
514    );
515  };
516
517  disconnectButtonClickEvent = (): void => {
518    let index = this.deviceSelect!.selectedIndex;
519    if (index !== -1) {
520      let selectOption = this.deviceSelect!.options[index];
521      let value = selectOption.value;
522      HdcDeviceManager.disConnect(value).then((): void => {
523        this.deviceSelect!.removeChild(selectOption);
524        if (this.nowChildItem === this.spWebShell) {
525          window.publish(window.SmartEvent.UI.DeviceDisConnect, value);
526        }
527        if (this.deviceSelect!.selectedIndex !== -1) {
528          let item = this.deviceSelect!.options[this.deviceSelect!.selectedIndex];
529          SpRecordTrace.serialNumber = item.value;
530        } else {
531          this.recordButton!.hidden = true;
532          this.disconnectButton!.hidden = true;
533          this.devicePrompt!.innerText = 'Device not connected';
534          this.sp!.search = false;
535          SpRecordTrace.serialNumber = '';
536        }
537      });
538    }
539  };
540
541  recordButtonMouseDownEvent = (event: MouseEvent): void => {
542    if (event.button === 0) {
543      if (this.recordButtonText!.textContent === this.record) {
544        this.recordButtonListener();
545      } else {
546        this.stopRecordListener();
547      }
548    }
549  };
550
551  private initConfigPage(): void {
552    this.recordSetting = new SpRecordSetting();
553    this.probesConfig = new SpProbesConfig();
554    this.traceCommand = new SpTraceCommand();
555    this.spAllocations = new SpAllocations();
556    this.spRecordPerf = new SpRecordPerf();
557    this.spFileSystem = new SpFileSystem();
558    this.spSdkConfig = new SpSdkConfig();
559    this.spVmTracker = new SpVmTracker();
560    this.spHiSysEvent = new SpHisysEvent();
561    this.spArkTs = new SpArkTs();
562    this.spHiLog = new SpHilogRecord();
563    this.spWebShell = new SpWebHdcShell();
564    this.spRecordTemplate = new SpRecordTemplate(this);
565    this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement;
566    if (this.record_template) {
567      this.appContent.append(this.spRecordTemplate);
568    } else {
569      this.appContent.append(this.recordSetting);
570    }
571    // @ts-ignore
572    if (navigator.usb) {
573      // @ts-ignore
574      navigator.usb.addEventListener(
575        'disconnect',
576        // @ts-ignore
577        (ev: USBConnectionEvent) => {
578          this.usbDisConnectionListener(ev);
579        }
580      );
581    }
582  }
583
584  private nativeMemoryHideBySelectVersion(): void {
585    let divConfigs = this.spAllocations?.shadowRoot?.querySelectorAll<HTMLDivElement>('.version-controller');
586    if (divConfigs) {
587      if (SpRecordTrace.selectVersion !== '3.2') {
588        for (let divConfig of divConfigs) {
589          divConfig!.style.zIndex = '1';
590        }
591      } else {
592        for (let divConfig of divConfigs) {
593          divConfig!.style.zIndex = '-1';
594        }
595      }
596    }
597  }
598
599  private selectedDevice(deviceVersion: string): void {
600    SpRecordTrace.selectVersion = this.getDeviceVersion(deviceVersion);
601    this.setDeviceVersionSelect(SpRecordTrace.selectVersion);
602  }
603
604  private appendDeviceVersion(): void {
605    SpRecordTrace.supportVersions.forEach((supportVersion) => {
606      let option = document.createElement('option');
607      option.className = 'select';
608      option.selected = supportVersion === '4.0+';
609      option.textContent = `OpenHarmony-${supportVersion}`;
610      option.setAttribute('device-version', supportVersion);
611      this.deviceVersion!.append(option);
612      SpRecordTrace.selectVersion = '4.0+';
613      this.nativeMemoryHideBySelectVersion();
614    });
615  }
616
617  private setDeviceVersionSelect(selected: string): void {
618    let children = this.deviceVersion!.children;
619    for (let i = 0; i < children.length; i++) {
620      let child = children[i] as HTMLOptionElement;
621      if (child.getAttribute('device-version') === selected) {
622        child.selected = true;
623        break;
624      }
625    }
626  }
627
628  stopRecordListener(): void {
629    this.recordButtonText!.textContent = this.record;
630    this.recordButtonDisable(true);
631    this.cancelButtonShow(false);
632    if (this.vs) {
633      let cmd = Cmd.formatString(CmdConstant.CMS_HDC_STOP, [SpRecordTrace.serialNumber]);
634      Cmd.execHdcCmd(cmd, (): void => {
635      });
636    } else {
637      let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement;
638      HdcDeviceManager.connect(selectedOption.value).then((result) => {
639        if (result) {
640          try {
641            HdcDeviceManager.shellResultAsString(CmdConstant.CMS_STOP, true).then((): void => {
642            });
643          } catch (exception) {
644            this.recordButtonDisable(false);
645            log(exception);
646          }
647        }
648      });
649    }
650  }
651
652  cancelRecordListener = (): void => {
653    this.recordButtonText!.textContent = this.record;
654    this.cancelButtonShow(false);
655    if (this.vs) {
656      let cmd = Cmd.formatString(CmdConstant.CMS_HDC_CANCEL, [SpRecordTrace.serialNumber]);
657      Cmd.execHdcCmd(cmd, () => {
658        this.freshMenuDisable(false);
659        this.freshConfigMenuDisable(false);
660        this.progressEL!.loading = false;
661        this.sp!.search = false;
662        this.litSearch!.clear();
663        this.addButton!.style.pointerEvents = 'auto';
664        this.deviceSelect!.style.pointerEvents = 'auto';
665        this.disconnectButton!.style.pointerEvents = 'auto';
666        this.deviceVersion!.style.pointerEvents = 'auto';
667      });
668    } else {
669      let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement;
670      HdcDeviceManager.connect(selectedOption.value).then((result) => {
671        if (result) {
672          this.freshMenuDisable(false);
673          this.freshConfigMenuDisable(false);
674          try {
675            this.progressEL!.loading = false;
676            this.sp!.search = false;
677            this.litSearch!.clear();
678            this.disconnectButton!.style.pointerEvents = 'auto';
679            this.addButton!.style.pointerEvents = 'auto';
680            this.deviceSelect!.style.pointerEvents = 'auto';
681            this.deviceVersion!.style.pointerEvents = 'auto';
682            SpRecordTrace.cancelRecord = true;
683            HdcDeviceManager.stopHiprofiler(CmdConstant.CMS_CANCEL).then((): void => {
684            });
685          } catch (exception) {
686            log(exception);
687          }
688        }
689      });
690    }
691  };
692
693  private cancelButtonShow(show: boolean): void {
694    if (show) {
695      this.cancelButton!.style.visibility = 'visible';
696    } else {
697      this.cancelButton!.style.visibility = 'hidden';
698    }
699  }
700
701  private traceCommandClickHandler(recordTrace: SpRecordTrace): void {
702    recordTrace.appContent!.innerHTML = '';
703    recordTrace.appContent!.append(recordTrace.traceCommand!);
704    recordTrace.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
705      PluginConvertUtils.BeanToCmdTxt(recordTrace.makeRequest(), false),
706      recordTrace.recordSetting!.output,
707      recordTrace.recordSetting!.maxDur
708    );
709    recordTrace.freshMenuItemsStatus('Trace command');
710  }
711
712  private initMenuItems(): void {
713    this._menuItems?.forEach((item): void => {
714      let th = new LitMainMenuItem();
715      th.setAttribute('icon', item.icon || '');
716      th.setAttribute('title', item.title || '');
717      th.style.height = '60px';
718      th.style.fontFamily = 'Helvetica-Bold';
719      th.style.fontSize = '16px';
720      th.style.lineHeight = '28px';
721      th.style.fontWeight = '700';
722      th.removeAttribute('file');
723      th.addEventListener('click', (): void => {
724        if (item.clickHandler) {
725          item.clickHandler(item);
726        }
727      });
728      this.menuGroup!.appendChild(th);
729    });
730  }
731
732  private recordCommandClickHandler(recordTrace: SpRecordTrace): void {
733    let request = recordTrace.makeRequest();
734    recordTrace.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
735      PluginConvertUtils.BeanToCmdTxt(request, false),
736      recordTrace.recordSetting!.output,
737      recordTrace.recordSetting!.maxDur
738    );
739  }
740
741  private hdcShellClickHandler(recordTrace: SpRecordTrace): void {
742    recordTrace.spWebShell!.shellDiv!.scrollTop = recordTrace.spWebShell!.currentScreenRemain;
743    setTimeout(() => {
744      recordTrace.spWebShell!.hdcShellFocus();
745    }, 100);
746    recordTrace.nowChildItem = recordTrace.spWebShell!;
747  }
748
749  private nativeMemoryClickHandler(recordTrace: SpRecordTrace): void {
750    let startNativeSwitch = recordTrace.spAllocations?.shadowRoot?.getElementById('switch-disabled') as LitSwitch;
751    let recordModeSwitch = recordTrace.probesConfig?.shadowRoot?.querySelector('lit-switch') as LitSwitch;
752    let checkDesBoxDis = recordTrace.probesConfig?.shadowRoot?.querySelectorAll('check-des-box');
753    let litCheckBoxDis = recordTrace.probesConfig?.shadowRoot?.querySelectorAll('lit-check-box');
754    recordTrace.ftraceSlider = recordTrace.probesConfig?.shadowRoot?.querySelector<LitSlider>('#ftrace-buff-size-slider');
755    startNativeSwitch.addEventListener('change', (event: any): void => {
756      let detail = event.detail;
757      if (detail!.checked) {
758        recordModeSwitch.removeAttribute('checked');
759        checkDesBoxDis?.forEach((item: any): void => {
760          item.setAttribute('disabled', '');
761          item.checked = false;
762        });
763        litCheckBoxDis?.forEach((item: any): void => {
764          item.setAttribute('disabled', '');
765          item.checked = false;
766        });
767        recordTrace.ftraceSlider!.setAttribute('disabled', '');
768      }
769    });
770    let divConfigs = recordTrace.spAllocations?.shadowRoot?.querySelectorAll<HTMLDivElement>('.version-controller');
771    if ((!SpRecordTrace.selectVersion || SpRecordTrace.selectVersion === '3.2') && divConfigs) {
772      for (let divConfig of divConfigs) {
773        divConfig!.style.zIndex = '-1';
774      }
775    }
776  }
777
778  private eBPFConfigClickHandler(recordTrace: SpRecordTrace): void {
779    recordTrace.spFileSystem!.setAttribute('long_trace', '');
780  }
781
782  private buildMenuItem(
783    title: string,
784    icon: string,
785    configPage: BaseElement,
786    clickHandlerFun?: Function,
787    fileChoose: boolean = false
788  ): MenuItem {
789    let that = this;
790    return {
791      title: title,
792      icon: icon,
793      fileChoose: fileChoose,
794      clickHandler: (): void => {
795        that.appContent!.innerHTML = '';
796        that.appContent!.append(configPage);
797        that.freshMenuItemsStatus(title);
798        if (clickHandlerFun) {
799          clickHandlerFun(that);
800        }
801      },
802    };
803  }
804
805  private buildTemplateTraceItem(): void {
806    this._menuItems = [
807      this.buildMenuItem('Record setting', 'properties', this.recordSetting!),
808      this.buildMenuItem('Trace template', 'realIntentionBulb', this.spRecordTemplate!),
809      this.buildMenuItem('Trace command', 'dbsetbreakpoint', this.spRecordTemplate!, this.traceCommandClickHandler),
810    ];
811  }
812
813  private buildNormalTraceItem(): void {
814    this._menuItems = [
815      this.buildMenuItem('Record setting', 'properties', this.recordSetting!),
816      this.buildMenuItem('Trace command', 'dbsetbreakpoint', this.traceCommand!, this.recordCommandClickHandler),
817      this.buildMenuItem('Hdc Shell', 'file-config', this.spWebShell!, this.hdcShellClickHandler),
818      this.buildMenuItem('Probes config', 'realIntentionBulb', this.probesConfig!),
819      this.buildMenuItem('Native Memory', 'externaltools', this.spAllocations!, this.nativeMemoryClickHandler),
820      this.buildMenuItem('Hiperf', 'realIntentionBulb', this.spRecordPerf!),
821      this.buildMenuItem('eBPF Config', 'file-config', this.spFileSystem!, this.eBPFConfigClickHandler),
822      this.buildMenuItem('VM Tracker', 'vm-tracker', this.spVmTracker!),
823      this.buildMenuItem('HiSystemEvent', 'externaltools', this.spHiSysEvent!),
824      this.buildMenuItem('Ark Ts', 'file-config', this.spArkTs!),
825      this.buildMenuItem('Hilog', 'realIntentionBulb', this.spHiLog!),
826      this.buildMenuItem('SDK Config', 'file-config', this.spSdkConfig!)
827    ];
828  }
829
830  // @ts-ignore
831  usbDisConnectionListener(event: USBConnectionEvent): void {
832    // @ts-ignore
833    let disConnectDevice: USBDevice = event.device;
834    for (let index = 0; index < this.deviceSelect!.children.length; index++) {
835      let option = this.deviceSelect!.children[index] as HTMLOptionElement;
836      if (option.value === disConnectDevice.serialNumber) {
837        let optValue = option.value;
838        HdcDeviceManager.disConnect(optValue).then(() => {
839        });
840        this.deviceSelect!.removeChild(option);
841        if (SpRecordTrace.serialNumber === optValue) {
842          if (this.nowChildItem === this.spWebShell) {
843            window.publish(window.SmartEvent.UI.DeviceDisConnect, optValue);
844          }
845          let options = this.deviceSelect!.options;
846          if (options.length > 0) {
847            let selectedOpt = options[this.deviceSelect!.selectedIndex];
848            SpRecordTrace.serialNumber = selectedOpt.value;
849          } else {
850            this.recordButton!.hidden = true;
851            this.disconnectButton!.hidden = true;
852            this.devicePrompt!.innerText = 'Device not connected';
853            SpRecordTrace.serialNumber = '';
854          }
855        }
856      }
857    }
858  }
859
860  private vsCodeRecordCmd(traceCommandStr: string): void {
861    Cmd.execHdcCmd(Cmd.formatString(CmdConstant.CMS_HDC_STOP, [SpRecordTrace.serialNumber]), (stopRes: string) => {
862      let cmd = Cmd.formatString(CmdConstant.CMD_MOUNT_DEVICES, [SpRecordTrace.serialNumber]);
863      Cmd.execHdcCmd(cmd, (res: string) => {
864        this.sp!.search = true;
865        this.progressEL!.loading = true;
866        this.litSearch!.clear();
867        this.litSearch!.setPercent(`tracing  ${this.recordSetting!.maxDur * 1000}ms`, -1);
868        this.initRecordUIState();
869        this.recordButtonText!.textContent = this.stop;
870        this.cancelButtonShow(true);
871        Cmd.execHdcTraceCmd(traceCommandStr, SpRecordTrace.serialNumber, (traceResult: string) => {
872          if (traceResult.indexOf('DestroySession done') != -1) {
873            this.litSearch!.setPercent('tracing htrace down', -1);
874            let cmd = Cmd.formatString(CmdConstant.CMD_FIEL_RECV_DEVICES, [
875              SpRecordTrace.serialNumber,
876              this.recordSetting!.output,
877            ]);
878            Cmd.execFileRecv(cmd, this.recordSetting!.output, (rt: ArrayBuffer) => {
879              this.litSearch!.setPercent('downloading Hitrace file ', 101);
880              let fileName = this.recordSetting!.output.substring(this.recordSetting!.output.lastIndexOf('/') + 1);
881              let file = new File([rt], fileName);
882              let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu;
883              let children = main.menus as Array<MenuGroup>;
884              let child = children[0].children as Array<MenuItem>;
885              let fileHandler = child[0].fileHandler;
886              if (fileHandler && !SpRecordTrace.cancelRecord) {
887                this.recordButtonText!.textContent = this.record;
888                this.cancelButtonShow(false);
889                this.freshMenuDisable(false);
890                this.freshConfigMenuDisable(false);
891                fileHandler({detail: file});
892              } else {
893                SpRecordTrace.cancelRecord = false;
894              }
895            });
896          } else {
897            this.litSearch!.setPercent('tracing htrace failed, please check your config ', -2);
898            this.recordButtonText!.textContent = this.record;
899            this.freshMenuDisable(false);
900            this.freshConfigMenuDisable(false);
901            this.progressEL!.loading = false;
902          }
903          this.buttonDisable(false);
904        });
905      });
906    });
907  }
908
909  private initRecordCmdStatus(): void {
910    this.appContent!.innerHTML = '';
911    this.appContent!.append(this.traceCommand!);
912    let config = this.makeRequest();
913    this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
914      PluginConvertUtils.BeanToCmdTxt(config, false),
915      this.recordSetting!.output,
916      this.recordSetting!.maxDur
917    );
918    this.freshMenuItemsStatus('Trace command');
919  }
920
921  private webRecordCmd(traceCommandStr: string, selectedOption: HTMLOptionElement): void {
922    HdcDeviceManager.connect(selectedOption.value).then((result) => {
923      log(`result is ${result}`);
924      if (result) {
925        this.initRecordCmdStatus();
926        try {
927          HdcDeviceManager.stopHiprofiler(CmdConstant.CMS_CANCEL).then(() => {
928            HdcDeviceManager.shellResultAsString(CmdConstant.CMD_MOUNT, true).then(() => {
929              this.sp!.search = true;
930              this.progressEL!.loading = true;
931              this.litSearch!.clear();
932              this.litSearch!.setPercent(`tracing  ${this.recordSetting!.maxDur * 1000}ms`, -1);
933              this.buttonDisable(true);
934              this.freshMenuDisable(true);
935              this.freshConfigMenuDisable(true);
936              if (SpApplication.isLongTrace) {
937                HdcDeviceManager.shellResultAsString(
938                  CmdConstant.CMD_CLEAR_LONG_FOLD + this.recordSetting!.longOutPath,
939                  false
940                ).then(() => {
941                  HdcDeviceManager.shellResultAsString(
942                    CmdConstant.CMD_MKDIR_LONG_FOLD + this.recordSetting!.longOutPath,
943                    false
944                  ).then(() => {
945                    this.recordLongTraceCmd(traceCommandStr);
946                  });
947                });
948              } else {
949                this.recordTraceCmd(traceCommandStr);
950              }
951            });
952          });
953        } catch (e) {
954          this.freshMenuDisable(false);
955          this.freshConfigMenuDisable(false);
956          this.buttonDisable(false);
957        }
958      } else {
959        this.sp!.search = true;
960        this.litSearch!.clear();
961        this.litSearch!.setPercent('please kill other hdc-server !', -2);
962      }
963    });
964  }
965
966  recordButtonListener(): void {
967    SpRecordTrace.cancelRecord = false;
968    let request = this.makeRequest();
969    this.showHint = true;
970    if (request.pluginConfigs.length === 0) {
971      this.hintEl!.textContent = 'It looks like you didn\'t add any probes. Please add at least one';
972      return;
973    }
974    this.showHint = false;
975    let traceCommandStr = PluginConvertUtils.createHdcCmd(
976      PluginConvertUtils.BeanToCmdTxt(request, false),
977      this.recordSetting!.output,
978      this.recordSetting!.maxDur
979    );
980    let pluginList: Array<string> = [];
981    request.pluginConfigs.forEach((pluginConfig) => {
982      pluginList.push(pluginConfig.pluginName);
983    });
984    SpStatisticsHttpUtil.addOrdinaryVisitAction({
985      action: 'config_page',
986      event: 'online_record',
987      eventData: {
988        plugin: pluginList,
989      },
990    });
991    let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement;
992    if (selectedOption) {
993      SpRecordTrace.serialNumber = selectedOption.value;
994    } else {
995      this.sp!.search = true;
996      this.litSearch!.clear();
997      this.progressEL!.loading = false;
998      this.litSearch!.setPercent('please connect device', -2);
999    }
1000    if (this.vs) {
1001      this.appContent!.innerHTML = '';
1002      this.appContent!.append(this.traceCommand!);
1003      this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd(
1004        PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false),
1005        this.recordSetting!.output,
1006        this.recordSetting!.maxDur
1007      );
1008      this.freshMenuItemsStatus('Trace command');
1009      this.vsCodeRecordCmd(traceCommandStr);
1010    } else {
1011      this.webRecordCmd(traceCommandStr, selectedOption);
1012    }
1013  }
1014
1015  private recordTraceCmd(traceCommandStr: string): void {
1016    HdcDeviceManager.shellResultAsString(CmdConstant.CMD_SHELL + traceCommandStr, false).then((traceResult) => {
1017      let re = this.isSuccess(traceResult);
1018      if (re === 0) {
1019        this.litSearch!.setPercent('Tracing htrace down', -1);
1020        HdcDeviceManager.shellResultAsString(CmdConstant.CMD_TRACE_FILE_SIZE + this.recordSetting!.output, false).then(
1021          (traceFileSize) => {
1022            this.litSearch!.setPercent(`TraceFileSize is ${traceFileSize}`, -1);
1023            if (traceFileSize.indexOf('No such') !== -1) {
1024              this.refreshDisableStyle(false, true, 'No such file or directory', -2);
1025            } else if (Number(traceFileSize) <= MaxFileSize) {
1026              HdcDeviceManager.fileRecv(this.recordSetting!.output, (perNumber: number) => {
1027                this.litSearch!.setPercent('Downloading Hitrace file ', perNumber);
1028              }).then((pullRes) => {
1029                this.litSearch!.setPercent('Downloading Hitrace file ', 101);
1030                pullRes.arrayBuffer().then((buffer) => {
1031                  let fileName = this.recordSetting!.output.substring(this.recordSetting!.output.lastIndexOf('/') + 1);
1032                  let file = new File([buffer], fileName);
1033                  let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu;
1034                  let children = main.menus as Array<MenuGroup>;
1035                  let child = children[0].children as Array<MenuItem>;
1036                  let fileHandler = child[0].fileHandler;
1037                  if (fileHandler && !SpRecordTrace.cancelRecord) {
1038                    this.refreshDisableStyle(false, false);
1039                    fileHandler({
1040                      detail: file,
1041                    });
1042                  } else {
1043                    SpRecordTrace.cancelRecord = false;
1044                  }
1045                });
1046              });
1047            } else {
1048              this.recordButtonText!.textContent = this.record;
1049              this.refreshDisableStyle(false, true, 'Htrace file is too big', -2);
1050            }
1051          }
1052        );
1053      } else if (re === 2) {
1054        this.refreshDisableStyle(false, true, 'Stop tracing htrace ', -1);
1055      } else if (re === -1) {
1056        this.refreshDisableStyle(false, true, 'The device is abnormal', -2);
1057        this.progressEL!.loading = false;
1058      } else {
1059        this.refreshDisableStyle(false, true, 'Tracing htrace failed, please check your config ', -2);
1060      }
1061    });
1062  }
1063
1064  private recordLongTraceCmd(traceCommandStr: string): void {
1065    HdcDeviceManager.shellResultAsString(CmdConstant.CMD_SHELL + traceCommandStr, false).then((traceResult) => {
1066      let re = this.isSuccess(traceResult);
1067      if (re === 0) {
1068        this.litSearch!.setPercent('tracing htrace down', -1);
1069        HdcDeviceManager.shellResultAsString(
1070          CmdConstant.CMD_TRACE_FILE_SIZE + this.recordSetting!.longOutPath,
1071          false
1072        ).then((traceFileSize) => {
1073          this.litSearch!.setPercent(`traceFileSize is ${traceFileSize}`, -1);
1074          if (traceFileSize.indexOf('No such') !== -1) {
1075            this.litSearch!.setPercent('No such file or directory', -2);
1076            this.buttonDisable(false);
1077            this.freshConfigMenuDisable(false);
1078            this.freshMenuDisable(false);
1079          } else {
1080            this.recordLongTrace();
1081          }
1082        });
1083      } else if (re === 2) {
1084        this.refreshDisableStyle(false, true, 'stop tracing htrace ', -1);
1085      } else if (re === -1) {
1086        this.refreshDisableStyle(false, true, 'The device is abnormal', -2);
1087        this.progressEL!.loading = false;
1088      } else {
1089        this.refreshDisableStyle(false, true, 'tracing htrace failed, please check your config ', -2);
1090      }
1091    });
1092  }
1093
1094  private refreshDisableStyle(
1095    disable: boolean,
1096    isFreshSearch: boolean,
1097    percentName?: string,
1098    percentValue?: number
1099  ): void {
1100    if (isFreshSearch) {
1101      this.litSearch!.setPercent(percentName, percentValue!);
1102    }
1103    this.recordButtonDisable(disable);
1104    this.freshConfigMenuDisable(disable);
1105    this.freshMenuDisable(disable);
1106    this.buttonDisable(disable);
1107  }
1108
1109  private getLongTraceTypePage(): Array<number> {
1110    let traceTypePage: Array<number> = [];
1111    for (let fileIndex = 0; fileIndex < this.longTraceList.length; fileIndex++) {
1112      let traceFileName = this.longTraceList[fileIndex];
1113      if (this.sp!.fileTypeList.some((fileType) => traceFileName.toLowerCase().includes(fileType))) {
1114        continue;
1115      }
1116      let firstLastIndexOf = traceFileName.lastIndexOf('.');
1117      let firstText = traceFileName.slice(0, firstLastIndexOf);
1118      let resultLastIndexOf = firstText.lastIndexOf('_');
1119      traceTypePage.push(Number(firstText.slice(resultLastIndexOf + 1, firstText.length)) - 1);
1120    }
1121    traceTypePage.sort((leftNum: number, rightNum: number) => leftNum - rightNum);
1122    return traceTypePage;
1123  }
1124
1125  private loadLongTraceFile(timStamp: number) {
1126    return new Promise(async (resolve) => {
1127      let traceTypePage = this.getLongTraceTypePage();
1128      for (let fileIndex = 0; fileIndex < this.longTraceList.length; fileIndex++) {
1129        if (this.longTraceList[fileIndex] !== '') {
1130          let types = this.sp!.fileTypeList.filter((type) =>
1131            this.longTraceList[fileIndex].toLowerCase().includes(type.toLowerCase())
1132          );
1133          let pageNumber = 0;
1134          let fileType = types[0];
1135          if (types.length === 0) {
1136            fileType = 'trace';
1137            let searchNumber =
1138              Number(
1139                this.longTraceList[fileIndex].substring(
1140                  this.longTraceList[fileIndex].lastIndexOf('_') + 1,
1141                  this.longTraceList[fileIndex].lastIndexOf('.')
1142                )
1143              ) - 1;
1144            pageNumber = traceTypePage.lastIndexOf(searchNumber);
1145          }
1146          let pullRes = await HdcDeviceManager.fileRecv(
1147            this.recordSetting!.longOutPath + this.longTraceList[fileIndex],
1148            (perNumber: number) => {
1149              this.litSearch!.setPercent(`downloading ${fileType} file `, perNumber);
1150            }
1151          );
1152          this.litSearch!.setPercent(`downloading ${fileType} file `, 101);
1153          let buffer = await pullRes.arrayBuffer();
1154          let chunks = Math.ceil(buffer.byteLength / indexDBMaxSize);
1155          let offset = 0;
1156          let sliceLen = 0;
1157          let message = {
1158            fileType: '',
1159            startIndex: 0,
1160            endIndex: 0,
1161            size: 0,
1162          };
1163          for (let chunkIndex = 0; chunkIndex < chunks; chunkIndex++) {
1164            let start = chunkIndex * indexDBMaxSize;
1165            let end = Math.min(start + indexDBMaxSize, buffer.byteLength);
1166            let chunk = buffer.slice(start, end);
1167            if (chunkIndex === 0) {
1168              message.fileType = fileType;
1169              message.startIndex = chunkIndex;
1170            }
1171            sliceLen = Math.min(buffer.byteLength - offset, indexDBMaxSize);
1172            if (chunkIndex === 0 && fileType === 'trace') {
1173              this.sp!.longTraceHeadMessageList.push({
1174                pageNum: pageNumber,
1175                data: buffer.slice(offset, kbSize),
1176              });
1177            }
1178            this.sp!.longTraceDataList.push({
1179              index: chunkIndex,
1180              fileType: fileType,
1181              pageNum: pageNumber,
1182              startOffsetSize: offset,
1183              endOffsetSize: offset + sliceLen,
1184            });
1185            await LongTraceDBUtils.getInstance().indexedDBHelp.add(LongTraceDBUtils.getInstance().tableName, {
1186              buf: chunk,
1187              id: `${fileType}_${timStamp}_${pageNumber}_${chunkIndex}`,
1188              fileType: fileType,
1189              pageNum: pageNumber,
1190              startOffset: offset,
1191              endOffset: offset + sliceLen,
1192              index: chunkIndex,
1193              timStamp: timStamp,
1194            });
1195            offset += sliceLen;
1196            if (offset >= buffer.byteLength) {
1197              message.endIndex = chunkIndex;
1198              message.size = buffer.byteLength;
1199              this.longTraceFileMapHandler(pageNumber, message);
1200            }
1201          }
1202        }
1203      }
1204      resolve(1);
1205    });
1206  }
1207
1208  private longTraceFileMapHandler(pageNumber: number, message: {
1209    fileType: string,
1210    startIndex: number,
1211    endIndex: number,
1212    size: number,
1213  }): void {
1214    if (this.sp!.longTraceTypeMessageMap) {
1215      if (this.sp!.longTraceTypeMessageMap?.has(pageNumber)) {
1216        let oldTypeList = this.sp!.longTraceTypeMessageMap?.get(pageNumber);
1217        oldTypeList?.push(message);
1218        this.sp!.longTraceTypeMessageMap?.set(pageNumber, oldTypeList!);
1219      } else {
1220        this.sp!.longTraceTypeMessageMap?.set(pageNumber, [message]);
1221      }
1222    } else {
1223      this.sp!.longTraceTypeMessageMap = new Map();
1224      this.sp!.longTraceTypeMessageMap.set(pageNumber, [message]);
1225    }
1226  }
1227
1228  private recordLongTrace(): void {
1229    let querySelector = this.sp!.shadowRoot?.querySelector('.long_trace_page') as HTMLDivElement;
1230    if (querySelector) {
1231      querySelector.style.display = 'none';
1232    }
1233    HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_LONG_FILES + this.recordSetting!.longOutPath, false).then(
1234      (result) => {
1235        this.longTraceList = result.split('\n').filter((fileName) => Boolean(fileName));
1236        if (this.longTraceList.length > 0) {
1237          this.sp!.longTraceHeadMessageList = [];
1238          this.sp!.longTraceDataList = [];
1239          this.sp!.longTraceTypeMessageMap = undefined;
1240          let timStamp = new Date().getTime();
1241          this.loadLongTraceFile(timStamp).then(() => {
1242            let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu;
1243            let children = main.menus as Array<MenuGroup>;
1244            let child = children[0].children as Array<MenuItem>;
1245            let fileHandler = child[1].clickHandler;
1246            if (fileHandler && !SpRecordTrace.cancelRecord) {
1247              this.freshConfigMenuDisable(false);
1248              this.freshMenuDisable(false);
1249              this.buttonDisable(false);
1250              this.recordButtonDisable(false);
1251              fileHandler(
1252                {
1253                  detail: {
1254                    timeStamp: timStamp,
1255                  },
1256                },
1257                true
1258              );
1259            } else {
1260              SpRecordTrace.cancelRecord = false;
1261            }
1262          });
1263        }
1264      }
1265    );
1266  }
1267
1268  private initRecordUIState(): void {
1269    this.buttonDisable(true);
1270    this.freshMenuDisable(true);
1271    this.freshConfigMenuDisable(true);
1272  }
1273
1274  private isSuccess(traceResult: string): number {
1275    if (traceResult.indexOf('CreateSession FAIL') !== -1 || traceResult.indexOf('failed') !== -1) {
1276      return 1;
1277    } else if (traceResult.indexOf('Signal') !== -1) {
1278      return 2;
1279    } else if (traceResult.indexOf('signal(2)') !== -1) {
1280      return 0;
1281    } else if (traceResult.indexOf('The device is abnormal') !== -1) {
1282      return -1;
1283    } else {
1284      return 0;
1285    }
1286  }
1287
1288  private makeRequest = (): CreateSessionRequest => {
1289    let request = createSessionRequest(this.recordSetting!);
1290    if (this.record_template) {
1291      let templateConfigs = this.spRecordTemplate?.getTemplateConfig();
1292      templateConfigs?.forEach((config) => {
1293        request.pluginConfigs.push(config);
1294      });
1295    } else {
1296      if (SpApplication.isLongTrace && request.sessionConfig) {
1297        request.sessionConfig.splitFile = true;
1298        request.sessionConfig!.splitFileMaxSizeMb = this.recordSetting!.longTraceSingleFileMaxSize;
1299        request.sessionConfig!.splitFileMaxNum = 20;
1300      }
1301      let reportingFrequency: number = 5;
1302      if (this.recordSetting!.maxDur <= 20) {
1303        reportingFrequency = 2;
1304      }
1305      createHTracePluginConfig(this.probesConfig!, request);
1306      createFpsPluginConfig(this.probesConfig!, request);
1307      createMonitorPlugin(this.probesConfig!, request);
1308      createMemoryPluginConfig(reportingFrequency, this.spVmTracker!, this.probesConfig!, request);
1309      createNativePluginConfig(reportingFrequency, this.spAllocations!, SpRecordTrace.selectVersion, request);
1310      createHiPerfConfig(reportingFrequency, this.spRecordPerf!, this.recordSetting!, request);
1311      createSystemConfig(this.spFileSystem!, this.recordSetting!, request);
1312      createSdkConfig(this.spSdkConfig!, request);
1313      createHiSystemEventPluginConfig(this.spHiSysEvent!, request);
1314      createArkTsConfig(this.spArkTs!, this.recordSetting!, request);
1315      createHiLogConfig(reportingFrequency, this.spHiLog!, request);
1316    }
1317    return request;
1318  };
1319
1320  initHtml(): string {
1321    return SpRecordTraceHtml;
1322  }
1323
1324  private freshConfigMenuDisable(disable: boolean): void {
1325    let querySelectors = this.shadowRoot?.querySelectorAll<LitMainMenuItem>('lit-main-menu-item');
1326    querySelectors!.forEach((item) => {
1327      if (item.title !== 'Hdc Shell') {
1328        if (disable) {
1329          item.style.pointerEvents = 'none';
1330        } else {
1331          item.style.pointerEvents = 'auto';
1332        }
1333        item.disabled = disable;
1334      }
1335    });
1336  }
1337
1338  public startRefreshDeviceList(): void {
1339    if (this.refreshDeviceTimer === undefined) {
1340      this.refreshDeviceTimer = window.setInterval((): void => {
1341        this.refreshDeviceList();
1342      }, 5000);
1343    }
1344  }
1345
1346  private recordButtonDisable(disable: boolean): void {
1347    this.recordButton!.style.pointerEvents = disable ? 'none' : 'auto';
1348  }
1349
1350  private buttonDisable(disable: boolean): void {
1351    let pointerEventValue = 'auto';
1352    this.recordButtonText!.textContent = this.record;
1353    if (disable) {
1354      pointerEventValue = 'none';
1355      this.recordButtonText!.textContent = this.stop;
1356    }
1357    this.cancelButtonShow(disable);
1358    this.disconnectButton!.style.pointerEvents = pointerEventValue;
1359    this.addButton!.style.pointerEvents = pointerEventValue;
1360    this.deviceSelect!.style.pointerEvents = pointerEventValue;
1361    this.deviceVersion!.style.pointerEvents = pointerEventValue;
1362  }
1363
1364  private freshMenuItemsStatus(currentValue: string): void {
1365    let litMainMenuGroup = this.shadowRoot?.querySelector<LitMainMenuGroup>('lit-main-menu-group');
1366    let litMainMenuItemNodeListOf = litMainMenuGroup!.querySelectorAll<LitMainMenuItem>('lit-main-menu-item');
1367    litMainMenuItemNodeListOf.forEach((item) => {
1368      item.back = item.title === currentValue;
1369    });
1370  }
1371
1372  synchronizeDeviceList(): void {
1373    this.deviceSelect!.innerHTML = '';
1374    if (SpRecordTrace.serialNumber !== '') {
1375      let option = document.createElement('option');
1376      option.className = 'select';
1377      option.selected = true;
1378      option.value = SpRecordTrace.serialNumber;
1379      option.textContent = SpRecordTrace.serialNumber;
1380      this.deviceSelect!.appendChild(option);
1381      this.recordButton!.hidden = false;
1382      this.disconnectButton!.hidden = false;
1383      this.devicePrompt!.innerText = '';
1384      if (SpRecordTrace.selectVersion && SpRecordTrace.selectVersion !== '') {
1385        this.setDeviceVersionSelect(SpRecordTrace.selectVersion);
1386      }
1387    }
1388  }
1389}
1390
1391const kbSize = 1024;
1392const timeOut = 200;
1393const unitSize = 48;
1394const indexDBMaxSize = unitSize * kbSize * kbSize;
1395export const MaxFileSize: number = kbSize * kbSize * kbSize;
1396