aboutsummaryrefslogtreecommitdiff
path: root/host/frontend/gcastv2/webrtc/assets/js/logcat.js
blob: aae94bc912525087b905f51e38046a4535786438 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
let adb_ws;
let logcat = document.getElementById('logcat');

let utf8Encoder = new TextEncoder();
let utf8Decoder = new TextDecoder();

const A_CNXN = 0x4e584e43;
const A_OPEN = 0x4e45504f;
const A_WRTE = 0x45545257;
const A_OKAY = 0x59414b4f;

const kLocalChannelId = 666;

function setU32LE(array, offset, x) {
    array[offset] = x & 0xff;
    array[offset + 1] = (x >> 8) & 0xff;
    array[offset + 2] = (x >> 16) & 0xff;
    array[offset + 3] = x >> 24;
}

function getU32LE(array, offset) {
    let x = array[offset]
        | (array[offset + 1] << 8)
        | (array[offset + 2] << 16)
        | (array[offset + 3] << 24);

    return x >>> 0;  // convert signed to unsigned if necessary.
}

function computeChecksum(array) {
    let sum = 0;
    let i;
    for (i = 0; i < array.length; ++i) {
        sum = ((sum + array[i]) & 0xffffffff) >>> 0;
    }

    return sum;
}

function createAdbMessage(command, arg0, arg1, payload) {
    let arrayBuffer = new ArrayBuffer(24 + payload.length);
    let array = new Uint8Array(arrayBuffer);
    setU32LE(array, 0, command);
    setU32LE(array, 4, arg0);
    setU32LE(array, 8, arg1);
    setU32LE(array, 12, payload.length);
    setU32LE(array, 16, computeChecksum(payload));
    setU32LE(array, 20, command ^ 0xffffffff);
    array.set(payload, 24);

    return arrayBuffer;
}

function adbOpenConnection() {
    let systemIdentity = utf8Encoder.encode("Cray_II:1234:whatever");

    let arrayBuffer = createAdbMessage(
        A_CNXN, 0x1000000, 256 * 1024, systemIdentity);

    adb_ws.send(arrayBuffer);
}

function adbOpenChannel() {
    let destination = utf8Encoder.encode("shell:logcat");

    let arrayBuffer = createAdbMessage(A_OPEN, kLocalChannelId, 0, destination);
    adb_ws.send(arrayBuffer);
}

function adbSendOkay(remoteId) {
    let payload = new Uint8Array(0);

    let arrayBuffer = createAdbMessage(
        A_OKAY, kLocalChannelId, remoteId, payload);

    adb_ws.send(arrayBuffer);
}

function adbOnMessage(ev) {
    // console.log("adb_ws: onmessage (" + ev.data.byteLength + " bytes)");

    let arrayBuffer = ev.data;
    let array = new Uint8Array(arrayBuffer);

    if (array.length < 24) {
        console.log("adb message too short.");
        return;
    }

    let command = getU32LE(array, 0);
    let magic = getU32LE(array, 20);

    if (command != ((magic ^ 0xffffffff) >>> 0)) {
        console.log("command = " + command + ", magic = " + magic);
        console.log("adb message command vs magic failed.");
        return;
    }

    let payloadLength = getU32LE(array, 12);

    if (array.length != 24 + payloadLength) {
        console.log("adb message length mismatch.");
        return;
    }

    let payloadChecksum = getU32LE(array, 16);
    let checksum = computeChecksum(array.slice(24));

    if (payloadChecksum != checksum) {
        console.log("adb message checksum mismatch.");
        return;
    }

    switch (command) {
        case A_CNXN:
        {
            console.log("connected.");

            adbOpenChannel();
            break;
        }

        case A_OKAY:
        {
            let remoteId = getU32LE(array, 4);
            console.log("channel created w/ remoteId " + remoteId);
            break;
        }

        case A_WRTE:
        {
            let payloadText = utf8Decoder.decode(array.slice(24));

            logcat.value += payloadText;

            // Scroll to bottom
            logcat.scrollTop = logcat.scrollHeight;

            let remoteId = getU32LE(array, 4);
            adbSendOkay(remoteId);
            break;
        }
    }
}

function init_logcat() {
    const wsProtocol = (location.protocol == "http:") ? "ws:" : "wss:";

    adb_ws = new WebSocket(
        wsProtocol + "//" + location.host + "/control_adb");

    adb_ws.binaryType = "arraybuffer";

    adb_ws.onopen = function() {
        console.log("adb_ws: onopen");

        adbOpenConnection();

        logcat.style.display = "initial";
    };
    adb_ws.onmessage = adbOnMessage;
}