1fb726d48Sopenharmony_ci/* 2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd. 3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License. 5fb726d48Sopenharmony_ci * You may obtain a copy of the License at 6fb726d48Sopenharmony_ci * 7fb726d48Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fb726d48Sopenharmony_ci * 9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and 13fb726d48Sopenharmony_ci * limitations under the License. 14fb726d48Sopenharmony_ci */ 15fb726d48Sopenharmony_ci 16fb726d48Sopenharmony_ciimport { Serialize } from '../common/Serialize'; 17fb726d48Sopenharmony_ciimport { HdcCommand } from './HdcCommand'; 18fb726d48Sopenharmony_ciimport { Utils } from '../common/Utils'; 19fb726d48Sopenharmony_ciimport { HANDSHAKE_MESSAGE } from '../common/ConstantType'; 20fb726d48Sopenharmony_ciimport { PayloadHead } from '../message/PayloadHead'; 21fb726d48Sopenharmony_ciimport { TransmissionInterface } from '../transmission/TransmissionInterface'; 22fb726d48Sopenharmony_ciimport { DataProcessing } from '../transmission/DataProcessing'; 23fb726d48Sopenharmony_ciimport { DataListener } from './DataListener'; 24fb726d48Sopenharmony_ciimport { DataMessage } from '../message/DataMessage'; 25fb726d48Sopenharmony_ciimport { SessionHandShake } from '../message/SessionHandShake'; 26fb726d48Sopenharmony_ciimport { AuthType } from '../message/AuthType'; 27fb726d48Sopenharmony_ciimport { debug, log } from '../../log/Log'; 28fb726d48Sopenharmony_ciimport { HdcStream } from './HdcStream'; 29fb726d48Sopenharmony_ciimport { toHex16 } from '../common/BaseConversion'; 30fb726d48Sopenharmony_ciimport { USBHead } from '../message/USBHead'; 31fb726d48Sopenharmony_ci 32fb726d48Sopenharmony_ciexport class HdcClient implements DataListener { 33fb726d48Sopenharmony_ci // @ts-ignore 34fb726d48Sopenharmony_ci usbDevice: USBDevice | undefined; 35fb726d48Sopenharmony_ci sessionId: number = 0; 36fb726d48Sopenharmony_ci private transmissionChannel: TransmissionInterface; 37fb726d48Sopenharmony_ci public readDataProcessing: DataProcessing; 38fb726d48Sopenharmony_ci private cmdStreams = new Map(); 39fb726d48Sopenharmony_ci private isSuccess: boolean = false; 40fb726d48Sopenharmony_ci private handBody: DataView | undefined; 41fb726d48Sopenharmony_ci private message: DataMessage | undefined; 42fb726d48Sopenharmony_ci private isSigna: boolean = false; 43fb726d48Sopenharmony_ci 44fb726d48Sopenharmony_ci constructor( 45fb726d48Sopenharmony_ci transmissionChannel: TransmissionInterface, 46fb726d48Sopenharmony_ci // @ts-ignore 47fb726d48Sopenharmony_ci usbDevice: USBDevice | undefined 48fb726d48Sopenharmony_ci ) { 49fb726d48Sopenharmony_ci this.transmissionChannel = transmissionChannel; 50fb726d48Sopenharmony_ci this.usbDevice = usbDevice; 51fb726d48Sopenharmony_ci this.readDataProcessing = new DataProcessing(this, transmissionChannel); 52fb726d48Sopenharmony_ci } 53fb726d48Sopenharmony_ci 54fb726d48Sopenharmony_ci async connectDevice(): Promise<boolean> { 55fb726d48Sopenharmony_ci debug('start Connect Device'); 56fb726d48Sopenharmony_ci this.sessionId = Utils.getSessionId(); 57fb726d48Sopenharmony_ci log(`sessionId is ${this.sessionId}`); 58fb726d48Sopenharmony_ci this.isSuccess = false; 59fb726d48Sopenharmony_ci await this.handShakeConnect(AuthType.AUTH_NONE, 'authtype 1 1'); 60fb726d48Sopenharmony_ci let timeStamp = new Date().getTime(); 61fb726d48Sopenharmony_ci while (await this.readHandShakeMsg()) { 62fb726d48Sopenharmony_ci if (new Date().getTime() - timeStamp > 10000) { 63fb726d48Sopenharmony_ci break; 64fb726d48Sopenharmony_ci } 65fb726d48Sopenharmony_ci // 后续daemon修复发送通道关闭信息后,可放开this.message?.channelClose以作判断 66fb726d48Sopenharmony_ci // 非握手包指令,不予理会 67fb726d48Sopenharmony_ci if (this.message?.commandFlag !== HdcCommand.CMD_KERNEL_HANDSHAKE) { 68fb726d48Sopenharmony_ci continue; 69fb726d48Sopenharmony_ci } 70fb726d48Sopenharmony_ci let backMessage = Serialize.parseHandshake(new Uint8Array(this.message.resArrayBuffer!)); 71fb726d48Sopenharmony_ci // 后续daemon修复增加sessionId数据判定后,可放开backMessage.sessionId !== this.sessionId以作判断 72fb726d48Sopenharmony_ci const returnBuf: string = backMessage.buf; 73fb726d48Sopenharmony_ci const returnAuth: number = backMessage.authType; 74fb726d48Sopenharmony_ci switch (returnAuth) { 75fb726d48Sopenharmony_ci case AuthType.AUTH_NONE: 76fb726d48Sopenharmony_ci continue; 77fb726d48Sopenharmony_ci case AuthType.AUTH_TOKEN: 78fb726d48Sopenharmony_ci continue; 79fb726d48Sopenharmony_ci case AuthType.AUTH_SIGNATURE: 80fb726d48Sopenharmony_ci const hdcMsgUrl = this.isSigna ? 'signatureHdcMsg' : 'encryptHdcMsg'; 81fb726d48Sopenharmony_ci const response = await fetch(`${window.location.origin}/application/${hdcMsgUrl}?message=` + returnBuf); 82fb726d48Sopenharmony_ci const dataBody = await response.json(); 83fb726d48Sopenharmony_ci let signatureHdcMsg = ''; 84fb726d48Sopenharmony_ci if (dataBody.success) { 85fb726d48Sopenharmony_ci signatureHdcMsg = dataBody.data.signatures; 86fb726d48Sopenharmony_ci } else { 87fb726d48Sopenharmony_ci break; 88fb726d48Sopenharmony_ci } 89fb726d48Sopenharmony_ci await this.handShakeConnect(AuthType.AUTH_SIGNATURE, signatureHdcMsg); 90fb726d48Sopenharmony_ci timeStamp = new Date().getTime(); 91fb726d48Sopenharmony_ci continue; 92fb726d48Sopenharmony_ci case AuthType.AUTH_PUBLICKEY: 93fb726d48Sopenharmony_ci if (returnBuf === 'authtype 1 1') { 94fb726d48Sopenharmony_ci this.isSigna = true; 95fb726d48Sopenharmony_ci } else { 96fb726d48Sopenharmony_ci this.isSigna = false; 97fb726d48Sopenharmony_ci } 98fb726d48Sopenharmony_ci const responsePub = await fetch(`${window.location.origin}/application/hdcPublicKey`); 99fb726d48Sopenharmony_ci const data = await responsePub.json(); 100fb726d48Sopenharmony_ci const publicKey = data.success && (`smartPerf-Host` + String.fromCharCode(12) + data.data.publicKey); 101fb726d48Sopenharmony_ci await this.handShakeConnect(AuthType.AUTH_PUBLICKEY, publicKey); 102fb726d48Sopenharmony_ci timeStamp = new Date().getTime(); 103fb726d48Sopenharmony_ci continue; 104fb726d48Sopenharmony_ci case AuthType.AUTH_OK: 105fb726d48Sopenharmony_ci if (returnBuf.toLocaleLowerCase().indexOf('unauth') === -1 || returnBuf.includes('SUCCESS')) { 106fb726d48Sopenharmony_ci this.handShakeSuccess(this.handBody!); 107fb726d48Sopenharmony_ci this.isSuccess = true; 108fb726d48Sopenharmony_ci break; 109fb726d48Sopenharmony_ci } else { 110fb726d48Sopenharmony_ci continue; 111fb726d48Sopenharmony_ci } 112fb726d48Sopenharmony_ci default: 113fb726d48Sopenharmony_ci continue; 114fb726d48Sopenharmony_ci } 115fb726d48Sopenharmony_ci } 116fb726d48Sopenharmony_ci return this.isSuccess; 117fb726d48Sopenharmony_ci } 118fb726d48Sopenharmony_ci 119fb726d48Sopenharmony_ci private async handShakeConnect(authType: number, buf: string): Promise<void> { 120fb726d48Sopenharmony_ci // @ts-ignore 121fb726d48Sopenharmony_ci let handShake: SessionHandShake = new SessionHandShake( 122fb726d48Sopenharmony_ci HANDSHAKE_MESSAGE, 123fb726d48Sopenharmony_ci authType, 124fb726d48Sopenharmony_ci this.sessionId, 125fb726d48Sopenharmony_ci // @ts-ignore 126fb726d48Sopenharmony_ci this.usbDevice.serialNumber, 127fb726d48Sopenharmony_ci buf, 128fb726d48Sopenharmony_ci 'Ver: 3.0.0b' 129fb726d48Sopenharmony_ci ); 130fb726d48Sopenharmony_ci let hs = Serialize.serializeSessionHandShake(handShake); 131fb726d48Sopenharmony_ci debug('start Connect hs ', hs); 132fb726d48Sopenharmony_ci await this.readDataProcessing.send( 133fb726d48Sopenharmony_ci handShake.sessionId, 134fb726d48Sopenharmony_ci 0, 135fb726d48Sopenharmony_ci HdcCommand.CMD_KERNEL_HANDSHAKE, 136fb726d48Sopenharmony_ci hs, 137fb726d48Sopenharmony_ci hs.length 138fb726d48Sopenharmony_ci ); 139fb726d48Sopenharmony_ci } 140fb726d48Sopenharmony_ci 141fb726d48Sopenharmony_ci private async readHandShakeMsg(): Promise<boolean> { 142fb726d48Sopenharmony_ci if (this.isSuccess) { 143fb726d48Sopenharmony_ci return false; 144fb726d48Sopenharmony_ci } 145fb726d48Sopenharmony_ci let handShake = await this.readDataProcessing.readUsbHead(); 146fb726d48Sopenharmony_ci this.handBody = await this.readDataProcessing.readBody(handShake!.dataSize); 147fb726d48Sopenharmony_ci this.message = new DataMessage(handShake!, this.handBody); 148fb726d48Sopenharmony_ci return true; 149fb726d48Sopenharmony_ci } 150fb726d48Sopenharmony_ci 151fb726d48Sopenharmony_ci private handShakeSuccess(handBody: DataView): void { 152fb726d48Sopenharmony_ci let playHeadArray = handBody.buffer.slice(0, PayloadHead.getPayloadHeadLength()); 153fb726d48Sopenharmony_ci let resultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(playHeadArray)); 154fb726d48Sopenharmony_ci debug('resultPayloadHead is ', resultPayloadHead); 155fb726d48Sopenharmony_ci let headSize = resultPayloadHead.headSize; 156fb726d48Sopenharmony_ci let dataSize = resultPayloadHead.dataSize; 157fb726d48Sopenharmony_ci let resPlayProtectBuffer = handBody.buffer.slice( 158fb726d48Sopenharmony_ci PayloadHead.getPayloadHeadLength(), 159fb726d48Sopenharmony_ci PayloadHead.getPayloadHeadLength() + headSize 160fb726d48Sopenharmony_ci ); 161fb726d48Sopenharmony_ci debug('PlayProtect is ', resPlayProtectBuffer); 162fb726d48Sopenharmony_ci let resData = handBody.buffer.slice( 163fb726d48Sopenharmony_ci PayloadHead.getPayloadHeadLength() + headSize, 164fb726d48Sopenharmony_ci PayloadHead.getPayloadHeadLength() + headSize + dataSize 165fb726d48Sopenharmony_ci ); 166fb726d48Sopenharmony_ci debug('resData is ', resData); 167fb726d48Sopenharmony_ci this.readDataProcessing.startReadData().then(() => {}); 168fb726d48Sopenharmony_ci } 169fb726d48Sopenharmony_ci public async disconnect(): Promise<void> { 170fb726d48Sopenharmony_ci try { 171fb726d48Sopenharmony_ci await this.transmissionChannel.close(); 172fb726d48Sopenharmony_ci this.readDataProcessing.stopReadData(); 173fb726d48Sopenharmony_ci this.cmdStreams.forEach((value) => { 174fb726d48Sopenharmony_ci value.putMessageInQueue(new DataMessage(new USBHead([0, 1], -1, -1, -1))); 175fb726d48Sopenharmony_ci }); 176fb726d48Sopenharmony_ci this.cmdStreams.clear(); 177fb726d48Sopenharmony_ci } catch (e) {} 178fb726d48Sopenharmony_ci } 179fb726d48Sopenharmony_ci 180fb726d48Sopenharmony_ci public bindStream(channel: number, hdcStream: HdcStream): void { 181fb726d48Sopenharmony_ci this.cmdStreams.set(channel, hdcStream); 182fb726d48Sopenharmony_ci } 183fb726d48Sopenharmony_ci 184fb726d48Sopenharmony_ci public unbindStream(channel: number): boolean { 185fb726d48Sopenharmony_ci this.cmdStreams.delete(channel); 186fb726d48Sopenharmony_ci return true; 187fb726d48Sopenharmony_ci } 188fb726d48Sopenharmony_ci 189fb726d48Sopenharmony_ci public unbindStopStream(channel: number): boolean { 190fb726d48Sopenharmony_ci this.cmdStreams.delete(channel); 191fb726d48Sopenharmony_ci return true; 192fb726d48Sopenharmony_ci } 193fb726d48Sopenharmony_ci 194fb726d48Sopenharmony_ci createDataMessage(data: DataMessage): void { 195fb726d48Sopenharmony_ci if (this.cmdStreams.has(data.getChannelId())) { 196fb726d48Sopenharmony_ci let stream = this.cmdStreams.get(data.getChannelId()); 197fb726d48Sopenharmony_ci if (stream) { 198fb726d48Sopenharmony_ci stream.putMessageInQueue(data); 199fb726d48Sopenharmony_ci } 200fb726d48Sopenharmony_ci } 201fb726d48Sopenharmony_ci } 202fb726d48Sopenharmony_ci} 203