1/* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17let adb_ws; 18let logcat = document.getElementById('logcat'); 19 20let utf8Encoder = new TextEncoder(); 21let utf8Decoder = new TextDecoder(); 22 23const A_CNXN = 0x4e584e43; 24const A_OPEN = 0x4e45504f; 25const A_WRTE = 0x45545257; 26const A_OKAY = 0x59414b4f; 27 28const kLocalChannelId = 666; 29 30let array = new Uint8Array(); 31 32function setU32LE(array, offset, x) { 33 array[offset] = x & 0xff; 34 array[offset + 1] = (x >> 8) & 0xff; 35 array[offset + 2] = (x >> 16) & 0xff; 36 array[offset + 3] = x >> 24; 37} 38 39function getU32LE(array, offset) { 40 let x = array[offset] 41 | (array[offset + 1] << 8) 42 | (array[offset + 2] << 16) 43 | (array[offset + 3] << 24); 44 45 return x >>> 0; // convert signed to unsigned if necessary. 46} 47 48function computeChecksum(array) { 49 let sum = 0; 50 let i; 51 for (i = 0; i < array.length; ++i) { 52 sum = ((sum + array[i]) & 0xffffffff) >>> 0; 53 } 54 55 return sum; 56} 57 58function createAdbMessage(command, arg0, arg1, payload) { 59 let arrayBuffer = new ArrayBuffer(24 + payload.length); 60 let array = new Uint8Array(arrayBuffer); 61 setU32LE(array, 0, command); 62 setU32LE(array, 4, arg0); 63 setU32LE(array, 8, arg1); 64 setU32LE(array, 12, payload.length); 65 setU32LE(array, 16, computeChecksum(payload)); 66 setU32LE(array, 20, command ^ 0xffffffff); 67 array.set(payload, 24); 68 69 return arrayBuffer; 70} 71 72function adbOpenConnection() { 73 let systemIdentity = utf8Encoder.encode("Cray_II:1234:whatever"); 74 75 let arrayBuffer = createAdbMessage( 76 A_CNXN, 0x1000000, 256 * 1024, systemIdentity); 77 78 adb_ws.send(arrayBuffer); 79} 80 81function adbOpenChannel() { 82 let destination = utf8Encoder.encode("shell:logcat"); 83 84 let arrayBuffer = createAdbMessage(A_OPEN, kLocalChannelId, 0, destination); 85 adb_ws.send(arrayBuffer); 86} 87 88function adbSendOkay(remoteId) { 89 let payload = new Uint8Array(0); 90 91 let arrayBuffer = createAdbMessage( 92 A_OKAY, kLocalChannelId, remoteId, payload); 93 94 adb_ws.send(arrayBuffer); 95} 96 97function JoinArrays(arr1, arr2) { 98 let arr = new Uint8Array(arr1.length + arr2.length); 99 arr.set(arr1, 0); 100 arr.set(arr2, arr1.length); 101 return arr; 102} 103 104function adbOnMessage(arrayBuffer) { 105 // console.log("adb_ws: onmessage (" + arrayBuffer.byteLength + " bytes)"); 106 array = JoinArrays(array, new Uint8Array(arrayBuffer)); 107 108 while (array.length > 0) { 109 if (array.length < 24) { 110 // Incomplete package, must wait for more data. 111 return; 112 } 113 114 let command = getU32LE(array, 0); 115 let magic = getU32LE(array, 20); 116 117 if (command != ((magic ^ 0xffffffff) >>> 0)) { 118 console.log("command = " + command + ", magic = " + magic); 119 console.log("adb message command vs magic failed."); 120 return; 121 } 122 123 let payloadLength = getU32LE(array, 12); 124 125 if (array.length < 24 + payloadLength) { 126 // Incomplete package, must wait for more data. 127 return; 128 } 129 130 let payloadChecksum = getU32LE(array, 16); 131 let checksum = computeChecksum(array.slice(24)); 132 133 if (payloadChecksum != checksum) { 134 console.log("adb message checksum mismatch."); 135 return; 136 } 137 138 switch (command) { 139 case A_CNXN: 140 { 141 console.log("connected."); 142 143 adbOpenChannel(); 144 break; 145 } 146 147 case A_OKAY: 148 { 149 let remoteId = getU32LE(array, 4); 150 console.log("channel created w/ remoteId " + remoteId); 151 break; 152 } 153 154 case A_WRTE: 155 { 156 let payloadText = utf8Decoder.decode(array.slice(24)); 157 158 // Limit to 100 lines 159 logcat.value = (logcat.value + payloadText).split('\n').slice(-100).join('\n'); 160 161 // Scroll to bottom 162 logcat.scrollTop = logcat.scrollHeight; 163 164 let remoteId = getU32LE(array, 4); 165 adbSendOkay(remoteId); 166 break; 167 } 168 } 169 array = array.subarray(24 + payloadLength, array.length); 170 } 171} 172 173function init_logcat(devConn) { 174 adb_ws = { 175 send: function(buffer) { 176 devConn.sendAdbMessage(buffer); 177 } 178 }; 179 180 logcat.style.display = "initial"; 181 devConn.onAdbMessage(msg => adbOnMessage(msg)); 182 183 adbOpenConnection(); 184} 185