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