| /* |
| * Copyright 2022, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import {assertDefined} from 'common/assert_utils'; |
| import {FunctionUtils, OnProgressUpdateType} from 'common/function_utils'; |
| import { |
| DeviceProperties, |
| proxyClient, |
| ProxyEndpoint, |
| proxyRequest, |
| ProxyState, |
| } from 'trace_collection/proxy_client'; |
| import {Connection} from './connection'; |
| import { |
| ConfigMap, |
| TraceConfigurationMap, |
| TRACES, |
| } from './trace_collection_utils'; |
| |
| export class ProxyConnection implements Connection { |
| proxy = proxyClient; |
| keep_alive_worker: NodeJS.Timer | undefined; |
| notConnected = [ |
| ProxyState.NO_PROXY, |
| ProxyState.UNAUTH, |
| ProxyState.INVALID_VERSION, |
| ]; |
| |
| constructor( |
| private proxyStateChangeCallback: (state: ProxyState) => void, |
| private progressCallback: OnProgressUpdateType = FunctionUtils.DO_NOTHING, |
| private traceConfigChangeCallback: ( |
| availableTracesConfig: TraceConfigurationMap, |
| ) => void, |
| ) { |
| this.proxy.setState(ProxyState.CONNECTING); |
| this.proxy.onProxyChange( |
| async (newState) => await this.onConnectChange(newState), |
| ); |
| const urlParams = new URLSearchParams(window.location.search); |
| if (urlParams.has('token')) { |
| this.proxy.proxyKey = assertDefined(urlParams.get('token')); |
| } else if (this.proxy.store.get('adb.proxyKey')) { |
| this.proxy.proxyKey = assertDefined(this.proxy.store.get('adb.proxyKey')); |
| } |
| this.proxy.getDevices(); |
| } |
| |
| devices() { |
| return this.proxy.devices; |
| } |
| |
| adbData() { |
| return this.proxy.adbData; |
| } |
| |
| state() { |
| return this.proxy.state; |
| } |
| |
| isDevicesState() { |
| return this.state() === ProxyState.DEVICES; |
| } |
| |
| isStartTraceState() { |
| return this.state() === ProxyState.START_TRACE; |
| } |
| |
| isErrorState() { |
| return this.state() === ProxyState.ERROR; |
| } |
| |
| isStartingTraceState() { |
| return this.state() === ProxyState.STARTING_TRACE; |
| } |
| |
| isEndTraceState() { |
| return this.state() === ProxyState.END_TRACE; |
| } |
| |
| isLoadDataState() { |
| return this.state() === ProxyState.LOAD_DATA; |
| } |
| |
| isConnectingState() { |
| return this.state() === ProxyState.CONNECTING; |
| } |
| |
| throwNoTargetsError() { |
| this.proxy.setState(ProxyState.ERROR, 'No targets selected'); |
| } |
| |
| setProxyKey(key: string) { |
| this.proxy.proxyKey = key; |
| this.proxy.store.add('adb.proxyKey', key); |
| } |
| |
| adbSuccess() { |
| return !this.notConnected.includes(this.proxy.state); |
| } |
| |
| selectedDevice(): DeviceProperties { |
| return this.proxy.devices[this.proxy.selectedDevice]; |
| } |
| |
| selectedDeviceId(): string { |
| return this.proxy.selectedDevice; |
| } |
| |
| restart() { |
| this.proxy.setState(ProxyState.CONNECTING); |
| } |
| |
| resetLastDevice() { |
| this.proxy.store.add('adb.lastDevice', ''); |
| this.restart(); |
| } |
| |
| selectDevice(id: string) { |
| this.proxy.selectDevice(id); |
| } |
| |
| keepAliveTrace(view: ProxyConnection) { |
| if (!view.isEndTraceState()) { |
| clearInterval(view.keep_alive_worker); |
| view.keep_alive_worker = undefined; |
| return; |
| } |
| proxyRequest.keepTraceAlive(view.proxy, (request: XMLHttpRequest) => { |
| if (request.responseText !== 'True') { |
| view.endTrace(); |
| } else if (view.keep_alive_worker === undefined) { |
| view.keep_alive_worker = setInterval(view.keepAliveTrace, 1000, view); |
| } |
| }); |
| } |
| |
| async startTrace( |
| requestedTraces: string[], |
| reqEnableConfig?: string[], |
| reqSelectedSfConfig?: ConfigMap, |
| reqSelectedWmConfig?: ConfigMap, |
| ) { |
| if (reqEnableConfig) { |
| proxyRequest.setEnabledConfig(this.proxy, reqEnableConfig); |
| } |
| if (reqSelectedSfConfig) { |
| proxyRequest.setSelectedConfig( |
| ProxyEndpoint.SELECTED_SF_CONFIG_TRACE, |
| this.proxy, |
| reqSelectedSfConfig, |
| ); |
| } |
| if (reqSelectedWmConfig) { |
| proxyRequest.setSelectedConfig( |
| ProxyEndpoint.SELECTED_WM_CONFIG_TRACE, |
| this.proxy, |
| reqSelectedWmConfig, |
| ); |
| } |
| await proxyClient.setState(ProxyState.STARTING_TRACE); |
| await proxyRequest.startTrace( |
| this.proxy, |
| requestedTraces, |
| (request: XMLHttpRequest) => this.keepAliveTrace(this), |
| ); |
| proxyClient.setState(ProxyState.END_TRACE); |
| } |
| |
| async endTrace() { |
| this.progressCallback(0); |
| await this.proxy.setState(ProxyState.LOAD_DATA); |
| await proxyRequest.endTrace(this.proxy, this.progressCallback); |
| } |
| |
| async dumpState(requestedDumps: string[]): Promise<boolean> { |
| this.progressCallback(0); |
| if (requestedDumps.length < 1) { |
| console.error('No targets selected'); |
| await this.proxy.setState(ProxyState.ERROR, 'No targets selected'); |
| return false; |
| } |
| await this.proxy.setState(ProxyState.LOAD_DATA); |
| await proxyRequest.dumpState( |
| this.proxy, |
| requestedDumps, |
| this.progressCallback, |
| ); |
| return true; |
| } |
| |
| isWaylandAvailable(): Promise<boolean> { |
| return new Promise((resolve, reject) => { |
| proxyRequest.call( |
| 'GET', |
| ProxyEndpoint.CHECK_WAYLAND, |
| (request: XMLHttpRequest) => { |
| resolve(request.responseText === 'true'); |
| }, |
| ); |
| }); |
| } |
| |
| async onConnectChange(newState: ProxyState) { |
| if (newState === ProxyState.CONNECTING) { |
| proxyClient.getDevices(); |
| } |
| if (newState === ProxyState.START_TRACE) { |
| const isWaylandAvailable = await this.isWaylandAvailable(); |
| if (isWaylandAvailable) { |
| const availableTracesConfig = TRACES['default']; |
| if (isWaylandAvailable) { |
| Object.assign(availableTracesConfig, TRACES['arc']); |
| } |
| this.traceConfigChangeCallback(availableTracesConfig); |
| } |
| } |
| this.proxyStateChangeCallback(newState); |
| } |
| } |