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