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.js'; 17import { checkDesBean, SpCheckDesBox } from './SpCheckDesBox.js'; 18import { LitCheckBox, LitCheckBoxChangeEvent } from '../../../base-ui/checkbox/LitCheckBox.js'; 19import { LitRadioGroup } from '../../../base-ui/radiobox/LitRadioGroup.js'; 20import { info, log } from '../../../log/Log.js'; 21import { LitSlider } from '../../../base-ui/slider/LitSlider'; 22 23@element('probes-config') 24export class SpProbesConfig extends BaseElement { 25 private traceConfigList: Array<checkDesBean> | undefined; 26 private memoryConfigList: Array<checkDesBean> | undefined; 27 private abilityConfigList: Array<checkDesBean> | undefined; 28 private hitraceConfigList: Array<any> | undefined; 29 private hitrace: SpCheckDesBox | undefined; 30 31 private _traceConfig: HTMLElement | undefined; 32 private _memoryConfig: HTMLElement | undefined | null; 33 private _abilityConfig: HTMLElement | undefined | null; 34 private ftraceBufferSizeResult: HTMLDivElement | null | undefined; 35 36 get traceConfig() { 37 let selectedTrace = this._traceConfig?.querySelectorAll<SpCheckDesBox>(`check-des-box[checked]`) || []; 38 let values = []; 39 for (const litCheckBoxElement of selectedTrace) { 40 values.push(litCheckBoxElement.value); 41 } 42 if (this.hitrace && this.hitrace.checked) { 43 values.push(this.hitrace.value); 44 } 45 info('traceConfig is :', values); 46 return values; 47 } 48 49 get ftraceBufferSize(): number { 50 if (this.ftraceBufferSizeResult?.hasAttribute('percent')) { 51 return Number(this.ftraceBufferSizeResult?.getAttribute('percent')); 52 } 53 return 20480; 54 } 55 56 get memoryConfig() { 57 let values = []; 58 let selectedMemory = this._memoryConfig?.querySelectorAll<SpCheckDesBox>( 59 `check-des-box[checked]` 60 ) as NodeListOf<SpCheckDesBox>; 61 for (const litCheckBoxElement of selectedMemory) { 62 values.push(litCheckBoxElement.value); 63 } 64 log('memoryConfig size is :' + values.length); 65 return values; 66 } 67 68 get recordAbility() { 69 let selectedMemory = this._abilityConfig?.querySelectorAll<SpCheckDesBox>( 70 `check-des-box[checked]` 71 ) as NodeListOf<SpCheckDesBox>; 72 return selectedMemory.length > 0; 73 } 74 75 get traceEvents() { 76 let values = []; 77 if (this.hitrace && this.hitrace.checked) { 78 let parent = this.shadowRoot?.querySelector('.user-events') as Element; 79 const siblingNode = parent?.querySelectorAll<LitCheckBox>(`lit-check-box[name=userEvents][checked]`); 80 for (const litCheckBoxElement of siblingNode) { 81 values.push(litCheckBoxElement.value); 82 } 83 } 84 log('traceEvents size is :' + values.length); 85 return values; 86 } 87 88 get hilogConfig() { 89 let logLevel = this.shadowRoot?.getElementById('logLevel') as LitCheckBox; 90 if (logLevel.checked) { 91 let logRadio = this.shadowRoot?.getElementById('log-radio') as LitRadioGroup; 92 return logRadio.value; 93 } else { 94 return []; 95 } 96 } 97 98 initElements(): void { 99 this.traceConfigList = [ 100 { 101 value: 'Scheduling details', 102 isSelect: true, 103 des: 'enables high-detailed tracking of scheduling events', 104 }, 105 { 106 value: 'CPU Frequency and idle states', 107 isSelect: true, 108 des: 'Records cpu frequency and idle state change viaftrace', 109 }, 110 { 111 value: 'Advanced ftrace config', 112 isSelect: false, 113 des: 114 'Enable individual events and tune the kernel-tracing(ftrace) module.' + 115 'The events enabled here are in addition to those from' + 116 ' enabled by other probes.', 117 }, 118 ]; 119 this._traceConfig = this.shadowRoot?.querySelector('.trace-config') as HTMLElement; 120 this.traceConfigList.forEach((configBean) => { 121 let checkDesBox = new SpCheckDesBox(); 122 checkDesBox.value = configBean.value; 123 checkDesBox.checked = configBean.isSelect; 124 checkDesBox.des = configBean.des; 125 checkDesBox.addEventListener('onchange', () => { 126 this.dispatchEvent(new CustomEvent('addProbe', {})); 127 }); 128 this._traceConfig?.appendChild(checkDesBox); 129 }); 130 this.memoryConfigList = [ 131 { 132 value: 'Kernel meminfo', 133 isSelect: false, 134 des: 'polling of /proc/meminfo', 135 }, 136 { 137 value: 'Virtual memory stats', 138 isSelect: false, 139 des: 140 'Periodically polls virtual memory stats from /proc/vmstat.' + 141 ' Allows to gather statistics about swap,' + 142 'eviction, compression and pagecache efficiency', 143 }, 144 ]; 145 this._memoryConfig = this.shadowRoot?.querySelector('.memory-config'); 146 this.memoryConfigList.forEach((configBean) => { 147 let checkDesBox = new SpCheckDesBox(); 148 checkDesBox.value = configBean.value; 149 checkDesBox.checked = configBean.isSelect; 150 checkDesBox.des = configBean.des; 151 checkDesBox.addEventListener('onchange', () => { 152 this.dispatchEvent(new CustomEvent('addProbe', {})); 153 }); 154 this._memoryConfig?.appendChild(checkDesBox); 155 }); 156 this.abilityConfigList = [ 157 { 158 value: 'AbilityMonitor', 159 isSelect: false, 160 des: 'Tracks the AbilityMonitor', 161 }, 162 ]; 163 this._abilityConfig = this.shadowRoot?.querySelector('.ability-config'); 164 this.abilityConfigList.forEach((configBean) => { 165 let checkDesBox = new SpCheckDesBox(); 166 checkDesBox.value = configBean.value; 167 checkDesBox.checked = configBean.isSelect; 168 checkDesBox.des = configBean.des; 169 checkDesBox.addEventListener('onchange', () => { 170 this.dispatchEvent(new CustomEvent('addProbe', {})); 171 }); 172 this._abilityConfig?.appendChild(checkDesBox); 173 }); 174 175 this.hitraceConfigList = [ 176 { value: 'ability', isSelect: true }, 177 { value: 'accesscontrol', isSelect: false }, 178 { value: 'accessibility', isSelect: false }, 179 { value: 'account', isSelect: false }, 180 { value: 'ace', isSelect: true }, 181 { value: 'app', isSelect: true }, 182 { value: 'ark', isSelect: true }, 183 { value: 'binder', isSelect: true }, 184 { value: 'bluetooth', isSelect: false }, 185 { value: 'cloud', isSelect: false }, 186 { value: 'commonlibrary', isSelect: false }, 187 { value: 'daudio', isSelect: false }, 188 { value: 'dcamera', isSelect: false }, 189 { value: 'deviceauth', isSelect: false }, 190 { value: 'devicemanager', isSelect: false }, 191 { value: 'deviceprofile', isSelect: false }, 192 { value: 'dhfwk', isSelect: false }, 193 { value: 'dinput', isSelect: false }, 194 { value: 'disk', isSelect: true }, 195 { value: 'distributeddatamgr', isSelect: false }, 196 { value: 'dlpcre', isSelect: false }, 197 { value: 'dsched', isSelect: false }, 198 { value: 'dscreen', isSelect: false }, 199 { value: 'dslm', isSelect: false }, 200 { value: 'dsoftbus', isSelect: false }, 201 { value: 'ffrt', isSelect: false }, 202 { value: 'filemanagement', isSelect: false }, 203 { value: 'freq', isSelect: true }, 204 { value: 'graphic', isSelect: true }, 205 { value: 'gresource', isSelect: false }, 206 { value: 'hdcd', isSelect: false }, 207 { value: 'hdf', isSelect: false }, 208 { value: 'huks', isSelect: false }, 209 { value: 'i2c', isSelect: false }, 210 { value: 'idle', isSelect: true }, 211 { value: 'interconn', isSelect: false }, 212 { value: 'irq', isSelect: true }, 213 { value: 'mdfs', isSelect: false }, 214 { value: 'memory', isSelect: false }, 215 { value: 'memreclaim', isSelect: true }, 216 { value: 'misc', isSelect: false }, 217 { value: 'mmc', isSelect: true }, 218 { value: 'msdp', isSelect: false }, 219 { value: 'multimodalinput', isSelect: true }, 220 { value: 'musl', isSelect: false }, 221 { value: 'net', isSelect: false }, 222 { value: 'notification', isSelect: false }, 223 { value: 'nweb', isSelect: false }, 224 { value: 'ohos', isSelect: true }, 225 { value: 'pagecache', isSelect: true }, 226 { value: 'power', isSelect: false }, 227 { value: 'regulators', isSelect: false }, 228 { value: 'rpc', isSelect: true }, 229 { value: 'samgr', isSelect: false }, 230 { value: 'sched', isSelect: true }, 231 { value: 'sensors', isSelect: false }, 232 { value: 'sync', isSelect: true }, 233 { value: 'usb', isSelect: false }, 234 { value: 'ufs', isSelect: false }, 235 { value: 'useriam', isSelect: false }, 236 { value: 'window', isSelect: true }, 237 { value: 'workq', isSelect: true }, 238 { value: 'zaudio', isSelect: true }, 239 { value: 'zcamera', isSelect: true }, 240 { value: 'zimage', isSelect: true }, 241 { value: 'zmedia', isSelect: true }, 242 ]; 243 this.hitrace = this.shadowRoot?.getElementById('hitrace') as SpCheckDesBox; 244 let parent = this.shadowRoot?.querySelector('.user-events') as Element; 245 this.hitraceConfigList?.forEach((hitraceConfig: any) => { 246 let litCheckBox = new LitCheckBox(); 247 litCheckBox.setAttribute('name', 'userEvents'); 248 litCheckBox.value = hitraceConfig.value; 249 litCheckBox.checked = hitraceConfig.isSelect; 250 litCheckBox.addEventListener('change', (ev: CustomEventInit<LitCheckBoxChangeEvent>) => { 251 let detail = ev.detail; 252 if (this.hitrace?.checked === false) { 253 this.hitrace.checked = detail!.checked; 254 } 255 if (detail!.checked === false && this.hitrace?.checked === true) { 256 let hasChecked = false; 257 const nodes = parent?.querySelectorAll<LitCheckBox>(`lit-check-box[name=userEvents]`); 258 nodes.forEach((vv) => { 259 if (vv.checked) { 260 hasChecked = true; 261 } 262 }); 263 if (!hasChecked) { 264 this.hitrace.checked = hasChecked; 265 } 266 } 267 this.dispatchEvent(new CustomEvent('addProbe', {})); 268 }); 269 parent.append(litCheckBox); 270 }); 271 this.bufferSizeSliderInit(); 272 } 273 274 private bufferSizeSliderInit() { 275 let ftraceBufferSizeSlider = this.shadowRoot?.querySelector<LitSlider>('#ftrace-buff-size-slider') as LitSlider; 276 this.ftraceBufferSizeResult = this.shadowRoot?.querySelector('#ftrace-buff-size-div') as HTMLDivElement; 277 ftraceBufferSizeSlider.sliderStyle = { 278 minRange: 2048, 279 maxRange: 307200, 280 defaultValue: '20480', 281 resultUnit: 'KB', 282 stepSize: 2, 283 lineColor: 'var(--dark-color3,#46B1E3)', 284 buttonColor: '#999999', 285 }; 286 let ftraceBufferSizeSliderParent = ftraceBufferSizeSlider!.parentNode as Element; 287 let ftraceBuffSizeResultInput = this.shadowRoot?.querySelector('.ftrace-buff-size-result') as HTMLInputElement; 288 ftraceBuffSizeResultInput.value = ftraceBufferSizeSlider.sliderStyle.defaultValue; 289 ftraceBufferSizeSlider.addEventListener('input', (evt) => { 290 ftraceBuffSizeResultInput.parentElement!.classList.remove('border-red'); 291 if (this.ftraceBufferSizeResult!.hasAttribute('percent')) { 292 ftraceBuffSizeResultInput.value = Number(this.ftraceBufferSizeResult!.getAttribute('percent')).toString(); 293 } else { 294 ftraceBuffSizeResultInput.value = '20480'; 295 } 296 }); 297 ftraceBufferSizeSliderParent.setAttribute('percent', '20480'); 298 ftraceBuffSizeResultInput.style.color = 'var(--dark-color1,#000000)'; 299 ftraceBuffSizeResultInput.addEventListener('input', (ev) => { 300 if (this.ftraceBufferSizeResult!.hasAttribute('percent')) { 301 this.ftraceBufferSizeResult!.removeAttribute('percent'); 302 } 303 ftraceBuffSizeResultInput.style.color = 'var(--dark-color1,#000000)'; 304 ftraceBuffSizeResultInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; 305 ftraceBuffSizeResultInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; 306 if (ftraceBuffSizeResultInput.value.trim() === '') { 307 ftraceBuffSizeResultInput.style.color = 'red'; 308 ftraceBufferSizeSliderParent.setAttribute('percent', '20480'); 309 return; 310 } 311 let ftraceBufferSize = Number(ftraceBuffSizeResultInput.value); 312 if ( 313 ftraceBufferSize < ftraceBufferSizeSlider!.sliderStyle.minRange || 314 ftraceBufferSize > ftraceBufferSizeSlider!.sliderStyle.maxRange 315 ) { 316 ftraceBuffSizeResultInput.parentElement!.classList.add('border-red'); 317 ftraceBufferSizeSliderParent.setAttribute('percent', '20480'); 318 } else { 319 ftraceBuffSizeResultInput.parentElement!.classList.remove('border-red'); 320 ftraceBufferSizeSlider!.percent = ftraceBuffSizeResultInput.value; 321 let htmlInputElement = ftraceBufferSizeSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; 322 htmlInputElement.value = ftraceBuffSizeResultInput.value; 323 ftraceBufferSizeSliderParent.setAttribute('percent', ftraceBuffSizeResultInput.value); 324 ftraceBufferSizeSliderParent.setAttribute('percentValue', ftraceBuffSizeResultInput.value); 325 } 326 }); 327 ftraceBuffSizeResultInput.addEventListener('focusout', (ev) => { 328 if (ftraceBuffSizeResultInput.value.trim() === '') { 329 ftraceBuffSizeResultInput.parentElement!.classList.remove('border-red'); 330 ftraceBufferSizeSliderParent.setAttribute('percent', '20480'); 331 ftraceBuffSizeResultInput.value = '20480'; 332 ftraceBuffSizeResultInput.style.color = 'var(--dark-color,#6a6f77)'; 333 ftraceBufferSizeSliderParent.setAttribute('percent', ftraceBuffSizeResultInput.value); 334 ftraceBufferSizeSliderParent.setAttribute('percentValue', ftraceBuffSizeResultInput.value); 335 ftraceBufferSizeSlider!.percent = ftraceBuffSizeResultInput.value; 336 let htmlInputElement = ftraceBufferSizeSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; 337 htmlInputElement.value = ftraceBuffSizeResultInput.value; 338 } 339 }); 340 } 341 342 initHtml(): string { 343 return ` 344 <style> 345 .recordText { 346 font-family: Helvetica-Bold; 347 font-size: 1em; 348 color: var(--dark-color1,#000000); 349 line-height: 28px; 350 font-weight: 700; 351 margin-bottom: 20px; 352 } 353 354 :host{ 355 display: inline-block; 356 background: var(--dark-background3,#FFFFFF); 357 width: 100%; 358 height: 100%; 359 border-radius: 0px 16px 16px 0px; 360 } 361 362 .root { 363 margin-right: 30px; 364 padding-top: 30px; 365 padding-left: 54px; 366 margin-bottom: 30px; 367 font-size:16px; 368 } 369 370 .config-page { 371 height: 95%; 372 font-size: 0.875em; 373 } 374 375 .trace-config{ 376 display: flex; 377 flex-direction: column; 378 width: 50%; 379 gap: 10px; 380 margin-bottom: 20px; 381 } 382 383 .memory-config{ 384 display: grid; 385 grid-template-columns: repeat(2, 1fr); 386 border-style: solid none none none; 387 border-color: #D5D5D5; 388 padding-top: 15px; 389 margin-top: 15px; 390 gap: 10px; 391 } 392 393 .ability-config{ 394 display: grid; 395 grid-template-columns: repeat(2, 1fr); 396 border-style: solid none none none; 397 border-color: #D5D5D5; 398 padding-top: 15px; 399 margin-top: 15px; 400 gap: 10px; 401 } 402 403 .span-col-2{ 404 grid-column: span 2 / auto; 405 } 406 407 .log-config{ 408 display: grid; 409 grid-template-columns: repeat(2, 1fr); 410 border-style: solid none none none; 411 border-color: #D5D5D5; 412 padding-top: 15px; 413 gap: 10px; 414 } 415 416 #hitrace-cat{ 417 display: grid; 418 grid-template-columns: 1fr 1fr; 419 } 420 .user-events{ 421 display: grid; 422 grid-template-columns: repeat(4, 1fr); 423 grid-template-rows: repeat(2, 1fr); 424 gap: 10px; 425 margin-left: 15px;; 426 } 427 #ftrace-buff-size-div { 428 width: 100%; 429 height: min-content; 430 display: grid; 431 grid-template-columns: 1fr min-content; 432 } 433 .buffer-size-des { 434 opacity: 0.6; 435 font-family: Helvetica; 436 font-size: 1em; 437 color: var(--dark-color,#000000); 438 text-align: left; 439 line-height: 20px; 440 font-weight: 400; 441 } 442 .ftrace-buff-size-result-div{ 443 display: grid; 444 grid-template-rows: 1fr; 445 grid-template-columns: min-content min-content; 446 background-color: var(--dark-background5,#F2F2F2); 447 -webkit-appearance:none; 448 color:var(--dark-color,#6a6f77); 449 width: 150px; 450 margin: 0 20px 0 0; 451 height: 40px; 452 border-radius:20px; 453 outline:0; 454 border:1px solid var(--dark-border,#c8cccf); 455 } 456 .ftrace-buff-size-result{ 457 background-color: var(--dark-background5,#F2F2F2); 458 -webkit-appearance:none; 459 color:var(--dark-color,#6a6f77); 460 border: none; 461 text-align: center; 462 width: 90px; 463 font-size:14px; 464 outline:0; 465 margin: 5px 0 5px 5px; 466 } 467 .border-red { 468 border:1px solid red; 469 } 470 </style> 471 <div class="root"> 472 <div class="recordText" >Record mode</div> 473 <div class="config-page"> 474 <div> 475 <div class="trace-config"></div> 476 <div class="span-col-2" id="hitrace-cat"> 477 <check-des-box id="hitrace" checked="true" value ="Hitrace categories" des="Enables C++ codebase annotations (HTRACE_BEGIN() / os.Trace())"> 478 </check-des-box> 479 <div class="user-events"> 480 <slot></slot> 481 </div> 482 </div> 483 <div> 484 <div> 485 <p>Buffer Size</p> 486 <p class="buffer-size-des">The ftrace buffer size range is 2048 KB to 307200 KB</p> 487 </div> 488 <div id="ftrace-buff-size-div"> 489 <lit-slider id="ftrace-buff-size-slider" defaultColor="var(--dark-color3,#46B1E3)" open dir="right"> 490 </lit-slider> 491 <div class='ftrace-buff-size-result-div'> 492 <input class="ftrace-buff-size-result" type="text" value='20480' onkeyup="this.value=this.value.replace(/\\D/g,'')"> 493 <span style="text-align: center; margin: 8px"> KB </span> 494 </div> 495 </div> 496 </div> 497 </div> 498 <div class="memory-config"> 499 <div class="span-col-2"> 500 <span>Memory Config</span> 501 </div> 502 </div> 503 <div class="ability-config"> 504 <div class="span-col-2"> 505 <span>Ability Config</span> 506 </div> 507 </div> 508 </div> 509 </div> 510 `; 511 } 512 513 //当 custom element首次被插入文档DOM时,被调用。 514 public connectedCallback() { 515 let parent = this.shadowRoot?.querySelector('.user-events') as Element; 516 const siblingNode = parent?.querySelectorAll<LitCheckBox>(`lit-check-box[name=userEvents]`); 517 this.hitrace!.addEventListener('onchange', (ev: CustomEventInit<LitCheckBoxChangeEvent>) => { 518 let detail = ev.detail; 519 siblingNode.forEach((node) => { 520 node.checked = detail!.checked; 521 }); 522 this.dispatchEvent(new CustomEvent('addProbe', {})); 523 }); 524 } 525} 526