• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2022, 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, OnProgressUpdateType} from 'common/function_utils';
18import {proxyClient, ProxyEndpoint, proxyRequest, ProxyState} from 'trace_collection/proxy_client';
19import {Connection, DeviceProperties} from './connection';
20import {ConfigMap} from './trace_collection_utils';
21import {TracingConfig} from './tracing_config';
22
23export class ProxyConnection implements Connection {
24  proxy = proxyClient;
25  keep_alive_worker: any = null;
26  notConnected = [ProxyState.NO_PROXY, ProxyState.UNAUTH, ProxyState.INVALID_VERSION];
27
28  constructor(
29    private proxyStateChangeCallback: (state: ProxyState) => void,
30    private progressCallback: OnProgressUpdateType = FunctionUtils.DO_NOTHING
31  ) {
32    this.proxy.setState(ProxyState.CONNECTING);
33    this.proxy.onProxyChange((newState) => this.onConnectChange(newState));
34    const urlParams = new URLSearchParams(window.location.search);
35    if (urlParams.has('token')) {
36      this.proxy.proxyKey = urlParams.get('token')!;
37    } else if (this.proxy.store.get('adb.proxyKey')) {
38      this.proxy.proxyKey = this.proxy.store.get('adb.proxyKey')!;
39    }
40    this.proxy.getDevices();
41  }
42
43  devices() {
44    return this.proxy.devices;
45  }
46
47  adbData() {
48    return this.proxy.adbData;
49  }
50
51  state() {
52    return this.proxy.state;
53  }
54
55  isDevicesState() {
56    return this.state() === ProxyState.DEVICES;
57  }
58
59  isStartTraceState() {
60    return this.state() === ProxyState.START_TRACE;
61  }
62
63  isErrorState() {
64    return this.state() === ProxyState.ERROR;
65  }
66
67  isEndTraceState() {
68    return this.state() === ProxyState.END_TRACE;
69  }
70
71  isLoadDataState() {
72    return this.state() === ProxyState.LOAD_DATA;
73  }
74
75  isConnectingState() {
76    return this.state() === ProxyState.CONNECTING;
77  }
78
79  throwNoTargetsError() {
80    this.proxy.setState(ProxyState.ERROR, 'No targets selected');
81  }
82
83  setProxyKey(key: string) {
84    this.proxy.proxyKey = key;
85    this.proxy.store.add('adb.proxyKey', key);
86    this.restart();
87  }
88
89  adbSuccess() {
90    return !this.notConnected.includes(this.proxy.state);
91  }
92
93  selectedDevice(): DeviceProperties {
94    return this.proxy.devices[this.proxy.selectedDevice];
95  }
96
97  selectedDeviceId(): string {
98    return this.proxy.selectedDevice;
99  }
100
101  restart() {
102    this.proxy.setState(ProxyState.CONNECTING);
103  }
104
105  resetLastDevice() {
106    this.proxy.store.add('adb.lastDevice', '');
107    this.restart();
108  }
109
110  selectDevice(id: string) {
111    this.proxy.selectDevice(id);
112  }
113
114  keepAliveTrace(view: ProxyConnection) {
115    if (!view.isEndTraceState()) {
116      clearInterval(view.keep_alive_worker);
117      view.keep_alive_worker = null;
118      return;
119    }
120    proxyRequest.keepTraceAlive(view);
121  }
122
123  startTrace(
124    reqEnableConfig?: string[],
125    reqSelectedSfConfig?: ConfigMap,
126    reqSelectedWmConfig?: ConfigMap
127  ) {
128    if (reqEnableConfig) {
129      proxyRequest.setEnabledConfig(this, reqEnableConfig);
130    }
131    if (reqSelectedSfConfig) {
132      proxyRequest.setSelectedConfig(
133        ProxyEndpoint.SELECTED_SF_CONFIG_TRACE,
134        this,
135        reqSelectedSfConfig
136      );
137    }
138    if (reqSelectedWmConfig) {
139      proxyRequest.setSelectedConfig(
140        ProxyEndpoint.SELECTED_WM_CONFIG_TRACE,
141        this,
142        reqSelectedWmConfig
143      );
144    }
145    proxyClient.setState(ProxyState.END_TRACE);
146    proxyRequest.startTrace(this, TracingConfig.getInstance().requestedTraces);
147  }
148
149  async endTrace() {
150    this.progressCallback(0);
151    this.proxy.setState(ProxyState.LOAD_DATA);
152    await proxyRequest.endTrace(this, this.progressCallback);
153  }
154
155  async dumpState(): Promise<boolean> {
156    this.progressCallback(0);
157    if (TracingConfig.getInstance().requestedDumps.length < 1) {
158      console.error('No targets selected');
159      this.proxy.setState(ProxyState.ERROR, 'No targets selected');
160      return false;
161    }
162    this.proxy.setState(ProxyState.LOAD_DATA);
163    await proxyRequest.dumpState(
164      this,
165      TracingConfig.getInstance().requestedDumps,
166      this.progressCallback
167    );
168    return true;
169  }
170
171  async isWaylandAvailable(): Promise<boolean> {
172    return new Promise((resolve, reject) => {
173      proxyRequest.call('GET', ProxyEndpoint.CHECK_WAYLAND, (request: XMLHttpRequest) => {
174        resolve(request.responseText === 'true');
175      });
176    });
177  }
178
179  async onConnectChange(newState: ProxyState) {
180    if (newState === ProxyState.CONNECTING) {
181      proxyClient.getDevices();
182    }
183    if (newState === ProxyState.START_TRACE) {
184      const isWaylandAvailable = await this.isWaylandAvailable();
185      TracingConfig.getInstance().setTraceConfigForAvailableTraces(isWaylandAvailable);
186    }
187    this.proxyStateChangeCallback(newState);
188  }
189}
190