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/base/ShadowRootInput'; 71import { WebSocketManager } from '../../webSocket/WebSocketManager'; 72import { TypeConstants } from '../../webSocket/Constants'; 73import { LitCheckBox } from '../../base-ui/checkbox/LitCheckBox'; 74const DEVICE_NOT_CONNECT = 75 '<div>1.请确认抓取设备上是否已勾选并确认总是允许smartPerf-Host调试的弹窗</div>' + 76 '<div>2.请关闭DevEco Studio,DevEco Testing等会占用hdc端口的应用</div>' + 77 '<div>3.确保PC端任务管理器中没有hdc进程。方法1、请使用系统管理员权限打开cmd窗口,并执行hdc kill;<br/>方法2、打开任务管理器,进入详情信息页面,找到 hdc.exe 然后结束此进程;</div>' + 78 '<div>4.若没有效果,请重新插拔一下手机。紧急情况可拷贝trace命令,在cmd窗口离线抓取</div>'; 79 80@element('sp-record-trace') 81export class SpRecordTrace extends BaseElement { 82 public static serialNumber: string = ''; 83 public static selectVersion: string | null; 84 public static isVscode = false; 85 public static cancelRecord = false; 86 static supportVersions = ['3.2', '4.0+', '5.0+']; 87 public deviceSelect: HTMLSelectElement | undefined; 88 public deviceVersion: HTMLSelectElement | undefined; 89 private _menuItems: Array<MenuItem> | undefined; 90 private recordButtonText: HTMLSpanElement | undefined; 91 private devicePrompt: HTMLSpanElement | undefined; 92 private recordButton: LitButton | undefined; 93 private cancelButton: LitButton | undefined; 94 private sp: SpApplication | undefined; 95 private progressEL: LitProgressBar | undefined; 96 private litSearch: LitSearch | undefined; 97 private addButton: LitButton | undefined | null; 98 private disconnectButton: LitButton | undefined | null; 99 private recordSetting: SpRecordSetting | undefined; 100 private probesConfig: SpProbesConfig | undefined; 101 private traceCommand: SpTraceCommand | undefined; 102 private spAllocations: SpAllocations | undefined; 103 private spRecordPerf: SpRecordPerf | undefined; 104 private spFileSystem: SpFileSystem | undefined; 105 private spSdkConfig: SpSdkConfig | undefined; 106 private spVmTracker: SpVmTracker | undefined; 107 private spHiSysEvent: SpHisysEvent | undefined; 108 private spRecordTemplate: SpRecordTemplate | undefined; 109 private spArkTs: SpArkTs | undefined; 110 private spHiLog: SpHilogRecord | undefined; 111 private spXPower: SpXPowerRecord | undefined; 112 private spFFRTConfig: SpFFRTConfig | undefined; 113 private ftraceSlider: LitSlider | undefined | null; 114 private spWebShell: SpWebHdcShell | undefined; 115 private menuGroup: LitMainMenuGroup | undefined | null; 116 private appContent: HTMLElement | undefined | null; 117 private optionNum: number = 0; 118 private record = 'Record'; 119 private stop = 'StopRecord'; 120 private nowChildItem: HTMLElement | undefined; 121 private longTraceList: Array<string> = []; 122 private fileList: Array<{ 123 fileName: string, 124 file: File 125 }> = []; 126 private refreshDeviceTimer: number | undefined; 127 private hintEl: HTMLSpanElement | undefined; 128 private selectedTemplate: Map<string, number> = new Map(); 129 private hintTimeOut: number = -1; 130 private MenuItemArkts: MenuItem | undefined | null; 131 private MenuItemArktsHtml: LitMainMenuItem | undefined | null; 132 private hdcList: Array<unknown> = []; 133 public useExtendCheck: LitCheckBox | undefined | null; 134 public static useExtend = false; 135 private useExtentTip: HTMLElement | undefined | null; 136 private usbSerialNum: Array<string> = []; 137 public static allProcessListStr: string; 138 public static usbGetCpuCount: string; 139 public static usbGetEvent: string; 140 public static usbGetApp: string; 141 private static usbGetVersion: string; 142 public static usbGetHisystem: string; 143 static snapShotList: Array<unknown> = []; 144 static snapShotDuration: number = 0; 145 static isSnapShotCapture: boolean = false; 146 147 set record_template(re: string) { 148 if (re === 'true') { 149 this.setAttribute('record_template', 'true'); 150 } else { 151 this.setAttribute('record_template', 'false'); 152 } 153 if (this.recordSetting) { 154 this.recordSetting.isRecordTemplate = re === 'true' ? true : false; 155 } 156 } 157 158 get record_template(): string { 159 return this.getAttribute('record_template')!; 160 } 161 162 set vs(vs: boolean) { 163 if (vs) { 164 SpRecordTrace.isVscode = true; 165 this.setAttribute('vs', ''); 166 } else { 167 SpRecordTrace.isVscode = false; 168 this.removeAttribute('vs'); 169 } 170 } 171 172 get vs(): boolean { 173 return this.hasAttribute('vs'); 174 } 175 176 private compareArray(devs: Array<string>): boolean { 177 let clearFlag: boolean = false; 178 if (devs.length !== this.deviceSelect!.options.length) { 179 clearFlag = true; 180 } else { 181 let optionArray: string[] = []; 182 for (let index = 0; index < this.deviceSelect!.options.length; index++) { 183 optionArray.push(this.deviceSelect!.options[index].value); 184 } 185 devs.forEach((value): void => { 186 if (optionArray.indexOf(value) === -1) { 187 clearFlag = true; 188 } 189 }); 190 } 191 return clearFlag; 192 } 193 194 private async refreshDeviceList(sn?: unknown): Promise<void> { 195 if (this.vs) { 196 this.refreshDeviceListByVs(); 197 } else { 198 this.deviceSelect!.innerHTML = ''; 199 // @ts-ignore 200 HdcDeviceManager.getDevices().then(async (devs: USBDevice[]) => { 201 if (devs.length === 0) { 202 this.recordButton!.hidden = true; 203 this.disconnectButton!.hidden = true; 204 this.cancelButton!.hidden = true; 205 this.devicePrompt!.innerText = 'Device not connected'; 206 this.hintEl!.innerHTML = DEVICE_NOT_CONNECT; 207 if (!this.showHint) { 208 this.showHint = true; 209 } 210 } 211 this.hdcList = devs; 212 let optionNum = 0; 213 for (let len = 0; len < devs.length; len++) { 214 let dev = devs[len]; 215 let option = document.createElement('option'); 216 option.className = 'select'; 217 if (typeof dev.serialNumber === 'string') { 218 optionNum++; 219 option.value = dev.serialNumber; 220 option.textContent = dev!.serialNumber ? dev!.serialNumber!.toString() : 'hdc Device'; 221 this.deviceSelect!.appendChild(option); 222 if (dev.serialNumber === sn) { 223 option.selected = true; 224 this.recordButton!.hidden = false; 225 this.disconnectButton!.hidden = false; 226 this.cancelButton!.hidden = true; 227 this.showHint = false; 228 this.devicePrompt!.innerText = ''; 229 this.hintEl!.textContent = ''; 230 SpRecordTrace.serialNumber = option.value; 231 this.refreshDeviceVersion(option); 232 } 233 } 234 } 235 if (!optionNum) { 236 this.deviceSelect!.style!.border = '2px solid red'; 237 setTimeout(() => { 238 this.deviceSelect!.style!.border = '1px solid #4D4D4D'; 239 }, 3000); 240 this.recordButton!.hidden = true; 241 this.disconnectButton!.hidden = true; 242 this.cancelButton!.hidden = true; 243 this.devicePrompt!.innerText = 'Device not connected'; 244 this.hintEl!.innerHTML = DEVICE_NOT_CONNECT; 245 if (!this.showHint) { 246 this.showHint = true; 247 } 248 } 249 }); 250 } 251 } 252 private refreshDeviceVersion(option: HTMLOptionElement): void { 253 HdcDeviceManager.connect(option.value).then(async (result) => { 254 if (result) { 255 if (this.MenuItemArkts && this.MenuItemArktsHtml) {//连接成功后,arkts开关置灰不能点击 256 this.MenuItemArktsHtml.style.color = 'gray'; 257 this.MenuItemArktsHtml.disabled = true; 258 if (this.MenuItemArkts.clickHandler) { 259 this.MenuItemArkts.clickHandler = undefined; 260 } 261 } 262 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_VERSION, false).then((version) => { 263 SpRecordTrace.selectVersion = this.getDeviceVersion(version); 264 this.setDeviceVersionSelect(SpRecordTrace.selectVersion); 265 this.nativeMemoryHideBySelectVersion(); 266 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 267 PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), 268 this.recordSetting!.output, 269 this.recordSetting!.maxDur 270 ); 271 if (this.nowChildItem === this.spWebShell) { 272 window.publish(window.SmartEvent.UI.DeviceConnect, option.value); 273 } 274 }); 275 } else { 276 SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; 277 this.setDeviceVersionSelect(SpRecordTrace.selectVersion); 278 this.nativeMemoryHideBySelectVersion(); 279 let cmdTxt = PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false); 280 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 281 cmdTxt, 282 this.recordSetting!.output, 283 this.recordSetting!.maxDur 284 ); 285 } 286 }); 287 } 288 private refreshDeviceListByVs(): void { 289 Cmd.execHdcCmd(CmdConstant.CMD_HDC_DEVICES, (res: string) => { 290 let devs: string[] = res.trim().replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); 291 if (devs.length === 1 && devs[0].indexOf('Empty') !== -1) { 292 this.deviceSelect!.innerHTML = ''; 293 return; 294 } 295 let clearFlag = this.compareArray(devs); 296 if (clearFlag) { 297 this.deviceSelect!.innerHTML = ''; 298 if (devs.length === 0) { 299 this.recordButton!.hidden = true; 300 this.disconnectButton!.hidden = true; 301 this.devicePrompt!.innerText = 'Device not connected'; 302 } 303 for (let i = 0; i < devs.length; i++) { 304 let dev = devs[i]; 305 let option = document.createElement('option'); 306 option.className = 'select'; 307 option.textContent = dev; 308 this.deviceSelect!.appendChild(option); 309 if (i === 0) { 310 option.selected = true; 311 this.recordButton!.hidden = false; 312 this.disconnectButton!.hidden = false; 313 SpRecordTrace.serialNumber = option.value; 314 this.devicePrompt!.innerText = ''; 315 } 316 } 317 } 318 }); 319 } 320 321 private getDeviceVersion(version: string): string { 322 if (version.indexOf('3.2') !== -1) { 323 return '3.2'; 324 } else if (version.indexOf('4.') !== -1) { 325 return '4.0+'; 326 } else if (version.indexOf('5.') !== -1) { 327 return '5.0+'; 328 } 329 return '3.2'; 330 } 331 332 private freshMenuDisable(disable: boolean): void { 333 let mainMenu = this.sp!.shadowRoot?.querySelector('#main-menu') as LitMainMenu; 334 mainMenu.menus?.forEach((men): void => { 335 // @ts-ignore 336 men.children.forEach((child: HTMLElement): void => { 337 // @ts-ignore 338 child.disabled = disable; 339 }); 340 }); 341 mainMenu.menus = mainMenu.menus; 342 } 343 344 refreshConfig(isTraceConfig: boolean): void { 345 let recordSettingEl = this.shadowRoot?.querySelector('record-setting') as SpRecordSetting; 346 if (recordSettingEl) { 347 if (isTraceConfig) { 348 recordSettingEl.setAttribute('trace_config', ''); 349 } else { 350 if (recordSettingEl.hasAttribute('trace_config')) { 351 recordSettingEl.removeAttribute('trace_config'); 352 } 353 } 354 } 355 } 356 357 refreshHint(): void { 358 let flags = FlagsConfig.getAllFlagConfig(); 359 let showHint = false; 360 for (let i = 0; i < flags.length; i++) { 361 let flag = flags[i]; 362 if (this.selectedTemplate.has(flag.title)) { 363 let selectedOption = flag.switchOptions.filter((option) => { 364 return option.selected; 365 }); 366 if (selectedOption[0].option === 'Disabled') { 367 showHint = true; 368 break; 369 } 370 } 371 } 372 this.showHint = showHint; 373 } 374 375 get showHint(): boolean { 376 return this.hasAttribute('show_hint'); 377 } 378 379 set showHint(bool: boolean) { 380 if (bool) { 381 if (this.hasAttribute('show_hint')) { 382 this.removeAttribute('show_hint'); 383 this.hintTimeOut = window.setTimeout(() => { 384 this.setAttribute('show_hint', ''); 385 }, timeOut); 386 } else { 387 this.setAttribute('show_hint', ''); 388 } 389 } else { 390 if (this.hintTimeOut !== -1) { 391 window.clearTimeout(this.hintTimeOut); 392 this.hintTimeOut = -1; 393 } 394 this.removeAttribute('show_hint'); 395 } 396 } 397 398 initElements(): void { 399 let parentElement = this.parentNode as HTMLElement; 400 if (parentElement) { 401 parentElement.style.overflow = 'hidden'; 402 } 403 this.sp = document.querySelector('sp-application') as SpApplication; 404 if (!this.shadowRoot || !this.sp) { 405 return; 406 } 407 this.initConfigPage(); 408 this.hintEl = this.shadowRoot.querySelector('#hint') as HTMLSpanElement; 409 this.deviceSelect = this.shadowRoot.querySelector('#device-select') as HTMLSelectElement; 410 this.deviceVersion = this.shadowRoot.querySelector('#device-version') as HTMLSelectElement; 411 this.devicePrompt = this.shadowRoot.querySelector('.prompt') as HTMLSpanElement; 412 this.disconnectButton = this.shadowRoot.querySelector<LitButton>('.disconnect'); 413 this.recordButton = this.shadowRoot.querySelector('.record') as LitButton; 414 this.recordButtonText = this.shadowRoot.querySelector('.record_text') as HTMLSpanElement; 415 this.cancelButton = this.shadowRoot.querySelector('.cancel') as LitButton; 416 this.progressEL = this.sp.shadowRoot?.querySelector('.progress') as LitProgressBar; 417 this.litSearch = this.sp.shadowRoot?.querySelector('#lit-record-search') as LitSearch; 418 this.menuGroup = this.shadowRoot.querySelector('#menu-group') as LitMainMenuGroup; 419 this.addButton = this.shadowRoot.querySelector<LitButton>('.add'); 420 if (this.record_template === 'true') { 421 this.buildTemplateTraceItem(); 422 } else { 423 this.buildNormalTraceItem(); 424 } 425 this.initMenuItems(); 426 this.appendDeviceVersion(); 427 if (this.deviceSelect.options && this.deviceSelect.options.length > 0) { 428 this.disconnectButton!.hidden = false; 429 this.recordButton.hidden = false; 430 this.cancelButton!.hidden = false; 431 this.devicePrompt.innerText = ''; 432 } else { 433 this.disconnectButton!.hidden = true; 434 this.recordButton.hidden = true; 435 this.cancelButton!.hidden = true; 436 this.devicePrompt.innerText = 'Device not connected'; 437 } 438 this.useExtendCheck = this.shadowRoot?.querySelector('#use-extend-check') as LitCheckBox; 439 this.useExtentTip = this.shadowRoot?.querySelector('#record_tip') as HTMLElement; 440 this.useExtendCheck?.addEventListener('change', (ev): void => { 441 // @ts-ignore 442 let detail = ev.detail; 443 SpRecordTrace.useExtend = detail.checked; 444 this.initMenuItems(); 445 this.buildNormalTraceItem(); 446 this.usbSerialNum = []; 447 SpRecordTrace.serialNumber = ''; 448 this.recordButton!.hidden = true; 449 this.disconnectButton!.hidden = true; 450 this.cancelButton!.hidden = true; 451 // @ts-ignore 452 while (this.deviceSelect!.firstChild) { 453 this.deviceSelect!.removeChild(this.deviceSelect!.firstChild); // 删除子节点 454 } 455 this.devicePrompt!.innerText = 'Device not connected'; 456 if (!detail.checked) { 457 this.spArkTs!.litSwitch!.checked = false; 458 this.spArkTs!.memoryDisable(); 459 this.spArkTs!.disable(); 460 this.useExtentTip!.style.display = 'none'; 461 this.useExtentTip!.innerHTML = ''; 462 } 463 }); 464 this.spArkTs?.addEventListener('showTip', () => { 465 this.isShowTipFunc('Ark Ts', this.spArkTs!.isStartArkts); 466 }); 467 this.recordSetting?.addEventListener('showTip', (event) => {// @ts-ignore 468 this.isShowTipFunc(event.detail.value, event.detail.isShow); 469 }); 470 } 471 472 isShowTipFunc(text: string, isShow: boolean): void { 473 if (isShow) { 474 let guideSrc = `https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}?action=help_27`; 475 this.useExtentTip!.style.display = 'block'; 476 // @ts-ignore 477 this.useExtentTip!.innerHTML = `若要抓取${text},请勾选 Use local hdc 开关,启动后台扩展服务进行抓取,相关指导: [</span style="cursor: pointer;"><a href=${guideSrc} style="color: blue;" target="_blank">指导</a><span>]`; 478 } else { 479 this.useExtentTip!.style.display = 'none'; 480 this.useExtentTip!.innerHTML = ''; 481 } 482 } 483 484 connectedCallback(): void { 485 super.connectedCallback(); 486 this.addButton!.addEventListener('click', this.addButtonClickEvent); 487 this.deviceSelect!.addEventListener('mousedown', this.deviceSelectMouseDownEvent); 488 this.deviceSelect!.addEventListener('change', this.deviceSelectChangeEvent); 489 this.deviceVersion!.addEventListener('change', this.deviceVersionChangeEvent); 490 this.disconnectButton?.addEventListener('click', this.disconnectButtonClickEvent); 491 this.recordButton?.addEventListener('mousedown', this.recordButtonMouseDownEvent); 492 this.cancelButton?.addEventListener('click', this.cancelRecordListener); 493 this.spRecordPerf?.addEventListener('addProbe', this.recordAddProbeEvent); 494 this.spAllocations?.addEventListener('addProbe', this.recordAddProbeEvent); 495 this.probesConfig?.addEventListener('addProbe', this.recordAddProbeEvent); 496 this.spRecordTemplate?.addEventListener('addProbe', this.recordTempAddProbe); 497 this.spRecordTemplate?.addEventListener('delProbe', this.recordTempDelProbe); 498 } 499 500 disconnectedCallback(): void { 501 super.disconnectedCallback(); 502 this.addButton!.removeEventListener('click', this.addButtonClickEvent); 503 this.deviceSelect!.removeEventListener('mousedown', this.deviceSelectMouseDownEvent); 504 this.deviceSelect!.removeEventListener('change', this.deviceSelectChangeEvent); 505 this.deviceVersion!.removeEventListener('change', this.deviceVersionChangeEvent); 506 this.disconnectButton?.removeEventListener('click', this.disconnectButtonClickEvent); 507 this.recordButton?.removeEventListener('mousedown', this.recordButtonMouseDownEvent); 508 this.cancelButton?.removeEventListener('click', this.cancelRecordListener); 509 this.spRecordPerf?.removeEventListener('addProbe', this.recordAddProbeEvent); 510 this.spAllocations?.removeEventListener('addProbe', this.recordAddProbeEvent); 511 this.probesConfig?.removeEventListener('addProbe', this.recordAddProbeEvent); 512 this.spRecordTemplate?.removeEventListener('addProbe', this.recordTempAddProbe); 513 this.spRecordTemplate?.removeEventListener('delProbe', this.recordTempDelProbe); 514 } 515 516 recordPluginFunc = (): void => { 517 this.useExtentTip!.style.display = 'none'; 518 this.useExtentTip!.innerHTML = ''; 519 520 this.sp!.search = true; 521 this.progressEL!.loading = true; 522 this.litSearch!.setPercent('Waiting to record...', -1); 523 this.initRecordCmdStatus(); 524 let request = this.makeRequest(false); 525 let htraceCmd = PluginConvertUtils.createHdcCmd( 526 PluginConvertUtils.BeanToCmdTxt(request, false), 527 this.recordSetting!.output, 528 this.recordSetting!.maxDur 529 ); 530 531 let encoder = new TextEncoder(); 532 let processName = this.spArkTs!.process.trim(); 533 let isRecordArkTs = (this.spArkTs!.isStartArkts && processName !== '') ? true : false; //是否抓取arkts trace 534 let isRecordHitrace = request.pluginConfigs.length > 0 ? true : false; // 是否抓取其他模块 hitrace 535 536 let isStartCpuProfiler = this.spArkTs!.isStartCpuProfiler; //cpu Profiler 开关是否打开 537 let isStartMemoryProfiler = this.spArkTs!.isStartMemoryProfiler; //memory Profiler 开关是否打开 538 let isCheckSnapshot = this.spArkTs!.radioBoxType === 0 ? true : false; // 是否check snapshot 539 let isCheckTimeLine = this.spArkTs!.radioBoxType === 1 ? true : false; // 是否 check timeline 540 541 let isLongTrace = SpApplication.isLongTrace; 542 let maxDur = this.recordSetting!.maxDur; // 抓取trace的时长 543 let snapShotDur = this.recordSetting!.snapShot;//截图 544 SpRecordTrace.snapShotDuration = snapShotDur; 545 let snapshotTimeInterval = this.spArkTs!.intervalValue; 546 let cpuProfTimeInt = this.spArkTs!.intervalCpuValue; 547 let captureNumericValue = this.spArkTs!.grabNumeric; // snapshot check box 548 let trackAllocations = this.spArkTs!.grabAllocations; // timeline check box 549 let enableCpuProfiler = this.spArkTs!.isStartCpuProfiler; 550 551 let params: unknown = { 552 isLongTrace: isLongTrace, 553 isRecordArkTs: isRecordArkTs, 554 isRecordHitrace: isRecordHitrace, 555 type: '', 556 processName: processName, 557 maxDur: maxDur, 558 snapShotDur: snapShotDur, 559 snapshotTimeInterval: snapshotTimeInterval, 560 cpuProfilerInterval: cpuProfTimeInt, 561 captureNumericValue: captureNumericValue, 562 trackAllocations: trackAllocations, 563 enableCpuProfiler: enableCpuProfiler, 564 htraceCmd: htraceCmd, 565 output: this.recordSetting!.output, 566 serialNum: SpRecordTrace.serialNumber 567 }; 568 569 if (isStartCpuProfiler && !isStartMemoryProfiler) { // @ts-ignore 570 params.type = 'cpuProf'; 571 } else if (!isStartCpuProfiler && isStartMemoryProfiler && isCheckSnapshot) {// @ts-ignore 572 params.type = 'snapshot'; 573 } else if (!isStartCpuProfiler && isStartMemoryProfiler && isCheckTimeLine) {// @ts-ignore 574 params.type = 'timeline'; 575 } else if (isStartCpuProfiler && isStartMemoryProfiler && isCheckSnapshot) {// @ts-ignore 576 params.type = 'cpuProf_snapshot'; 577 } else if (isStartCpuProfiler && isStartMemoryProfiler && isCheckTimeLine) {// @ts-ignore 578 params.type = 'cpuProf_timeline'; 579 } 580 581 let onmessageCallBack = (cmd: number, result: unknown): void => {// @ts-ignore 582 if (cmd === 2 && result.byteLength > 0) { 583 let name = this.recordSetting!.output.split('/').reverse()[0];// @ts-ignore 584 let file = new File([result], name); 585 let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; 586 let children = main.menus as Array<MenuGroup>; 587 let child = children[0].children as Array<MenuItem>; 588 let fileHandler = child[0].fileHandler; 589 if (fileHandler) { 590 this.refreshDisableStyle(false, false); 591 this.recordButton!.hidden = false; 592 this.cancelButton!.hidden = true; 593 fileHandler({ 594 detail: file, 595 }); 596 } 597 } else if (cmd === 3) { 598 this.sp!.search = false; 599 this.progressEL!.loading = false;// @ts-ignore 600 let errorMsg = new TextDecoder().decode(result); 601 this.useExtentTip!.style.display = 'block'; 602 let urlAsciiArr = [104, 116, 116, 112, 115, 58, 47, 47, 119, 105, 107, 105, 46, 104, 117, 97, 119, 101, 105, 46, 99, 111, 109, 47, 100, 111, 109, 97, 105, 110, 115, 47, 55, 54, 57, 49, 49, 47, 119, 105, 107, 105, 47, 49, 50, 53, 52, 56, 48, 47, 87, 73, 75, 73, 50, 48, 50, 53, 48, 49, 49, 54, 53, 55, 53, 48, 52, 53, 52]; 603 let exceptGuid = String.fromCodePoint(...urlAsciiArr); 604 this.useExtentTip!.innerHTML = `抓取trace异常:${errorMsg} 可根据[<span style='cursor:pointer;'><a href=${exceptGuid} syule = 'color:blue;' target='_blank'>常见异常处理</a></span>]解决异常`; 605 this.refreshDisableStyle(false, false); 606 this.recordButton!.hidden = false; 607 this.cancelButton!.hidden = true; 608 this.sp!.search = false; 609 this.progressEL!.loading = false; 610 } else if (cmd === 4) { 611 let aElement = document.createElement('a');// @ts-ignore 612 aElement.href = URL.createObjectURL(new Blob([result!])); 613 aElement.download = 'arkts.htrace'; 614 aElement.click(); 615 } else if (cmd === 5) {// @ts-ignore 616 SpRecordTrace.snapShotList = JSON.parse(new TextDecoder('utf-8').decode(result)) as string[]; 617 SpRecordTrace.isSnapShotCapture = true; 618 } else if (cmd === 6) { 619 this.litSearch!.setPercent('Start to record...', -1); 620 } else if (cmd === 7) { 621 this.litSearch!.setPercent('Tracing htrace down', -1); 622 } else if (cmd === 8) { 623 this.litSearch!.setPercent('Downloading Hitrace file...', -1); 624 } else if (cmd === 9) {// @ts-ignore 625 let re = JSON.parse(new TextDecoder('utf-8').decode(result)); 626 let binaryString = window.atob(re.data); 627 let len = binaryString.length; 628 let bytes = new Uint8Array(len); 629 for (let i = 0; i < len; i++) { 630 bytes[i] = binaryString.charCodeAt(i); 631 } 632 re.data = bytes.buffer; 633 let fileInfo = { 634 fileName: re.fileName, 635 file: new File([re.data], re.fileName) 636 }; 637 this.fileList.push(fileInfo); 638 this.longTraceList.push(fileInfo.fileName); 639 if (this.fileList.length === re.total) { 640 this.openLongTraceHandle(); 641 } 642 } 643 }; 644 WebSocketManager.getInstance()!.registerMessageListener(TypeConstants.ARKTS_TYPE, onmessageCallBack, this.eventCallBack); 645 WebSocketManager.getInstance()!.sendMessage(TypeConstants.ARKTS_TYPE, 1, encoder.encode(JSON.stringify(params))); 646 }; 647 648 async openLongTraceHandle() { 649 this.fileList.sort((a, b) => { 650 const getNumber = (name: string) => { 651 const match = name.match(/_(\d+)\.htrace$/); 652 return match ? parseInt(match[1]) : 0; 653 }; 654 return getNumber(a.fileName) - getNumber(b.fileName); 655 }); 656 let timStamp = new Date().getTime(); 657 this.sp!.longTraceHeadMessageList = []; 658 for (const fileInfo of this.fileList) { 659 await this.saveLongTrace(fileInfo.file, timStamp); 660 } 661 await this.openLongTrace(timStamp); 662 this.fileList = []; 663 this.longTraceList = []; 664 } 665 666 async saveLongTrace(file: File, timStamp: number) { 667 let traceTypePage = this.getLongTraceTypePage(); 668 let types = this.sp!.fileTypeList.filter(type => 669 file.name.toLowerCase().includes(type.toLowerCase()) 670 ); 671 let pageNumber = 0; 672 let fileType = types[0] || 'trace'; 673 if (types.length === 0) { 674 let searchNumber = Number( 675 file.name.substring( 676 file.name.lastIndexOf('_') + 1, 677 file.name.lastIndexOf('.') 678 ) 679 ) - 1; 680 pageNumber = traceTypePage.lastIndexOf(searchNumber); 681 } 682 this.litSearch!.setPercent(`downloading ${fileType} file`, 101); 683 await this.saveIndexDBByLongTrace(file, fileType, pageNumber, timStamp); 684 } 685 686 async openLongTrace(timStamp: number) { 687 let main = this.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; 688 let children = main.menus as Array<MenuGroup>; 689 let child = children[1].children as Array<MenuItem>; 690 let fileHandler = child[0].clickHandler; 691 if (fileHandler && !SpRecordTrace.cancelRecord) { 692 this.freshConfigMenuDisable(false); 693 this.freshMenuDisable(false); 694 this.buttonDisable(false); 695 this.recordButtonDisable(false); 696 fileHandler({ 697 detail: { 698 timeStamp: timStamp 699 } 700 }, true); 701 } else { 702 SpRecordTrace.cancelRecord = false; 703 } 704 } 705 706 recordTempAddProbe = (ev: CustomEventInit<{ elementId: string }>): void => { 707 if ( 708 FlagsConfig.DEFAULT_CONFIG.find((flagItem) => { 709 return flagItem.title === ev.detail!.elementId; 710 }) 711 ) { 712 this.selectedTemplate.set(ev.detail!.elementId, 1); 713 let flagConfig = FlagsConfig.getFlagsConfig(ev.detail!.elementId); 714 if (flagConfig![ev.detail!.elementId] !== 'Enabled') { 715 this.hintEl!.textContent = 'Please open the corresponding Flags tag when parsing'; 716 if (!this.showHint) { 717 this.showHint = true; 718 } 719 } 720 } 721 }; 722 723 recordTempDelProbe = (ev: CustomEventInit<{ elementId: string }>): void => { 724 if ( 725 FlagsConfig.DEFAULT_CONFIG.find((flagItem): boolean => { 726 return flagItem.title === ev.detail!.elementId; 727 }) 728 ) { 729 this.selectedTemplate.delete(ev.detail!.elementId); 730 if (this.selectedTemplate.size === 0) { 731 this.showHint = false; 732 } 733 } 734 }; 735 736 recordAddProbeEvent = (): void => { 737 this.showHint = false; 738 }; 739 740 addButtonClickEvent = (event: MouseEvent): void => { 741 if (SpRecordTrace.useExtend) { 742 this.useExtentTip!.innerHTML = ''; 743 this.useExtentTip!.style.display = 'none'; 744 WebSocketManager.getInstance()!.registerMessageListener(TypeConstants.USB_TYPE, this.webSocketCallBackasync, this.eventCallBack); 745 WebSocketManager.getInstance()!.sendMessage(TypeConstants.USB_TYPE, TypeConstants.USB_SN_CMD); 746 } else if (this.vs) { 747 this.refreshDeviceList(); 748 } else { 749 // @ts-ignore 750 HdcDeviceManager.findDevice().then((usbDevices): void => { 751 log(usbDevices); 752 HdcDeviceManager.connect(usbDevices.serialNumber).then((res) => { 753 if (res) { 754 this.refreshDeviceList(usbDevices.serialNumber); 755 } else { 756 this.recordButton!.hidden = true; 757 this.disconnectButton!.hidden = true; 758 this.cancelButton!.hidden = true; 759 this.devicePrompt!.innerText = 'Device not connected'; 760 this.hintEl!.innerHTML = DEVICE_NOT_CONNECT; 761 if (!this.showHint) { 762 this.showHint = true; 763 } 764 } 765 }); 766 }); 767 } 768 }; 769 770 eventCallBack = (result: string): void => { 771 this.recordButton!.hidden = true; 772 this.disconnectButton!.hidden = true; 773 this.cancelButton!.hidden = true; 774 this.disconnectButtonClickEvent(); 775 this.useExtentTip!.style.display = 'block'; 776 // @ts-ignore 777 this.useExtentTip!.innerHTML = this.getStatusesPrompt()[result].prompt; 778 }; 779 780 getStatusesPrompt(): unknown { 781 let guideSrc = `https://${window.location.host.split(':')[0]}:${window.location.port 782 }${window.location.pathname}?action=help_27`; 783 return { 784 unconnected: { 785 prompt: `未连接,请启动本地扩展程序再试![</span style="cursor: pointer;"><a href=${guideSrc} style="color: blue;" target="_blank">指导</a><span>]` 786 }, // 重连 787 connected: { 788 prompt: '扩展程序连接中,请稍后再试' 789 }, // 中间 790 logined: { 791 prompt: '扩展程序连接中,请稍后再试' 792 }, // 中间 793 loginFailedByLackSession: { 794 prompt: '当前所有会话都在使用中,请释放一些会话再试!' 795 }, // 重连 796 upgrading: { 797 prompt: '扩展程序连接中,请稍后再试!' 798 }, // 中间 799 upgradeSuccess: { 800 prompt: '扩展程序已完成升级,重启中,请稍后再试!' 801 }, // 重连 802 upgradeFailed: { 803 prompt: '刷新页面触发升级,或卸载扩展程序重装!' 804 }, // 重连 805 }; 806 }; 807 808 usbGetVersion(dev: string) { 809 let option = document.createElement('option'); 810 option.className = 'select'; 811 this.optionNum++; 812 // @ts-ignore 813 option.value = dev; 814 // @ts-ignore 815 option.textContent = dev.toString(); 816 this.deviceSelect!.appendChild(option); 817 if (dev.toString() === SpRecordTrace.serialNumber || SpRecordTrace.serialNumber === '') { 818 SpRecordTrace.serialNumber = dev; 819 option.selected = true; 820 this.recordButton!.hidden = false; 821 this.disconnectButton!.hidden = false; 822 this.cancelButton!.hidden = true; 823 this.devicePrompt!.innerText = ''; 824 this.hintEl!.textContent = ''; 825 // @ts-ignore 826 WebSocketManager.getInstance()!.sendMessage(TypeConstants.USB_TYPE, TypeConstants.USB_GET_VERSION, new TextEncoder().encode(dev)); 827 setTimeout(() => { 828 if (SpRecordTrace.usbGetVersion) { 829 SpRecordTrace.selectVersion = this.getDeviceVersion(SpRecordTrace.usbGetVersion); 830 this.setDeviceVersionSelect(SpRecordTrace.selectVersion); 831 this.nativeMemoryHideBySelectVersion(); 832 } 833 }, 1000); 834 } 835 } 836 837 webSocketCallBackasync = (cmd: number, result: Uint8Array): void => { 838 const decoder = new TextDecoder(); 839 const jsonString = decoder.decode(result); 840 let jsonRes = JSON.parse(jsonString); 841 if (cmd === TypeConstants.USB_SN_CMD) { 842 this.hdcList = jsonRes.resultMessage; 843 HdcDeviceManager.findDevice().then((usbDevices): void => { 844 SpRecordTrace.serialNumber = usbDevices.serialNumber; 845 this.usbSerialNum = jsonRes.resultMessage; 846 this.optionNum = 0; 847 if (this.usbSerialNum.length === 1) { 848 if (this.usbSerialNum[0].includes('Empty')) { 849 this.usbSerialNum.shift(); 850 this.recordButton!.hidden = true; 851 this.disconnectButton!.hidden = true; 852 this.cancelButton!.hidden = true; 853 this.devicePrompt!.innerText = 'Device not connected'; 854 this.deviceSelect!.style!.border = '2px solid red'; 855 setTimeout(() => { 856 this.deviceSelect!.style!.border = '1px solid #4D4D4D'; 857 }, 3000); 858 this.useExtentTip!.style.display = 'block'; 859 this.useExtentTip!.innerHTML = '手机连接有问题,请重新插拔一下手机,或者请使用系统管理员权限打开cmd窗口,并执行hdc shell'; 860 return; 861 }else{ 862 this.usbGetVersion(this.usbSerialNum[0]); 863 } 864 }else if(this.usbSerialNum.length > 1 && usbDevices.serialNumber === ''){ 865 this.usbSerialNum.shift(); 866 this.recordButton!.hidden = true; 867 this.disconnectButton!.hidden = true; 868 this.cancelButton!.hidden = true; 869 this.devicePrompt!.innerText = 'Device not connected'; 870 this.deviceSelect!.style!.border = '2px solid red'; 871 setTimeout(() => { 872 this.deviceSelect!.style!.border = '1px solid #4D4D4D'; 873 }, 3000); 874 this.useExtentTip!.style.display = 'block'; 875 this.useExtentTip!.innerHTML = '加密设备仅限连接一台'; 876 return; 877 } 878 // @ts-ignore 879 while (this.deviceSelect!.firstChild) { 880 this.deviceSelect!.removeChild(this.deviceSelect!.firstChild); // 删除子节点 881 } 882 for (let len = 0; len < this.usbSerialNum.length; len++) { 883 let dev = this.usbSerialNum[len]; 884 this.usbGetVersion(dev); 885 } 886 if (!this.optionNum) { 887 this.deviceSelect!.style!.border = '2px solid red'; 888 setTimeout(() => { 889 this.deviceSelect!.style!.border = '1px solid #4D4D4D'; 890 }, 3000); 891 this.recordButton!.hidden = true; 892 this.disconnectButton!.hidden = true; 893 this.cancelButton!.hidden = true; 894 this.devicePrompt!.innerText = 'Device not connected'; 895 this.useExtentTip!.style.display = 'block'; 896 this.useExtentTip!.innerHTML = '手机连接有问题,请重新插拔一下手机,或者请使用系统管理员权限打开cmd窗口,并执行hdc shell'; 897 } 898 }); 899 } else if (cmd === TypeConstants.USB_GET_PROCESS) { 900 // @ts-ignore 901 SpRecordTrace.allProcessListStr = jsonRes.resultMessage; 902 } else if (cmd === TypeConstants.USB_GET_CPU_COUNT) { 903 SpRecordTrace.usbGetCpuCount = jsonRes.resultMessage; 904 } else if (cmd === TypeConstants.USB_GET_EVENT) { 905 SpRecordTrace.usbGetEvent = jsonRes.resultMessage; 906 } else if (cmd === TypeConstants.USB_GET_APP) { 907 SpRecordTrace.usbGetApp = jsonRes.resultMessage; 908 } else if (cmd === TypeConstants.USB_GET_VERSION) { 909 SpRecordTrace.usbGetVersion = jsonRes.resultMessage; 910 } else if (cmd === TypeConstants.USB_GET_HISYSTEM) { 911 SpRecordTrace.usbGetHisystem = jsonRes.resultMessage; 912 } 913 }; 914 915 deviceSelectMouseDownEvent = (evt: MouseEvent): void => { 916 if (this.deviceSelect!.options.length === 0) { 917 evt.preventDefault(); 918 } 919 }; 920 921 deviceSelectChangeEvent = (): void => { 922 if (this.deviceSelect!.options.length > 0) { 923 this.recordButton!.hidden = false; 924 this.disconnectButton!.hidden = false; 925 this.cancelButton!.hidden = false; 926 this.devicePrompt!.innerText = ''; 927 } else { 928 this.recordButton!.hidden = true; 929 this.disconnectButton!.hidden = true; 930 this.cancelButton!.hidden = true; 931 this.devicePrompt!.innerText = 'Device not connected'; 932 } 933 934 if (SpRecordTrace.useExtend) { 935 let deviceItem = this.deviceSelect!.options[this.deviceSelect!.selectedIndex]; 936 let value = deviceItem.value; 937 SpRecordTrace.serialNumber = value; 938 return; 939 } 940 941 let deviceItem = this.deviceSelect!.options[this.deviceSelect!.selectedIndex]; 942 let value = deviceItem.value; 943 SpRecordTrace.serialNumber = value; 944 if (this.vs) { 945 let cmd = Cmd.formatString(CmdConstant.CMD_GET_VERSION_DEVICES, [SpRecordTrace.serialNumber]); 946 Cmd.execHdcCmd(cmd, (deviceVersion: string) => { 947 this.selectedDevice(deviceVersion); 948 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 949 PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), 950 this.recordSetting!.output, 951 this.recordSetting!.maxDur 952 ); 953 }); 954 } else { 955 HdcDeviceManager.connect(value).then((result): void => { 956 if (result) { 957 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_VERSION, true).then((deviceVersion) => { 958 this.selectedDevice(deviceVersion); 959 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 960 PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), 961 this.recordSetting!.output, 962 this.recordSetting!.maxDur 963 ); 964 if (this.nowChildItem === this.spWebShell) { 965 window.publish(window.SmartEvent.UI.DeviceConnect, value); 966 } 967 }); 968 } else { 969 SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; 970 this.setDeviceVersionSelect(SpRecordTrace.selectVersion); 971 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 972 PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), 973 this.recordSetting!.output, 974 this.recordSetting!.maxDur 975 ); 976 } 977 }); 978 } 979 }; 980 981 deviceVersionChangeEvent = (): void => { 982 let versionItem = this.deviceVersion!.options[this.deviceVersion!.selectedIndex]; 983 SpRecordTrace.selectVersion = versionItem.getAttribute('device-version'); 984 this.spAllocations!.startup_mode = false; 985 this.spAllocations!.recordJsStack = false; 986 this.nativeMemoryHideBySelectVersion(); 987 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 988 PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), 989 this.recordSetting!.output, 990 this.recordSetting!.maxDur 991 ); 992 }; 993 994 disconnectButtonClickEvent = (): void => { 995 this.setDeviceVersionSelect('5.0+'); 996 let index = this.deviceSelect!.selectedIndex; 997 if (index !== -1 && this.deviceSelect!.options.length > 0) { 998 for (let i = 0; i < this.deviceSelect!.options.length; i++) { 999 let selectOption = this.deviceSelect!.options[i]; 1000 let value = selectOption.value; 1001 HdcDeviceManager.disConnect(value).then((): void => { 1002 this.deviceSelect!.removeChild(selectOption); 1003 if (this.nowChildItem === this.spWebShell) { 1004 window.publish(window.SmartEvent.UI.DeviceDisConnect, value); 1005 } 1006 let options = this.deviceSelect!.options; 1007 if (options.length <= 0) { 1008 this.recordButton!.hidden = true; 1009 this.disconnectButton!.hidden = true; 1010 this.cancelButton!.hidden = true; 1011 this.devicePrompt!.innerText = 'Device not connected'; 1012 this.sp!.search = false; 1013 SpRecordTrace.serialNumber = ''; 1014 } 1015 }); 1016 } 1017 } 1018 }; 1019 1020 recordButtonMouseDownEvent = (event: MouseEvent): void => { 1021 if (event.button === 0) { 1022 if (this.recordButtonText!.textContent === this.record) { 1023 this.recordButtonListener(); 1024 } else { 1025 this.stopRecordListener(); 1026 } 1027 } 1028 }; 1029 1030 private initConfigPage(): void { 1031 this.recordSetting = new SpRecordSetting(); 1032 this.probesConfig = new SpProbesConfig(); 1033 this.traceCommand = new SpTraceCommand(); 1034 this.spAllocations = new SpAllocations(); 1035 this.spRecordPerf = new SpRecordPerf(); 1036 this.spFileSystem = new SpFileSystem(); 1037 this.spSdkConfig = new SpSdkConfig(); 1038 this.spVmTracker = new SpVmTracker(); 1039 this.spHiSysEvent = new SpHisysEvent(); 1040 this.spArkTs = new SpArkTs(); 1041 this.spHiLog = new SpHilogRecord(); 1042 this.spXPower = new SpXPowerRecord(); 1043 this.spFFRTConfig = new SpFFRTConfig(); 1044 this.spWebShell = new SpWebHdcShell(); 1045 this.spRecordTemplate = new SpRecordTemplate(this); 1046 this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement; 1047 if (this.record_template === 'true') { 1048 this.appContent.append(this.spRecordTemplate); 1049 } else { 1050 this.appContent.append(this.recordSetting); 1051 } 1052 // @ts-ignore 1053 if (navigator.usb) { 1054 // @ts-ignore 1055 navigator.usb.addEventListener( 1056 'disconnect', 1057 // @ts-ignore 1058 (ev: USBConnectionEvent) => { 1059 this.usbDisConnectionListener(ev); 1060 } 1061 ); 1062 } 1063 } 1064 1065 reConfigPage(): void { 1066 this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement; 1067 this.appContent.innerHTML = ''; 1068 this._menuItems = []; 1069 if (this.record_template === 'true') { 1070 this.appContent.append(this.spRecordTemplate!); 1071 this.buildTemplateTraceItem(); 1072 } else { 1073 this.appContent.append(this.recordSetting!); 1074 this.buildNormalTraceItem(); 1075 } 1076 this.initMenuItems(); 1077 } 1078 1079 private nativeMemoryHideBySelectVersion(): void { 1080 let divConfigs = this.spAllocations?.shadowRoot?.querySelectorAll<HTMLDivElement>('.version-controller'); 1081 if (divConfigs) { 1082 if (SpRecordTrace.selectVersion !== '3.2') { 1083 for (let divConfig of divConfigs) { 1084 divConfig!.style.zIndex = '1'; 1085 } 1086 } else { 1087 for (let divConfig of divConfigs) { 1088 divConfig!.style.zIndex = '-1'; 1089 } 1090 } 1091 } 1092 } 1093 1094 private selectedDevice(deviceVersion: string): void { 1095 SpRecordTrace.selectVersion = this.getDeviceVersion(deviceVersion); 1096 this.setDeviceVersionSelect(SpRecordTrace.selectVersion); 1097 } 1098 1099 private appendDeviceVersion(): void { 1100 SpRecordTrace.supportVersions.forEach((supportVersion) => { 1101 let option = document.createElement('option'); 1102 option.className = 'select'; 1103 option.selected = supportVersion === '5.0+'; 1104 option.textContent = `OpenHarmony-${supportVersion}`; 1105 option.setAttribute('device-version', supportVersion); 1106 this.deviceVersion!.append(option); 1107 SpRecordTrace.selectVersion = '5.0+'; 1108 this.nativeMemoryHideBySelectVersion(); 1109 }); 1110 } 1111 1112 private setDeviceVersionSelect(selected: string): void { 1113 let children = this.deviceVersion!.children; 1114 for (let i = 0; i < children.length; i++) { 1115 let child = children[i] as HTMLOptionElement; 1116 if (child.getAttribute('device-version') === selected) { 1117 child.selected = true; 1118 break; 1119 } 1120 } 1121 } 1122 1123 stopRecordListener(): void { 1124 this.recordButtonText!.textContent = this.record; 1125 this.recordButtonDisable(true); 1126 this.cancelButtonShow(false); 1127 if (this.vs) { 1128 let cmd = Cmd.formatString(CmdConstant.CMS_HDC_STOP, [SpRecordTrace.serialNumber]); 1129 Cmd.execHdcCmd(cmd, (): void => { }); 1130 } else { 1131 let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement; 1132 HdcDeviceManager.connect(selectedOption.value).then((result) => { 1133 if (result) { 1134 try { 1135 HdcDeviceManager.shellResultAsString(CmdConstant.CMS_STOP, true).then((): void => { }); 1136 } catch (exception) { 1137 this.recordButtonDisable(false); 1138 log(exception); 1139 } 1140 } 1141 }); 1142 } 1143 } 1144 1145 cancelRecordListener = (): void => { 1146 this.recordButtonText!.textContent = this.record; 1147 this.cancelButtonShow(false); 1148 if (this.vs) { 1149 let cmd = Cmd.formatString(CmdConstant.CMS_HDC_CANCEL, [SpRecordTrace.serialNumber]); 1150 Cmd.execHdcCmd(cmd, () => { 1151 this.freshMenuDisable(false); 1152 this.freshConfigMenuDisable(false); 1153 this.progressEL!.loading = false; 1154 this.sp!.search = false; 1155 this.litSearch!.clear(); 1156 this.addButton!.style.pointerEvents = 'auto'; 1157 this.deviceSelect!.style.pointerEvents = 'auto'; 1158 this.disconnectButton!.style.pointerEvents = 'auto'; 1159 this.deviceVersion!.style.pointerEvents = 'auto'; 1160 }); 1161 } else { 1162 let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement; 1163 HdcDeviceManager.connect(selectedOption.value).then((result) => { 1164 if (result) { 1165 this.freshMenuDisable(false); 1166 this.freshConfigMenuDisable(false); 1167 try { 1168 this.progressEL!.loading = false; 1169 this.sp!.search = false; 1170 this.litSearch!.clear(); 1171 this.disconnectButton!.style.pointerEvents = 'auto'; 1172 this.addButton!.style.pointerEvents = 'auto'; 1173 this.deviceSelect!.style.pointerEvents = 'auto'; 1174 this.deviceVersion!.style.pointerEvents = 'auto'; 1175 SpRecordTrace.cancelRecord = true; 1176 HdcDeviceManager.stopHiprofiler(CmdConstant.CMS_CANCEL).then((): void => { }); 1177 } catch (exception) { 1178 log(exception); 1179 } 1180 } 1181 }); 1182 } 1183 }; 1184 1185 private cancelButtonShow(show: boolean): void { 1186 if (show) { 1187 this.cancelButton!.style.visibility = 'visible'; 1188 } else { 1189 this.cancelButton!.style.visibility = 'hidden'; 1190 } 1191 } 1192 1193 private traceCommandClickHandler(recordTrace: SpRecordTrace): void { 1194 recordTrace.appContent!.innerHTML = ''; 1195 recordTrace.appContent!.append(recordTrace.traceCommand!); 1196 recordTrace.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 1197 PluginConvertUtils.BeanToCmdTxt(recordTrace.makeRequest(), false), 1198 recordTrace.recordSetting!.output, 1199 recordTrace.recordSetting!.maxDur 1200 ); 1201 recordTrace.freshMenuItemsStatus('Trace command'); 1202 } 1203 1204 private initMenuItems(): void { 1205 this.menuGroup!.innerHTML = ''; 1206 this._menuItems?.forEach((item): void => { 1207 let th = new LitMainMenuItem(); 1208 th.setAttribute('icon', item.icon || ''); 1209 th.setAttribute('title', item.title || ''); 1210 th.style.height = '60px'; 1211 th.style.fontFamily = 'Helvetica-Bold'; 1212 th.style.fontSize = '16px'; 1213 th.style.lineHeight = '28px'; 1214 th.style.fontWeight = '700'; 1215 th.removeAttribute('file'); 1216 th.addEventListener('click', (): void => { 1217 if (item.clickHandler) { 1218 item.clickHandler(item); 1219 } 1220 }); 1221 if (item.title === 'eBPF Config') { 1222 if (th && item) {//ebpf开关置灰不能点击 1223 th.style.color = 'gray'; 1224 th.disabled = true; 1225 if (item.clickHandler) { 1226 item.clickHandler = undefined; 1227 } 1228 } 1229 } 1230 if (SpRecordTrace.useExtend && item.title === 'Hdc Shell') { 1231 if (th && item) { 1232 th.style.color = 'gray'; 1233 th.disabled = true; 1234 if (item.clickHandler) { 1235 item.clickHandler = undefined; 1236 } 1237 } 1238 } 1239 this.menuGroup!.appendChild(th); 1240 }); 1241 } 1242 1243 private recordCommandClickHandler(recordTrace: SpRecordTrace): void { 1244 let request = recordTrace.makeRequest(); 1245 recordTrace.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 1246 PluginConvertUtils.BeanToCmdTxt(request, false), 1247 recordTrace.recordSetting!.output, 1248 recordTrace.recordSetting!.maxDur 1249 ); 1250 } 1251 1252 private hdcShellClickHandler(recordTrace: SpRecordTrace): void { 1253 recordTrace.spWebShell!.shellDiv!.scrollTop = recordTrace.spWebShell!.currentScreenRemain; 1254 setTimeout(() => { 1255 recordTrace.spWebShell!.hdcShellFocus(); 1256 }, 100); 1257 recordTrace.nowChildItem = recordTrace.spWebShell!; 1258 } 1259 1260 private nativeMemoryClickHandler(recordTrace: SpRecordTrace): void { 1261 let startNativeSwitch = recordTrace.spAllocations?.shadowRoot?.getElementById('switch-disabled') as LitSwitch; 1262 let recordModeSwitch = recordTrace.probesConfig?.shadowRoot?.querySelector('lit-switch') as LitSwitch; 1263 let checkDesBoxDis = recordTrace.probesConfig?.shadowRoot?.querySelectorAll('check-des-box'); 1264 let litCheckBoxDis = recordTrace.probesConfig?.shadowRoot?.querySelectorAll('lit-check-box'); 1265 recordTrace.ftraceSlider = 1266 recordTrace.probesConfig?.shadowRoot?.querySelector<LitSlider>('#ftrace-buff-size-slider'); 1267 startNativeSwitch.addEventListener('change', (event: unknown): void => { 1268 //@ts-ignore 1269 let detail = event.detail; 1270 if (detail!.checked) { 1271 recordModeSwitch.removeAttribute('checked'); 1272 checkDesBoxDis?.forEach((item: unknown): void => { 1273 //@ts-ignore 1274 item.setAttribute('disabled', ''); 1275 //@ts-ignore 1276 item.checked = false; 1277 }); 1278 litCheckBoxDis?.forEach((item: unknown): void => { 1279 //@ts-ignore 1280 item.setAttribute('disabled', ''); 1281 //@ts-ignore 1282 item.checked = false; 1283 }); 1284 recordTrace.ftraceSlider!.setAttribute('disabled', ''); 1285 } 1286 }); 1287 let divConfigs = recordTrace.spAllocations?.shadowRoot?.querySelectorAll<HTMLDivElement>('.version-controller'); 1288 if ((!SpRecordTrace.selectVersion || SpRecordTrace.selectVersion === '3.2') && divConfigs) { 1289 for (let divConfig of divConfigs) { 1290 divConfig!.style.zIndex = '-1'; 1291 } 1292 } 1293 } 1294 1295 private eBPFConfigClickHandler(recordTrace: SpRecordTrace): void { 1296 recordTrace.spFileSystem!.setAttribute('long_trace', ''); 1297 } 1298 1299 private buildMenuItem( 1300 title: string, 1301 icon: string, 1302 configPage: BaseElement, 1303 clickHandlerFun?: Function, 1304 fileChoose: boolean = false 1305 ): MenuItem { 1306 return { 1307 title: title, 1308 icon: icon, 1309 fileChoose: fileChoose, 1310 clickHandler: (): void => { 1311 this.appContent!.innerHTML = ''; 1312 this.appContent!.append(configPage); 1313 ShadowRootInput.preventBubbling(configPage); 1314 this.freshMenuItemsStatus(title); 1315 if (clickHandlerFun) { 1316 clickHandlerFun(this); 1317 } 1318 }, 1319 }; 1320 } 1321 1322 private buildTemplateTraceItem(): void { 1323 this._menuItems = [ 1324 this.buildMenuItem('Record setting', 'properties', this.recordSetting!), 1325 this.buildMenuItem('Trace template', 'realIntentionBulb', this.spRecordTemplate!), 1326 this.buildMenuItem('Trace command', 'dbsetbreakpoint', this.spRecordTemplate!, this.traceCommandClickHandler), 1327 ]; 1328 } 1329 1330 private buildNormalTraceItem(): void { 1331 this._menuItems = [ 1332 this.buildMenuItem('Record setting', 'properties', this.recordSetting!), 1333 this.buildMenuItem('Trace command', 'dbsetbreakpoint', this.traceCommand!, this.recordCommandClickHandler), 1334 this.buildMenuItem('Hdc Shell', 'file-config', this.spWebShell!, this.hdcShellClickHandler), 1335 this.buildMenuItem('Probes config', 'realIntentionBulb', this.probesConfig!), 1336 this.buildMenuItem('Native Memory', 'externaltools', this.spAllocations!, this.nativeMemoryClickHandler), 1337 this.buildMenuItem('Hiperf', 'realIntentionBulb', this.spRecordPerf!), 1338 this.buildMenuItem('eBPF Config', 'file-config', this.spFileSystem!, this.eBPFConfigClickHandler), 1339 this.buildMenuItem('VM Tracker', 'vm-tracker', this.spVmTracker!), 1340 this.buildMenuItem('HiSystemEvent', 'externaltools', this.spHiSysEvent!), 1341 this.buildMenuItem('Ark Ts', 'file-config', this.spArkTs!), 1342 this.buildMenuItem('FFRT', 'file-config', this.spFFRTConfig!), 1343 this.buildMenuItem('Hilog', 'realIntentionBulb', this.spHiLog!), 1344 this.buildMenuItem('Xpower', 'externaltools', this.spXPower!), 1345 ]; 1346 } 1347 1348 // @ts-ignore 1349 usbDisConnectionListener(event: USBConnectionEvent): void { 1350 // @ts-ignore 1351 let disConnectDevice: USBDevice = event.device; 1352 for (let index = 0; index < this.deviceSelect!.children.length; index++) { 1353 let option = this.deviceSelect!.children[index] as HTMLOptionElement; 1354 if (option.value === disConnectDevice.serialNumber) { 1355 let optValue = option.value; 1356 HdcDeviceManager.disConnect(optValue).then(() => { }); 1357 this.deviceSelect!.removeChild(option); 1358 if (SpRecordTrace.serialNumber === optValue) { 1359 if (this.nowChildItem === this.spWebShell) { 1360 window.publish(window.SmartEvent.UI.DeviceDisConnect, optValue); 1361 } 1362 let options = this.deviceSelect!.options; 1363 if (options.length > 0) { 1364 let selectedOpt = options[this.deviceSelect!.selectedIndex]; 1365 SpRecordTrace.serialNumber = selectedOpt.value; 1366 } else { 1367 this.recordButton!.hidden = true; 1368 this.disconnectButton!.hidden = true; 1369 this.cancelButton!.hidden = true; 1370 this.devicePrompt!.innerText = 'Device not connected'; 1371 SpRecordTrace.serialNumber = ''; 1372 } 1373 } 1374 } 1375 } 1376 } 1377 1378 private vsCodeRecordCmd(traceCommandStr: string): void { 1379 Cmd.execHdcCmd(Cmd.formatString(CmdConstant.CMS_HDC_STOP, [SpRecordTrace.serialNumber]), (stopRes: string) => { 1380 let cmd = Cmd.formatString(CmdConstant.CMD_MOUNT_DEVICES, [SpRecordTrace.serialNumber]); 1381 Cmd.execHdcCmd(cmd, (res: string) => { 1382 this.sp!.search = true; 1383 this.progressEL!.loading = true; 1384 this.litSearch!.clear(); 1385 this.litSearch!.setPercent(`tracing ${this.recordSetting!.maxDur * 1000}ms`, -1); 1386 this.initRecordUIState(); 1387 this.recordButtonText!.textContent = this.stop; 1388 this.cancelButtonShow(true); 1389 Cmd.execHdcTraceCmd(traceCommandStr, SpRecordTrace.serialNumber, (traceResult: string): void => { 1390 if (traceResult.indexOf('DestroySession done') !== -1) { 1391 this.litSearch!.setPercent('tracing htrace down', -1); 1392 let cmd = Cmd.formatString(CmdConstant.CMD_FIEL_RECV_DEVICES, [ 1393 SpRecordTrace.serialNumber, 1394 this.recordSetting!.output, 1395 ]); 1396 Cmd.execFileRecv(cmd, this.recordSetting!.output, (rt: ArrayBuffer): void => { 1397 this.litSearch!.setPercent('downloading Hitrace file ', 101); 1398 let fileName = this.recordSetting!.output.substring(this.recordSetting!.output.lastIndexOf('/') + 1); 1399 let file = new File([rt], fileName); 1400 let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; 1401 let children = main.menus as Array<MenuGroup>; 1402 let child = children[0].children as Array<MenuItem>; 1403 let fileHandler = child[0].fileHandler; 1404 if (fileHandler && !SpRecordTrace.cancelRecord) { 1405 this.recordButtonText!.textContent = this.record; 1406 this.cancelButtonShow(false); 1407 this.freshMenuDisable(false); 1408 this.freshConfigMenuDisable(false); 1409 fileHandler({ detail: file }); 1410 } else { 1411 SpRecordTrace.cancelRecord = false; 1412 } 1413 }); 1414 } else { 1415 this.litSearch!.setPercent('tracing htrace failed, please check your config ', -2); 1416 this.recordButtonText!.textContent = this.record; 1417 this.freshMenuDisable(false); 1418 this.freshConfigMenuDisable(false); 1419 this.progressEL!.loading = false; 1420 } 1421 this.buttonDisable(false); 1422 }); 1423 }); 1424 }); 1425 } 1426 1427 private initRecordCmdStatus(): void { 1428 this.appContent!.innerHTML = ''; 1429 this.appContent!.append(this.traceCommand!); 1430 let config = this.makeRequest(); 1431 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 1432 PluginConvertUtils.BeanToCmdTxt(config, false), 1433 this.recordSetting!.output, 1434 this.recordSetting!.maxDur 1435 ); 1436 this.freshMenuItemsStatus('Trace command'); 1437 } 1438 1439 private webRecordCmd(traceCommandStr: string, selectedOption: HTMLOptionElement): void { 1440 HdcDeviceManager.connect(selectedOption.value).then((result) => { 1441 log(`result is ${result}`); 1442 if (result) { 1443 this.initRecordCmdStatus(); 1444 try { 1445 HdcDeviceManager.stopHiprofiler(CmdConstant.CMS_CANCEL).then(() => { 1446 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_MOUNT, true).then(() => { 1447 this.sp!.search = true; 1448 this.progressEL!.loading = true; 1449 this.litSearch!.clear(); 1450 this.litSearch!.setPercent(`tracing ${this.recordSetting!.maxDur * 1000}ms`, -1); 1451 this.buttonDisable(true); 1452 this.cancelButton!.hidden = false; 1453 this.freshMenuDisable(true); 1454 this.freshConfigMenuDisable(true); 1455 if (SpApplication.isLongTrace) { 1456 HdcDeviceManager.shellResultAsString( 1457 `${CmdConstant.CMD_CLEAR_LONG_FOLD + this.recordSetting!.longOutPath}*`, 1458 false 1459 ).then(() => { 1460 HdcDeviceManager.shellResultAsString( 1461 CmdConstant.CMD_MKDIR_LONG_FOLD + this.recordSetting!.longOutPath, 1462 false 1463 ).then(() => { 1464 HdcDeviceManager.shellResultAsString( 1465 CmdConstant.CMD_SET_FOLD_AUTHORITY + this.recordSetting!.longOutPath, 1466 false 1467 ).then(() => { 1468 this.recordLongTraceCmd(traceCommandStr); 1469 }); 1470 }); 1471 }); 1472 } else { 1473 this.recordTraceCmd(traceCommandStr); 1474 } 1475 }); 1476 }); 1477 } catch (e) { 1478 this.freshMenuDisable(false); 1479 this.freshConfigMenuDisable(false); 1480 this.buttonDisable(false); 1481 } 1482 } else { 1483 this.sp!.search = true; 1484 this.litSearch!.clear(); 1485 this.litSearch!.setPercent('please kill other hdc-server !', -2); 1486 } 1487 }); 1488 } 1489 1490 recordButtonListener(): void { 1491 SpRecordTrace.cancelRecord = false; 1492 let request = this.makeRequest(); 1493 let isRecordArkTs = (this.spArkTs!.isStartArkts && this.spArkTs!.process.trim() !== '') ? true : false; 1494 if (request.pluginConfigs.length === 0 && !isRecordArkTs) { 1495 this.useExtentTip!.style.display = 'block'; 1496 this.useExtentTip!.innerHTML = "It looks like you didn't add any probes. Please add at least one"; 1497 return; 1498 } 1499 this.useExtentTip!.style.display = 'none'; 1500 this.useExtentTip!.innerHTML = ''; 1501 if (SpRecordTrace.useExtend) { 1502 this.recordButton!.hidden = true; 1503 this.buttonDisable(true, true); 1504 this.freshMenuDisable(true); 1505 this.freshConfigMenuDisable(true); 1506 this.recordPluginFunc(); 1507 return; 1508 } 1509 1510 let traceCommandStr = PluginConvertUtils.createHdcCmd( 1511 PluginConvertUtils.BeanToCmdTxt(request, false), 1512 this.recordSetting!.output, 1513 this.recordSetting!.maxDur 1514 ); 1515 let pluginList: Array<string> = []; 1516 request.pluginConfigs.forEach((pluginConfig) => { 1517 pluginList.push(pluginConfig.pluginName); 1518 }); 1519 SpStatisticsHttpUtil.addOrdinaryVisitAction({ 1520 action: 'config_page', 1521 event: 'online_record', 1522 eventData: { 1523 plugin: pluginList, 1524 }, 1525 }); 1526 let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement; 1527 if (selectedOption) { 1528 SpRecordTrace.serialNumber = selectedOption.value; 1529 } else { 1530 this.sp!.search = true; 1531 this.litSearch!.clear(); 1532 this.progressEL!.loading = false; 1533 this.litSearch!.setPercent('please connect device', -2); 1534 } 1535 if (this.vs) { 1536 this.appContent!.innerHTML = ''; 1537 this.appContent!.append(this.traceCommand!); 1538 this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( 1539 PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), 1540 this.recordSetting!.output, 1541 this.recordSetting!.maxDur 1542 ); 1543 this.freshMenuItemsStatus('Trace command'); 1544 this.vsCodeRecordCmd(traceCommandStr); 1545 } else { 1546 this.webRecordCmd(traceCommandStr, selectedOption); 1547 } 1548 } 1549 1550 private recordTraceCmd(traceCommandStr: string): void { 1551 let executeCmdCallBack = (cmdStateResult: string): void => { 1552 if (cmdStateResult.includes('tracing ')) { 1553 this.litSearch!.setPercent('Start to record...', -1); 1554 } 1555 }; 1556 this.litSearch!.setPercent('Waiting to record...', -1); 1557 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_SHELL + traceCommandStr, false, executeCmdCallBack).then((traceResult) => { 1558 let re = this.isSuccess(traceResult); 1559 if (re === 0) { 1560 this.litSearch!.setPercent('Tracing htrace down', -1); 1561 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_TRACE_FILE_SIZE + this.recordSetting!.output, false).then( 1562 (traceFileSize) => { 1563 this.litSearch!.setPercent(`TraceFileSize is ${traceFileSize}`, -1); 1564 if (traceFileSize.indexOf('No such') !== -1) { 1565 this.refreshDisableStyle(false, true, 'No such file or directory', -2); 1566 } else if (Number(traceFileSize) <= MaxFileSize) { 1567 HdcDeviceManager.fileRecv(this.recordSetting!.output, (perNumber: number) => { 1568 this.litSearch!.setPercent('Downloading Hitrace file ', perNumber); 1569 }).then((pullRes) => { 1570 this.litSearch!.setPercent('Downloading Hitrace file ', 101); 1571 pullRes.arrayBuffer().then((buffer) => { 1572 let fileName = this.recordSetting!.output.substring(this.recordSetting!.output.lastIndexOf('/') + 1); 1573 let file = new File([buffer], fileName); 1574 let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; 1575 let children = main.menus as Array<MenuGroup>; 1576 let child = children[0].children as Array<MenuItem>; 1577 let fileHandler = child[0].fileHandler; 1578 if (fileHandler && !SpRecordTrace.cancelRecord) { 1579 this.refreshDisableStyle(false, false); 1580 fileHandler({ 1581 detail: file, 1582 }); 1583 } else { 1584 SpRecordTrace.cancelRecord = false; 1585 } 1586 }); 1587 }); 1588 } else { 1589 this.recordButtonText!.textContent = this.record; 1590 this.refreshDisableStyle(false, true, 'Htrace file is too big', -2); 1591 } 1592 } 1593 ); 1594 } else if (re === 2) { 1595 this.refreshDisableStyle(false, true, 'Stop tracing htrace ', -1); 1596 } else if (re === -1) { 1597 this.refreshDisableStyle(false, true, 'The device is abnormal', -2); 1598 this.progressEL!.loading = false; 1599 } else { 1600 this.refreshDisableStyle(false, true, 'Tracing htrace failed, please check your config ', -2); 1601 } 1602 }); 1603 } 1604 1605 private recordLongTraceCmd(traceCommandStr: string): void { 1606 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_SHELL + traceCommandStr, false).then((traceResult) => { 1607 let re = this.isSuccess(traceResult); 1608 if (re === 0) { 1609 this.litSearch!.setPercent('tracing htrace down', -1); 1610 HdcDeviceManager.shellResultAsString( 1611 CmdConstant.CMD_TRACE_FILE_SIZE + this.recordSetting!.longOutPath, 1612 false 1613 ).then((traceFileSize) => { 1614 this.litSearch!.setPercent(`traceFileSize is ${traceFileSize}`, -1); 1615 if (traceFileSize.indexOf('No such') !== -1) { 1616 this.litSearch!.setPercent('No such file or directory', -2); 1617 this.buttonDisable(false); 1618 this.freshConfigMenuDisable(false); 1619 this.freshMenuDisable(false); 1620 } else { 1621 this.recordLongTrace(); 1622 } 1623 }); 1624 } else if (re === 2) { 1625 this.refreshDisableStyle(false, true, 'stop tracing htrace ', -1); 1626 } else if (re === -1) { 1627 this.refreshDisableStyle(false, true, 'The device is abnormal', -2); 1628 this.progressEL!.loading = false; 1629 } else { 1630 this.refreshDisableStyle(false, true, 'tracing htrace failed, please check your config ', -2); 1631 } 1632 }); 1633 } 1634 1635 private refreshDisableStyle( 1636 disable: boolean, 1637 isFreshSearch: boolean, 1638 percentName?: string, 1639 percentValue?: number 1640 ): void { 1641 if (isFreshSearch) { 1642 this.litSearch!.setPercent(percentName, percentValue!); 1643 } 1644 this.recordButtonDisable(disable); 1645 this.freshConfigMenuDisable(disable); 1646 this.freshMenuDisable(disable); 1647 this.buttonDisable(disable); 1648 } 1649 1650 private getLongTraceTypePage(): Array<number> { 1651 let traceTypePage: Array<number> = []; 1652 for (let fileIndex = 0; fileIndex < this.longTraceList.length; fileIndex++) { 1653 let traceFileName = this.longTraceList[fileIndex]; 1654 if (this.sp!.fileTypeList.some((fileType) => traceFileName.toLowerCase().includes(fileType))) { 1655 continue; 1656 } 1657 let firstLastIndexOf = traceFileName.lastIndexOf('.'); 1658 let firstText = traceFileName.slice(0, firstLastIndexOf); 1659 let resultLastIndexOf = firstText.lastIndexOf('_'); 1660 traceTypePage.push(Number(firstText.slice(resultLastIndexOf + 1, firstText.length)) - 1); 1661 } 1662 traceTypePage.sort((leftNum: number, rightNum: number) => leftNum - rightNum); 1663 return traceTypePage; 1664 } 1665 1666 private loadLongTraceFile(timStamp: number): Promise<unknown> { 1667 return new Promise(async (resolve): Promise<void> => { 1668 let traceTypePage = this.getLongTraceTypePage(); 1669 for (let fileIndex = 0; fileIndex < this.longTraceList.length; fileIndex++) { 1670 if (this.longTraceList[fileIndex] !== '') { 1671 let types = this.sp!.fileTypeList.filter((type) => 1672 this.longTraceList[fileIndex].toLowerCase().includes(type.toLowerCase()) 1673 ); 1674 let pageNumber = 0; 1675 let fileType = types[0]; 1676 if (types.length === 0) { 1677 fileType = 'trace'; 1678 let searchNumber = 1679 Number( 1680 this.longTraceList[fileIndex].substring( 1681 this.longTraceList[fileIndex].lastIndexOf('_') + 1, 1682 this.longTraceList[fileIndex].lastIndexOf('.') 1683 ) 1684 ) - 1; 1685 pageNumber = traceTypePage.lastIndexOf(searchNumber); 1686 } 1687 let pullRes = await HdcDeviceManager.fileRecv( 1688 this.recordSetting!.longOutPath + this.longTraceList[fileIndex], 1689 (perNumber: number) => { 1690 this.litSearch!.setPercent(`downloading ${fileType} file `, perNumber); 1691 } 1692 ); 1693 this.litSearch!.setPercent(`downloading ${fileType} file `, 101); 1694 await this.saveIndexDBByLongTrace(pullRes, fileType, pageNumber, timStamp); 1695 } 1696 } 1697 resolve(1); 1698 }); 1699 } 1700 1701 private async saveIndexDBByLongTrace( 1702 pullRes: Blob, 1703 fileType: string, 1704 pageNumber: number, 1705 timStamp: number 1706 ): Promise<void> { 1707 let buffer = await pullRes.arrayBuffer(); 1708 let chunks = Math.ceil(buffer.byteLength / indexDBMaxSize); 1709 let offset = 0; 1710 let sliceLen = 0; 1711 let message = { fileType: '', startIndex: 0, endIndex: 0, size: 0 }; 1712 for (let chunkIndex = 0; chunkIndex < chunks; chunkIndex++) { 1713 let start = chunkIndex * indexDBMaxSize; 1714 let end = Math.min(start + indexDBMaxSize, buffer.byteLength); 1715 let chunk = buffer.slice(start, end); 1716 if (chunkIndex === 0) { 1717 message.fileType = fileType; 1718 message.startIndex = chunkIndex; 1719 } 1720 sliceLen = Math.min(buffer.byteLength - offset, indexDBMaxSize); 1721 if (chunkIndex === 0 && fileType === 'trace') { 1722 this.sp!.longTraceHeadMessageList.push({ pageNum: pageNumber, data: buffer.slice(offset, kbSize) }); 1723 } 1724 this.sp!.longTraceDataList.push({ 1725 index: chunkIndex, 1726 fileType: fileType, 1727 pageNum: pageNumber, 1728 startOffsetSize: offset, 1729 endOffsetSize: offset + sliceLen, 1730 }); 1731 await LongTraceDBUtils.getInstance().indexedDBHelp.add(LongTraceDBUtils.getInstance().tableName, { 1732 buf: chunk, 1733 id: `${fileType}_${timStamp}_${pageNumber}_${chunkIndex}`, 1734 fileType: fileType, 1735 pageNum: pageNumber, 1736 startOffset: offset, 1737 endOffset: offset + sliceLen, 1738 index: chunkIndex, 1739 timStamp: timStamp, 1740 }); 1741 offset += sliceLen; 1742 if (offset >= buffer.byteLength) { 1743 message.endIndex = chunkIndex; 1744 message.size = buffer.byteLength; 1745 this.longTraceFileMapHandler(pageNumber, message); 1746 } 1747 } 1748 } 1749 1750 private longTraceFileMapHandler( 1751 pageNumber: number, 1752 message: { 1753 fileType: string; 1754 startIndex: number; 1755 endIndex: number; 1756 size: number; 1757 } 1758 ): void { 1759 if (this.sp!.longTraceTypeMessageMap) { 1760 if (this.sp!.longTraceTypeMessageMap?.has(pageNumber)) { 1761 let oldTypeList = this.sp!.longTraceTypeMessageMap?.get(pageNumber); 1762 oldTypeList?.push(message); 1763 this.sp!.longTraceTypeMessageMap?.set(pageNumber, oldTypeList!); 1764 } else { 1765 this.sp!.longTraceTypeMessageMap?.set(pageNumber, [message]); 1766 } 1767 } else { 1768 this.sp!.longTraceTypeMessageMap = new Map(); 1769 this.sp!.longTraceTypeMessageMap.set(pageNumber, [message]); 1770 } 1771 } 1772 1773 private recordLongTrace(): void { 1774 let querySelector = this.sp!.shadowRoot?.querySelector('.long_trace_page') as HTMLDivElement; 1775 if (querySelector) { 1776 querySelector.style.display = 'none'; 1777 } 1778 HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_LONG_FILES + this.recordSetting!.longOutPath, false).then( 1779 (result) => { 1780 this.longTraceList = result.split('\n').filter((fileName) => Boolean(fileName)); 1781 if (this.longTraceList.length > 0) { 1782 this.sp!.longTraceHeadMessageList = []; 1783 this.sp!.longTraceDataList = []; 1784 this.sp!.longTraceTypeMessageMap = undefined; 1785 let timStamp = new Date().getTime(); 1786 this.loadLongTraceFile(timStamp).then(() => { 1787 let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; 1788 let children = main.menus as Array<MenuGroup>; 1789 let child = children[1].children as Array<MenuItem>; 1790 let fileHandler = child[0].clickHandler; 1791 if (fileHandler && !SpRecordTrace.cancelRecord) { 1792 this.freshConfigMenuDisable(false); 1793 this.freshMenuDisable(false); 1794 this.buttonDisable(false); 1795 this.recordButtonDisable(false); 1796 fileHandler( 1797 { 1798 detail: { 1799 timeStamp: timStamp, 1800 }, 1801 }, 1802 true 1803 ); 1804 } else { 1805 SpRecordTrace.cancelRecord = false; 1806 } 1807 }); 1808 } 1809 } 1810 ); 1811 } 1812 1813 private initRecordUIState(): void { 1814 this.buttonDisable(true); 1815 this.freshMenuDisable(true); 1816 this.freshConfigMenuDisable(true); 1817 } 1818 1819 private isSuccess(traceResult: string): number { 1820 if (traceResult.indexOf('CreateSession FAIL') !== -1 || traceResult.indexOf('failed') !== -1) { 1821 return 1; 1822 } else if (traceResult.indexOf('Signal') !== -1) { 1823 return 2; 1824 } else if (traceResult.indexOf('signal(2)') !== -1) { 1825 return 0; 1826 } else if (traceResult.indexOf('The device is abnormal') !== -1) { 1827 return -1; 1828 } else { 1829 return 0; 1830 } 1831 } 1832 1833 private makeRequest = (isCreateArkTsConfig = true): CreateSessionRequest => { 1834 let request = createSessionRequest(this.recordSetting!); 1835 if (this.record_template === 'true') { 1836 let templateConfigs = this.spRecordTemplate?.getTemplateConfig(); 1837 templateConfigs?.forEach((config) => { 1838 request.pluginConfigs.push(config); 1839 }); 1840 } else { 1841 if (SpApplication.isLongTrace && request.sessionConfig) { 1842 request.sessionConfig.splitFile = true; 1843 request.sessionConfig!.splitFileMaxSizeMb = this.recordSetting!.longTraceSingleFileMaxSize; 1844 request.sessionConfig!.splitFileMaxNum = 20; 1845 } 1846 let reportingFrequency: number = 5; 1847 if (this.recordSetting!.maxDur <= 20) { 1848 reportingFrequency = 2; 1849 } 1850 createHTracePluginConfig(this.probesConfig!, request); 1851 createFpsPluginConfig(this.probesConfig!, request); 1852 createMonitorPlugin(this.probesConfig!, request); 1853 createMemoryPluginConfig(reportingFrequency, this.spVmTracker!, this.probesConfig!, request); 1854 createNativePluginConfig(reportingFrequency, this.spAllocations!, SpRecordTrace.selectVersion, request); 1855 createHiPerfConfig(reportingFrequency, this.spRecordPerf!, this.recordSetting!, request); 1856 createSystemConfig(this.spFileSystem!, this.recordSetting!, request); 1857 createSdkConfig(this.spSdkConfig!, request); 1858 createHiSystemEventPluginConfig(this.spHiSysEvent!, request); 1859 if (isCreateArkTsConfig) { 1860 createArkTsConfig(this.spArkTs!, this.recordSetting!, request); 1861 } 1862 createHiLogConfig(reportingFrequency, this.spHiLog!, request); 1863 createFFRTPluginConfig(this.spFFRTConfig!, SpRecordTrace.selectVersion, request); 1864 createXPowerConfig(this.spXPower!, request); 1865 } 1866 return request; 1867 }; 1868 1869 initHtml(): string { 1870 return SpRecordTraceHtml; 1871 } 1872 1873 private freshConfigMenuDisable(disable: boolean): void { 1874 let querySelectors = this.shadowRoot?.querySelectorAll<LitMainMenuItem>('lit-main-menu-item'); 1875 querySelectors!.forEach((item) => { 1876 if (item.title !== 'Hdc Shell') { 1877 if (disable) { 1878 item.style.pointerEvents = 'none'; 1879 } else { 1880 item.style.pointerEvents = 'auto'; 1881 } 1882 item.disabled = disable; 1883 } 1884 }); 1885 } 1886 1887 public startRefreshDeviceList(): void { 1888 if (this.refreshDeviceTimer === undefined) { 1889 this.refreshDeviceTimer = window.setInterval((): void => { 1890 this.refreshDeviceList(); 1891 }, 5000); 1892 } 1893 } 1894 1895 private recordButtonDisable(disable: boolean): void { 1896 this.recordButton!.style.pointerEvents = disable ? 'none' : 'auto'; 1897 } 1898 1899 private buttonDisable(disable: boolean, isUseExtend = false): void { 1900 let pointerEventValue = 'auto'; 1901 this.recordButtonText!.textContent = this.record; 1902 if (disable) { 1903 pointerEventValue = 'none'; 1904 if (!isUseExtend) { 1905 this.recordButtonText!.textContent = this.stop; 1906 } 1907 } 1908 if (!isUseExtend) { 1909 this.cancelButtonShow(disable); 1910 } 1911 this.disconnectButton!.style.pointerEvents = pointerEventValue; 1912 this.addButton!.style.pointerEvents = pointerEventValue; 1913 this.deviceSelect!.style.pointerEvents = pointerEventValue; 1914 this.deviceVersion!.style.pointerEvents = pointerEventValue; 1915 this.useExtendCheck!.style.pointerEvents = pointerEventValue;// arkts trace 1916 } 1917 1918 private freshMenuItemsStatus(currentValue: string): void { 1919 let litMainMenuGroup = this.shadowRoot?.querySelector<LitMainMenuGroup>('lit-main-menu-group'); 1920 let litMainMenuItemNodeListOf = litMainMenuGroup!.querySelectorAll<LitMainMenuItem>('lit-main-menu-item'); 1921 litMainMenuItemNodeListOf.forEach((item) => { 1922 item.back = item.title === currentValue; 1923 }); 1924 } 1925 1926 synchronizeDeviceList(): void { 1927 this.deviceSelect!.innerHTML = ''; 1928 if (SpRecordTrace.serialNumber !== '') { 1929 for (let i = 0; i < this.hdcList.length; i++) { 1930 let dev = this.hdcList[i]; 1931 // @ts-ignore 1932 let serialNumber = typeof (dev) === 'string' ? dev : dev.serialNumber; 1933 let option = document.createElement('option'); 1934 option.className = 'select'; 1935 //@ts-ignore 1936 option.selected = serialNumber === SpRecordTrace.serialNumber; 1937 //@ts-ignore 1938 option.value = serialNumber; 1939 //@ts-ignore 1940 option.textContent = serialNumber; 1941 this.deviceSelect!.appendChild(option); 1942 this.recordButton!.hidden = false; 1943 this.disconnectButton!.hidden = false; 1944 this.cancelButton!.hidden = false; 1945 this.devicePrompt!.innerText = ''; 1946 } 1947 if (SpRecordTrace.selectVersion && SpRecordTrace.selectVersion !== '') { 1948 this.setDeviceVersionSelect(SpRecordTrace.selectVersion); 1949 } 1950 } 1951 } 1952} 1953 1954const kbSize = 1024; 1955const timeOut = 200; 1956const unitSize = 48; 1957const indexDBMaxSize = unitSize * kbSize * kbSize; 1958export const MaxFileSize: number = kbSize * kbSize * kbSize; 1959