• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18
19let utf8Encoder = new TextEncoder();
20let utf8Decoder = new TextDecoder();
21
22const A_CNXN = 0x4e584e43;
23const A_OPEN = 0x4e45504f;
24const A_WRTE = 0x45545257;
25const A_OKAY = 0x59414b4f;
26
27const kLocalChannelId = 666;
28
29let array = new Uint8Array();
30
31function setU32LE(array, offset, x) {
32    array[offset] = x & 0xff;
33    array[offset + 1] = (x >> 8) & 0xff;
34    array[offset + 2] = (x >> 16) & 0xff;
35    array[offset + 3] = x >> 24;
36}
37
38function getU32LE(array, offset) {
39    let x = array[offset]
40        | (array[offset + 1] << 8)
41        | (array[offset + 2] << 16)
42        | (array[offset + 3] << 24);
43
44    return x >>> 0;  // convert signed to unsigned if necessary.
45}
46
47function computeChecksum(array) {
48    let sum = 0;
49    let i;
50    for (i = 0; i < array.length; ++i) {
51        sum = ((sum + array[i]) & 0xffffffff) >>> 0;
52    }
53
54    return sum;
55}
56
57function createAdbMessage(command, arg0, arg1, payload) {
58    let arrayBuffer = new ArrayBuffer(24 + payload.length);
59    let array = new Uint8Array(arrayBuffer);
60    setU32LE(array, 0, command);
61    setU32LE(array, 4, arg0);
62    setU32LE(array, 8, arg1);
63    setU32LE(array, 12, payload.length);
64    setU32LE(array, 16, computeChecksum(payload));
65    setU32LE(array, 20, command ^ 0xffffffff);
66    array.set(payload, 24);
67
68    return arrayBuffer;
69}
70
71function adbOpenConnection() {
72    let systemIdentity = utf8Encoder.encode("Cray_II:1234:whatever");
73
74    let arrayBuffer = createAdbMessage(
75        A_CNXN, 0x1000000, 256 * 1024, systemIdentity);
76
77    adb_ws.send(arrayBuffer);
78}
79
80function adbShell(command) {
81    let destination = utf8Encoder.encode("shell:" + command);
82
83    let arrayBuffer = createAdbMessage(A_OPEN, kLocalChannelId, 0, destination);
84    adb_ws.send(arrayBuffer);
85    awaitConnection();
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
104// Simple lifecycle management that executes callbacks based on connection state.
105//
106// Any attempt to initiate a command (e.g. creating a connection, sending a message)
107// (re)starts a timer. Any response back from any command stops that timer.
108const timeoutMs = 3000;
109let connectedCb;
110let disconnectedCb;
111let disconnectedTimeout;
112function awaitConnection() {
113  clearTimeout(disconnectedTimeout);
114  if (disconnectedCb) {
115    disconnectedTimeout = setTimeout(disconnectedCb, timeoutMs);
116  }
117}
118function connected() {
119  if (disconnectedTimeout) {
120    clearTimeout(disconnectedTimeout);
121  }
122  if (connectedCb) {
123    connectedCb();
124  }
125}
126
127function adbOnMessage(arrayBuffer) {
128    // console.log("adb_ws: onmessage (" + arrayBuffer.byteLength + " bytes)");
129    array = JoinArrays(array, new Uint8Array(arrayBuffer));
130
131    while (array.length > 0) {
132        if (array.length < 24) {
133            // Incomplete package, must wait for more data.
134            return;
135        }
136
137        let command = getU32LE(array, 0);
138        let magic = getU32LE(array, 20);
139
140        if (command != ((magic ^ 0xffffffff) >>> 0)) {
141            console.log("command = " + command + ", magic = " + magic);
142            console.log("adb message command vs magic failed.");
143            return;
144        }
145
146        let payloadLength = getU32LE(array, 12);
147
148        if (array.length < 24 + payloadLength) {
149            // Incomplete package, must wait for more data.
150            return;
151        }
152
153        let payloadChecksum = getU32LE(array, 16);
154        let checksum = computeChecksum(array.slice(24));
155
156        if (payloadChecksum != checksum) {
157            console.log("adb message checksum mismatch.");
158            // This can happen if a shell command executes while another
159            // channel is receiving data.
160        }
161
162        switch (command) {
163            case A_CNXN:
164            {
165                console.log("WebRTC adb connected.");
166                connected();
167                break;
168            }
169
170            case A_OKAY:
171            {
172                let remoteId = getU32LE(array, 4);
173                console.log("WebRTC adb channel created w/ remoteId " + remoteId);
174                connected();
175                break;
176            }
177
178            case A_WRTE:
179            {
180                let remoteId = getU32LE(array, 4);
181                adbSendOkay(remoteId);
182                break;
183            }
184        }
185        array = array.subarray(24 + payloadLength, array.length);
186    }
187}
188
189function init_adb(devConn, ccb = connectedCb, dcb = disconnectedCb) {
190    if (adb_ws) return;
191
192    adb_ws = {
193      send: function(buffer) {
194        devConn.sendAdbMessage(buffer);
195      }
196    };
197    connectedCb = ccb;
198    disconnectedCb = dcb;
199    awaitConnection();
200
201    devConn.onAdbMessage(msg => adbOnMessage(msg));
202
203    adbOpenConnection();
204}
205