• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2025 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
17import {FunctionUtils} from 'common/function_utils';
18import {ErrorListener, WebSocketStream} from './websocket_stream';
19
20interface AdbResponse {
21  error?: {
22    type: string;
23    message: string;
24  };
25}
26
27export type DataListener = (data: Uint8Array) => void;
28
29export abstract class AdbWebSocketStream extends WebSocketStream {
30  protected onData: DataListener = FunctionUtils.DO_NOTHING;
31
32  constructor(
33    sock: WebSocket,
34    private deviceSerialNumber: string,
35    private service: string,
36    errorListener: ErrorListener,
37  ) {
38    super(sock);
39    this.onError = async (msg: string) => {
40      await errorListener(msg);
41      this.close();
42    };
43    sock.onmessage = async (e: MessageEvent) => {
44      try {
45        if (e.data instanceof ArrayBuffer) {
46          this.onData(new Uint8Array(e.data));
47        } else if (e.data instanceof Blob) {
48          this.onData(new Uint8Array(await e.data.arrayBuffer()));
49        } else {
50          throw new Error('Expected message data to be ArrayBuffer or Blob');
51        }
52      } catch (error) {
53        console.debug('WebSocket failed, state: ' + sock.readyState);
54        let adbError: string | undefined;
55        if (typeof e.data === 'string') {
56          try {
57            const data: AdbResponse = JSON.parse(e.data);
58            if (data.error) {
59              adbError = data.error.message;
60            }
61          } catch (e) {
62            // do nothing
63          }
64        }
65        this.onError(
66          `Could not parse data:\nReceived: ${e.data}` +
67            `\nError: ${(error as Error).message}.` +
68            (adbError ? `\nADB Error: ` + adbError : ''),
69        );
70      }
71    };
72  }
73
74  override async connect(args = '') {
75    await this.write(
76      JSON.stringify({
77        header: {
78          serialNumber: this.deviceSerialNumber,
79          command: this.service + ':' + args,
80        },
81      }),
82    );
83  }
84}
85