Display filename of active view/trace (if available)
- Search filename of active view (if available) and display it in the toolbar (page top-center) - Rename TraceViewComponent's event emitters as specified in Angular style guides Fix: b/258214773 Test: npm run build:all && npm run test:all Change-Id: I05abb10a9c78ffc8c3208ba081251d068a17a5a7
This commit is contained in:
@@ -104,6 +104,7 @@ describe("AppComponent", () => {
|
||||
component.dataLoaded = false;
|
||||
fixture.detectChanges();
|
||||
expect(htmlElement.querySelector(".welcome-info")).toBeTruthy();
|
||||
expect(htmlElement.querySelector(".active-trace-file-info")).toBeFalsy();
|
||||
expect(htmlElement.querySelector(".collect-traces-card")).toBeTruthy();
|
||||
expect(htmlElement.querySelector(".upload-traces-card")).toBeTruthy();
|
||||
expect(htmlElement.querySelector(".viewers")).toBeFalsy();
|
||||
@@ -113,6 +114,7 @@ describe("AppComponent", () => {
|
||||
component.dataLoaded = true;
|
||||
fixture.detectChanges();
|
||||
expect(htmlElement.querySelector(".welcome-info")).toBeFalsy();
|
||||
expect(htmlElement.querySelector(".active-trace-file-info")).toBeTruthy();
|
||||
expect(htmlElement.querySelector(".collect-traces-card")).toBeFalsy();
|
||||
expect(htmlElement.querySelector(".upload-traces-card")).toBeFalsy();
|
||||
expect(htmlElement.querySelector(".viewers")).toBeTruthy();
|
||||
|
||||
@@ -58,7 +58,11 @@ import {UploadTracesComponent} from "./upload_traces.component";
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer">
|
||||
<span *ngIf="dataLoaded" class="active-trace-file-info mat-body-2">
|
||||
{{activeTraceFileInfo}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button *ngIf="dataLoaded" color="primary" mat-stroked-button
|
||||
(click)="onUploadNewClick()">
|
||||
@@ -97,8 +101,8 @@ import {UploadTracesComponent} from "./upload_traces.component";
|
||||
class="viewers"
|
||||
[viewers]="viewers"
|
||||
[store]="store"
|
||||
(onDownloadTracesButtonClick)="onDownloadTracesButtonClick()"
|
||||
(onActiveViewChanged)="handleActiveViewChanged($event)"
|
||||
(downloadTracesButtonClick)="onDownloadTracesButtonClick()"
|
||||
(activeViewChanged)="onActiveViewChanged($event)"
|
||||
></trace-view>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
@@ -164,6 +168,7 @@ import {UploadTracesComponent} from "./upload_traces.component";
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
.viewers {
|
||||
height: 0;
|
||||
@@ -214,7 +219,8 @@ export class AppComponent implements AppComponentDependencyInversion {
|
||||
viewers: Viewer[] = [];
|
||||
isDarkModeOn!: boolean;
|
||||
dataLoaded = false;
|
||||
activeView: View|undefined;
|
||||
activeView?: View;
|
||||
activeTraceFileInfo = "";
|
||||
collapsedTimelineHeight = 0;
|
||||
@ViewChild(UploadTracesComponent) uploadTracesComponent?: UploadTracesComponent;
|
||||
@ViewChild(TimelineComponent) timelineComponent?: TimelineComponent;
|
||||
@@ -313,30 +319,38 @@ export class AppComponent implements AppComponentDependencyInversion {
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
private async makeTraceFilesForDownload(): Promise<File[]> {
|
||||
return this.traceData.getLoadedTraces().map(trace => {
|
||||
const traceType = TRACE_INFO[trace.type].name;
|
||||
const newName = traceType + "/" + FileUtils.removeDirFromFileName(trace.file.name);
|
||||
return new File([trace.file], newName);
|
||||
});
|
||||
}
|
||||
|
||||
handleActiveViewChanged(view: View) {
|
||||
onActiveViewChanged(view: View) {
|
||||
this.activeView = view;
|
||||
this.activeTraceFileInfo = this.makeActiveTraceFileInfo(view);
|
||||
this.timelineData.setActiveViewTraceTypes(view.dependencies);
|
||||
}
|
||||
|
||||
getActiveTraceType(): TraceType|undefined {
|
||||
if (this.activeView === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (this.activeView.dependencies.length !== 1) {
|
||||
throw Error("Viewers with dependencies length !== 1 are not supported.");
|
||||
}
|
||||
return this.activeView.dependencies[0];
|
||||
}
|
||||
|
||||
goToLink(url: string){
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
private makeActiveTraceFileInfo(view: View): string {
|
||||
const traceFile = this.traceData
|
||||
.getLoadedTraces()
|
||||
.find(trace => trace.type === view.dependencies[0])
|
||||
?.traceFile;
|
||||
|
||||
if (!traceFile) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!traceFile.parentArchive) {
|
||||
return traceFile.file.name;
|
||||
}
|
||||
|
||||
return `${traceFile.parentArchive.name} - ${traceFile.file.name}`;
|
||||
}
|
||||
|
||||
private async makeTraceFilesForDownload(): Promise<File[]> {
|
||||
return this.traceData.getLoadedTraces().map(trace => {
|
||||
const traceType = TRACE_INFO[trace.type].name;
|
||||
const newName = traceType + "/" + FileUtils.removeDirFromFileName(trace.traceFile.file.name);
|
||||
return new File([trace.traceFile.file], newName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
NgZone,
|
||||
ViewEncapsulation
|
||||
} from "@angular/core";
|
||||
import { TraceFile} from "common/trace/trace";
|
||||
import { TraceData} from "app/trace_data";
|
||||
import { ProxyConnection } from "trace_collection/proxy_connection";
|
||||
import { Connection } from "trace_collection/connection";
|
||||
@@ -473,8 +475,8 @@ export class CollectTracesComponent implements OnInit, OnDestroy {
|
||||
private async loadFiles() {
|
||||
console.log("loading files", this.connect.adbData());
|
||||
this.traceData.clear();
|
||||
|
||||
const parserErrors = await this.traceData.loadTraces(this.connect.adbData());
|
||||
const traceFiles = this.connect.adbData().map(file => new TraceFile(file));
|
||||
const parserErrors = await this.traceData.loadTraces(traceFiles);
|
||||
ParserErrorSnackBarComponent.showIfNeeded(this.ngZone, this.snackBar, parserErrors);
|
||||
this.traceDataLoaded.emit();
|
||||
console.log("finished loading data!");
|
||||
|
||||
@@ -96,7 +96,7 @@ describe("TraceViewComponent", () => {
|
||||
});
|
||||
|
||||
it("emits event on download button click", () => {
|
||||
const spy = spyOn(component.onDownloadTracesButtonClick, "emit");
|
||||
const spy = spyOn(component.downloadTracesButtonClick, "emit");
|
||||
|
||||
const downloadButton: null|HTMLButtonElement =
|
||||
htmlElement.querySelector(".save-button");
|
||||
|
||||
@@ -40,19 +40,20 @@ interface Tab extends View {
|
||||
<div class="header-items-wrapper">
|
||||
<nav mat-tab-nav-bar class="tabs-navigation-bar">
|
||||
<a
|
||||
*ngFor="let tab of tabs"
|
||||
mat-tab-link
|
||||
[active]="isCurrentActiveTab(tab)"
|
||||
(click)="onTabClick(tab)"
|
||||
class="tab"
|
||||
*ngFor="let tab of tabs"
|
||||
mat-tab-link
|
||||
[active]="isCurrentActiveTab(tab)"
|
||||
(click)="onTabClick(tab)"
|
||||
class="tab"
|
||||
>{{tab.title}}</a>
|
||||
</nav>
|
||||
<button
|
||||
color="primary"
|
||||
mat-button
|
||||
class="save-button"
|
||||
(click)="onDownloadTracesButtonClick.emit()"
|
||||
>Download all traces</button>
|
||||
color="primary"
|
||||
mat-button
|
||||
class="save-button"
|
||||
(click)="downloadTracesButtonClick.emit()"
|
||||
>Download all traces
|
||||
</button>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="trace-view-content">
|
||||
@@ -96,8 +97,8 @@ interface Tab extends View {
|
||||
export class TraceViewComponent {
|
||||
@Input() viewers!: Viewer[];
|
||||
@Input() store!: PersistentStore;
|
||||
@Output() onDownloadTracesButtonClick = new EventEmitter<void>();
|
||||
@Output() onActiveViewChanged = new EventEmitter<View>();
|
||||
@Output() downloadTracesButtonClick = new EventEmitter<void>();
|
||||
@Output() activeViewChanged = new EventEmitter<View>();
|
||||
|
||||
private elementRef: ElementRef;
|
||||
|
||||
@@ -184,7 +185,7 @@ export class TraceViewComponent {
|
||||
}
|
||||
|
||||
this.currentActiveTab = tab;
|
||||
this.onActiveViewChanged.emit(tab);
|
||||
this.activeViewChanged.emit(tab);
|
||||
}
|
||||
|
||||
public isCurrentActiveTab(tab: Tab) {
|
||||
|
||||
@@ -26,8 +26,8 @@ import {MatSnackBar} from "@angular/material/snack-bar";
|
||||
import {UploadTracesComponentDependencyInversion} from "./upload_traces_component_dependency_inversion";
|
||||
import {TraceData} from "app/trace_data";
|
||||
import {TRACE_INFO} from "app/trace_info";
|
||||
import {Trace} from "common/trace/trace";
|
||||
import {FileUtils} from "common/utils/file_utils";
|
||||
import {Trace, TraceFile} from "common/trace/trace";
|
||||
import {FileUtils, OnFile} from "common/utils/file_utils";
|
||||
import {ParserErrorSnackBarComponent} from "./parser_error_snack_bar_component";
|
||||
|
||||
@Component({
|
||||
@@ -67,7 +67,7 @@ import {ParserErrorSnackBarComponent} from "./parser_error_snack_bar_component";
|
||||
</mat-icon>
|
||||
|
||||
<p matLine>
|
||||
{{trace.file.name}} ({{TRACE_INFO[trace.type].name}})
|
||||
{{trace.traceFile.file.name}} ({{TRACE_INFO[trace.type].name}})
|
||||
</p>
|
||||
|
||||
<button color="primary" mat-icon-button
|
||||
@@ -223,14 +223,19 @@ export class UploadTracesComponent implements UploadTracesComponentDependencyInv
|
||||
this.changeDetectorRef.detectChanges();
|
||||
};
|
||||
|
||||
const traceFiles: TraceFile[] = [];
|
||||
const onFile: OnFile = (file: File, parentArchive?: File) => {
|
||||
traceFiles.push(new TraceFile(file, parentArchive));
|
||||
};
|
||||
|
||||
this.isLoadingFiles = true;
|
||||
this.progressMessage = "Unzipping files...";
|
||||
this.changeDetectorRef.detectChanges();
|
||||
const unzippedFiles = await FileUtils.unzipFilesIfNeeded(files, onProgressUpdate);
|
||||
await FileUtils.unzipFilesIfNeeded(files, onFile, onProgressUpdate);
|
||||
|
||||
this.progressMessage = "Parsing files...";
|
||||
this.changeDetectorRef.detectChanges();
|
||||
const parserErrors = await this.traceData.loadTraces(unzippedFiles, onProgressUpdate);
|
||||
const parserErrors = await this.traceData.loadTraces(traceFiles, onProgressUpdate);
|
||||
|
||||
this.isLoadingFiles = false;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
@@ -20,6 +20,7 @@ import {UploadTracesComponentStub} from "./components/upload_traces_component_st
|
||||
import {Mediator} from "./mediator";
|
||||
import {AbtChromeExtensionProtocolStub} from "abt_chrome_extension/abt_chrome_extension_protocol_stub";
|
||||
import {CrossToolProtocolStub} from "cross_tool/cross_tool_protocol_stub";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {RealTimestamp} from "common/trace/timestamp";
|
||||
import {UnitTestUtils} from "test/unit/utils";
|
||||
import {ViewerFactory} from "viewers/viewer_factory";
|
||||
@@ -195,10 +196,14 @@ describe("Mediator", () => {
|
||||
|
||||
const loadTraces = async () => {
|
||||
const traces = [
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/SurfaceFlinger.pb"),
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/WindowManager.pb"),
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/screen_recording_metadata_v2.mp4"),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/SurfaceFlinger.pb")),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/WindowManager.pb")),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/screen_recording_metadata_v2.mp4")),
|
||||
];
|
||||
const errors = await traceData.loadTraces(traces);
|
||||
expect(errors).toEqual([]);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {TraceData} from "./trace_data";
|
||||
import {UnitTestUtils} from "test/unit/utils";
|
||||
@@ -33,7 +34,7 @@ describe("TraceData", () => {
|
||||
|
||||
it("is robust to invalid trace files", async () => {
|
||||
const invalidTraceFiles = [
|
||||
await UnitTestUtils.getFixtureFile("winscope_homepage.png"),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile("winscope_homepage.png"))
|
||||
];
|
||||
|
||||
const errors = await traceData.loadTraces(invalidTraceFiles);
|
||||
@@ -44,8 +45,8 @@ describe("TraceData", () => {
|
||||
it("is robust to mixed valid and invalid trace files", async () => {
|
||||
expect(traceData.getLoadedTraces().length).toEqual(0);
|
||||
const traces = [
|
||||
await UnitTestUtils.getFixtureFile("winscope_homepage.png"),
|
||||
await UnitTestUtils.getFixtureFile("traces/dump_WindowManager.pb"),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile("winscope_homepage.png")),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile("traces/dump_WindowManager.pb"))
|
||||
];
|
||||
const errors = await traceData.loadTraces(traces);
|
||||
expect(traceData.getLoadedTraces().length).toEqual(1);
|
||||
@@ -54,8 +55,9 @@ describe("TraceData", () => {
|
||||
|
||||
it("is robust to trace files with no entries", async () => {
|
||||
const traceFilesWithNoEntries = [
|
||||
await UnitTestUtils.getFixtureFile(
|
||||
"traces/no_entries_InputMethodClients.pb")
|
||||
new TraceFile(
|
||||
await UnitTestUtils.getFixtureFile("traces/no_entries_InputMethodClients.pb")
|
||||
)
|
||||
];
|
||||
|
||||
const errors = await traceData.loadTraces(traceFilesWithNoEntries);
|
||||
@@ -85,7 +87,7 @@ describe("TraceData", () => {
|
||||
|
||||
const traces = traceData.getLoadedTraces();
|
||||
expect(traces.length).toEqual(2);
|
||||
expect(traces[0].file).toBeTruthy();
|
||||
expect(traces[0].traceFile.file).toBeTruthy();
|
||||
|
||||
const actualTraceTypes = new Set(traces.map(trace => trace.type));
|
||||
const expectedTraceTypes = new Set([TraceType.SURFACE_FLINGER, TraceType.WINDOW_MANAGER]);
|
||||
@@ -94,8 +96,10 @@ describe("TraceData", () => {
|
||||
|
||||
it("gets trace entries for a given timestamp", async () => {
|
||||
const traceFiles = [
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/SurfaceFlinger.pb"),
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/WindowManager.pb"),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/SurfaceFlinger.pb")),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/WindowManager.pb"))
|
||||
];
|
||||
|
||||
const errors = await traceData.loadTraces(traceFiles);
|
||||
@@ -111,7 +115,10 @@ describe("TraceData", () => {
|
||||
expect(entries.size).toEqual(0);
|
||||
}
|
||||
{
|
||||
const twoHundredYearsTimestamp = new Timestamp(TimestampType.REAL, 200n * 365n * 24n * 60n * 3600n * 1000000000n);
|
||||
const twoHundredYearsTimestamp = new Timestamp(
|
||||
TimestampType.REAL,
|
||||
200n * 365n * 24n * 60n * 3600n * 1000000000n
|
||||
);
|
||||
const entries = traceData.getTraceEntries(twoHundredYearsTimestamp);
|
||||
expect(entries.size).toEqual(2);
|
||||
}
|
||||
@@ -135,7 +142,8 @@ describe("TraceData", () => {
|
||||
expect(traceData.getScreenRecordingVideo()).toBeUndefined();
|
||||
|
||||
const traceFiles = [
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/screen_recording_metadata_v2.mp4"),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/screen_recording_metadata_v2.mp4"))
|
||||
];
|
||||
await traceData.loadTraces(traceFiles);
|
||||
|
||||
@@ -156,8 +164,10 @@ describe("TraceData", () => {
|
||||
|
||||
const loadValidSfWmTraces = async () => {
|
||||
const traceFiles = [
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/SurfaceFlinger.pb"),
|
||||
await UnitTestUtils.getFixtureFile("traces/elapsed_and_real_timestamp/WindowManager.pb"),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/SurfaceFlinger.pb")),
|
||||
new TraceFile(await UnitTestUtils.getFixtureFile(
|
||||
"traces/elapsed_and_real_timestamp/WindowManager.pb")),
|
||||
];
|
||||
|
||||
const errors = await traceData.loadTraces(traceFiles);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import {ArrayUtils} from "common/utils/array_utils";
|
||||
import {ScreenRecordingTraceEntry} from "common/trace/screen_recording";
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {Trace} from "common/trace/trace";
|
||||
import {Trace, TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {FunctionUtils, OnProgressUpdateType} from "common/utils/function_utils";
|
||||
import {Parser} from "parsers/parser";
|
||||
@@ -34,11 +34,11 @@ class TraceData {
|
||||
private commonTimestampType?: TimestampType;
|
||||
|
||||
public async loadTraces(
|
||||
traces: File[],
|
||||
traceFiles: TraceFile[],
|
||||
onLoadProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING):
|
||||
Promise<ParserError[]> {
|
||||
const [parsers, parserErrors] =
|
||||
await this.parserFactory.createParsers(traces, onLoadProgressUpdate);
|
||||
await this.parserFactory.createParsers(traceFiles, onLoadProgressUpdate);
|
||||
this.parsers = parsers;
|
||||
return parserErrors;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,15 @@
|
||||
|
||||
import {TraceType} from "./trace_type";
|
||||
|
||||
interface Trace {
|
||||
type: TraceType
|
||||
file: File,
|
||||
export interface Trace {
|
||||
type: TraceType;
|
||||
traceFile: TraceFile;
|
||||
}
|
||||
|
||||
export {Trace};
|
||||
export class TraceFile {
|
||||
constructor(
|
||||
public file: File,
|
||||
public parentArchive?: File
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
import JSZip from "jszip";
|
||||
import {FunctionUtils, OnProgressUpdateType} from "./function_utils";
|
||||
|
||||
export type OnFile = (file: File, parentArchive: File|undefined) => void;
|
||||
|
||||
class FileUtils {
|
||||
static getFileExtension(file: File) {
|
||||
const split = file.name.split(".");
|
||||
@@ -72,25 +74,24 @@ class FileUtils {
|
||||
|
||||
static async unzipFilesIfNeeded(
|
||||
files: File[],
|
||||
onProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING): Promise<File[]> {
|
||||
const unzippedFiles: File[] = [];
|
||||
|
||||
onFile: OnFile,
|
||||
onProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING) {
|
||||
for (let i=0; i<files.length; i++) {
|
||||
const file = files[i];
|
||||
|
||||
const onSubprogressUpdate = (subPercentage: number) => {
|
||||
const percentage = 100 * i / files.length
|
||||
+ subPercentage / files.length;
|
||||
onProgressUpdate(percentage);
|
||||
};
|
||||
|
||||
if (FileUtils.isZipFile(files[i])) {
|
||||
const unzippedFile = await FileUtils.unzipFile(files[i], onSubprogressUpdate);
|
||||
unzippedFiles.push(...unzippedFile);
|
||||
if (FileUtils.isZipFile(file)) {
|
||||
const unzippedFile = await FileUtils.unzipFile(file, onSubprogressUpdate);
|
||||
unzippedFile.forEach(unzippedFile => onFile(unzippedFile, file));
|
||||
} else {
|
||||
unzippedFiles.push(files[i]);
|
||||
onFile(file, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return unzippedFiles;
|
||||
}
|
||||
|
||||
static isZipFile(file: File) {
|
||||
|
||||
@@ -13,22 +13,23 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {ArrayUtils} from "common/utils/array_utils";
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {Trace} from "common/trace/trace";
|
||||
import {Trace, TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
|
||||
abstract class Parser {
|
||||
protected trace: File;
|
||||
protected trace: TraceFile;
|
||||
protected decodedEntries: any[] = [];
|
||||
private timestamps: Map<TimestampType, Timestamp[]> = new Map<TimestampType, Timestamp[]>();
|
||||
|
||||
protected constructor(trace: File) {
|
||||
protected constructor(trace: TraceFile) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public async parse() {
|
||||
const traceBuffer = new Uint8Array(await this.trace.arrayBuffer());
|
||||
const traceBuffer = new Uint8Array(await this.trace.file.arrayBuffer());
|
||||
|
||||
const magicNumber = this.getMagicNumber();
|
||||
if (magicNumber !== undefined)
|
||||
@@ -98,7 +99,7 @@ abstract class Parser {
|
||||
public getTrace(): Trace {
|
||||
return {
|
||||
type: this.getTraceType(),
|
||||
file: this.trace
|
||||
traceFile: this.trace
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {Parser} from "./parser";
|
||||
import {AccessibilityTraceFileProto} from "./proto_types";
|
||||
|
||||
class ParserAccessibility extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,15 @@ import {Parser} from "./parser";
|
||||
import {CommonTestUtils} from "test/common/utils";
|
||||
import {UnitTestUtils} from "test/unit/utils";
|
||||
import {ParserFactory} from "./parser_factory";
|
||||
import {TraceType} from "../common/trace/trace_type";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
|
||||
describe("Parser", () => {
|
||||
it("is robust to empty trace file", async () => {
|
||||
const trace = await CommonTestUtils.getFixtureFile("traces/empty.pb");
|
||||
const trace = new TraceFile(
|
||||
await CommonTestUtils.getFixtureFile("traces/empty.pb"),
|
||||
undefined
|
||||
);
|
||||
const [parsers, errors] = await new ParserFactory().createParsers([trace]);
|
||||
expect(parsers.length).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {FunctionUtils, OnProgressUpdateType} from "common/utils/function_utils";
|
||||
import {Parser} from "./parser";
|
||||
import {ParserAccessibility} from "./parser_accessibility";
|
||||
@@ -47,21 +48,21 @@ export class ParserFactory {
|
||||
private parsers = new Map<TraceType, Parser>();
|
||||
|
||||
async createParsers(
|
||||
traces: File[],
|
||||
traceFiles: TraceFile[],
|
||||
onProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING):
|
||||
Promise<[Parser[], ParserError[]]> {
|
||||
const errors: ParserError[] = [];
|
||||
|
||||
if (traces.length === 0) {
|
||||
if (traceFiles.length === 0) {
|
||||
errors.push(new ParserError(ParserErrorType.NO_INPUT_FILES));
|
||||
}
|
||||
|
||||
for (const [index, trace] of traces.entries()) {
|
||||
for (const [index, traceFile] of traceFiles.entries()) {
|
||||
let hasFoundParser = false;
|
||||
|
||||
for (const ParserType of ParserFactory.PARSERS) {
|
||||
try {
|
||||
const parser = new ParserType(trace);
|
||||
const parser = new ParserType(traceFile);
|
||||
await parser.parse();
|
||||
hasFoundParser = true;
|
||||
if (this.shouldUseParser(parser, errors)) {
|
||||
@@ -75,11 +76,11 @@ export class ParserFactory {
|
||||
}
|
||||
|
||||
if (!hasFoundParser) {
|
||||
console.log(`Failed to load trace ${trace.name}`);
|
||||
errors.push(new ParserError(ParserErrorType.UNSUPPORTED_FORMAT, trace));
|
||||
console.log(`Failed to load trace ${traceFile.file.name}`);
|
||||
errors.push(new ParserError(ParserErrorType.UNSUPPORTED_FORMAT, traceFile.file));
|
||||
}
|
||||
|
||||
onProgressUpdate(100 * (index + 1) / traces.length);
|
||||
onProgressUpdate(100 * (index + 1) / traceFiles.length);
|
||||
}
|
||||
|
||||
return [Array.from(this.parsers.values()), errors];
|
||||
@@ -88,30 +89,30 @@ export class ParserFactory {
|
||||
private shouldUseParser(newParser: Parser, errors: ParserError[]): boolean {
|
||||
const oldParser = this.parsers.get(newParser.getTraceType());
|
||||
if (!oldParser) {
|
||||
console.log(`Loaded trace ${newParser.getTrace().file.name} (trace type: ${newParser.getTraceType()})`);
|
||||
console.log(`Loaded trace ${newParser.getTrace().traceFile.file.name} (trace type: ${newParser.getTraceType()})`);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newParser.getEntriesLength() > oldParser.getEntriesLength()) {
|
||||
console.log(
|
||||
`Loaded trace ${newParser.getTrace().file.name} (trace type: ${newParser.getTraceType()}).` +
|
||||
` Replace trace ${oldParser.getTrace().file.name}`
|
||||
`Loaded trace ${newParser.getTrace().traceFile.file.name} (trace type: ${newParser.getTraceType()}).` +
|
||||
` Replace trace ${oldParser.getTrace().traceFile.file.name}`
|
||||
);
|
||||
errors.push(
|
||||
new ParserError(
|
||||
ParserErrorType.OVERRIDE, oldParser.getTrace().file, oldParser.getTraceType()
|
||||
ParserErrorType.OVERRIDE, oldParser.getTrace().traceFile.file, oldParser.getTraceType()
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Skipping trace ${newParser.getTrace().file.name} (trace type: ${newParser.getTraceType()}).` +
|
||||
` Keep trace ${oldParser.getTrace().file.name}`
|
||||
`Skipping trace ${newParser.getTrace().traceFile.file.name} (trace type: ${newParser.getTraceType()}).` +
|
||||
` Keep trace ${oldParser.getTrace().traceFile.file.name}`
|
||||
);
|
||||
errors.push(
|
||||
new ParserError(
|
||||
ParserErrorType.OVERRIDE, newParser.getTrace().file, newParser.getTraceType()
|
||||
ParserErrorType.OVERRIDE, newParser.getTrace().traceFile.file, newParser.getTraceType()
|
||||
)
|
||||
);
|
||||
return false;
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {Parser} from "./parser";
|
||||
import {InputMethodClientsTraceFileProto} from "./proto_types";
|
||||
@@ -22,7 +24,7 @@ import { TimeUtils } from "common/utils/time_utils";
|
||||
import { ImeUtils } from "viewers/common/ime_utils";
|
||||
|
||||
class ParserInputMethodClients extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import { TraceTreeNode } from "common/trace/trace_tree_node";
|
||||
import { TimeUtils } from "common/utils/time_utils";
|
||||
@@ -21,7 +23,7 @@ import {Parser} from "./parser";
|
||||
import {InputMethodManagerServiceTraceFileProto} from "./proto_types";
|
||||
|
||||
class ParserInputMethodManagerService extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import { TraceTreeNode } from "common/trace/trace_tree_node";
|
||||
import { TimeUtils } from "common/utils/time_utils";
|
||||
@@ -22,7 +24,7 @@ import {Parser} from "./parser";
|
||||
import {InputMethodServiceTraceFileProto} from "./proto_types";
|
||||
|
||||
class ParserInputMethodService extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {FormattedLogMessage, LogMessage, ProtoLogTraceEntry, UnformattedLogMessage} from "common/trace/protolog";
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {Parser} from "./parser";
|
||||
import {ProtoLogFileProto} from "./proto_types";
|
||||
import configJson from "../../../../../frameworks/base/data/etc/services.core.protolog.json";
|
||||
|
||||
class ParserProtoLog extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {ArrayUtils} from "common/utils/array_utils";
|
||||
import {Parser} from "./parser";
|
||||
@@ -26,7 +28,7 @@ class ScreenRecordingMetadataEntry {
|
||||
}
|
||||
|
||||
class ParserScreenRecording extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ class ParserScreenRecording extends Parser {
|
||||
const currentTimestamp = new Timestamp(TimestampType.ELAPSED, entry.timestampElapsedNs);
|
||||
const videoTimeSeconds =
|
||||
ScreenRecordingUtils.timestampToVideoTimeSeconds(initialTimestamp, currentTimestamp);
|
||||
const videoData = this.trace;
|
||||
const videoData = this.trace.file;
|
||||
return new ScreenRecordingTraceEntry(videoTimeSeconds, videoData);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {ArrayUtils} from "common/utils/array_utils";
|
||||
import {Parser} from "./parser";
|
||||
import {ScreenRecordingTraceEntry} from "common/trace/screen_recording";
|
||||
|
||||
class ParserScreenRecordingLegacy extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
}
|
||||
|
||||
@@ -51,7 +53,7 @@ class ParserScreenRecordingLegacy extends Parser {
|
||||
const videoTimeSeconds =
|
||||
Number(currentTimestamp.getValueNs() - initialTimestamp.getValueNs()) / 1000000000
|
||||
+ ParserScreenRecordingLegacy.EPSILON;
|
||||
const videoData = this.trace;
|
||||
const videoData = this.trace.file;
|
||||
return new ScreenRecordingTraceEntry(videoTimeSeconds, videoData);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {LayerTraceEntry} from "common/trace/flickerlib/layers/LayerTraceEntry";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {Parser} from "./parser";
|
||||
import {LayersTraceFileProto} from "./proto_types";
|
||||
|
||||
class ParserSurfaceFlinger extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {TransactionsTraceEntry} from "common/trace/transactions";
|
||||
import {Parser} from "./parser";
|
||||
import {TransactionsTraceFileProto} from "./proto_types";
|
||||
|
||||
class ParserTransactions extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {Parser} from "./parser";
|
||||
import {WindowManagerTraceFileProto} from "./proto_types";
|
||||
import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState";
|
||||
|
||||
class ParserWindowManager extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
@@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
import {Parser} from "./parser";
|
||||
import {WindowManagerServiceDumpProto} from "./proto_types";
|
||||
import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState";
|
||||
|
||||
class ParserWindowManagerDump extends Parser {
|
||||
constructor(trace: File) {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Parser} from "parsers/parser";
|
||||
import {ParserFactory} from "parsers/parser_factory";
|
||||
import {CommonTestUtils} from "test/common/utils";
|
||||
@@ -21,12 +22,15 @@ import {
|
||||
WindowManagerState
|
||||
} from "common/trace/flickerlib/common";
|
||||
import {Timestamp, TimestampType} from "common/trace/timestamp";
|
||||
import {TraceFile} from "common/trace/trace";
|
||||
import {TraceType} from "common/trace/trace_type";
|
||||
|
||||
class UnitTestUtils extends CommonTestUtils {
|
||||
static async getParser(filename: string): Promise<Parser> {
|
||||
const trace = await CommonTestUtils.getFixtureFile(filename);
|
||||
const [parsers, errors] = await new ParserFactory().createParsers([trace]);
|
||||
const file = new TraceFile(
|
||||
await CommonTestUtils.getFixtureFile(filename),
|
||||
undefined);
|
||||
const [parsers, errors] = await new ParserFactory().createParsers([file]);
|
||||
expect(parsers.length).toEqual(1);
|
||||
return parsers[0];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user