Merge "Parsers receive Blob instead of Uint8Array"

This commit is contained in:
Kean Mariotti
2022-07-11 06:48:01 +00:00
committed by Android (Google) Code Review
33 changed files with 760 additions and 559 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,10 @@
"version": "0.0.0",
"scripts": {
"start": "webpack serve --config webpack.config.dev.js --open --hot",
"build:kotlin": "npx kotlinc-js -source-map -source-map-embed-sources always -module-kind commonjs -output kotlin_build/flicker.js ../../../platform_testing/libraries/flicker/src/com/android/server/wm/traces/common",
"build:kotlin": "rm -rf kotlin_build && npx kotlinc-js -source-map -source-map-embed-sources always -module-kind commonjs -output kotlin_build/flicker.js ../../../platform_testing/libraries/flicker/src/com/android/server/wm/traces/common",
"build:prod": "webpack --config webpack.config.prod.js --progress",
"build:unit": "webpack --config webpack.config.unit.spec.js",
"build:e2e": "npx tsc -p ./src/test/e2e",
"build:e2e": "rm -rf dist/e2e.spec && npx tsc -p ./src/test/e2e",
"build:all": "npm run build:kotlin && npm run build:prod && npm run build:unit && npm run build:e2e",
"test:unit": "jasmine dist/unit.spec/bundle.js",
"test:component": "npx karma start",

View File

@@ -31,8 +31,15 @@ exports.config = {
},
chromeDriver: "./node_modules/webdriver-manager/selenium/chromedriver_103.0.5060.53",
// allow specifying the file protocol within browser.get(...)
allScriptsTimeout: 10000,
getPageTimeout: 10000,
jasmineNodeOpts: {
defaultTimeoutInterval: 10000,
},
onPrepare: function() {
// allow specifying the file protocol within browser.get(...)
browser.ignoreSynchronization = true;
browser.waitForAngular();
browser.sleep(500);

View File

@@ -51,11 +51,10 @@ export class AppComponent {
}
public async onInputFile(event: Event) {
const buffers = await this.readInputFiles(event);
const files = await this.getInputFiles(event);
this.core = new Core();
await this.core.bootstrap(buffers);
await this.core.bootstrap(files);
const viewersDiv = document.querySelector("div#viewers")!;
viewersDiv.innerHTML = "";
@@ -71,25 +70,13 @@ export class AppComponent {
}
//TODO: extend with support for multiple files, archives, etc...
private async readInputFiles(event: Event): Promise<Uint8Array[]> {
private getInputFiles(event: Event): File[] {
const files: any = (event?.target as HTMLInputElement)?.files;
if (!files || !files[0]) {
console.log("Invalid input file");
return [];
}
const file: File = files[0];
const buffer: Uint8Array = await new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = async (e) => {
const buffer = new Uint8Array(<ArrayBuffer> e.target!.result);
resolve(buffer);
};
reader.readAsArrayBuffer(file);
});
return [buffer];
return [files[0]];
}
}

View File

@@ -28,8 +28,8 @@ class Core {
this.viewers = [];
}
async bootstrap(buffers: Uint8Array[]) {
this.parsers = new ParserFactory().createParsers(buffers);
async bootstrap(traces: Blob[]) {
this.parsers = await new ParserFactory().createParsers(traces);
console.log("created parsers: ", this.parsers);
const activeTraceTypes = this.parsers.map(parser => parser.getTraceTypeId());

View File

@@ -16,7 +16,7 @@
class ScreenRecordingTraceEntry {
constructor(public timestamp: number,
public videoTimeSeconds: number,
public videoData: Uint8Array) {
public videoData: Blob) {
}
};

View File

@@ -17,17 +17,23 @@ import {ArrayUtils} from '../common/utils/array_utils';
import {TraceTypeId} from "common/trace/type_id";
abstract class Parser {
constructor(buffer: Uint8Array) {
protected constructor(trace: Blob) {
this.trace = trace;
}
public async parse() {
const traceBuffer = new Uint8Array(await this.trace.arrayBuffer());
const magicNumber = this.getMagicNumber();
if (magicNumber !== undefined)
{
const bufferContainsMagicNumber = ArrayUtils.equal(magicNumber, buffer.slice(0, magicNumber.length));
const bufferContainsMagicNumber = ArrayUtils.equal(magicNumber, traceBuffer.slice(0, magicNumber.length));
if (!bufferContainsMagicNumber) {
throw TypeError("buffer doesn't contain expected magic number");
}
}
this.decodedEntries = this.decodeTrace(buffer);
this.decodedEntries = this.decodeTrace(traceBuffer);
this.timestamps = this.decodedEntries.map((entry: any) => this.getTimestamp(entry));
}
@@ -52,12 +58,13 @@ abstract class Parser {
}
protected abstract getMagicNumber(): undefined|number[];
protected abstract decodeTrace(buffer: Uint8Array): any[];
protected abstract decodeTrace(trace: Uint8Array): any[];
protected abstract getTimestamp(decodedEntry: any): number;
protected abstract processDecodedEntry(decodedEntry: any): any;
protected decodedEntries: any[];
protected timestamps: number[];
protected trace: Blob;
protected decodedEntries: any[] = [];
protected timestamps: number[] = [];
}
export {Parser};

View File

@@ -21,9 +21,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserAccessibility", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_Accessibility.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const trace = TestUtils.getFixtureBlob("trace_Accessibility.pb");
const parsers = await new ParserFactory().createParsers([trace]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -18,8 +18,8 @@ import {Parser} from './parser'
import {AccessibilityTraceFileProto} from './proto_types';
class ParserAccessibility extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {

View File

@@ -21,9 +21,9 @@ import {TestUtils} from "test/test_utils";
describe("Parser", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_WindowManager.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_WindowManager.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -39,13 +39,14 @@ class ParserFactory {
ParserWindowManagerDump,
]
createParsers(buffers: Uint8Array[]): Parser[] {
async createParsers(traces: Blob[]): Promise<Parser[]> {
const parsers: Parser[] = [];
for (const buffer of buffers) {
for (const trace of traces) {
for (const ParserType of ParserFactory.PARSERS) {
try {
const parser = new ParserType(buffer);
const parser = new ParserType(trace);
await parser.parse();
parsers.push(parser);
break;
} catch(error) {

View File

@@ -21,9 +21,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserInputMethodlClients", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_InputMethodClients.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_InputMethodClients.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -18,8 +18,8 @@ import {Parser} from './parser'
import {InputMethodClientsTraceFileProto} from './proto_types';
class ParserInputMethodClients extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
getTraceTypeId(): TraceTypeId {

View File

@@ -21,9 +21,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserInputMethodManagerService", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_InputMethodManagerService.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_InputMethodManagerService.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -18,8 +18,8 @@ import {Parser} from './parser'
import {InputMethodManagerServiceTraceFileProto} from './proto_types';
class ParserInputMethodManagerService extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
getTraceTypeId(): TraceTypeId {

View File

@@ -21,9 +21,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserInputMethodService", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_InputMethodService.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_InputMethodService.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -18,8 +18,8 @@ import {Parser} from './parser'
import {InputMethodServiceTraceFileProto} from './proto_types';
class ParserInputMethodService extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
getTraceTypeId(): TraceTypeId {

View File

@@ -31,9 +31,9 @@ describe("ParserProtoLog", () => {
timestamp: Number(850746266486),
};
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_ProtoLog.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_ProtoLog.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -20,8 +20,8 @@ import {ProtoLogFileProto} from "./proto_types";
import configJson from "../../../../../frameworks/base/data/etc/services.core.protolog.json";
class ParserProtoLog extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {

View File

@@ -22,9 +22,9 @@ import {ParserFactory} from './parser_factory';
describe("ParserScreenRecording", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("screen_recording.mp4");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("screen_recording.mp4");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -19,8 +19,8 @@ import {Parser} from "./parser"
import {ScreenRecordingTraceEntry} from "common/trace/screen_recording";
class ParserScreenRecording extends Parser {
constructor(private videoData: Uint8Array) {
super(videoData);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {
@@ -43,7 +43,8 @@ class ParserScreenRecording extends Parser {
override processDecodedEntry(timestamp: number): ScreenRecordingTraceEntry {
const videoTimeSeconds = (timestamp - this.timestamps[0]) / 1000000000 + ParserScreenRecording.EPSILON;
return new ScreenRecordingTraceEntry(timestamp, videoTimeSeconds, this.videoData);
const videoData = this.trace;
return new ScreenRecordingTraceEntry(timestamp, videoTimeSeconds, videoData);
}
private searchMagicString(videoData: Uint8Array): number {

View File

@@ -22,9 +22,9 @@ import {ParserFactory} from './parser_factory';
describe("ParserSurfaceFlinger", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_SurfaceFlinger.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_SurfaceFlinger.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -19,8 +19,8 @@ import {Parser} from './parser'
import {LayersTraceFileProto} from './proto_types';
class ParserSurfaceFlinger extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {

View File

@@ -22,9 +22,9 @@ import {ParserFactory} from './parser_factory';
describe("ParserSurfaceFlingerDump", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("dump_SurfaceFlinger.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("dump_SurfaceFlinger.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -21,9 +21,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserTransactions", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_Transactions.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_Transactions.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -18,8 +18,8 @@ import {Parser} from './parser'
import {TransactionsTraceFileProto} from './proto_types';
class ParserTransactions extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {

View File

@@ -22,9 +22,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserWindowManager", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("trace_WindowManager.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("trace_WindowManager.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -19,8 +19,8 @@ import {WindowManagerTraceFileProto} from './proto_types';
import {WindowManagerState} from 'common/trace/flickerlib/windows/WindowManagerState';
class ParserWindowManager extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {

View File

@@ -22,9 +22,9 @@ import {TestUtils} from "test/test_utils";
describe("ParserWindowManagerDump", () => {
let parser: Parser;
beforeAll(() => {
const buffer = TestUtils.loadFixture("dump_WindowManager.pb");
const parsers = new ParserFactory().createParsers([buffer]);
beforeAll(async () => {
const buffer = TestUtils.getFixtureBlob("dump_WindowManager.pb");
const parsers = await new ParserFactory().createParsers([buffer]);
expect(parsers.length).toEqual(1);
parser = parsers[0];
});

View File

@@ -19,8 +19,8 @@ import {WindowManagerServiceDumpProto} from './proto_types';
import {WindowManagerState} from 'common/trace/flickerlib/windows/WindowManagerState';
class ParserWindowManagerDump extends Parser {
constructor(buffer: Uint8Array) {
super(buffer);
constructor(trace: Blob) {
super(trace);
}
override getTraceTypeId(): TraceTypeId {

View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
// This class is needed for testing because Node.js doesn't provide the Web API's Blob type
class Blob {
constructor(buffer: ArrayBuffer) {
this.size = buffer.byteLength;
this.type = "application/octet-stream";
this.buffer = buffer;
}
arrayBuffer(): Promise<ArrayBuffer> {
return new Promise<ArrayBuffer>((resolve, reject) => {
resolve(this.buffer);
});
}
slice(start?: number, end?: number, contentType?: string): Blob {
throw new Error("Not implemented!");
}
stream(): any {
throw new Error("Not implemented!");
}
text(): Promise<string> {
throw new Error("Not implemented!");
}
readonly size: number;
readonly type: string;
private readonly buffer: ArrayBuffer;
}
export {Blob};

View File

@@ -16,14 +16,15 @@
import {browser, element, by} from 'protractor';
import {TestUtils} from '../test_utils';
describe("winscope", () => {
beforeAll(() => {
describe("Viewer WindowManager", () => {
beforeAll(async () => {
browser.manage().timeouts().implicitlyWait(1000);
browser.get("file://" + TestUtils.getProductionIndexHtmlPath());
}),
it("processes trace and renders view", () => {
const inputfile = element(by.css("input[type=\"file\"]"));
inputfile.sendKeys(TestUtils.getFixturePath("trace_WindowManager.pb"));
const inputFile = element(by.css("input[type=\"file\"]"));
inputFile.sendKeys(TestUtils.getFixturePath("trace_WindowManager.pb"));
const windowManagerViewerTitle = element(by.css(".viewer-window-manager .title"));
expect(windowManagerViewerTitle.getText()).toContain("Window Manager");

View File

@@ -13,14 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require("fs");
const path = require("path");
import * as fs from "fs";
import * as path from "path";
import {Blob} from "./blob";
class TestUtils {
static loadFixture(filename: string): Uint8Array {
const fullPath = path.resolve(__dirname, path.join("../../src/test/fixtures", filename));
const data = fs.readFileSync(TestUtils.getFixturePath(filename));
return new Uint8Array(data);
static getFixtureBlob(filename: string): Blob {
const buffer = TestUtils.loadFixture(filename);
return new Blob(buffer);
}
static loadFixture(filename: string): ArrayBuffer {
return fs.readFileSync(TestUtils.getFixturePath(filename));
}
static getFixturePath(filename: string): string {
@@ -34,6 +38,6 @@ class TestUtils {
static getProjectRootPath(): string {
return path.join(__dirname, "../..");
}
};
}
export {TestUtils};