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