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 { TraficEnum } from './utils/QueryEnum';
17import { energyList } from './utils/AllMemoryCache';
18import { Args } from './CommonArgs';
19
20export const systemDataSql = (args: Args): string => {
21  return `SELECT S.id,
22                 S.ts - ${args.recordStartNS
23    }                                                                   AS startNs,
24                 D.data                                                                                         AS eventName,
25                 (case when D.data = 'POWER_RUNNINGLOCK' then 1 when D.data = 'GNSS_STATE' then 2 else 0 end) AS appKey,
26                 contents                                                                                       AS eventValue,
27                 ((S.ts - ${args.recordStartNS}) / (${Math.floor((args.endNS - args.startNS) / args.width)}))   as px
28          FROM hisys_all_event AS S
29                   LEFT JOIN data_dict AS D ON S.event_name_id = D.id
30                   LEFT JOIN data_dict AS D2 ON S.domain_id = D2.id
31          WHERE eventName IN ('POWER_RUNNINGLOCK', 'GNSS_STATE', 'WORK_START', 'WORK_REMOVE', 'WORK_STOP', 'WORK_ADD')
32            and startNs >= ${Math.floor(args.startNS)}
33            and startNs <= ${Math.floor(args.endNS)}
34          group by px;`;
35};
36
37export const systemDataMemSql = (args: Args): string => {
38  return `SELECT S.id,
39                 S.ts - ${args.recordStartNS}                                                                         AS startNs,
40                 D.data                                                                                               AS eventName,
41                 (case when D.data = 'POWER_RUNNINGLOCK' then '1' when D.data = 'GNSS_STATE' then '2' else '0' end) AS appKey,
42                 contents                                                                                             AS eventValue
43          FROM hisys_all_event AS S
44                   LEFT JOIN data_dict AS D ON S.event_name_id = D.id
45                   LEFT JOIN data_dict AS D2 ON S.domain_id = D2.id
46          WHERE eventName IN
47                ('POWER_RUNNINGLOCK', 'GNSS_STATE', 'WORK_START', 'WORK_REMOVE', 'WORK_STOP', 'WORK_ADD');`;
48};
49
50export const chartEnergyAnomalyDataSql = (args: Args): string => {
51  return `
52      select S.id,
53             S.ts - ${args.recordStartNS}                  as startNs,
54             D.data                                        as eventName,
55             D2.data                                       as appKey,
56             (case
57                  when S.type==1 then group_concat(S.string_value, ',')
58                  else group_concat(S.int_value, ',') end) as eventValue
59      from hisys_event_measure as S
60               left join data_dict as D
61                         on D.id = S.name_id
62               left join app_name as APP on APP.id = S.key_id
63               left join data_dict as D2 on D2.id = APP.app_key
64      where D.data in
65            ('ANOMALY_SCREEN_OFF_ENERGY', 'ANOMALY_KERNEL_WAKELOCK', 'ANOMALY_CPU_HIGH_FREQUENCY', 'ANOMALY_WAKEUP')
66         or (D.data in ('ANOMALY_RUNNINGLOCK', 'ANORMALY_APP_ENERGY', 'ANOMALY_GNSS_ENERGY', 'ANOMALY_CPU_ENERGY',
67                        'ANOMALY_ALARM_WAKEUP')
68          and D2.data in ('APPNAME'))
69      group by S.serial, D.data`;
70};
71export const queryPowerValueSql = (args: Args): string => {
72  return `
73      SELECT S.id,
74             S.ts - ${args.recordStartNS}                                                        as startNs,
75             D.data                                                                              AS eventName,
76             D2.data                                                                             AS appKey,
77             group_concat((CASE WHEN S.type = 1 THEN S.string_value ELSE S.int_value END), ',') AS eventValue
78      FROM hisys_event_measure AS S
79               LEFT JOIN data_dict AS D
80                         ON D.id = S.name_id
81               LEFT JOIN app_name AS APP
82                         ON APP.id = S.key_id
83               LEFT JOIN data_dict AS D2
84                         ON D2.id = APP.app_key
85      where D.data in ('POWER_IDE_CPU', 'POWER_IDE_LOCATION', 'POWER_IDE_GPU', 'POWER_IDE_DISPLAY', 'POWER_IDE_CAMERA',
86                       'POWER_IDE_BLUETOOTH', 'POWER_IDE_FLASHLIGHT', 'POWER_IDE_AUDIO', 'POWER_IDE_WIFISCAN')
87        and D2.data in
88            ('BACKGROUND_ENERGY', 'FOREGROUND_ENERGY', 'SCREEN_ON_ENERGY', 'SCREEN_OFF_ENERGY', 'ENERGY', 'APPNAME')
89      GROUP BY S.serial,
90               APP.app_key,
91               D.data,
92               D2.data
93      ORDER BY eventName;`;
94};
95
96export const queryStateDataSql = (args: Args): string => {
97  return `
98      select S.id,
99             S.ts - ${args.recordStartNS} as startNs,
100             D.data                       as eventName,
101             D2.data                      as appKey,
102             S.int_value                  as eventValue
103      from hisys_event_measure as S
104               left join data_dict as D on D.id = S.name_id
105               left join app_name as APP on APP.id = S.key_id
106               left join data_dict as D2 on D2.id = APP.app_key
107      where (case when 'SENSOR_STATE'== '${args.eventName}' then D.data like '%SENSOR%' else D.data = '${args.eventName}' end)
108        and D2.data in ('BRIGHTNESS', 'STATE', 'VALUE', 'LEVEL', 'VOLUME', 'OPER_TYPE', 'VOLUME')
109      group by S.serial, APP.app_key, D.data, D2.data;`;
110};
111
112export const queryStateProtoDataSql = (args: Args): string => {
113  return `
114      SELECT S.id,
115             S.ts - ${args.recordStartNS} AS startNs,
116             D.data                       AS eventName,
117             ''                           AS appKey,
118             contents                     AS eventValue
119      FROM hisys_all_event AS S
120               LEFT JOIN data_dict AS D ON S.event_name_id = D.id
121               LEFT JOIN data_dict AS D2 ON S.domain_id = D2.id
122      WHERE eventName = ${args.eventName}`;
123};
124let systemList: Array<unknown> = [];
125let anomalyList: Array<unknown> = [];
126let powerList: Array<unknown> = [];
127
128export function resetEnergyEvent(): void {
129  systemList = [];
130  anomalyList = [];
131  powerList = [];
132}
133
134export function energySysEventReceiver(data: unknown, proc: Function): void {
135  // @ts-ignore
136  if (data.params.trafic === TraficEnum.Memory) {
137    if (systemList.length === 0) {
138      // @ts-ignore
139      systemList = proc(systemDataMemSql(data.params));
140    }
141    // @ts-ignore
142    systemBufferHandler(data, systemList, data.params.trafic !== TraficEnum.SharedArrayBuffer);
143    // @ts-ignore
144  } else if (data.params.trafic === TraficEnum.ProtoBuffer) {
145    // @ts-ignore
146    let sql = systemDataSql(data.params);
147    let res = proc(sql);
148    // @ts-ignore
149    systemBufferHandler(data, res, data.params.trafic !== TraficEnum.SharedArrayBuffer);
150  }
151}
152
153export function hiSysEnergyAnomalyDataReceiver(data: unknown, proc: Function): void {
154  // @ts-ignore
155  if (data.params.trafic === TraficEnum.Memory) {
156    if (anomalyList.length === 0) {
157      // @ts-ignore
158      anomalyList = proc(chartEnergyAnomalyDataSql(data.params));
159    }
160    // @ts-ignore
161    anomalyBufferHandler(data, anomalyList, data.params.trafic !== TraficEnum.SharedArrayBuffer);
162    // @ts-ignore
163  } else if (data.params.trafic === TraficEnum.ProtoBuffer) {
164    // @ts-ignore
165    let sql = chartEnergyAnomalyDataSql(data.params);
166    let res = proc(sql);
167    // @ts-ignore
168    anomalyBufferHandler(data, res, data.params.trafic !== TraficEnum.SharedArrayBuffer);
169  }
170}
171
172export function hiSysEnergyPowerReceiver(data: unknown, proc: Function): void {
173  // @ts-ignore
174  if (data.params.trafic === TraficEnum.Memory) {
175    if (powerList.length === 0) {
176      // @ts-ignore
177      powerList = proc(queryPowerValueSql(data.params));
178    }
179    // @ts-ignore
180    powerBufferHandler(data, powerList, data.params.trafic !== TraficEnum.SharedArrayBuffer);
181    // @ts-ignore
182  } else if (data.params.trafic === TraficEnum.ProtoBuffer) {
183    // @ts-ignore
184    let sql = queryPowerValueSql(data.params);
185    let res = proc(sql);
186    // @ts-ignore
187    powerBufferHandler(data, res, data.params.trafic !== TraficEnum.SharedArrayBuffer);
188  }
189}
190
191export function hiSysEnergyStateReceiver(data: unknown, proc: Function): void {
192  // @ts-ignore
193  if (data.params.trafic === TraficEnum.Memory) {
194    let res: unknown[];
195    let list: unknown[];
196    // @ts-ignore
197    if (!energyList.has(data.params.eventName)) {
198      // @ts-ignore
199      list = proc(queryStateDataSql(data.params));
200      // @ts-ignore
201      energyList.set(data.params.eventName, list);
202    } else {
203      // @ts-ignore
204      list = energyList.get(data.params.eventName) || [];
205    }
206    res = list;
207    // @ts-ignore
208    stateBufferHandler(data, res, data.params.trafic !== TraficEnum.SharedArrayBuffer);
209    // @ts-ignore
210  } else if (data.params.trafic === TraficEnum.ProtoBuffer) {
211    // @ts-ignore
212    let stateDataSql = queryStateDataSql(data.params);
213    let stateDataRes = proc(stateDataSql);
214    // @ts-ignore
215    stateBufferHandler(data, stateDataRes, data.params.trafic !== TraficEnum.SharedArrayBuffer);
216  }
217}
218
219function systemBufferHandler(data: unknown, res: unknown[], transfer: boolean): void {
220  let hiSysEnergy = new HiSysEnergy(data, res, transfer);
221  let systemDataList: unknown = [];
222  let workCountMap: Map<string, number> = new Map<string, number>();
223  let nameIdMap: Map<string, Array<unknown>> = new Map<string, []>();
224  res.forEach((it, index) => {
225    // @ts-ignore
226    data.params.trafic === TraficEnum.ProtoBuffer && (it = it.energyData);
227    // @ts-ignore
228    let parsedData = it.eventValue;
229    // @ts-ignore
230    if (typeof it.eventValue === 'string') {
231      try {
232        // @ts-ignore
233        parsedData = JSON.parse(it.eventValue);
234      } catch (error) { }
235    }
236    // @ts-ignore
237    it.eventValue = parsedData;
238    let beanData: unknown = {};
239    // @ts-ignore
240    if (it.appKey === '1') {
241      // @ts-ignore
242      eventNameWithPowerRunninglock(beanData, it, systemDataList);
243      // @ts-ignore
244    } else if (it.appKey === '2') {
245      // @ts-ignore
246      eventNameWithGnssState(beanData, it, systemDataList);
247    } else {
248      // @ts-ignore
249      beanData.dataType = 3;
250      // @ts-ignore
251      if (it.eventValue.NAME) {
252        // @ts-ignore
253        beanData.appName = it.NAME;
254      }
255      // @ts-ignore
256      if (it.eventValue.WORKID) {
257        // @ts-ignore
258        beanData.workId = it.WORKID;
259      }
260      // @ts-ignore
261      if (it.eventName === 'WORK_START') {
262        // @ts-ignore
263        eventNameWithWorkStart(nameIdMap, beanData, workCountMap, it, systemDataList);
264        // @ts-ignore
265      } else if (it.eventName === 'WORK_STOP') {
266        // @ts-ignore
267        eventNameWithWorkStop(nameIdMap, beanData, workCountMap, it, systemDataList);
268      }
269    }
270    // @ts-ignore
271    hiSysEnergy.id[index] = beanData.id;
272    // @ts-ignore
273    hiSysEnergy.startNs[index] = beanData.startNs;
274    // @ts-ignore
275    hiSysEnergy.count[index] = beanData.count;
276    // @ts-ignore
277    hiSysEnergy.type[index] = beanData.dataType;
278    // @ts-ignore
279    hiSysEnergy.token[index] = beanData.token;
280    // @ts-ignore
281    hiSysEnergy.dataType[index] = beanData.dataType;
282  });
283  postMessage(data, transfer, hiSysEnergy, res.length);
284}
285
286function eventNameWithPowerRunninglock(beanData: unknown, it: unknown, systemDataList: Array<unknown>): void {
287  let lockCount = 0;
288  let tokedIds: Array<string> = [];
289  // @ts-ignore
290  beanData.dataType = 1;
291  // @ts-ignore
292  if (it.eventValue.TAG.endsWith('_ADD')) {
293    // @ts-ignore
294    beanData.startNs = it.startNs;
295    lockCount++;
296    // @ts-ignore
297    beanData.id = it.id;
298    // @ts-ignore
299    beanData.count = lockCount;
300    // @ts-ignore
301    beanData.token = it.eventValue.MESSAGE.split('=')[1];
302    // @ts-ignore
303    beanData.type = 1;
304    // @ts-ignore
305    tokedIds.push(beanData.token);
306    systemDataList.push(beanData);
307  } else {
308    // @ts-ignore
309    beanData.id = it.id;
310    // @ts-ignore
311    beanData.startNs = it.startNs;
312    // @ts-ignore
313    let toked = it.eventValue.MESSAGE.split('=')[1];
314    let number = tokedIds.indexOf(toked);
315    if (number > -1) {
316      lockCount--;
317      // @ts-ignore
318      beanData.count = lockCount;
319      // @ts-ignore
320      beanData.token = it.eventValue.MESSAGE.split('=')[1];
321      // @ts-ignore
322      beanData.type = 1;
323      systemDataList.push(beanData);
324      Reflect.deleteProperty(tokedIds, 'number');
325    }
326  }
327}
328
329function eventNameWithGnssState(beanData: unknown, it: unknown, systemDataList: Array<unknown>): void {
330  let locationIndex = -1;
331  let locationCount = 0;
332  // @ts-ignore
333  beanData.dataType = 2;
334  // @ts-ignore
335  if (it.eventValue.STATE === 'stop') {
336    if (locationIndex === -1) {
337      // @ts-ignore
338      beanData.startNs = 0;
339      // @ts-ignore
340      beanData.count = 1;
341    } else {
342      // @ts-ignore
343      beanData.startNs = it.startNs;
344      locationCount--;
345      // @ts-ignore
346      beanData.count = locationCount;
347    }
348    // @ts-ignore
349    beanData.state = 'stop';
350  } else {
351    // @ts-ignore
352    beanData.startNs = it.startNs;
353    locationCount++;
354    // @ts-ignore
355    beanData.count = locationCount;
356    // @ts-ignore
357    beanData.state = 'start';
358  }
359  locationIndex = 0;
360  // @ts-ignore
361  beanData.type = 2;
362  systemDataList.push(beanData);
363}
364
365function eventNameWithWorkStart(
366  nameIdMap: Map<string, Array<unknown>>,
367  beanData: unknown,
368  workCountMap: Map<string, number>,
369  it: unknown,
370  systemDataList: Array<unknown>
371): void {
372  // @ts-ignore
373  let nameIdList = nameIdMap.get(beanData.appName);
374  let workCount = 0;
375  if (nameIdList === undefined) {
376    workCount = 1;
377    // @ts-ignore
378    nameIdMap.set(beanData.appName, [beanData.workId]);
379  } else {
380    // @ts-ignore
381    nameIdList.push(beanData.workId);
382    workCount = nameIdList.length;
383  }
384  // @ts-ignore
385  let count = workCountMap.get(beanData.appName);
386  if (count === undefined) {
387    // @ts-ignore
388    workCountMap.set(beanData.appName, 1);
389  } else {
390    // @ts-ignore
391    workCountMap.set(beanData.appName, count + 1);
392  }
393  // @ts-ignore
394  beanData.startNs = it.startNs;
395  // @ts-ignore
396  beanData.count = workCount;
397  // @ts-ignore
398  beanData.type = 0;
399  systemDataList.push(beanData);
400}
401
402function eventNameWithWorkStop(
403  nameIdMap: Map<string, Array<unknown>>,
404  beanData: unknown,
405  workCountMap: Map<string, number>,
406  it: unknown,
407  systemDataList: Array<unknown>
408): void {
409  // @ts-ignore
410  let nameIdList: unknown = nameIdMap.get(beanData.appName);
411  // @ts-ignore
412  let index = nameIdList.indexOf(beanData.workId);
413  if (nameIdList !== undefined && index > -1) {
414    // @ts-ignore
415    nameIdList.remove(index);
416    // @ts-ignore
417    let workCount = workCountMap.get(beanData.appName);
418    if (workCount !== undefined) {
419      workCount = workCount - 1;
420      // @ts-ignore
421      workCountMap.set(beanData.appName, workCount);
422      // @ts-ignore
423      beanData.startNs = it.startNs;
424      // @ts-ignore
425      beanData.count = workCount;
426      // @ts-ignore
427      beanData.type = 0;
428      systemDataList.push(beanData);
429    }
430  }
431}
432
433function postMessage(data: unknown, transfer: boolean, hiSysEnergy: HiSysEnergy, len: number): void {
434  (self as unknown as Worker).postMessage(
435    {
436      // @ts-ignore
437      id: data.id,
438      // @ts-ignore
439      action: data.action,
440      results: transfer
441        ? {
442          id: hiSysEnergy.id.buffer,
443          startNs: hiSysEnergy.startNs.buffer,
444          count: hiSysEnergy.count.buffer,
445          type: hiSysEnergy.type.buffer,
446          token: hiSysEnergy.token.buffer,
447          dataType: hiSysEnergy.dataType.buffer,
448        }
449        : {},
450      len: len,
451      transfer: transfer,
452    },
453    transfer
454      ? [
455        hiSysEnergy.id.buffer,
456        hiSysEnergy.startNs.buffer,
457        hiSysEnergy.count.buffer,
458        hiSysEnergy.type.buffer,
459        hiSysEnergy.token.buffer,
460        hiSysEnergy.dataType.buffer,
461      ]
462      : []
463  );
464}
465
466class HiSysEnergy {
467  id: Uint16Array;
468  startNs: Float64Array;
469  count: Uint32Array;
470  type: Uint32Array;
471  token: Float64Array;
472  dataType: Uint16Array;
473
474  constructor(data: unknown, res: unknown[], transfer: boolean) {
475    // @ts-ignore
476    this.id = new Uint16Array(transfer ? res.length : data.params.sharedArrayBuffers.id);
477    // @ts-ignore
478    this.startNs = new Float64Array(transfer ? res.length : data.params.sharedArrayBuffers.startNs);
479    // @ts-ignore
480    this.count = new Uint32Array(transfer ? res.length : data.params.sharedArrayBuffers.count);
481    // @ts-ignore
482    this.type = new Uint32Array(transfer ? res.length : data.params.sharedArrayBuffers.type);
483    // @ts-ignore
484    this.token = new Float64Array(transfer ? res.length : data.params.sharedArrayBuffers.token);
485    // @ts-ignore
486    this.dataType = new Uint16Array(transfer ? res.length : data.params.sharedArrayBuffers.dataType);
487  }
488}
489
490function anomalyBufferHandler(data: unknown, res: unknown[], transfer: boolean): void {
491  // @ts-ignore
492  let id = new Int32Array(transfer ? res.length : data.params.sharedArrayBuffers.id);
493  // @ts-ignore
494  let startNs = new Float64Array(transfer ? res.length : data.params.sharedArrayBuffers.startNs);
495  res.forEach((it, index) => {
496    // @ts-ignore
497    data.params.trafic === TraficEnum.ProtoBuffer && (it = it.energyData);
498    // @ts-ignore
499    id[index] = it.id;
500    // @ts-ignore
501    startNs[index] = it.startNs;
502  });
503  (self as unknown as Worker).postMessage(
504    {
505      // @ts-ignore
506      id: data.id,
507      // @ts-ignore
508      action: data.action,
509      results: transfer
510        ? {
511          id: id.buffer,
512          startNs: startNs.buffer,
513        }
514        : {},
515      len: res.length,
516      transfer: transfer,
517    },
518    transfer ? [startNs.buffer, id.buffer] : []
519  );
520}
521
522function powerBufferHandler(data: unknown, res: unknown[], transfer: boolean): void {
523  // @ts-ignore
524  let id = new Uint32Array(transfer ? res.length : data.params.sharedArrayBuffers.id);
525  // @ts-ignore
526  let startNs = new Float64Array(transfer ? res.length : data.params.sharedArrayBuffers.startNs);
527  res.forEach((it, index) => {
528    // @ts-ignore
529    data.params.trafic === TraficEnum.ProtoBuffer && (it = it.energyData);
530    // @ts-ignore
531    id[index] = it.id;
532    // @ts-ignore
533    startNs[index] = it.startNs;
534  });
535  (self as unknown as Worker).postMessage(
536    {
537      // @ts-ignore
538      id: data.id,
539      // @ts-ignore
540      action: data.action,
541      results: transfer
542        ? {
543          id: id.buffer,
544          startNs: startNs.buffer,
545        }
546        : {},
547      len: res.length,
548      transfer: transfer,
549    },
550    transfer ? [id.buffer, startNs.buffer] : []
551  );
552}
553
554function stateBufferHandler(data: unknown, res: unknown[], transfer: boolean): void {
555  // @ts-ignore
556  let startNs = new Float64Array(transfer ? res.length : data.params.sharedArrayBuffers.startNs);
557  // @ts-ignore
558  let eventValue = new Float32Array(transfer ? res.length : data.params.sharedArrayBuffers.eventValue);
559  // @ts-ignore
560  let id = new Uint32Array(transfer ? res.length : data.params.sharedArrayBuffers.id);
561  res.forEach((it, index) => {
562    // @ts-ignore
563    data.params.trafic === TraficEnum.ProtoBuffer && (it = it.energyData);
564    // @ts-ignore
565    id[index] = it.id;
566    // @ts-ignore
567    startNs[index] = it.startNs;
568    // @ts-ignore
569    let eventName = it.eventName.toLocaleLowerCase();
570    if (eventName.includes('sensor')) {
571      if (eventName.includes('enable')) {
572        eventValue[index] = 0;
573      } else {
574        eventValue[index] = 1;
575      }
576    } else {
577      // @ts-ignore
578      eventValue[index] = it.eventValue;
579    }
580  });
581  (self as unknown as Worker).postMessage(
582    {
583      // @ts-ignore
584      id: data.id,
585      // @ts-ignore
586      action: data.action,
587      results: transfer
588        ? {
589          id: id.buffer,
590          startNs: startNs.buffer,
591          eventValue: eventValue.buffer,
592        }
593        : {},
594      len: res.length,
595      transfer: transfer,
596    },
597    transfer ? [id.buffer, startNs.buffer, eventValue.buffer] : []
598  );
599}
600