• 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 { HdcClient } from './hdcclient/HdcClient.js';
17import { UsbTransmissionChannel } from './transmission/UsbTransmissionChannel.js';
18import { HDC_DEVICE_FILTERS } from './common/ConstantType.js';
19import { FormatCommand } from './hdcclient/FormatCommand.js';
20import { log } from '../log/Log.js';
21import { HdcStream } from './hdcclient/HdcStream.js';
22import { HdcCommand } from './hdcclient/HdcCommand.js';
23import { SpRecordTrace } from '../trace/component/SpRecordTrace.js';
24
25export class HdcDeviceManager {
26  private static clientList: Map<string, HdcClient> = new Map();
27  private static currentHdcClient: HdcClient;
28  private static FILE_RECV_PREFIX_STRING = 'hdc file recv -cwd C:\\ ';
29
30  /**
31   * getDevices
32   */
33  // @ts-ignore
34  public static async getDevices(): Promise<USBDevice[]> {
35    // @ts-ignore
36    return navigator.usb.getDevices();
37  }
38
39  /**
40   * findDevice
41   */
42  public static findDevice() {
43    if (!('usb' in navigator)) {
44      throw new Error('WebUSB not supported by the browser (requires HTTPS)');
45    }
46    // @ts-ignore
47    return navigator.usb.requestDevice({ filters: HDC_DEVICE_FILTERS });
48  }
49
50  /**
51   * connect by serialNumber
52   *
53   * @param serialNumber serialNumber
54   */
55  public static async connect(serialNumber: string): Promise<boolean> {
56    let client = this.clientList.get(serialNumber);
57    if (client) {
58      if (client.usbDevice!.opened) {
59        log('device Usb is Open');
60        return true;
61      } else {
62        if (SpRecordTrace.serialNumber == serialNumber) {
63          SpRecordTrace.serialNumber = '';
64        }
65        log('device Usb not Open');
66        return false;
67      }
68    } else {
69      let connectDevice = await this.getDeviceBySerialNumber(serialNumber);
70      let usbChannel = await UsbTransmissionChannel.openHdcDevice(connectDevice);
71      if (usbChannel) {
72        let hdcClient = new HdcClient(usbChannel, connectDevice);
73        let connected = await hdcClient.connectDevice();
74        if (connected) {
75          this.currentHdcClient = hdcClient;
76          this.clientList.set(serialNumber, hdcClient);
77        }
78        log('device Usb connected : ' + connected);
79        return connected;
80      } else {
81        log('device Usb connected failed: ');
82        return false;
83      }
84    }
85  }
86
87  // @ts-ignore
88  public static async getDeviceBySerialNumber(serialNumber: string): Promise<USBDevice> {
89    // @ts-ignore
90    const devices = await navigator.usb.getDevices();
91    // @ts-ignore
92    return devices.find((dev) => dev.serialNumber === serialNumber);
93  }
94
95  /**
96   * disConnect by serialNumber
97   *
98   * @param serialNumber
99   */
100  public static async disConnect(serialNumber: string): Promise<boolean> {
101    let hdcClient = this.clientList.get(serialNumber);
102    if (hdcClient) {
103      await hdcClient.disconnect();
104      this.clientList.delete(serialNumber);
105      return true;
106    } else {
107      return true;
108    }
109  }
110
111  /**
112   * Execute shell on the currently connected device and return the result as a string
113   *
114   * @param cmd cmd
115   */
116  public static async shellResultAsString(cmd: string, isSkipResult: boolean): Promise<string> {
117    if (this.currentHdcClient) {
118      let hdcStream = new HdcStream(this.currentHdcClient, false);
119      await hdcStream.DoCommand(cmd);
120      let result: string = '';
121      while (true) {
122        let dataMessage = await hdcStream.getMessage();
123        if (dataMessage.channelClose || isSkipResult) {
124          result += dataMessage.getDataToString();
125          await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false));
126          log('result is end, close');
127          break;
128        }
129        if (dataMessage.usbHead.sessionId == -1) {
130          return Promise.resolve('The device is abnormal');
131        }
132        result += dataMessage.getDataToString();
133      }
134      await hdcStream.closeStream();
135      await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false));
136      return Promise.resolve(result);
137    }
138    return Promise.reject('not select device');
139  }
140
141  /**
142   * Execute shell on the currently connected device and return the result as a string
143   *
144   * @param cmd cmd
145   */
146  public static async stopHiprofiler(cmd: string, isSkipResult: boolean): Promise<string> {
147    if (this.currentHdcClient) {
148      let hdcStream = new HdcStream(this.currentHdcClient, true);
149      await hdcStream.DoCommand(cmd);
150      let result: string = '';
151      while (true) {
152        let dataMessage = await hdcStream.getMessage();
153        if (dataMessage.channelClose || isSkipResult) {
154          await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false));
155          log('result is end, close');
156          break;
157        }
158        result += dataMessage.getDataToString();
159      }
160      await hdcStream.closeStopStream();
161      await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false));
162      return Promise.resolve(result);
163    }
164    return Promise.reject('not select device');
165  }
166
167  /**
168   * Execute shell on the currently connected device, the result is returned as Blob
169   *
170   * @param cmd cmd
171   */
172  public static async shellResultAsBlob(cmd: string, isSkipResult: boolean): Promise<Blob> {
173    if (this.currentHdcClient) {
174      let hdcStream = new HdcStream(this.currentHdcClient, false);
175      log('cmd is ' + cmd);
176      await hdcStream.DoCommand(cmd);
177      let finalBuffer;
178      while (true) {
179        let dataMessage = await hdcStream.getMessage();
180        if (dataMessage.channelClose || isSkipResult) {
181          log('result is end, close');
182          break;
183        }
184        let res = dataMessage.getData();
185        if (res) {
186          if (!finalBuffer) {
187            finalBuffer = new Uint8Array(res);
188          } else {
189            finalBuffer = HdcDeviceManager.appendBuffer(finalBuffer, new Uint8Array(res));
190          }
191        }
192      }
193      await hdcStream.closeStream();
194      if (finalBuffer) {
195        return Promise.resolve(new Blob([finalBuffer]));
196      }
197      return Promise.resolve(new Blob());
198    }
199    return Promise.reject('not select device');
200  }
201
202  /**
203   * appendBuffer
204   *
205   * @param buffer1 firstBuffer
206   * @param buffer2 secondBuffer
207   * @private
208   */
209  private static appendBuffer(buffer1: Uint8Array, buffer2: Uint8Array) {
210    let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
211    tmp.set(buffer1, 0);
212    tmp.set(buffer2, buffer1.byteLength);
213    return tmp;
214  }
215
216  /**
217   * Pull the corresponding file from the device side
218   *
219   * @param filename filename
220   */
221  public static async fileRecv(filename: string, callBack: Function): Promise<Blob> {
222    let finalBuffer;
223    if (this.currentHdcClient) {
224      let hdcStream = new HdcStream(this.currentHdcClient, false);
225      await hdcStream.DoCommand(HdcDeviceManager.FILE_RECV_PREFIX_STRING + filename + ' ./');
226      if (!finalBuffer && hdcStream.fileSize > 0) {
227        finalBuffer = new Uint8Array(hdcStream.fileSize);
228        log('Uint8Array size is ' + finalBuffer.byteLength);
229      }
230      let offset = 0;
231      while (true) {
232        let dataMessage = await hdcStream.getMessage();
233        if (dataMessage.channelClose) {
234          log('result is end, close');
235          break;
236        }
237        if (dataMessage.commandFlag == HdcCommand.CMD_FILE_FINISH) {
238          await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '', false));
239          log('CMD_FILE_FINISH is end, close');
240          break;
241        }
242        let res = dataMessage.getData();
243        if (res) {
244          let resRS: ArrayBuffer = res.slice(64);
245          if (finalBuffer) {
246            finalBuffer.set(new Uint8Array(resRS), offset);
247            offset += resRS.byteLength;
248            callBack(((offset / hdcStream.fileSize) * 100).toFixed(3));
249          }
250        }
251        if (hdcStream.fileSize != -1 && offset >= hdcStream.fileSize) {
252          callBack(100);
253          await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_FILE_FINISH, '', false));
254        }
255      }
256    }
257    if (finalBuffer) {
258      return Promise.resolve(new Blob([finalBuffer]));
259    } else {
260      return Promise.resolve(new Blob([]));
261    }
262  }
263}
264