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