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