• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { ColorUtils } from '../../component/trace/base/ColorUtils';
17import {
18  BaseStruct,
19  drawLoadingFrame,
20  isFrameContainPoint,
21  PerfRender,
22  Rect,
23  RequestMessage,
24} from './ProcedureWorkerCommon';
25import { TraceRow } from '../../component/trace/base/TraceRow';
26
27export class EnergyAnomalyRender extends PerfRender {
28  renderMainThread(
29    req: {
30      useCache: boolean;
31      context: CanvasRenderingContext2D;
32      type: string;
33      appName: string;
34      canvasWidth: number;
35    },
36    row: TraceRow<EnergyAnomalyStruct>
37  ): void {
38    let list = row.dataList;
39    let filter = row.dataListCache;
40    anomaly(
41      list,
42      filter,
43      TraceRow.range!.startNS,
44      TraceRow.range!.endNS,
45      TraceRow.range!.totalNS,
46      row.frame,
47      req.appName,
48      req.useCache || !TraceRow.range!.refresh
49    );
50    if (list.length > 0) {
51      filter.length = 0;
52      list.forEach((item) => {
53        filter.push(item);
54      });
55    }
56    drawLoadingFrame(req.context, row.dataListCache, row);
57    req.context.beginPath();
58    let find = false;
59    let spApplication = document.getElementsByTagName('sp-application')[0];
60    let isDark = spApplication.hasAttribute('dark');
61    drawLegend(req, isDark);
62    for (let re of filter) {
63      EnergyAnomalyStruct.draw(req.context, re);
64      if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
65        EnergyAnomalyStruct.hoverEnergyAnomalyStruct = re;
66        find = true;
67      }
68    }
69    if (!find && row.isHover) {
70      EnergyAnomalyStruct.hoverEnergyAnomalyStruct = undefined;
71    }
72    req.context.fillStyle = ColorUtils.FUNC_COLOR[0];
73    req.context.strokeStyle = ColorUtils.FUNC_COLOR[0];
74    req.context.closePath();
75  }
76
77  render(
78    energyAnomalyRequest: RequestMessage,
79    list: Array<EnergyAnomalyStruct>,
80    filter: Array<EnergyAnomalyStruct>,
81    dataList2: Array<EnergyAnomalyStruct>
82  ): void {}
83}
84
85export function drawLegend(
86  req: {
87    useCache: boolean;
88    context: CanvasRenderingContext2D;
89    type: string;
90    appName: string;
91    canvasWidth: number;
92  },
93  isDark?: boolean
94): void {
95  req.context.font = '12px Arial';
96  let text = req.context.measureText('System Abnormality');
97  req.context.fillStyle = '#E64566';
98  req.context.strokeStyle = '#E64566';
99  let textColor = isDark ? '#FFFFFF' : '#333';
100  let canvasEndX = req.context.canvas.clientWidth - EnergyAnomalyStruct.OFFSET_WIDTH;
101  let rectPadding: number;
102  let textPadding: number;
103  let textMargin: number;
104  let currentTextWidth: number;
105  let lastTextMargin: number;
106  rectPadding = 280;
107  textPadding = 270;
108  textMargin = 250;
109  currentTextWidth = canvasEndX - textMargin + text.width;
110  lastTextMargin = currentTextWidth + 12;
111  req!.context.fillRect(canvasEndX - rectPadding, 12, 8, 8);
112  req.context.globalAlpha = 1;
113  req.context.fillStyle = textColor;
114  req.context.textBaseline = 'middle';
115  req.context.fillText('System Abnormality', canvasEndX - textPadding, 18);
116  req.context.fillStyle = '#FFC880';
117  req.context.strokeStyle = '#FFC880';
118  req.context.fillRect(currentTextWidth, 12, 8, 8);
119  req.context.globalAlpha = 1;
120  req.context.fillStyle = textColor;
121  req.context.textBaseline = 'middle';
122  req.context.fillText('Application Abnormality', lastTextMargin, 18);
123  req.context.fillStyle = '#333';
124}
125
126export function anomaly(
127  arr: Array<EnergyAnomalyStruct>,
128  res: Array<EnergyAnomalyStruct>,
129  startNS: number,
130  endNS: number,
131  totalNS: number,
132  frame: Rect,
133  appName: string,
134  use: boolean
135): void {
136  arr.length = 0;
137  if (use && res.length > 0) {
138    let pns = (endNS - startNS) / frame.width;
139    let y = frame.y;
140    for (let i = 0; i < res.length; i++) {
141      let it = res[i];
142      if ((it.startNS || 0) > startNS && (it.startNS || 0) < endNS) {
143        if (!it.frame) {
144          it.frame = new Rect(0, 0, 0, 0);
145          it.frame.y = y;
146        }
147        it.frame.height = 20 + radius * 2;
148        if (it.startNS! + 50000 > (startNS || 0) && (it.startNS || 0) < (endNS || 0)) {
149          EnergyAnomalyStruct.setAnomalyFrame(it, pns, startNS || 0, endNS || 0, frame);
150          if (it.appKey === 'APPNAME' && it.eventValue!.split(',').indexOf(appName!) >= 0) {
151            arr.push(it);
152          }
153          if (it.appKey !== 'APPNAME') {
154            arr.push(it);
155          }
156        }
157      } else {
158        it.frame = undefined;
159      }
160    }
161    return;
162  }
163}
164
165export class EnergyAnomalyStruct extends BaseStruct {
166  static hoverEnergyAnomalyStruct: EnergyAnomalyStruct | undefined;
167  static selectEnergyAnomalyStruct: EnergyAnomalyStruct | undefined;
168  static SYSTEM_EXCEPTION = new Set([
169    'ANOMALY_SCREEN_OFF_ENERGY',
170    'ANOMALY_ALARM_WAKEUP',
171    'ANOMALY_KERNEL_WAKELOCK',
172    'ANOMALY_CPU_HIGH_FREQUENCY',
173    'ANOMALY_WAKEUP',
174  ]);
175  static OFFSET_WIDTH: number = 266;
176  id: number | undefined;
177  type: number | undefined;
178  startNS: number | undefined;
179  height: number | undefined;
180  eventName: string | undefined;
181  appKey: string | undefined;
182  eventValue: string | undefined;
183
184  static draw(ctx: CanvasRenderingContext2D, data: EnergyAnomalyStruct): void {
185    if (data.frame) {
186      EnergyAnomalyStruct.drawRoundRectPath(ctx, data.frame.x - 7, 20 - 7, radius, data);
187    }
188  }
189
190  static drawRoundRectPath(
191    ctx: CanvasRenderingContext2D,
192    x: number,
193    y: number,
194    radius: number,
195    data: EnergyAnomalyStruct
196  ): void {
197    ctx.beginPath();
198    ctx.arc(x + 7, y + 22, radius, 0, Math.PI * 2);
199    ctx.closePath();
200    let color = '';
201    if (EnergyAnomalyStruct.SYSTEM_EXCEPTION.has(<string>data.eventName)) {
202      color = '#E64566';
203    } else {
204      color = '#FFC880';
205    }
206    // 填充背景颜色
207    ctx.fillStyle = color;
208    ctx.fill();
209    ctx.stroke();
210    // 填充文字颜色
211    ctx.font = '12px Arial';
212    ctx.fillStyle = ColorUtils.GREY_COLOR;
213    ctx.textAlign = 'center';
214    ctx.fillText('E', x + 7, y + 23);
215  }
216
217  static setAnomalyFrame(node: EnergyAnomalyStruct, pns: number, startNS: number, endNS: number, frame: Rect): void {
218    if (!node.frame) {
219      node.frame = new Rect(0, 0, 0, 0);
220    }
221    if ((node.startNS || 0) < startNS) {
222      node.frame.x = 0;
223    } else {
224      node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns);
225    }
226    if ((node.startNS || 0) > endNS) {
227      node.frame.width = frame.width - node.frame.x;
228    } else {
229      node.frame.width = Math.ceil(((node.startNS || 0) - startNS) / pns - node.frame.x);
230    }
231    if (node.frame.width < 1) {
232      node.frame.width = 1;
233    }
234  }
235}
236let radius = 12;
237