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
16importScripts('trace_converter_builtin.js');
17self.onerror = function (error: unknown): void {};
18
19let convertModule: unknown = null;
20
21const CONTENT_TYPE_CMDLINES = 2;
22const CONTENT_TYPE_TGIDS = 3;
23const CONTENT_TYPE_HEADER_PAGE = 30;
24const CONTENT_TYPE_PRINTK_FORMATS = 31;
25const CONTENT_TYPE_KALLSYMS = 32;
26
27function initConvertWASM(): Promise<string> {
28  return new Promise((resolve, reject) => {
29    // @ts-ignore
30    let wasm = trace_converter_builtin_wasm;
31    convertModule = wasm({
32      locateFile: (s: unknown): unknown => {
33        return s;
34      },
35      print: (line: unknown): void => {},
36      printErr: (line: unknown): void => {},
37      onAbort: (): void => {
38        reject('on abort');
39      },
40      onRuntimeInitialized: (): void => {
41        resolve('ok');
42      },
43    });
44  });
45}
46
47function isRawTrace(uint8Array: Uint8Array): boolean {
48  let rowTraceStr = Array.from(new Uint16Array(uint8Array.buffer.slice(0, 2)));
49  return rowTraceStr[0] === 57161;
50}
51
52const ARRAY_BUF_SIZE = 2 * 1024 * 1024;
53self.onmessage = async (e: MessageEvent): Promise<void> => {
54  if (e.data.action === 'getConvertData') {
55    await initConvertWASM();
56    let fileData = e.data.buffer;
57    const stepSize = 4 * 1024 * 1024;
58    let totalSize = fileData.byteLength;
59    // @ts-ignore
60    let traceInsPtr = convertModule._GetTraceConverterIns(); // 获取TraceConverter 实例
61    // @ts-ignore
62    convertModule._SetDebugFlag(false, traceInsPtr); // 设置是否为debug模式
63    let currentPosition = 1024;
64    // @ts-ignore
65    let dataHeader = convertModule._malloc(1100);
66    let traceAllData = new Uint8Array(e.data.buffer);
67    let isRawTraceConvert = isRawTrace(e.data);
68    if (isRawTraceConvert) {
69      [totalSize, currentPosition, traceAllData] = handleRowTrace(
70        e,
71        fileData,
72        dataHeader,
73        traceInsPtr,
74        currentPosition,
75        traceAllData,
76        totalSize
77      );
78    } else {
79      handleHTrace(fileData, dataHeader, traceInsPtr);
80    }
81    // @ts-ignore
82    let dataPtr = convertModule._malloc(stepSize);
83    // @ts-ignore
84    let arrayBufferPtr = convertModule._malloc(ARRAY_BUF_SIZE);
85    // @ts-ignore
86    convertModule._free(dataHeader);
87    let bodyDataStr: string[] = [];
88    let callback = (heapPtr: number, size: number): void => {
89      // @ts-ignore
90      let out = convertModule.HEAPU8.slice(heapPtr, heapPtr + size);
91      let dec = new TextDecoder();
92      let str = dec.decode(out);
93      bodyDataStr.push(str);
94    };
95    // @ts-ignore
96    let bodyFn = convertModule.addFunction(callback, 'vii');
97    // @ts-ignore
98    convertModule._SetCallback(bodyFn, traceInsPtr);
99    convertData(
100      currentPosition,
101      traceAllData,
102      arrayBufferPtr,
103      dataPtr,
104      traceInsPtr,
105      isRawTraceConvert,
106      stepSize,
107      totalSize
108    );
109    // @ts-ignore
110    convertModule._GetRemainingData(traceInsPtr);
111    let headerData: string[] = [];
112    let headerCallback = (heapPtr: number, size: number): void => {
113      // @ts-ignore
114      let out = convertModule.HEAPU8.slice(heapPtr, heapPtr + size);
115      let dec = new TextDecoder();
116      let str = dec.decode(out);
117      headerData.push(str);
118    };
119    // @ts-ignore
120    let headerFn = convertModule.addFunction(headerCallback, 'vii');
121    // @ts-ignore
122    convertModule._SetCallback(headerFn, traceInsPtr);
123    // @ts-ignore
124    convertModule._GetFinalHeader(traceInsPtr);
125    let allDataStr = headerData.concat(bodyDataStr);
126    // @ts-ignore
127    convertModule._ReleaseTraceConverterIns(traceInsPtr); // 释放TraceConverter 实例
128    // @ts-ignore
129    convertModule._free(arrayBufferPtr); //释放分片内存
130    // @ts-ignore
131    convertModule._free(dataPtr);
132    postMessage(e, allDataStr);
133  }
134};
135
136function handleHTrace(fileData: Array<unknown>, dataHeader: unknown, traceInsPtr: unknown): void {
137  // @ts-ignore
138  let uint8Array = new Uint8Array(fileData.slice(0, 1024));
139  // @ts-ignore
140  convertModule.HEAPU8.set(uint8Array, dataHeader);
141  // @ts-ignore
142  convertModule._SendFileHeader(dataHeader, 1024, traceInsPtr);
143}
144
145function handleRowTrace(
146  e: MessageEvent,
147  fileData: Array<unknown>,
148  dataHeader: unknown,
149  traceInsPtr: unknown,
150  currentPosition: number,
151  traceAllData: Uint8Array,
152  totalSize: number
153): [number, number, Uint8Array] {
154  // @ts-ignore
155  let uint8Array = new Uint8Array(fileData.slice(0, 12));
156  // @ts-ignore
157  convertModule.HEAPU8.set(uint8Array, dataHeader);
158  // @ts-ignore
159  convertModule._SendRawFileHeader(dataHeader, 12, traceInsPtr);
160  currentPosition = 12;
161  let allRowTraceData = new Uint8Array(e.data.buffer);
162  let commonDataOffsetList: Array<{
163    startOffset: number;
164    endOffset: number;
165  }> = [];
166  let commonTotalLength = setCommonDataOffsetList(e, allRowTraceData, commonDataOffsetList);
167  let commonTotalOffset = 0;
168  let commonTotalData = new Uint8Array(commonTotalLength);
169  commonDataOffsetList.forEach((item) => {
170    commonTotalData.set(allRowTraceData.slice(item.startOffset, item.endOffset), commonTotalOffset);
171    commonTotalOffset += item.endOffset - item.startOffset;
172  });
173  traceAllData = new Uint8Array(allRowTraceData.length + commonTotalData.length);
174  traceAllData.set(allRowTraceData.slice(0, currentPosition), 0);
175  traceAllData.set(commonTotalData, currentPosition);
176  traceAllData.set(allRowTraceData.slice(currentPosition), commonTotalData.length + currentPosition);
177  totalSize += commonTotalData.length;
178  return [totalSize, currentPosition, traceAllData];
179}
180
181function isCommonData(dataType: number): boolean {
182  return (
183    dataType === CONTENT_TYPE_CMDLINES ||
184    dataType === CONTENT_TYPE_TGIDS ||
185    dataType === CONTENT_TYPE_HEADER_PAGE ||
186    dataType === CONTENT_TYPE_PRINTK_FORMATS ||
187    dataType === CONTENT_TYPE_KALLSYMS
188  );
189}
190
191function setCommonDataOffsetList(
192  e: MessageEvent,
193  allRowTraceData: Uint8Array,
194  commonDataOffsetList: Array<unknown>
195): number {
196  let commonTotalLength: number = 0;
197  let commonOffset = 12;
198  let tlvTypeLength = 4;
199  while (commonOffset < allRowTraceData.length) {
200    let commonDataOffset = {
201      startOffset: commonOffset,
202      endOffset: commonOffset,
203    };
204    let dataTypeData = e.data.buffer.slice(commonOffset, commonOffset + tlvTypeLength);
205    commonOffset += tlvTypeLength;
206    let dataType = Array.from(new Uint32Array(dataTypeData));
207    let currentLData = e.data.buffer.slice(commonOffset, commonOffset + tlvTypeLength);
208    commonOffset += tlvTypeLength;
209    let currentVLength = Array.from(new Uint32Array(currentLData));
210    commonOffset += currentVLength[0];
211    commonDataOffset.endOffset = commonOffset;
212    if (isCommonData(dataType[0])) {
213      commonTotalLength += commonDataOffset.endOffset - commonDataOffset.startOffset;
214      commonDataOffsetList.push(commonDataOffset);
215    }
216  }
217  return commonTotalLength;
218}
219
220function convertData(
221  currentPosition: number,
222  traceAllData: Uint8Array,
223  arrayBufferPtr: unknown,
224  dataPtr: unknown,
225  traceInsPtr: unknown,
226  isRawTraceConvert: boolean = false,
227  stepSize: number,
228  totalSize: number
229): void {
230  while (currentPosition < totalSize) {
231    let endPosition = Math.min(currentPosition + stepSize, totalSize);
232    let currentChunk = new Uint8Array(traceAllData.slice(currentPosition, endPosition));
233    // @ts-ignore
234    convertModule.HEAPU8.set(currentChunk, dataPtr);
235    let leftLen = currentChunk.length;
236    let processedLen = 0;
237    let blockSize = 0;
238    let blockPtr = dataPtr;
239    while (leftLen > 0) {
240      if (leftLen > ARRAY_BUF_SIZE) {
241        blockSize = ARRAY_BUF_SIZE;
242      } else {
243        blockSize = leftLen;
244      }
245      // @ts-ignore
246      let subArrayBuffer = convertModule.HEAPU8.subarray(blockPtr, blockPtr + blockSize);
247      // @ts-ignore
248      convertModule.HEAPU8.set(subArrayBuffer, arrayBufferPtr);
249      // 调用分片转换接口
250      if (isRawTraceConvert) {
251        // @ts-ignore
252        convertModule._ConvertRawBlockData(arrayBufferPtr, subArrayBuffer.length, traceInsPtr); // raw trace
253      } else {
254        // @ts-ignore
255        convertModule._ConvertBlockData(arrayBufferPtr, subArrayBuffer.length, traceInsPtr); // htrace
256      }
257      processedLen = processedLen + blockSize;
258      // @ts-ignore
259      blockPtr = dataPtr + processedLen;
260      leftLen = currentChunk.length - processedLen;
261    }
262    currentPosition = endPosition;
263  }
264}
265
266function postMessage(e: MessageEvent, allDataStr: Array<string>): void {
267  self.postMessage(
268    {
269      id: e.data.id,
270      action: 'convert',
271      status: true,
272      results: new Blob(allDataStr, { type: 'text/plain' }),
273      buffer: e.data.buffer,
274    },
275    // @ts-ignore
276    [e.data.buffer!]
277  );
278}
279