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 { SpCheckDesBox } from './SpCheckDesBox';
18import { LitCheckBox, LitCheckBoxChangeEvent } from '../../../base-ui/checkbox/LitCheckBox';
19import { LitRadioGroup } from '../../../base-ui/radiobox/LitRadioGroup';
20import { info, log } from '../../../log/Log';
21import { LitSlider } from '../../../base-ui/slider/LitSlider';
22import LitSwitch from '../../../base-ui/switch/lit-switch';
23import { SpProbesConfigHtml } from './SpProbesConfig.html';
24
25@element('probes-config')
26export class SpProbesConfig extends BaseElement {
27  private hitrace: SpCheckDesBox | undefined;
28  private _traceConfig: HTMLElement | undefined;
29  private _memoryConfig: HTMLElement | undefined | null;
30  private _abilityConfig: HTMLElement | undefined | null;
31  private ftraceBufferSizeResult: HTMLDivElement | null | undefined;
32  private ftraceSlider: LitSlider | null | undefined;
33
34  private ftraceBuffSizeResultInput: HTMLInputElement | null | undefined;
35
36  set startSamp(allocationStart: boolean) {
37    if (allocationStart) {
38      this.setAttribute('startSamp', '');
39    } else {
40      this.removeAttribute('startSamp');
41    }
42  }
43
44  get startSamp(): boolean {
45    return this.hasAttribute('startSamp');
46  }
47
48  get traceConfig(): string[] {
49    let selectedTrace = this._traceConfig?.querySelectorAll<SpCheckDesBox>('check-des-box[checked]') || [];
50    let values = [];
51    for (const litCheckBoxElement of selectedTrace) {
52      values.push(litCheckBoxElement.value);
53    }
54    if (this.hitrace && this.hitrace.checked) {
55      values.push(this.hitrace.value);
56    }
57    info('traceConfig is :', values);
58    return values;
59  }
60
61  get ftraceBufferSize(): number {
62    if (this.ftraceBufferSizeResult?.hasAttribute('percent')) {
63      return Number(this.ftraceBufferSizeResult?.getAttribute('percent'));
64    }
65    return 20480;
66  }
67
68  get memoryConfig(): string[] {
69    let values = [];
70    let selectedMemory = this._memoryConfig?.querySelectorAll<SpCheckDesBox>(
71      'check-des-box[checked]'
72    ) as NodeListOf<SpCheckDesBox>;
73    for (const litCheckBoxElement of selectedMemory) {
74      values.push(litCheckBoxElement.value);
75    }
76    log(`memoryConfig size is :${values.length}`);
77    return values;
78  }
79
80  get recordAbility(): boolean {
81    let selectedMemory = this._abilityConfig?.querySelectorAll<SpCheckDesBox>(
82      'check-des-box[checked]'
83    ) as NodeListOf<SpCheckDesBox>;
84    return selectedMemory.length > 0;
85  }
86
87  get traceEvents(): string[] {
88    let values = [];
89    if (this.hitrace && this.hitrace.checked) {
90      let parent = this.shadowRoot?.querySelector('.user-events') as Element;
91      const siblingNode = parent?.querySelectorAll<LitCheckBox>('lit-check-box[name=userEvents][checked]');
92      for (const litCheckBoxElement of siblingNode) {
93        values.push(litCheckBoxElement.value);
94      }
95    }
96    log(`traceEvents size is :${values.length}`);
97    return values;
98  }
99
100  get hilogConfig(): string[] {
101    let logLevel = this.shadowRoot?.getElementById('logLevel') as LitCheckBox;
102    if (logLevel.checked) {
103      let logRadio = this.shadowRoot?.getElementById('log-radio') as LitRadioGroup;
104      return logRadio.value;
105    } else {
106      return [];
107    }
108  }
109
110  private initTraceConfigList(): void {
111    this._traceConfig = this.shadowRoot?.querySelector('.trace-config') as HTMLElement;
112    traceConfigList.forEach((configBean) => {
113      let checkDesBox = new SpCheckDesBox();
114      checkDesBox.value = configBean.value;
115      checkDesBox.checked = configBean.isSelect;
116      checkDesBox.des = configBean.des;
117      checkDesBox.addEventListener('onchange', () => {
118        this.dispatchEvent(new CustomEvent('addProbe', {}));
119      });
120      this._traceConfig?.appendChild(checkDesBox);
121    });
122  }
123
124  private initMemoryConfigList(): void {
125    this._memoryConfig = this.shadowRoot?.querySelector('.memory-config');
126    memoryConfigList.forEach((configBean) => {
127      let checkDesBox = new SpCheckDesBox();
128      checkDesBox.value = configBean.value;
129      checkDesBox.checked = configBean.isSelect;
130      checkDesBox.des = configBean.des;
131      checkDesBox.addEventListener('onchange', () => {
132        this.dispatchEvent(new CustomEvent('addProbe', {}));
133      });
134      this._memoryConfig?.appendChild(checkDesBox);
135    });
136  }
137
138  private initAbilityConfigList(): void {
139    this._abilityConfig = this.shadowRoot?.querySelector('.ability-config');
140    abilityConfigList.forEach((configBean) => {
141      let checkDesBox = new SpCheckDesBox();
142      checkDesBox.value = configBean.value;
143      checkDesBox.checked = configBean.isSelect;
144      checkDesBox.des = configBean.des;
145      checkDesBox.addEventListener('onchange', () => {
146        this.dispatchEvent(new CustomEvent('addProbe', {}));
147      });
148      this._abilityConfig?.appendChild(checkDesBox);
149    });
150  }
151
152  private initHiTraceConfigList(): void {
153    this.hitrace = this.shadowRoot?.getElementById('hitrace') as SpCheckDesBox;
154    let parent = this.shadowRoot?.querySelector('.user-events') as Element;
155    hiTraceConfigList.forEach((hitraceConfig: unknown) => {
156      let litCheckBox = new LitCheckBox();
157      litCheckBox.setAttribute('name', 'userEvents');
158      //@ts-ignore
159      litCheckBox.value = hitraceConfig.value;
160      //@ts-ignore
161      litCheckBox.checked = hitraceConfig.isSelect;
162      litCheckBox.addEventListener('change', (ev: CustomEventInit<LitCheckBoxChangeEvent>) => {
163        let detail = ev.detail;
164        if (this.hitrace?.checked === false) {
165          this.hitrace.checked = detail!.checked;
166        }
167        if (!detail!.checked && this.hitrace?.checked === true) {
168          let hasChecked = false;
169          const nodes = parent?.querySelectorAll<LitCheckBox>('lit-check-box[name=userEvents]');
170          nodes.forEach((vv) => {
171            if (vv.checked) {
172              hasChecked = true;
173            }
174          });
175          if (!hasChecked) {
176            this.hitrace.checked = hasChecked;
177          }
178        }
179        this.dispatchEvent(new CustomEvent('addProbe', {}));
180      });
181      parent.append(litCheckBox);
182    });
183  }
184
185  initElements(): void {
186    this.ftraceBuffSizeResultInput = this.shadowRoot?.querySelector('.ftrace-buff-size-result') as HTMLInputElement;
187    this.ftraceBuffSizeResultInput!.addEventListener('keydown', (ev: unknown) => {
188      //@ts-ignore
189      if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') {
190        //@ts-ignore
191        ev.preventDefault();
192      }
193    });
194    this.initTraceConfigList();
195    this.initMemoryConfigList();
196    this.initAbilityConfigList();
197    this.initHiTraceConfigList();
198    this.bufferSizeSliderInit();
199    let litSwitch = this.shadowRoot?.querySelector('lit-switch') as LitSwitch;
200    this.ftraceSlider = this.shadowRoot?.querySelector<LitSlider>('#ftrace-buff-size-slider');
201    litSwitch.addEventListener('change', (event: unknown) => {
202      //@ts-ignore
203      let detail = event.detail;
204      if (detail!.checked) {
205        this.unDisable();
206      } else {
207        this.disable();
208      }
209    });
210  }
211
212  private bufferSizeSliderInit(): void {
213    let bufferSizeSlider = this.shadowRoot?.querySelector<LitSlider>('#ftrace-buff-size-slider') as LitSlider;
214    this.ftraceBufferSizeResult = this.shadowRoot?.querySelector('#ftrace-buff-size-div') as HTMLDivElement;
215    bufferSizeSlider.sliderStyle = {
216      minRange: 2048,
217      maxRange: 307200,
218      defaultValue: '204800',
219      resultUnit: 'KB',
220      stepSize: 2,
221      lineColor: 'var(--dark-color3,#46B1E3)',
222      buttonColor: '#999999',
223    };
224    let bufferSizeSliderParent = bufferSizeSlider!.parentNode as Element;
225    let buffSizeResult = this.shadowRoot?.querySelector('.ftrace-buff-size-result') as HTMLInputElement;
226    buffSizeResult!.onkeydown = (ev): void => {
227      // @ts-ignore
228      if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') {
229        ev.preventDefault();
230      }
231    };
232    buffSizeResult.value = bufferSizeSlider.sliderStyle.defaultValue;
233    bufferSizeSlider.addEventListener('input', () => {
234      buffSizeResult.parentElement!.classList.remove('border-red');
235      if (this.ftraceBufferSizeResult!.hasAttribute('percent')) {
236        buffSizeResult.value = Number(this.ftraceBufferSizeResult!.getAttribute('percent')).toString();
237      } else {
238        buffSizeResult.value = '20480';
239      }
240    });
241    bufferSizeSliderParent.setAttribute('percent', '20480');
242    buffSizeResult.style.color = 'var(--dark-color1,#000000)';
243    buffSizeResult.addEventListener('input', () => {
244      this.ftraceBuffSizeResultInputHandler(buffSizeResult, bufferSizeSliderParent, bufferSizeSlider);
245    });
246    buffSizeResult.addEventListener('focusout', () => {
247      if (buffSizeResult.value.trim() === '') {
248        buffSizeResult.parentElement!.classList.remove('border-red');
249        bufferSizeSliderParent.setAttribute('percent', '20480');
250        buffSizeResult.value = '20480';
251        buffSizeResult.style.color = 'var(--dark-color,#6a6f77)';
252        bufferSizeSliderParent.setAttribute('percent', buffSizeResult.value);
253        bufferSizeSliderParent.setAttribute('percentValue', buffSizeResult.value);
254        bufferSizeSlider!.percent = buffSizeResult.value;
255        let htmlInputElement = bufferSizeSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement;
256        htmlInputElement.value = buffSizeResult.value;
257      }
258    });
259  }
260
261  private ftraceBuffSizeResultInputHandler(
262    buffSizeResultEl: HTMLInputElement,
263    bufferSizeSliderParentEl: Element,
264    bufferSizeSliderEl: LitSlider
265  ): void {
266    if (this.ftraceBufferSizeResult!.hasAttribute('percent')) {
267      this.ftraceBufferSizeResult!.removeAttribute('percent');
268    }
269    buffSizeResultEl.style.color = 'var(--dark-color1,#000000)';
270    buffSizeResultEl.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)';
271    buffSizeResultEl.style.backgroundColor = 'var(--dark-background5,#F2F2F2)';
272    if (buffSizeResultEl.value.trim() === '') {
273      buffSizeResultEl.style.color = 'red';
274      bufferSizeSliderParentEl.setAttribute('percent', '20480');
275      return;
276    }
277    let ftraceBufferSize = Number(buffSizeResultEl.value);
278    if (
279      ftraceBufferSize < bufferSizeSliderEl!.sliderStyle.minRange ||
280      ftraceBufferSize > bufferSizeSliderEl!.sliderStyle.maxRange
281    ) {
282      buffSizeResultEl.parentElement!.classList.add('border-red');
283      bufferSizeSliderParentEl.setAttribute('percent', '20480');
284    } else {
285      buffSizeResultEl.parentElement!.classList.remove('border-red');
286      bufferSizeSliderEl!.percent = buffSizeResultEl.value;
287      let htmlInputElement = bufferSizeSliderEl!.shadowRoot?.querySelector('#slider') as HTMLInputElement;
288      htmlInputElement.value = buffSizeResultEl.value;
289      bufferSizeSliderParentEl.setAttribute('percent', buffSizeResultEl.value);
290      bufferSizeSliderParentEl.setAttribute('percentValue', buffSizeResultEl.value);
291    }
292  }
293
294  private unDisable(): void {
295    this.startSamp = true;
296    let checkDesBoxDis = this.shadowRoot?.querySelectorAll<SpCheckDesBox>('check-des-box');
297    let litCheckBoxDis = this.shadowRoot?.querySelectorAll<LitCheckBox>('lit-check-box');
298    let defaultSelected: unknown = [];
299    //@ts-ignore
300    defaultSelected = defaultSelected.concat(traceConfigList, memoryConfigList, abilityConfigList, hiTraceConfigList);
301    this.shadowRoot?.querySelector<SpCheckDesBox>("[value='Hitrace categories']")?.setAttribute('checked', 'true');
302    this.ftraceSlider!.removeAttribute('disabled');
303    checkDesBoxDis?.forEach((item: SpCheckDesBox) => {
304      item.removeAttribute('disabled');
305    });
306    litCheckBoxDis?.forEach((item: LitCheckBox) => {
307      item.removeAttribute('disabled');
308    });
309    //@ts-ignore
310    defaultSelected.filter((item: unknown) => {
311      //@ts-ignore
312      if (item.isSelect) {
313        //@ts-ignore
314        this.shadowRoot?.querySelector<SpCheckDesBox>(`[value='${item.value}']`)?.setAttribute('checked', 'true');
315      }
316    });
317  }
318
319  private disable(): void {
320    this.startSamp = false;
321    let checkDesBoxDis = this.shadowRoot?.querySelectorAll<SpCheckDesBox>('check-des-box');
322    let litCheckBoxDis = this.shadowRoot?.querySelectorAll<LitCheckBox>('lit-check-box');
323
324    this.ftraceSlider!.setAttribute('disabled', '');
325
326    checkDesBoxDis?.forEach((item: SpCheckDesBox) => {
327      item.setAttribute('disabled', '');
328      item.checked = false;
329    });
330
331    litCheckBoxDis?.forEach((item: LitCheckBox) => {
332      item.setAttribute('disabled', '');
333      item.checked = false;
334    });
335  }
336
337  initHtml(): string {
338    return SpProbesConfigHtml;
339  }
340
341  //当 custom element首次被插入文档DOM时,被调用。
342  public connectedCallback(): void {
343    let parent = this.shadowRoot?.querySelector('.user-events') as Element;
344    const siblingNode = parent?.querySelectorAll<LitCheckBox>('lit-check-box[name=userEvents]');
345    this.hitrace!.addEventListener('onchange', (ev: CustomEventInit<LitCheckBoxChangeEvent>) => {
346      let detail = ev.detail;
347      siblingNode.forEach((node) => {
348        node.checked = detail!.checked;
349      });
350      this.dispatchEvent(new CustomEvent('addProbe', {}));
351    });
352  }
353}
354
355const hiTraceConfigList = [
356  { value: 'ability', isSelect: true },
357  { value: 'accesscontrol', isSelect: false },
358  { value: 'accessibility', isSelect: false },
359  { value: 'account', isSelect: false },
360  { value: 'ace', isSelect: true },
361  { value: 'app', isSelect: true },
362  { value: 'ark', isSelect: true },
363  { value: 'binder', isSelect: true },
364  { value: 'bluetooth', isSelect: false },
365  { value: 'cloud', isSelect: false },
366  { value: 'commonlibrary', isSelect: false },
367  { value: 'daudio', isSelect: false },
368  { value: 'dcamera', isSelect: false },
369  { value: 'deviceauth', isSelect: false },
370  { value: 'devicemanager', isSelect: false },
371  { value: 'deviceprofile', isSelect: false },
372  { value: 'dhfwk', isSelect: false },
373  { value: 'dinput', isSelect: false },
374  { value: 'disk', isSelect: true },
375  { value: 'distributeddatamgr', isSelect: false },
376  { value: 'dlpcre', isSelect: false },
377  { value: 'dsched', isSelect: false },
378  { value: 'dscreen', isSelect: false },
379  { value: 'dslm', isSelect: false },
380  { value: 'dsoftbus', isSelect: false },
381  { value: 'ffrt', isSelect: false },
382  { value: 'filemanagement', isSelect: false },
383  { value: 'freq', isSelect: true },
384  { value: 'graphic', isSelect: true },
385  { value: 'gresource', isSelect: false },
386  { value: 'hdcd', isSelect: false },
387  { value: 'hdf', isSelect: false },
388  { value: 'huks', isSelect: false },
389  { value: 'i2c', isSelect: false },
390  { value: 'idle', isSelect: true },
391  { value: 'interconn', isSelect: false },
392  { value: 'irq', isSelect: true },
393  { value: 'mdfs', isSelect: false },
394  { value: 'memory', isSelect: false },
395  { value: 'memreclaim', isSelect: true },
396  { value: 'misc', isSelect: false },
397  { value: 'mmc', isSelect: true },
398  { value: 'msdp', isSelect: false },
399  { value: 'multimodalinput', isSelect: true },
400  { value: 'musl', isSelect: false },
401  { value: 'net', isSelect: false },
402  { value: 'notification', isSelect: true },
403  { value: 'nweb', isSelect: false },
404  { value: 'ohos', isSelect: true },
405  { value: 'pagecache', isSelect: true },
406  { value: 'power', isSelect: false },
407  { value: 'regulators', isSelect: false },
408  { value: 'rpc', isSelect: true },
409  { value: 'samgr', isSelect: false },
410  { value: 'sched', isSelect: true },
411  { value: 'sensors', isSelect: false },
412  { value: 'sync', isSelect: true },
413  { value: 'usb', isSelect: false },
414  { value: 'ufs', isSelect: false },
415  { value: 'useriam', isSelect: false },
416  { value: 'virse', isSelect: false },
417  { value: 'window', isSelect: true },
418  { value: 'workq', isSelect: true },
419  { value: 'zaudio', isSelect: true },
420  { value: 'zcamera', isSelect: true },
421  { value: 'zimage', isSelect: true },
422  { value: 'zmedia', isSelect: true },
423];
424
425const traceConfigList = [
426  {
427    value: 'Scheduling details',
428    isSelect: true,
429    des: 'enables high-detailed tracking of scheduling events',
430  },
431  {
432    value: 'CPU Frequency and idle states',
433    isSelect: true,
434    des: 'Records cpu frequency and idle state change viaftrace',
435  },
436  {
437    value: 'Advanced ftrace config',
438    isSelect: false,
439    des:
440      'Enable individual events and tune the kernel-tracing(ftrace) module.' +
441      'The events enabled here are in addition to those from' +
442      ' enabled by other probes.',
443  },
444];
445
446const memoryConfigList = [
447  {
448    value: 'Kernel meminfo',
449    isSelect: false,
450    des: 'polling of /proc/meminfo',
451  },
452  {
453    value: 'Virtual memory stats',
454    isSelect: false,
455    des:
456      'Periodically polls virtual memory stats from /proc/vmstat.' +
457      ' Allows to gather statistics about swap,' +
458      'eviction, compression and pagecache efficiency',
459  },
460];
461
462const abilityConfigList = [
463  {
464    value: 'AbilityMonitor',
465    isSelect: false,
466    des: 'Tracks the AbilityMonitor',
467  },
468];
469