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