@@ -59,9 +60,10 @@ import { PersistentStore } from "../common/persistent_store";
export class AppComponent {
title = "winscope-ng";
- private core!: Core;
+ core: Core = new Core();
states = ProxyState;
store: PersistentStore = new PersistentStore();
+ dataLoaded: boolean = false;
constructor(
@Inject(Injector) injector: Injector
@@ -70,10 +72,16 @@ export class AppComponent {
createCustomElement(ViewerWindowManagerComponent, {injector}));
}
- public async onInputFile(event: Event) {
- const files = await this.getInputFiles(event);
+ onCoreChange(newCore: Core) {
+ this.core = newCore;
+ }
- this.core = new Core();
+ onDataLoadedChange(loaded: boolean) {
+ this.dataLoaded = loaded;
+ }
+
+ public async onInputFile(event: Event) {
+ const files = this.getInputFiles(event);
await this.core.bootstrap(files);
const viewersDiv = document.querySelector("div#viewers")!;
@@ -99,4 +107,9 @@ export class AppComponent {
return [files[0]];
}
+
+ public clearData() {
+ this.dataLoaded = false;
+ this.core.clearData();
+ }
}
diff --git a/tools/winscope-ng/src/app/app.module.ts b/tools/winscope-ng/src/app/app.module.ts
index 444abe182..0cb216f58 100644
--- a/tools/winscope-ng/src/app/app.module.ts
+++ b/tools/winscope-ng/src/app/app.module.ts
@@ -18,10 +18,10 @@ import { HttpClientModule } from "@angular/common/http";
import { AppComponent } from "./app.component";
import { ViewerWindowManagerComponent } from "viewers/viewer_window_manager/viewer_window_manager.component";
-import { CollectTracesComponent } from "trace_collection/collect_traces.component";
-import { AdbProxyComponent } from "trace_collection/adb_proxy.component";
-import { WebAdbComponent } from "trace_collection/web_adb/web_adb.component";
-import { TraceConfigComponent } from "trace_collection/trace_config.component";
+import { CollectTracesComponent } from "./collect_traces.component";
+import { AdbProxyComponent } from "./adb_proxy.component";
+import { WebAdbComponent } from "./web_adb.component";
+import { TraceConfigComponent } from "./trace_config.component";
@NgModule({
declarations: [
diff --git a/tools/winscope-ng/src/trace_collection/collect_traces.component.spec.ts b/tools/winscope-ng/src/app/collect_traces.component.spec.ts
similarity index 100%
rename from tools/winscope-ng/src/trace_collection/collect_traces.component.spec.ts
rename to tools/winscope-ng/src/app/collect_traces.component.spec.ts
diff --git a/tools/winscope-ng/src/app/collect_traces.component.ts b/tools/winscope-ng/src/app/collect_traces.component.ts
new file mode 100644
index 000000000..21bd42ab2
--- /dev/null
+++ b/tools/winscope-ng/src/app/collect_traces.component.ts
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 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 { Component, Input, OnInit, Output, EventEmitter } from "@angular/core";
+import { ProxyConnection, Device, configureTraces } from "../trace_collection/connection";
+import { ProxyState } from "../trace_collection/proxy_client";
+import { traceConfigurations, configMap, SelectionConfiguration } from "../trace_collection/trace_collection_utils";
+import { Core } from "app/core";
+import { PersistentStore } from "../common/persistent_store";
+
+
+@Component({
+ selector: "collect-traces",
+ template: `
+
Collect Traces
+
+
+ Connecting...
+
+
+
+
+
+
+
+
+
+
{{ devices().length > 0 ? "Connected devices:" : "No devices detected" }}
+
+
+
+ {{ connect.proxy.devices[deviceId].authorised ? "smartphone" : "screen_lock_portrait" }}
+
+
+ {{ connect.proxy.devices[deviceId].authorised ? connect.proxy.devices[deviceId].model : "unauthorised" }} ({{ deviceId }})
+
+
+
+
+
+
+
+
+
+ smartphone
+
+ {{ selectedDevice().model }} ({{ connect.proxy.selectedDevice }})
+
+
+
+
+
+
+
+
+
+
+
+
Trace targets:
+
+
+
+
+
Dump targets:
+
+ {{connect.DUMPS[dumpKey].name}}
+
+
+
+
+
+
error
+
Error:
+
+ {{ connect.proxy.errorText }}
+
+
+
+
+
+ Tracing...
+
+
+
+
+
+ Loading data...
+
+
+
+
+ `,
+ styles: [".device-choice {cursor: pointer}"]
+})
+export class CollectTracesComponent implements OnInit {
+ objectKeys = Object.keys;
+ isAdbProxy = true;
+ startTrace = false;
+ startDump = false;
+ traceConfigurations = traceConfigurations;
+ connect: any = new ProxyConnection();
+ downloadProxyUrl = "https://android.googlesource.com/platform/development/+/master/tools/winscope-ng/adb/winscope_proxy.py";
+
+ @Input()
+ store: PersistentStore = new PersistentStore();
+
+ @Input()
+ core: Core = new Core();
+
+ @Output()
+ coreChange = new EventEmitter
();
+
+ @Input()
+ dataLoaded: boolean = false;
+
+ @Output()
+ dataLoadedChange = new EventEmitter();
+
+ ngOnInit(): void {
+ if (this.isAdbProxy) {
+ this.connect = new ProxyConnection();
+ } else {
+ //TODO: change to WebAdbConnection
+ this.connect = new ProxyConnection();
+ }
+ }
+
+ ngOnDestroy(): void {
+ this.connect.proxy.removeOnProxyChange(this.onProxyChange);
+ }
+
+ public onAddKey(key: string) {
+ this.store.addToStore("adb.proxyKey", key);
+ this.connect.setProxyKey(key);
+ this.restart();
+ }
+
+ public onProxyChange(newState: ProxyState) {
+ this.connect.onConnectChange(newState);
+ }
+
+ public adbSuccess() {
+ return this.connect.adbSuccess();
+ }
+
+ public devices(): Array {
+ return this.connect.devices();
+ }
+
+ public selectedDevice(): Device {
+ return this.connect.selectedDevice();
+ }
+
+ public restart() {
+ this.connect.restart();
+ }
+
+ public resetLastDevice() {
+ this.connect.resetLastDevice();
+ }
+
+ public selectDevice(id: string) {
+ this.connect.selectDevice(id);
+ }
+
+ public displayAdbProxyTab() {
+ this.isAdbProxy = true;
+ this.connect = new ProxyConnection();
+ }
+
+ public displayWebAdbTab() {
+ this.isAdbProxy = false;
+ //TODO: change to WebAdbConnection
+ this.connect = new ProxyConnection();
+ }
+
+ public requestedTraces() {
+ const tracesFromCollection: Array = [];
+ const req = Object.keys(this.connect.DYNAMIC_TRACES())
+ .filter((traceKey:string) => {
+ const traceConfig = this.connect.DYNAMIC_TRACES()[traceKey];
+ if (traceConfig.isTraceCollection) {
+ traceConfig.config.enableConfigs.forEach((innerTrace:any) => {
+ if (innerTrace.enabled) {
+ tracesFromCollection.push(innerTrace.key);
+ }
+ });
+ return false;
+ }
+ return traceConfig.run;
+ });
+ return req.concat(tracesFromCollection);
+ }
+
+ public requestedDumps() {
+ return Object.keys(this.connect.DUMPS)
+ .filter((dumpKey:any) => {
+ return this.connect.DUMPS[dumpKey].enabled;
+ });
+ }
+
+ public requestedEnableConfig(): Array | null{
+ const req: Array = [];
+ Object.keys(this.connect.DYNAMIC_TRACES())
+ .forEach((traceKey:any) => {
+ const trace = this.connect.DYNAMIC_TRACES()[traceKey];
+ if(!trace.isTraceCollection
+ && trace.run
+ && trace.config
+ && trace.config.enableConfigs) {
+ trace.config.enableConfigs.forEach((con:any) => {
+ if (con.enabled) {
+ req.push(con.key);
+ }
+ });
+ }
+ });
+ if (req.length === 0) {
+ return null;
+ }
+ return req;
+ }
+
+ public requestedSelection(traceType: string) {
+ if (!this.connect.DYNAMIC_TRACES()[traceType].run) {
+ return null;
+ }
+ const selected: configMap = {};
+ this.connect.DYNAMIC_TRACES()[traceType].config.selectionConfigs.forEach(
+ (con: SelectionConfiguration) => {
+ selected[con.key] = con.value;
+ }
+ );
+ return selected;
+ }
+
+ public startTracing() {
+ this.startTrace = true;
+ console.log("begin tracing");
+ configureTraces.reqTraces = this.requestedTraces();
+ const reqEnableConfig = this.requestedEnableConfig();
+ const reqSelectedSfConfig = this.requestedSelection("layers_trace");
+ const reqSelectedWmConfig = this.requestedSelection("window_trace");
+ if (configureTraces.reqTraces.length < 1) {
+ this.connect.throwNoTargetsError();
+ return;
+ }
+ this.connect.startTrace(
+ reqEnableConfig,
+ reqSelectedSfConfig,
+ reqSelectedWmConfig
+ );
+ }
+
+ public async dumpState() {
+ this.startDump = true;
+ console.log("begin dump");
+ configureTraces.reqDumps = this.requestedDumps();
+ await this.connect.dumpState();
+ while (!this.connect.proxy.dataReady) {
+ await this.waitForData(1000);
+ }
+ await this.loadFiles();
+ }
+
+ public async endTrace() {
+ console.log("end tracing");
+ await this.connect.endTrace();
+ while (!this.connect.proxy.dataReady) {
+ await this.waitForData(1000);
+ }
+ await this.loadFiles();
+ }
+
+ public async loadFiles() {
+ console.log("loading files", this.connect.adbData());
+ await this.core.bootstrap(this.connect.adbData());
+ this.dataLoaded = true;
+ this.dataLoadedChange.emit(this.dataLoaded);
+ this.coreChange.emit(this.core);
+ console.log("finished loading data!");
+ }
+
+ public tabClass(adbTab: boolean) {
+ let isActive: string;
+ if (adbTab) {
+ isActive = this.isAdbProxy ? "active" : "inactive";
+ } else {
+ isActive = !this.isAdbProxy ? "active" : "inactive";
+ }
+ return ["tab", isActive];
+ }
+
+ private waitForData(ms: number) {
+ return new Promise( resolve => setTimeout(resolve, ms) );
+ }
+}
diff --git a/tools/winscope-ng/src/app/core.ts b/tools/winscope-ng/src/app/core.ts
index d3a305573..1d023ebc1 100644
--- a/tools/winscope-ng/src/app/core.ts
+++ b/tools/winscope-ng/src/app/core.ts
@@ -71,6 +71,11 @@ class Core {
viewer.notifyCurrentTraceEntries(traceEntries);
});
}
+
+ clearData() {
+ this.parsers = [];
+ this.viewers = [];
+ }
}
export { Core };
diff --git a/tools/winscope-ng/src/trace_collection/trace_config.component.spec.ts b/tools/winscope-ng/src/app/trace_config.component.spec.ts
similarity index 100%
rename from tools/winscope-ng/src/trace_collection/trace_config.component.spec.ts
rename to tools/winscope-ng/src/app/trace_config.component.spec.ts
diff --git a/tools/winscope-ng/src/app/trace_config.component.ts b/tools/winscope-ng/src/app/trace_config.component.ts
new file mode 100644
index 000000000..213f85c12
--- /dev/null
+++ b/tools/winscope-ng/src/app/trace_config.component.ts
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 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 { Component, Input, OnChanges, SimpleChanges } from "@angular/core";
+import { EnableConfiguration, SelectionConfiguration, TraceConfiguration } from "../trace_collection/trace_collection_utils";
+
+@Component({
+ selector: "trace-config",
+ template: `
+
+
{{trace.name}}
+
+
+
{{enableConfig.name}}
+
+
+ {{selectionConfig.name}}
+
+ {{ option }}
+
+
+
+
+
+ `,
+ styles: [".adv-config {margin-left: 5rem;}"],
+})
+
+export class TraceConfigComponent {
+ @Input()
+ trace: TraceConfiguration = {};
+
+ public traceEnableConfigs(): Array {
+ if (this.trace.config) {
+ return this.trace.config.enableConfigs;
+ } else {
+ return [];
+ }
+ }
+
+ public traceSelectionConfigs(): Array {
+ if (this.trace.config) {
+ return this.trace.config.selectionConfigs;
+ } else {
+ return [];
+ }
+ }
+
+ public someTraces(): boolean {
+ return this.traceEnableConfigs().filter(trace => trace.enabled).length > 0
+ && !this.trace.run;
+ }
+
+ public changeRunTrace(run: boolean): void {
+ this.trace.run = run;
+ if (this.trace.isTraceCollection) {
+ this.traceEnableConfigs().forEach((c: EnableConfiguration) => (c.enabled = run));
+ }
+ }
+
+ public changeTraceCollectionConfig(): void {
+ if (this.trace.isTraceCollection) {
+ this.trace.run = this.traceEnableConfigs().every((c: EnableConfiguration) => c.enabled);
+ }
+ }
+}
diff --git a/tools/winscope-ng/src/trace_collection/web_adb/web_adb.component.spec.ts b/tools/winscope-ng/src/app/web_adb.component.spec.ts
similarity index 100%
rename from tools/winscope-ng/src/trace_collection/web_adb/web_adb.component.spec.ts
rename to tools/winscope-ng/src/app/web_adb.component.spec.ts
diff --git a/tools/winscope-ng/src/trace_collection/web_adb/web_adb.component.ts b/tools/winscope-ng/src/app/web_adb.component.ts
similarity index 100%
rename from tools/winscope-ng/src/trace_collection/web_adb/web_adb.component.ts
rename to tools/winscope-ng/src/app/web_adb.component.ts
diff --git a/tools/winscope-ng/src/styles.css b/tools/winscope-ng/src/styles.css
index 8c859d63e..7886217ba 100644
--- a/tools/winscope-ng/src/styles.css
+++ b/tools/winscope-ng/src/styles.css
@@ -49,6 +49,10 @@ mat-icon {
margin: 5px;
}
+.icon-message {
+ vertical-align: middle;
+}
+
.card-block {
margin: 15px;
}
diff --git a/tools/winscope-ng/src/trace_collection/collect_traces.component.ts b/tools/winscope-ng/src/trace_collection/collect_traces.component.ts
deleted file mode 100644
index aeb96ff55..000000000
--- a/tools/winscope-ng/src/trace_collection/collect_traces.component.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 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 {Component, Input, OnInit} from "@angular/core";
-import { Connection, ProxyConnection, Device } from "./connection";
-import { ProxyState } from "./proxy_client";
-import { traceConfigurations, configMap } from "./trace_collection_utils";
-import { PersistentStore } from "../common/persistent_store";
-
-@Component({
- selector: "collect-traces",
- template: `
- Collect Traces
-
-
- Connecting...
-
-
-
-
-
-
-
-
-
-
{{ devices().length > 0 ? "Connected devices:" : "No devices detected" }}
-
-
- {{ connect.proxy.devices[deviceId].authorised ? "smartphone" : "screen_lock_portrait" }}
- {{ connect.proxy.devices[deviceId].authorised ? connect.proxy.devices[deviceId].model : "unauthorised" }} ({{ deviceId }})
-
-
-
-
-
-
-
-
- smartphone
- {{ selectedDevice().model }} ({{ connect.proxy.selectedDevice }})
-
-
-
-
-
-
-
-
-
-
-
Trace targets:
-
-
-
-
-
Dump targets:
-
- {{DUMPS[dumpKey]}}
-
-
-
-
-
-
error
-
Error:
-
- {{ errorText }}
-
-
-
-
-
-
Tracing...
-
-
- {{ errorText }}
-
-
-
-
-
- Loading data...
-
-
-
-
- `,
- styles: [".device-choice {cursor: pointer}"]
-})
-export class CollectTracesComponent implements OnInit {
- objectKeys = Object.keys;
- isAdbProxy = true;
- startTrace = false;
- startDump = false;
- errorText = "";
- traceConfigurations = traceConfigurations;
-
- connect: any = new ProxyConnection();
-
- downloadProxyUrl = "https://android.googlesource.com/platform/development/+/master/tools/winscope-ng/adb/winscope_proxy.py";
-
- states = ProxyState;
-
- @Input()
- store: PersistentStore = new PersistentStore();
-
- ngOnInit(): void {
- if (this.isAdbProxy) {
- this.connect = new ProxyConnection();
- } else {
- //TODO: change to WebAdbConnection
- this.connect = new ProxyConnection();
- }
- }
-
- ngOnDestroy(): void {
- this.connect.proxy.removeOnProxyChange(this.onProxyChange);
- }
-
- public onAddKey(key: string) {
- this.store.addToStore("adb.proxyKey", key);
- this.connect.setProxyKey(key);
- this.restart();
- }
-
- public onConnectChange(newState: Connection) {
- this.connect.onConnectChange(newState);
- }
-
- public onProxyChange(newState: ProxyState, errorText: string) {
- this.connect.onConnectChange(newState);
- }
-
-
- public adbSuccess() {
- return this.connect.adbSuccess();
- }
-
- public devices(): Array {
- return this.connect.devices();
- }
-
- public selectedDevice(): Device {
- return this.connect.selectedDevice();
- }
-
- public restart() {
- this.connect.restart();
- }
-
- public resetLastDevice() {
- this.connect.resetLastDevice();
- }
-
- public selectDevice(id: string) {
- this.connect.selectDevice(id);
- }
-
- public displayAdbProxyTab() {
- this.isAdbProxy = true;
- this.connect = new ProxyConnection();
- }
-
- public displayWebAdbTab() {
- this.isAdbProxy = false;
- //TODO: change to WebAdbConnection
- this.connect = new ProxyConnection();
- }
-
- public startTracing() {
- this.startTrace = true;
- console.log("begin tracing");
- }
-
- public dumpState() {
- this.startDump = true;
- console.log("begin dump");
- }
-
- public endTrace() {
- console.log("end trace");
- }
-
- public setAvailableTraces() {
- this.connect.setAvailableTraces();
- }
-
- public tabClass(adbTab: boolean) {
- let isActive: string;
- if (adbTab) {
- isActive = this.isAdbProxy ? "active" : "inactive";
- } else {
- isActive = !this.isAdbProxy ? "active" : "inactive";
- }
- return ["tab", isActive];
- }
-
- DYNAMIC_TRACES: any = null;
-
- DUMPS: configMap = {
- "window_dump": "Window Manager",
- "layers_dump": "Surface Flinger"
- };
-
-}
\ No newline at end of file
diff --git a/tools/winscope-ng/src/trace_collection/connection.ts b/tools/winscope-ng/src/trace_collection/connection.ts
index 658d46c93..2ae50467f 100644
--- a/tools/winscope-ng/src/trace_collection/connection.ts
+++ b/tools/winscope-ng/src/trace_collection/connection.ts
@@ -1,5 +1,5 @@
-import { proxyClient, ProxyState, ProxyEndpoint, ProxyClient } from "trace_collection/proxy_client";
-import {TRACES, traceConfigurations} from "./trace_collection_utils";
+import { proxyRequest, proxyClient, ProxyState, ProxyEndpoint } from "trace_collection/proxy_client";
+import { TRACES } from "./trace_collection_utils";
export interface Device {
authorised: boolean;
@@ -13,24 +13,44 @@ export interface Connection {
selectedDevice(): Device;
restart(): any;
selectDevice(id:string): any;
- DYNAMIC_TRACES: any;
+ DYNAMIC_TRACES(): any;
state(): ProxyState;
onConnectChange(newState: any): any;
- setAvailableTraces(): any;
resetLastDevice(): any;
+ isDevicesState(): boolean;
+ isStartTraceState(): boolean;
+ isErrorState(): boolean;
+ isEndTraceState(): boolean;
+ isLoadDataState(): boolean;
+ isConnectingState(): boolean;
+ isNoProxy(): boolean;
+ isInvalidProxy(): boolean;
+ isUnauthProxy(): boolean;
+ throwNoTargetsError(): any;
+ startTrace(
+ reqEnableConfig?: Array,
+ reqSelectedSfConfig?: any,
+ reqSelectedWmConfig?: any
+ ): any;
+ DUMPS: any;
+ endTrace(): any;
+ dumpState(req:Array): any;
+ adbData(): any;
}
export class ProxyConnection implements Connection {
- DYNAMIC_TRACES: any;
proxy = proxyClient;
-
- public state() {
- return this.proxy.state;
- }
-
- public devices() {
- return Object.keys(this.proxy.devices);
- }
+ DUMPS: any = {
+ "window_dump": {
+ name: "Window Manager",
+ enabled: true,
+ },
+ "layers_dump": {
+ name: "Surface Flinger",
+ enabled: true,
+ }
+ };
+ keep_alive_worker: any = null;
notConnected = [
ProxyState.NO_PROXY,
ProxyState.UNAUTH,
@@ -47,26 +67,68 @@ export class ProxyConnection implements Connection {
this.proxy.getDevices();
}
- public onConnectChange(newState: ProxyState) {
- if (newState === ProxyState.CONNECTING) {
- proxyClient.getDevices();
- }
- if (newState == ProxyState.START_TRACE) {
- proxyClient.call("GET", ProxyEndpoint.CHECK_WAYLAND, this, function(request: any,view:any) {
- try {
- if(request.responseText == "true") {
- //view.appendOptionalTraces('arc', view.TRACES);
- }
- } catch(err) {
- console.error(err);
- proxyClient.setState(ProxyState.ERROR, request.responseText);
- }
- });
- }
+ public devices() {
+ return Object.keys(this.proxy.devices);
+ }
+
+ public adbData() {
+ return this.proxy.adbData;
+ }
+
+ DYNAMIC_TRACES() {
+ return configureTraces.DYNAMIC_TRACES;
+ }
+
+ public state() {
+ return this.proxy.state;
+ }
+
+ public isDevicesState() {
+ return this.state() === ProxyState.DEVICES;
+ }
+
+ public isStartTraceState() {
+ return this.state() === ProxyState.START_TRACE;
+ }
+
+ public isErrorState() {
+ return this.state() === ProxyState.ERROR;
+ }
+
+ public isEndTraceState() {
+ return this.state() === ProxyState.END_TRACE;
+ }
+
+ public isLoadDataState() {
+ return this.state() === ProxyState.LOAD_DATA;
+ }
+
+ public isConnectingState() {
+ return this.state() === ProxyState.CONNECTING;
+ }
+
+ public isNoProxy() {
+ return this.state() === ProxyState.NO_PROXY;
+ }
+
+ public isInvalidProxy() {
+ return this.state() === ProxyState.INVALID_VERSION;
+ }
+
+ public isUnauthProxy() {
+ return this.state() === ProxyState.UNAUTH;
+ }
+
+ public throwNoTargetsError() {
+ this.proxy.setState(ProxyState.ERROR, "No targets selected");
+ }
+
+ public dataReady() {
+ return this.proxy.dataReady;
}
public setProxyKey(key: string) {
- proxyClient.proxyKey = key;
+ this.proxy.proxyKey = key;
this.restart();
}
@@ -83,7 +145,7 @@ export class ProxyConnection implements Connection {
}
public resetLastDevice() {
- this.proxy.resetLastDevice();
+ this.proxy.store.addToStore("adb.lastDevice", "");
this.restart();
}
@@ -91,17 +153,82 @@ export class ProxyConnection implements Connection {
this.proxy.selectDevice(id);
}
- public setAvailableTraces() {
- this.DYNAMIC_TRACES = TRACES["default"];
- proxyClient.call("GET", ProxyEndpoint.CHECK_WAYLAND, this, function(request:any, view:any) {
- try {
- if(request.responseText == "true") {
- //view.appendOptionalTraces('arc');
- }
- } catch(err) {
- console.error(err);
- proxyClient.setState(ProxyState.ERROR, request.responseText);
+ public keepAliveTrace(view:any) {
+ if (!view.isEndTraceState()) {
+ clearInterval(view.keep_alive_worker);
+ view.keep_alive_worker = null;
+ return;
+ }
+ proxyRequest.call("GET", `${ProxyEndpoint.STATUS}${view.proxy.selectedDevice}/`, view, function(request:any, newView:any) {
+ if (request.responseText !== "True") {
+ newView.endTrace();
+ } else if (newView.keep_alive_worker === null) {
+ newView.keep_alive_worker = setInterval(newView.keepAliveTrace, 1000, newView);
}
});
}
+
+ public startTrace(
+ reqEnableConfig: any,
+ reqSelectedSfConfig: any,
+ reqSelectedWmConfig: any
+ ) {
+ if (reqEnableConfig) {
+ proxyRequest.call("POST", `${ProxyEndpoint.CONFIG_TRACE}${this.proxy.selectedDevice}/`, this, null, null, reqEnableConfig);
+ }
+ if (reqSelectedSfConfig) {
+ proxyRequest.call("POST", `${ProxyEndpoint.SELECTED_SF_CONFIG_TRACE}${this.proxy.selectedDevice}/`, this, null, null, reqSelectedSfConfig);
+ }
+ if (reqSelectedWmConfig) {
+ proxyRequest.call("POST", `${ProxyEndpoint.SELECTED_WM_CONFIG_TRACE}${this.proxy.selectedDevice}/`, this, null, null, reqSelectedWmConfig);
+ }
+ proxyClient.setState(ProxyState.END_TRACE);
+ proxyRequest.call("POST", `${ProxyEndpoint.START_TRACE}${this.proxy.selectedDevice}/`, this, function(request:any, view:any) {
+ view.keepAliveTrace(view);
+ }, null, configureTraces.reqTraces);
+ }
+
+ public async endTrace() {
+ this.proxy.setState(ProxyState.LOAD_DATA);
+ await proxyRequest.call("POST", `${ProxyEndpoint.END_TRACE}${this.proxy.selectedDevice}/`, this,
+ async function (request:any, view:any) {
+ await proxyClient.updateAdbData(configureTraces.reqTraces, 0, "trace", view);
+ });
+ }
+
+ public dumpState() {
+ if (configureTraces.reqDumps.length < 1) {
+ this.proxy.setState(ProxyState.ERROR, "No targets selected");
+ return;
+ }
+ this.proxy.setState(ProxyState.LOAD_DATA);
+ proxyRequest.call("POST", `${ProxyEndpoint.DUMP}${this.proxy.selectedDevice}/`, this, function(request:any, view:any) {
+ view.proxy.updateAdbData(configureTraces.reqDumps, 0, "dump", view);
+ }, null, configureTraces.reqDumps);
+ }
+
+ public onConnectChange(newState: ProxyState) {
+ if (newState === ProxyState.CONNECTING) {
+ proxyClient.getDevices();
+ }
+ if (newState == ProxyState.START_TRACE) {
+ configureTraces.setAvailableTraces();
+ }
+ }
}
+
+class ConfigureTraces {
+ DYNAMIC_TRACES = TRACES["default"];
+ reqTraces: string[] = [];
+ reqDumps: string[] = [];
+
+ setAvailableTraces() {
+ proxyRequest.call("GET", ProxyEndpoint.CHECK_WAYLAND, this, proxyRequest.setAvailableTraces);
+ }
+ appendOptionalTraces(view:any, device_key:string) {
+ for(const key in TRACES[device_key]) {
+ view.DYNAMIC_TRACES[key] = TRACES[device_key][key];
+ }
+ }
+}
+export const configureTraces = new ConfigureTraces();
\ No newline at end of file
diff --git a/tools/winscope-ng/src/trace_collection/proxy_client.ts b/tools/winscope-ng/src/trace_collection/proxy_client.ts
index de906035a..43e0008ee 100644
--- a/tools/winscope-ng/src/trace_collection/proxy_client.ts
+++ b/tools/winscope-ng/src/trace_collection/proxy_client.ts
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { PersistentStore } from "common/persistent_store";
+import { PersistentStore } from "../common/persistent_store";
+import { TRACES } from "./trace_collection_utils";
export enum ProxyState {
ERROR = 0,
@@ -40,25 +41,11 @@ export enum ProxyEndpoint {
CHECK_WAYLAND = "/checkwayland/",
}
-export class ProxyClient {
- readonly WINSCOPE_PROXY_URL = "http://localhost:5544";
- readonly VERSION = "0.8";
-
- state: ProxyState = ProxyState.CONNECTING;
- stateChangeListeners: {(param:ProxyState, errorText:string): void;}[] = [];
- refresh_worker: NodeJS.Timeout | undefined = undefined;
- devices: any = {};
- selectedDevice = "";
- errorText = "";
-
- proxyKey = "";
- lastDevice = "";
-
- store = new PersistentStore();
-
- call(method: string, path: string, view: any, onSuccess: any, type = null, jsonRequest = null) {
+// from here, all requests to the proxy are made
+class ProxyRequest {
+ async call(method: string, path: string, view: any, onSuccess: any, type: any = null, jsonRequest:any = null) {
const request = new XMLHttpRequest();
- const client = this;
+ const client = proxyClient;
request.onreadystatechange = function() {
if (this.readyState !== 4) {
return;
@@ -79,7 +66,7 @@ export class ProxyClient {
} else if (this.responseType === "arraybuffer") {
client.errorText = String.fromCharCode.apply(null, new Array(this.response));
}
- client.setState(ProxyState.ERROR);
+ client.setState(ProxyState.ERROR, client.errorText);
}
};
request.responseType = type || "";
@@ -98,6 +85,88 @@ export class ProxyClient {
}
}
+ getDevices = function(request: any, view: any) {
+ const client = proxyClient;
+ try {
+ client.devices = JSON.parse(request.responseText);
+ const last = client.store.getFromStore("adb.lastDevice");
+ if (last && client.devices[last] &&
+ client.devices[last].authorised) {
+ client.selectDevice(last);
+ } else {
+ if (client.refresh_worker === null) {
+ client.refresh_worker = setInterval(client.getDevices, 1000);
+ }
+ client.setState(ProxyState.DEVICES);
+ }
+ } catch (err) {
+ console.error(err);
+ client.errorText = request.responseText;
+ client.setState(ProxyState.ERROR, client.errorText);
+ }
+ };
+
+ setAvailableTraces = function(request:any, view:any) {
+ try {
+ view.DYNAMIC_TRACES = TRACES["default"];
+ if(request.responseText == "true") {
+ view.appendOptionalTraces(view, "arc");
+ }
+ } catch(err) {
+ proxyClient.setState(ProxyState.ERROR, request.responseText);
+ }
+ };
+
+ updateAdbData = async (request: any, view: any) => {
+ let idx = proxyClient.adbParams.idx;
+ let files = proxyClient.adbParams.files;
+ let traceType = proxyClient.adbParams.traceType;
+ try {
+ const enc = new TextDecoder("utf-8");
+ const resp = enc.decode(request.response);
+ const filesByType = JSON.parse(resp);
+
+ for (const filetype in filesByType) {
+ const files = filesByType[filetype];
+ for (const encodedFileBuffer of files) {
+ const buffer = Uint8Array.from(atob(encodedFileBuffer), (c) => c.charCodeAt(0));
+ const blob = new Blob([buffer]);
+ proxyClient.adbData.push(blob);
+ }
+ }
+ if (idx < files.length - 1) {
+ proxyClient.updateAdbData(files, idx + 1, traceType, view);
+ } else {
+ proxyClient.dataReady = true;
+ }
+ } catch (error) {
+ proxyClient.setState(ProxyState.ERROR, request.responseText);
+ }
+ }
+}
+export const proxyRequest = new ProxyRequest();
+
+// stores all the changing variables from proxy and sets up calls from ProxyRequest
+export class ProxyClient {
+ readonly WINSCOPE_PROXY_URL = "http://localhost:5544";
+ readonly VERSION = "0.8";
+ state: ProxyState = ProxyState.CONNECTING;
+ stateChangeListeners: {(param:ProxyState, errorText:string): void;}[] = [];
+ refresh_worker: NodeJS.Timer | null = null;
+ devices: any = {};
+ selectedDevice = "";
+ errorText = "";
+ adbData: Array = [];
+ proxyKey = "";
+ lastDevice = "";
+ store = new PersistentStore();
+ dataReady: boolean = false;
+ adbParams = {
+ files: [],
+ idx: -1,
+ traceType: null,
+ };
+
setState(state:ProxyState, errorText = "") {
this.state = state;
this.errorText = errorText;
@@ -117,46 +186,25 @@ export class ProxyClient {
getDevices() {
if (this.state !== ProxyState.DEVICES && this.state !== ProxyState.CONNECTING) {
- clearInterval(this.refresh_worker);
- this.refresh_worker = undefined;
+ clearInterval(this.refresh_worker!);
+ this.refresh_worker = null;
return;
}
- const client = this;
- this.call("GET", ProxyEndpoint.DEVICES, this, function(request: any, view: any) {
- try {
- client.devices = JSON.parse(request.responseText);
- const last = client.store.getFromStore("adb.lastDevice");
- if (last && client.devices[last] &&
- client.devices[last].authorised) {
- client.selectDevice(last);
- } else {
- if (client.refresh_worker === undefined) {
- client.refresh_worker = setInterval(client.getDevices, 1000);
- }
- client.setState(ProxyState.DEVICES);
- }
- } catch (err) {
- console.error(err);
- client.errorText = request.responseText;
- client.setState(ProxyState.ERROR);
- }
- });
+ proxyRequest.call("GET", ProxyEndpoint.DEVICES, this, proxyRequest.getDevices);
}
selectDevice(device_id: string) {
this.selectedDevice = device_id;
this.store.addToStore("adb.lastDevice", device_id);
- this.lastDevice = device_id;
this.setState(ProxyState.START_TRACE);
}
- deviceId() {
- return this.selectedDevice;
- }
-
- resetLastDevice() {
- this.lastDevice = "";
- this.store.addToStore("adb.lastDevice", "");
+ async updateAdbData(files:any, idx:any, traceType:any, view: any) {
+ this.adbParams.files = files;
+ this.adbParams.idx = idx;
+ this.adbParams.traceType = traceType;
+ await proxyRequest.call("GET", `${ProxyEndpoint.FETCH}${this.selectedDevice}/${files[idx]}/`, view,
+ proxyRequest.updateAdbData, "arraybuffer");
}
}
diff --git a/tools/winscope-ng/src/trace_collection/trace_collection_utils.ts b/tools/winscope-ng/src/trace_collection/trace_collection_utils.ts
index 99a78472a..28c4201a0 100644
--- a/tools/winscope-ng/src/trace_collection/trace_collection_utils.ts
+++ b/tools/winscope-ng/src/trace_collection/trace_collection_utils.ts
@@ -1,10 +1,14 @@
-
-interface TraceConfiguration {
- name: string,
- defaultCheck?: boolean,
+export interface TraceConfiguration {
+ name?: string,
+ run?: boolean,
+ isTraceCollection?: boolean,
config?: ConfigurationOptions
}
+interface TraceConfigurationMap {
+ [key: string]: TraceConfiguration
+}
+
export interface ConfigurationOptions {
enableConfigs: Array,
selectionConfigs: Array
@@ -12,10 +16,12 @@ export interface ConfigurationOptions {
export interface EnableConfiguration {
name: string,
- defaultCheck: boolean,
+ key: string,
+ enabled: boolean,
}
export interface SelectionConfiguration {
+ key: string,
name: string,
options: Array,
value: string
@@ -25,46 +31,10 @@ export type configMap = {
[key: string]: Array | string;
}
-export const TRACES = {
- "default": {
- "window_trace": {
- name: "Window Manager",
- },
- "accessibility_trace": {
- name: "Accessibility",
- },
- "layers_trace": {
- name: "Surface Flinger",
- },
- "transactions": {
- name: "Transaction",
- },
- "proto_log": {
- name: "ProtoLog",
- },
- "screen_recording": {
- name: "Screen Recording",
- },
- "ime_trace_clients": {
- name: "Input Method Clients",
- },
- "ime_trace_service": {
- name: "Input Method Service",
- },
- "ime_trace_managerservice": {
- name: "Input Method Manager Service",
- },
- },
- "arc": {
- "wayland_trace": {
- name: "Wayland",
- },
- },
-};
-
-const wmTraceSelectionConfigs = [
+const wmTraceSelectionConfigs: Array = [
{
- name: "wmbuffersize (KB)",
+ key: "wmbuffersize",
+ name: "buffer size (KB)",
options: [
"4000",
"8000",
@@ -74,7 +44,8 @@ const wmTraceSelectionConfigs = [
value: "4000"
},
{
- name: "tracingtype",
+ key: "tracingtype",
+ name: "tracing type",
options: [
"frame",
"transaction",
@@ -82,7 +53,8 @@ const wmTraceSelectionConfigs = [
value: "frame"
},
{
- name: "tracinglevel",
+ key: "tracinglevel",
+ name: "tracing level",
options: [
"verbose",
"debug",
@@ -92,54 +64,126 @@ const wmTraceSelectionConfigs = [
},
];
-
-export const traceConfigurations: Array = [
+const sfTraceEnableConfigs: Array = [
{
- name: "Surface Flinger",
- defaultCheck: true,
- config: {
- enableConfigs: [
- {name: "composition", defaultCheck: false},
- {name: "metadata", defaultCheck: false},
- {name: "hwc", defaultCheck: false},
- {name: "tracebuffers", defaultCheck: false}
- ],
- selectionConfigs: [
- {
- name: "sfbuffersize (KB)",
- options: ["4000","8000","16000","32000",],
- value: "4000"
- }
- ]
- }
+ name: "composition",
+ key: "composition",
+ enabled: true
},
{
+ name: "metadata",
+ key: "metadata",
+ enabled: true
+ },
+ {
+ name: "hwc",
+ key: "hwc",
+ enabled: true
+ },
+ {
+ name: "trace buffers",
+ key: "tracebuffers",
+ enabled: true
+ }
+];
+
+const sfTraceSelectionConfigs: Array = [
+ {
+ key: "sfbuffersize",
+ name: "buffer size (KB)",
+ options: ["4000","8000","16000","32000"],
+ value: "4000"
+ }
+];
+
+export const traceConfigurations: TraceConfigurationMap = {
+ "layers_trace": {
+ name: "Surface Flinger",
+ run: true,
+ config: {
+ enableConfigs: sfTraceEnableConfigs,
+ selectionConfigs: sfTraceSelectionConfigs,
+ }
+ },
+ "window_trace": {
name: "Window Manager",
- defaultCheck: true,
+ run: true,
config: {
enableConfigs: [],
selectionConfigs: wmTraceSelectionConfigs,
}
},
- {
+ "screen_recording": {
name: "Screen Recording",
+ run: true,
},
- {
- name: "Accessibility",
- },
- {
- name: "Transaction",
- },
- {
+ "ime_tracing": {
name: "IME Tracing",
- defaultCheck: true,
+ run: true,
+ isTraceCollection: true,
config: {
enableConfigs: [
- {name: "Input Method Clients", defaultCheck: true},
- {name: "Input Method Service", defaultCheck: true},
- {name: "Input Method Manager Service", defaultCheck: true},
+ {
+ name: "Input Method Clients",
+ key: "ime_trace_clients",
+ enabled: true,
+ },
+ {
+ name: "Input Method Service",
+ key: "ime_trace_service",
+ enabled: true,
+ },
+ {
+ name: "Input Method Manager Service",
+ key: "ime_trace_managerservice",
+ enabled: true,
+ },
],
selectionConfigs: []
}
},
-];
+ "ime_trace_clients": {
+ name: "Input Method Clients",
+ run: true,
+ },
+ "ime_trace_service": {
+ name: "Input Method Service",
+ run: true,
+ },
+ "ime_trace_managerservice": {
+ name: "Input Method Manager Service",
+ run: true,
+ },
+ "accessibility_trace": {
+ name: "Accessibility",
+ run: false,
+ },
+ "transactions": {
+ name: "Transaction",
+ run: false,
+ },
+ "proto_log": {
+ name: "ProtoLog",
+ run: false,
+ },
+ "wayland_trace": {
+ name: "Wayland",
+ run: false,
+ },
+};
+
+
+export const TRACES: { [key: string]: TraceConfigurationMap; } = {
+ "default": {
+ "window_trace": traceConfigurations["window_trace"],
+ "accessibility_trace": traceConfigurations["accessibility_trace"],
+ "layers_trace": traceConfigurations["layers_trace"],
+ "transactions": traceConfigurations["transactions"],
+ "proto_log": traceConfigurations["proto_log"],
+ "screen_recording": traceConfigurations["screen_recording"],
+ "ime_tracing": traceConfigurations["ime_tracing"],
+ },
+ "arc": {
+ "wayland_trace": traceConfigurations["wayland_trace"],
+ },
+};
diff --git a/tools/winscope-ng/src/trace_collection/trace_config.component.ts b/tools/winscope-ng/src/trace_collection/trace_config.component.ts
deleted file mode 100644
index 8b2ce9606..000000000
--- a/tools/winscope-ng/src/trace_collection/trace_config.component.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 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 { ConfigurationOptions, SelectionConfiguration } from "./trace_collection_utils";
-import { Component, Input, Output, EventEmitter } from "@angular/core";
-import { ProxyState, ProxyClient } from "./proxy_client";
-
-
-@Component({
- selector: "trace-config",
- template: `
-
-
{{name}}
-
-
{{enableConfig.name}}
-
-
- {{con.name}}
-
- {{ option }}
-
-
-
-
-
- `,
- styles: [".adv-config {margin-left: 5rem;}"],
-})
-
-export class TraceConfigComponent {
- states = ProxyState;
- objectKeys = Object.keys;
-
- @Input()
- name = "";
-
- @Input()
- configs: ConfigurationOptions | null = null;
-
- @Input()
- defaultCheck: boolean | undefined = false;
-
- public traceEnableConfigs(): Array {
- if (this.configs && this.configs.enableConfigs) {
- return this.configs.enableConfigs;
- } else {
- return [];
- }
- }
-
- public traceSelectionConfigs(): Array {
- if (this.configs) {
- return this.configs.selectionConfigs;
- } else {
- return [];
- }
- }
-}
\ No newline at end of file