diff --git a/tools/winscope-ng/src/app/app.component.ts b/tools/winscope-ng/src/app/app.component.ts index b2d586d21..dc6eca0b7 100644 --- a/tools/winscope-ng/src/app/app.component.ts +++ b/tools/winscope-ng/src/app/app.component.ts @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Component, Injector, Inject } from "@angular/core"; -import { createCustomElement } from "@angular/elements"; -import { ViewerWindowManagerComponent } from "viewers/viewer_window_manager/viewer_window_manager.component"; -import { Core } from "./core"; -import { ProxyState } from "trace_collection/proxy_client"; -import { PersistentStore } from "../common/persistent_store"; +import {Component, Inject, Injector} from "@angular/core"; +import {createCustomElement} from "@angular/elements"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {PersistentStore} from "common/persistent_store"; +import {ViewerWindowManagerComponent} from "viewers/viewer_window_manager/viewer_window_manager.component"; +import {Core} from "./core"; +import {ProxyState} from "trace_collection/proxy_client"; @Component({ selector: "app-root", @@ -81,7 +82,7 @@ export class AppComponent { } public notifyCurrentTimestamp() { - const dummyTimestamp = 1000000; //TODO: get timestamp from time scrub + const dummyTimestamp = new Timestamp(TimestampType.ELAPSED, 1000000n); this.core.notifyCurrentTimestamp(dummyTimestamp); } diff --git a/tools/winscope-ng/src/app/core.ts b/tools/winscope-ng/src/app/core.ts index 57d476c61..1f2810395 100644 --- a/tools/winscope-ng/src/app/core.ts +++ b/tools/winscope-ng/src/app/core.ts @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "parsers/parser"; import {ParserFactory} from "parsers/parser_factory"; import { setTraces } from "trace_collection/set_traces"; @@ -35,10 +36,10 @@ class Core { this.parsers = await new ParserFactory().createParsers(traces); console.log("created parsers: ", this.parsers); - const activeTraceTypes = this.parsers.map(parser => parser.getTraceTypeId()); + const activeTraceTypes = this.parsers.map(parser => parser.getTraceType()); console.log("active trace types: ", activeTraceTypes); - this.viewers = new ViewerFactory().createViewers(new Set(activeTraceTypes)); + this.viewers = new ViewerFactory().createViewers(new Set(activeTraceTypes)); console.log("created viewers: ", this.viewers); } @@ -46,27 +47,37 @@ class Core { return this.viewers.map(viewer => viewer.getView()); } - getTimestamps(): number[] { - const mergedTimestamps: number[] = []; + getTimestamps(): Timestamp[] { + for (const type of [TimestampType.REAL, TimestampType.ELAPSED]) { + const mergedTimestamps: Timestamp[] = []; - this.parsers - .map(parser => parser.getTimestamps()) - .forEach(timestamps => { - mergedTimestamps.push(...timestamps); - }); + let isTypeProvidedByAllParsers = true; - const uniqueTimestamps = [... new Set(mergedTimestamps)]; + for(const timestamps of this.parsers.map(parser => parser.getTimestamps(type))) { + if (timestamps === undefined) { + isTypeProvidedByAllParsers = false; + break; + } + mergedTimestamps.push(...timestamps!); + } - return uniqueTimestamps; + if (isTypeProvidedByAllParsers) { + const uniqueTimestamps = [... new Set(mergedTimestamps)]; + uniqueTimestamps.sort(); + return uniqueTimestamps; + } + } + + throw new Error("Failed to create aggregated timestamps (any type)"); } - notifyCurrentTimestamp(timestamp: number) { - const traceEntries: Map = new Map(); + notifyCurrentTimestamp(timestamp: Timestamp) { + const traceEntries: Map = new Map(); this.parsers.forEach(parser => { const entry = parser.getTraceEntry(timestamp); if (entry != undefined) { - traceEntries.set(parser.getTraceTypeId(), entry); + traceEntries.set(parser.getTraceType(), entry); } }); diff --git a/tools/winscope-ng/src/common/trace/screen_recording.ts b/tools/winscope-ng/src/common/trace/screen_recording.ts index 907655950..2bc398069 100644 --- a/tools/winscope-ng/src/common/trace/screen_recording.ts +++ b/tools/winscope-ng/src/common/trace/screen_recording.ts @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + class ScreenRecordingTraceEntry { - constructor(public timestamp: number, - public videoTimeSeconds: number, + constructor(public videoTimeSeconds: number, public videoData: Blob) { } } diff --git a/tools/winscope-ng/src/common/trace/timestamp.ts b/tools/winscope-ng/src/common/trace/timestamp.ts new file mode 100644 index 000000000..2c409cf4a --- /dev/null +++ b/tools/winscope-ng/src/common/trace/timestamp.ts @@ -0,0 +1,44 @@ +/* + * 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. + */ + +enum TimestampType { + ELAPSED, + REAL, +} + +class Timestamp { + constructor(type: TimestampType, valueNs: bigint) { + this.type = type; + this.valueNs = valueNs; + } + + public getType(): TimestampType { + return this.type; + } + + public getValueNs(): bigint { + return this.valueNs; + } + + public valueOf(): bigint { + return this.getValueNs(); + } + + private readonly type: TimestampType; + private readonly valueNs: bigint; +} + +export {Timestamp, TimestampType}; diff --git a/tools/winscope-ng/src/common/trace/type_id.ts b/tools/winscope-ng/src/common/trace/trace_type.ts similarity index 95% rename from tools/winscope-ng/src/common/trace/type_id.ts rename to tools/winscope-ng/src/common/trace/trace_type.ts index 508076e05..0d51d2efe 100644 --- a/tools/winscope-ng/src/common/trace/type_id.ts +++ b/tools/winscope-ng/src/common/trace/trace_type.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -enum TraceTypeId { +enum TraceType { ACCESSIBILITY, WINDOW_MANAGER, SURFACE_FLINGER, @@ -32,4 +32,4 @@ enum TraceTypeId { ERROR, } -export {TraceTypeId}; +export {TraceType}; diff --git a/tools/winscope-ng/src/common/utils/array_utils.spec.ts b/tools/winscope-ng/src/common/utils/array_utils.spec.ts index f52898951..f1e880154 100644 --- a/tools/winscope-ng/src/common/utils/array_utils.spec.ts +++ b/tools/winscope-ng/src/common/utils/array_utils.spec.ts @@ -81,15 +81,74 @@ describe("ArrayUtils", () => { it("toUintLittleEndian", () => { const buffer = new Uint8Array([0, 0, 1, 1]); - expect(ArrayUtils.toUintLittleEndian(buffer, 0, -1)).toEqual(0); - expect(ArrayUtils.toUintLittleEndian(buffer, 0, 0)).toEqual(0); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff]), 0, -1)).toEqual(0n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff]), 0, 0)).toEqual(0n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff]), 1, 1)).toEqual(0n); - expect(ArrayUtils.toUintLittleEndian(buffer, 0, 1)).toEqual(0); - expect(ArrayUtils.toUintLittleEndian(buffer, 0, 2)).toEqual(0); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0x00, 0x01, 0xff]), 0, 1)).toEqual(0n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0x00, 0x01, 0xff]), 1, 2)).toEqual(1n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0x00, 0x01, 0xff]), 2, 3)).toEqual(255n); - expect(ArrayUtils.toUintLittleEndian(buffer, 3, 4)).toEqual(1); - expect(ArrayUtils.toUintLittleEndian(buffer, 2, 4)).toEqual(1 + 256); - expect(ArrayUtils.toUintLittleEndian(buffer, 1, 4)).toEqual(256 + 256*256); - expect(ArrayUtils.toUintLittleEndian(buffer, 0, 3)).toEqual(256*256); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0x00, 0x00]), 0, 2)).toEqual(0n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0x01, 0x00]), 0, 2)).toEqual(1n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0x00, 0x01]), 0, 2)).toEqual(256n); + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff]), 0, 2)).toEqual(0xffffn); + + expect(ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff]), 0, 4)).toEqual(0xffffffffn); + + expect( + ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 0, 8)) + .toEqual(0xffffffffffffffffn); + + expect( + ArrayUtils.toUintLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 0, 9)) + .toEqual(0xffffffffffffffffffn); + }); + + it("toIntLittleEndian", () => { + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff]), 0, -1)).toEqual(0n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff]), 0, 0)).toEqual(0n); + + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x00]), 0, 1)).toEqual(0n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x01]), 0, 1)).toEqual(1n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x7f]), 0, 1)).toEqual(127n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x80]), 0, 1)).toEqual(-128n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff]), 0, 1)).toEqual(-1n); + + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0x7f]), 0, 2)).toEqual(32767n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x00, 0x80]), 0, 2)).toEqual(-32768n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x01, 0x80]), 0, 2)).toEqual(-32767n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff]), 0, 2)).toEqual(-1n); + + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0x7f]), 0, 4)).toEqual(0x7fffffffn); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x00, 0x00, 0x00, 0x80]), 0, 4)).toEqual(-0x80000000n); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0x01, 0x00, 0x00, 0x80]), 0, 4)).toEqual(-0x7fffffffn); + expect(ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff]), 0, 4)).toEqual(-1n); + + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), 0, 8) + ).toEqual(0x7fffffffffffffffn); + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), 0, 8) + ).toEqual(-0x8000000000000000n); + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), 0, 8) + ).toEqual(-0x7fffffffffffffffn); + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 0, 8) + ).toEqual(-1n); + + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), 0, 9) + ).toEqual(0x7fffffffffffffffffn); + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), 0, 9) + ).toEqual(-0x800000000000000000n); + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), 0, 9) + ).toEqual(-0x7fffffffffffffffffn); + expect( + ArrayUtils.toIntLittleEndian(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 0, 9) + ).toEqual(-1n); }); }); diff --git a/tools/winscope-ng/src/common/utils/array_utils.ts b/tools/winscope-ng/src/common/utils/array_utils.ts index 60bcc3223..b9a54689b 100644 --- a/tools/winscope-ng/src/common/utils/array_utils.ts +++ b/tools/winscope-ng/src/common/utils/array_utils.ts @@ -86,14 +86,30 @@ class ArrayUtils { return result; } - static toUintLittleEndian(buffer: Uint8Array, start: number, end: number) { - let result = 0; - for (let i = end-1; i>=start; --i) { - result *= 256; - result += buffer[i]; + static toUintLittleEndian(buffer: Uint8Array, start: number, end: number): bigint { + let result = 0n; + for (let i = end-1; i >= start; --i) { + result *= 256n; + result += BigInt(buffer[i]); } return result; } + + static toIntLittleEndian(buffer: Uint8Array, start: number, end: number): bigint { + const numOfBits = BigInt(Math.max(0, 8 * (end-start))); + if (numOfBits <= 0n) { + return 0n; + } + + let result = ArrayUtils.toUintLittleEndian(buffer, start, end); + const maxSignedValue = 2n ** (numOfBits - 1n) - 1n; + if (result > maxSignedValue) { + const valuesRange = 2n ** numOfBits; + result -= valuesRange; + } + + return result; + } } export {ArrayUtils}; diff --git a/tools/winscope-ng/src/parsers/parser.ts b/tools/winscope-ng/src/parsers/parser.ts index 23909f8bc..9614a2dae 100644 --- a/tools/winscope-ng/src/parsers/parser.ts +++ b/tools/winscope-ng/src/parsers/parser.ts @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {ArrayUtils} from "../common/utils/array_utils"; -import {TraceTypeId} from "common/trace/type_id"; +import {ArrayUtils} from "common/utils/array_utils"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; abstract class Parser { protected constructor(trace: Blob) { @@ -34,17 +35,39 @@ abstract class Parser { } this.decodedEntries = this.decodeTrace(traceBuffer); - this.timestamps = this.decodedEntries.map((entry: any) => this.getTimestamp(entry)); + + for (const type of [TimestampType.ELAPSED, TimestampType.REAL]) { + const timestamps: Timestamp[] = []; + let areTimestampsValid = true; + + for (const entry of this.decodedEntries) { + const timestamp = this.getTimestamp(type, entry); + if (timestamp === undefined) { + areTimestampsValid = false; + break; + } + timestamps.push(timestamp); + } + + if (areTimestampsValid) { + this.timestamps.set(type, timestamps); + } + } } - public abstract getTraceTypeId(): TraceTypeId; + public abstract getTraceType(): TraceType; - public getTimestamps(): number[] { - return this.timestamps; + public getTimestamps(type: TimestampType): undefined|Timestamp[] { + return this.timestamps.get(type); } - public getTraceEntry(timestamp: number): undefined|any { - const index = ArrayUtils.binarySearchLowerOrEqual(this.getTimestamps(), timestamp); + public getTraceEntry(timestamp: Timestamp): undefined|any { + const timestamps = this.getTimestamps(timestamp.getType()); + if (timestamps === undefined) { + throw TypeError(`Timestamps with type "${timestamp.getType()}" not available`); + } + + const index = ArrayUtils.binarySearchLowerOrEqual(timestamps, timestamp); if (index === undefined) { return undefined; } @@ -59,12 +82,12 @@ abstract class Parser { protected abstract getMagicNumber(): undefined|number[]; protected abstract decodeTrace(trace: Uint8Array): any[]; - protected abstract getTimestamp(decodedEntry: any): number; + protected abstract getTimestamp(type: TimestampType, decodedEntry: any): undefined|Timestamp; protected abstract processDecodedEntry(decodedEntry: any): any; protected trace: Blob; protected decodedEntries: any[] = []; - protected timestamps: number[] = []; + private timestamps: Map = new Map(); } export {Parser}; diff --git a/tools/winscope-ng/src/parsers/parser_accessibility.spec.ts b/tools/winscope-ng/src/parsers/parser_accessibility.spec.ts index b55362f12..5965cd5ed 100644 --- a/tools/winscope-ng/src/parsers/parser_accessibility.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_accessibility.spec.ts @@ -13,32 +13,75 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {ParserFactory} from "./parser_factory"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserAccessibility", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const trace = TestUtils.getFixtureBlob("trace_Accessibility.pb"); - const parsers = await new ParserFactory().createParsers([trace]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/Accessibility.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.ACCESSIBILITY); + }); + + it("provides elapsed timestamps", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 14499089524n), + new Timestamp(TimestampType.ELAPSED, 14499599656n), + new Timestamp(TimestampType.ELAPSED, 14953120693n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)!.slice(0, 3)) + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 1659107089100052652n), + new Timestamp(TimestampType.REAL, 1659107089100562784n), + new Timestamp(TimestampType.REAL, 1659107089554083821n), + ]; + expect(parser.getTimestamps(TimestampType.REAL)!.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 14499599656n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(14499599656n); + }); + + it("retrieves trace entry from real timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089100562784n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(14499599656n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.ACCESSIBILITY); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([850297444302, 850297882046, 850756176154, 850773581835]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/Accessibility.pb"); + }); - it("retrieves trace entry", () => { - expect(Number(parser.getTraceEntry(850297444302)!.elapsedRealtimeNanos)) - .toEqual(850297444302); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.ACCESSIBILITY); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)![0]) + .toEqual(new Timestamp(TimestampType.ELAPSED, 850297444302n)); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_accessibility.ts b/tools/winscope-ng/src/parsers/parser_accessibility.ts index 28ed4012c..2dd8747a3 100644 --- a/tools/winscope-ng/src/parsers/parser_accessibility.ts +++ b/tools/winscope-ng/src/parsers/parser_accessibility.ts @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {AccessibilityTraceFileProto} from "./proto_types"; class ParserAccessibility extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.ACCESSIBILITY; + override getTraceType(): TraceType { + return TraceType.ACCESSIBILITY; } override getMagicNumber(): number[] { @@ -31,17 +33,31 @@ class ParserAccessibility extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { - return (AccessibilityTraceFileProto.decode(buffer)).entry; + const decoded = AccessibilityTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return decoded.entry; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type === TimestampType.ELAPSED) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { + return new Timestamp(type, this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos)); + } + return undefined; } override processDecodedEntry(entryProto: any): any { return entryProto; } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x41, 0x31, 0x31, 0x59, 0x54, 0x52, 0x41, 0x43]; // .A11YTRAC } diff --git a/tools/winscope-ng/src/parsers/parser_common.spec.ts b/tools/winscope-ng/src/parsers/parser_common.spec.ts index 41ef38e14..60d45f553 100644 --- a/tools/winscope-ng/src/parsers/parser_common.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_common.spec.ts @@ -13,48 +13,98 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; -import {ParserFactory} from "./parser_factory"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("Parser", () => { - let parser: Parser; + describe("real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_WindowManager.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/WindowManager.pb"); + }); + + it("provides timestamps", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 1659107089075566202n), + new Timestamp(TimestampType.REAL, 1659107089999048990n), + new Timestamp(TimestampType.REAL, 1659107090010194213n) + ]; + expect(parser.getTimestamps(TimestampType.REAL)!.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry (no timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089075566201n); + expect(parser.getTraceEntry(timestamp)) + .toEqual(undefined); + }); + + it("retrieves trace entry (equal timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089075566202n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(14474594000n); + }); + + it("retrieves trace entry (equal timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089999048990n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(15398076788n); + }); + + it("retrieves trace entry (lower timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089999048991n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(15398076788n); + }); }); - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([850254319343, 850763506110, 850782750048]); - }); + describe("elapsed timestamp", () => { + let parser: Parser; - it("retrieves trace entry (no timestamp matches)", () => { - expect(parser.getTraceEntry(850254319342)) - .toEqual(undefined); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/WindowManager.pb"); + }); - it("retrieves trace entry (equal timestamp matches)", () => { - expect(Number(parser.getTraceEntry(850254319343)!.timestampMs)) - .toEqual(850254319343); - }); + it("provides timestamps", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 850254319343n), + new Timestamp(TimestampType.ELAPSED, 850763506110n), + new Timestamp(TimestampType.ELAPSED, 850782750048n) + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)) + .toEqual(expected); + }); - it("retrieves trace entry (equal timestamp matches)", () => { - expect(Number(parser.getTraceEntry(850763506110)!.timestampMs)) - .toEqual(850763506110); - }); + it("retrieves trace entry (no timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 850254319342n); + expect(parser.getTraceEntry(timestamp)) + .toEqual(undefined); + }); - it("retrieves trace entry (lower timestamp matches)", () => { - expect(Number(parser.getTraceEntry(850254319344)!.timestampMs)) - .toEqual(850254319343); - }); + it("retrieves trace entry (equal timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 850254319343n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(850254319343n); + }); - it("retrieves trace entry (equal timestamp matches)", () => { - expect(Number(parser.getTraceEntry(850763506111)!.timestampMs)) - .toEqual(850763506110); + it("retrieves trace entry (equal timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 850763506110n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(850763506110n); + }); + + it("retrieves trace entry (lower timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 850254319344n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(850254319343n); + }); + + it("retrieves trace entry (equal timestamp matches)", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 850763506111n); + expect(BigInt(parser.getTraceEntry(timestamp)!.timestampMs)) + .toEqual(850763506110n); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_factory.ts b/tools/winscope-ng/src/parsers/parser_factory.ts index 449685717..fac3ba087 100644 --- a/tools/winscope-ng/src/parsers/parser_factory.ts +++ b/tools/winscope-ng/src/parsers/parser_factory.ts @@ -20,6 +20,7 @@ import {ParserInputMethodManagerService} from "./parser_input_method_manager_ser import {ParserInputMethodService} from "./parser_input_method_service"; import {ParserProtoLog} from "./parser_protolog"; import {ParserScreenRecording} from "./parser_screen_recording"; +import {ParserScreenRecordingLegacy} from "./parser_screen_recording_legacy"; import {ParserSurfaceFlinger} from "./parser_surface_flinger"; import {ParserTransactions} from "./parser_transactions"; import {ParserWindowManager} from "./parser_window_manager"; @@ -33,6 +34,7 @@ class ParserFactory { ParserInputMethodService, ParserProtoLog, ParserScreenRecording, + ParserScreenRecordingLegacy, ParserSurfaceFlinger, ParserTransactions, ParserWindowManager, diff --git a/tools/winscope-ng/src/parsers/parser_input_method_clients.spec.ts b/tools/winscope-ng/src/parsers/parser_input_method_clients.spec.ts index 7530b3455..167942506 100644 --- a/tools/winscope-ng/src/parsers/parser_input_method_clients.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_input_method_clients.spec.ts @@ -13,34 +13,78 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; -import {ParserFactory} from "./parser_factory"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserInputMethodlClients", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_InputMethodClients.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/InputMethodClients.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.INPUT_METHOD_CLIENTS); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)!.length) + .toEqual(13); + + const expected = [ + new Timestamp(TimestampType.ELAPSED, 15613638434n), + new Timestamp(TimestampType.ELAPSED, 15647516364n), + new Timestamp(TimestampType.ELAPSED, 15677650967n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)!.slice(0, 3)) + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 1659107090215405395n), + new Timestamp(TimestampType.REAL, 1659107090249283325n), + new Timestamp(TimestampType.REAL, 1659107090279417928n), + ]; + expect(parser.getTimestamps(TimestampType.REAL)!.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 15647516364n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(15647516364n); + }); + + it("retrieves trace entry from real timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107090249283325n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(15647516364n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.INPUT_METHOD_CLIENTS); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - expect(parser.getTimestamps().length) - .toEqual(33); - expect(parser.getTimestamps().slice(0, 3)) - .toEqual([1149083651642, 1149083950633, 1149127567251]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/InputMethodClients.pb"); + }); - it("retrieves trace entry", () => { - expect(Number(parser.getTraceEntry(1149083651642)!.elapsedRealtimeNanos)) - .toEqual(1149083651642); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.INPUT_METHOD_CLIENTS); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)![0]) + .toEqual(new Timestamp(TimestampType.ELAPSED, 1149083651642n)); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)![0]) + .toEqual(new Timestamp(TimestampType.ELAPSED, 1149083651642n)); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_input_method_clients.ts b/tools/winscope-ng/src/parsers/parser_input_method_clients.ts index 06886288e..c3783b2c8 100644 --- a/tools/winscope-ng/src/parsers/parser_input_method_clients.ts +++ b/tools/winscope-ng/src/parsers/parser_input_method_clients.ts @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {InputMethodClientsTraceFileProto} from "./proto_types"; class ParserInputMethodClients extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - getTraceTypeId(): TraceTypeId { - return TraceTypeId.INPUT_METHOD_CLIENTS; + getTraceType(): TraceType { + return TraceType.INPUT_METHOD_CLIENTS; } override getMagicNumber(): number[] { @@ -31,17 +33,32 @@ class ParserInputMethodClients extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { + const decoded = InputMethodClientsTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return (InputMethodClientsTraceFileProto.decode(buffer)).entry; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type === TimestampType.ELAPSED) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs != undefined) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos) + this.realToElapsedTimeOffsetNs); + } + return undefined; } override processDecodedEntry(entryProto: any): any { return entryProto; } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMCTRACE } diff --git a/tools/winscope-ng/src/parsers/parser_input_method_manager_service.spec.ts b/tools/winscope-ng/src/parsers/parser_input_method_manager_service.spec.ts index 7592c8dc5..b6d0794fe 100644 --- a/tools/winscope-ng/src/parsers/parser_input_method_manager_service.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_input_method_manager_service.spec.ts @@ -13,32 +13,65 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; -import {ParserFactory} from "./parser_factory"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserInputMethodManagerService", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_InputMethodManagerService.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/InputMethodManagerService.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.INPUT_METHOD_MANAGER_SERVICE); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)) + .toEqual([new Timestamp(TimestampType.ELAPSED, 15963782518n)]); + }); + + it("provides real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual([new Timestamp(TimestampType.REAL, 1659107090565549479n)]); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 15963782518n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(15963782518n); + }); + + it("retrieves trace entry from real timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107090565549479n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(15963782518n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.INPUT_METHOD_MANAGER_SERVICE); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([1149226290110, 1149237707591, 1149238950389]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/InputMethodManagerService.pb"); + }); - it("retrieves trace entry", () => { - expect(Number(parser.getTraceEntry(1149226290110)!.elapsedRealtimeNanos)) - .toEqual(1149226290110); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.INPUT_METHOD_MANAGER_SERVICE); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)![0]) + .toEqual(new Timestamp(TimestampType.ELAPSED, 1149226290110n)); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_input_method_manager_service.ts b/tools/winscope-ng/src/parsers/parser_input_method_manager_service.ts index 0b5802ba6..d1517f3a2 100644 --- a/tools/winscope-ng/src/parsers/parser_input_method_manager_service.ts +++ b/tools/winscope-ng/src/parsers/parser_input_method_manager_service.ts @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {InputMethodManagerServiceTraceFileProto} from "./proto_types"; class ParserInputMethodManagerService extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - getTraceTypeId(): TraceTypeId { - return TraceTypeId.INPUT_METHOD_MANAGER_SERVICE; + getTraceType(): TraceType { + return TraceType.INPUT_METHOD_MANAGER_SERVICE; } override getMagicNumber(): number[] { @@ -31,17 +33,31 @@ class ParserInputMethodManagerService extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { - return (InputMethodManagerServiceTraceFileProto.decode(buffer)).entry; + const decoded = InputMethodManagerServiceTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return decoded.entry; } - protected override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + protected override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type === TimestampType.ELAPSED) { + return new Timestamp(TimestampType.ELAPSED, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { + return new Timestamp(type, this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos)); + } + return undefined; } protected override processDecodedEntry(entryProto: any): any { return entryProto; } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMMTRACE } diff --git a/tools/winscope-ng/src/parsers/parser_input_method_service.spec.ts b/tools/winscope-ng/src/parsers/parser_input_method_service.spec.ts index 7f71b3a84..a606f45c8 100644 --- a/tools/winscope-ng/src/parsers/parser_input_method_service.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_input_method_service.spec.ts @@ -13,32 +13,72 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {ParserFactory} from "./parser_factory"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserInputMethodService", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_InputMethodService.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/InputMethodService.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.INPUT_METHOD_SERVICE); + }); + + it("provides elapsed timestamps", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 16578752896n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)) + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 1659107091180519857n), + ]; + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 16578752896n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(16578752896n); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107091180519857n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(16578752896n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.INPUT_METHOD_SERVICE); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([1149230019887, 1149234359324, 1149241227244, 1149243083608, 1149249518016, 1149249784617, 1149272993520]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/InputMethodService.pb"); + }); - it("retrieves trace entry", () => { - expect(Number(parser.getTraceEntry(1149230019887)!.elapsedRealtimeNanos)) - .toEqual(1149230019887); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.INPUT_METHOD_SERVICE); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)![0]) + .toEqual(new Timestamp(TimestampType.ELAPSED, 1149230019887n)); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_input_method_service.ts b/tools/winscope-ng/src/parsers/parser_input_method_service.ts index b88bc5dc9..5ed664c27 100644 --- a/tools/winscope-ng/src/parsers/parser_input_method_service.ts +++ b/tools/winscope-ng/src/parsers/parser_input_method_service.ts @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {InputMethodServiceTraceFileProto} from "./proto_types"; class ParserInputMethodService extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - getTraceTypeId(): TraceTypeId { - return TraceTypeId.INPUT_METHOD_SERVICE; + getTraceType(): TraceType { + return TraceType.INPUT_METHOD_SERVICE; } override getMagicNumber(): number[] { @@ -31,17 +33,31 @@ class ParserInputMethodService extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { - return (InputMethodServiceTraceFileProto.decode(buffer)).entry; + const decoded = InputMethodServiceTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return decoded.entry; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type === TimestampType.ELAPSED) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { + return new Timestamp(type, this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos)); + } + return undefined; } override processDecodedEntry(entryProto: any): any { return entryProto; } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMSTRACE } diff --git a/tools/winscope-ng/src/parsers/parser_protolog.spec.ts b/tools/winscope-ng/src/parsers/parser_protolog.spec.ts index b4419c5d2..018138c64 100644 --- a/tools/winscope-ng/src/parsers/parser_protolog.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_protolog.spec.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; -import {ParserFactory} from "./parser_factory"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; import {LogMessage} from "../common/trace/protolog"; describe("ParserProtoLog", () => { @@ -32,26 +32,44 @@ describe("ParserProtoLog", () => { }; beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_ProtoLog.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/ProtoLog.pb"); }); it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.PROTO_LOG); + expect(parser.getTraceType()).toEqual(TraceType.PROTO_LOG); }); - it("provides timestamps", () => { - const timestamps = parser.getTimestamps(); + it("provides elapsed timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!; expect(timestamps.length) .toEqual(50); + + const expected = [ + new Timestamp(TimestampType.ELAPSED, 850746266486n), + new Timestamp(TimestampType.ELAPSED, 850746336718n), + new Timestamp(TimestampType.ELAPSED, 850746350430n), + ]; expect(timestamps.slice(0, 3)) - .toEqual([850746266486, 850746336718, 850746350430]); + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.REAL)!; + expect(timestamps.length) + .toEqual(50); + + const expected = [ + new Timestamp(TimestampType.REAL, 1655727125377266486n), + new Timestamp(TimestampType.REAL, 1655727125377336718n), + new Timestamp(TimestampType.REAL, 1655727125377350430n), + ]; + expect(timestamps.slice(0, 3)) + .toEqual(expected); }); it("reconstructs human-readable log message", () => { - const actualMessage = parser.getTraceEntry(850746266486)!; + const timestamp = new Timestamp(TimestampType.ELAPSED, 850746266486n); + const actualMessage = parser.getTraceEntry(timestamp)!; expect(actualMessage).toBeInstanceOf(LogMessage); expect(Object.assign({}, actualMessage)).toEqual(expectedFirstLogMessage); diff --git a/tools/winscope-ng/src/parsers/parser_protolog.ts b/tools/winscope-ng/src/parsers/parser_protolog.ts index dd6fdb4af..e8656c6e6 100644 --- a/tools/winscope-ng/src/parsers/parser_protolog.ts +++ b/tools/winscope-ng/src/parsers/parser_protolog.ts @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {LogMessage, FormattedLogMessage, UnformattedLogMessage} from "common/trace/protolog"; -import {TraceTypeId} from "common/trace/type_id"; +import {FormattedLogMessage, LogMessage, UnformattedLogMessage} from "common/trace/protolog"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +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"; @@ -24,8 +25,8 @@ class ParserProtoLog extends Parser { super(trace); } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.PROTO_LOG; + override getTraceType(): TraceType { + return TraceType.PROTO_LOG; } override getMagicNumber(): number[] { @@ -47,6 +48,8 @@ class ParserProtoLog extends Parser { throw new TypeError(message); } + this.realToElapsedTimeOffsetNs = BigInt(fileProto.realTimeToElapsedTimeOffsetMillis) * 1000000n; + fileProto.log.sort((a: any, b: any) => { return Number(a.elapsedRealtimeNanos) - Number(b.elapsedRealtimeNanos); }); @@ -54,8 +57,14 @@ class ParserProtoLog extends Parser { return fileProto.log; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type == TimestampType.ELAPSED) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type == TimestampType.REAL) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos) + this.realToElapsedTimeOffsetNs!); + } + return undefined; } override processDecodedEntry(entryProto: any): LogMessage { @@ -81,6 +90,7 @@ class ParserProtoLog extends Parser { }); } + private realToElapsedTimeOffsetNs: undefined|bigint = undefined; private static readonly MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG private static readonly PROTOLOG_VERSION = "1.0.0"; } diff --git a/tools/winscope-ng/src/parsers/parser_screen_recording.spec.ts b/tools/winscope-ng/src/parsers/parser_screen_recording.spec.ts index c65e80787..8dfff7714 100644 --- a/tools/winscope-ng/src/parsers/parser_screen_recording.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_screen_recording.spec.ts @@ -14,49 +14,81 @@ * limitations under the License. */ import {ScreenRecordingTraceEntry} from "common/trace/screen_recording"; -import {TraceTypeId} from "common/trace/type_id"; -import {TestUtils} from "test/test_utils"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; +import {UnitTestUtils} from "test/unit/utils"; import {Parser} from "./parser"; -import {ParserFactory} from "./parser_factory"; describe("ParserScreenRecording", () => { let parser: Parser; beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("screen_recording.mp4"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/screen_recording.mp4"); }); it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.SCREEN_RECORDING); + expect(parser.getTraceType()).toEqual(TraceType.SCREEN_RECORDING); }); - it("provides timestamps", () => { - const timestamps = parser.getTimestamps(); + it ("provides elapsed timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!; expect(timestamps.length) - .toEqual(85); + .toEqual(15); + const expected = [ + new Timestamp(TimestampType.ELAPSED, 144857685000n), + new Timestamp(TimestampType.ELAPSED, 144866679000n), + new Timestamp(TimestampType.ELAPSED, 144875772000n), + ]; expect(timestamps.slice(0, 3)) - .toEqual([19446131807000, 19446158500000, 19446167117000]); - - expect(timestamps.slice(timestamps.length-3, timestamps.length)) - .toEqual([19448470076000, 19448487525000, 19448501007000]); + .toEqual(expected); }); - it("retrieves trace entry", () => { + it("provides real timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.REAL)!; + + expect(timestamps.length) + .toEqual(15); + + const expected = [ + new Timestamp(TimestampType.REAL, 1659687791485257266n), + new Timestamp(TimestampType.REAL, 1659687791494251266n), + new Timestamp(TimestampType.REAL, 1659687791503344266n), + ]; + expect(timestamps.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { { - const entry = parser.getTraceEntry(19446131807000)!; + const timestamp = new Timestamp(TimestampType.ELAPSED, 144857685000n); + const entry = parser.getTraceEntry(timestamp)!; expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry); expect(Number(entry.videoTimeSeconds)).toBeCloseTo(0); } { - const entry = parser.getTraceEntry(19448501007000)!; + const timestamp = new Timestamp(TimestampType.ELAPSED, 145300550000n); + const entry = parser.getTraceEntry(timestamp)!; expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry); - expect(Number(entry.videoTimeSeconds)).toBeCloseTo(2.37, 0.001); + expect(Number(entry.videoTimeSeconds)).toBeCloseTo(0.442, 0.001); + } + }); + + it("retrieves trace entry from real timestamp", () => { + { + const timestamp = new Timestamp(TimestampType.REAL, 1659687791485257266n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry); + expect(Number(entry.videoTimeSeconds)).toBeCloseTo(0); + } + + { + const timestamp = new Timestamp(TimestampType.REAL, 1659687791928122266n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry); + expect(Number(entry.videoTimeSeconds)).toBeCloseTo(0.322, 0.001); } }); }); diff --git a/tools/winscope-ng/src/parsers/parser_screen_recording.ts b/tools/winscope-ng/src/parsers/parser_screen_recording.ts index 465120f07..92dc05867 100644 --- a/tools/winscope-ng/src/parsers/parser_screen_recording.ts +++ b/tools/winscope-ng/src/parsers/parser_screen_recording.ts @@ -13,38 +13,72 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +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 ScreenRecordingMetadataEntry { + constructor(public timestampMonotonicNs: bigint, public timestampRealtimeNs: bigint) { + } +} + class ParserScreenRecording extends Parser { constructor(trace: Blob) { super(trace); } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.SCREEN_RECORDING; + override getTraceType(): TraceType { + return TraceType.SCREEN_RECORDING; } override getMagicNumber(): number[] { return ParserScreenRecording.MPEG4_MAGIC_NMBER; } - override decodeTrace(videoData: Uint8Array): number[] { - const posCount = this.searchMagicString(videoData); - const [posTimestamps, count] = this.parseTimestampsCount(videoData, posCount); - return this.parseTimestamps(videoData, posTimestamps, count); + override decodeTrace(videoData: Uint8Array): ScreenRecordingMetadataEntry[] { + const posVersion = this.searchMagicString(videoData); + const [posTimeOffset, metadataVersion] = this.parseMetadataVersion(videoData, posVersion); + if (metadataVersion !== 1) { + throw TypeError(`Metadata version "${metadataVersion}" not supported`); + } + const [posCount, timeOffsetNs] = this.parseRealToMonotonicTimeOffsetNs(videoData, posTimeOffset); + const [posTimestamps, count] = this.parseFramesCount(videoData, posCount); + const timestampsMonotonicNs = this.parseTimestampsMonotonicNs(videoData, posTimestamps, count); + + return timestampsMonotonicNs.map((timestampMonotonicNs: bigint) => { + return new ScreenRecordingMetadataEntry(timestampMonotonicNs, timestampMonotonicNs + timeOffsetNs); + }); } - override getTimestamp(decodedEntry: number): number { - return decodedEntry; + override getTimestamp(type: TimestampType, decodedEntry: ScreenRecordingMetadataEntry): undefined|Timestamp { + if (type !== TimestampType.ELAPSED && type !== TimestampType.REAL) { + return undefined; + } + if (type === TimestampType.ELAPSED) { + // Traces typically contain "elapsed" timestamps (SYSTEM_TIME_BOOTTIME), + // whereas screen recordings contain SYSTEM_TIME_MONOTONIC timestamps. + // + // Here we are pretending that screen recordings contain "elapsed" timestamps + // as well, in order to synchronize with the other traces. + // + // If no device suspensions are involved, SYSTEM_TIME_MONOTONIC should indeed + // correspond to SYSTEM_TIME_BOOTTIME and things will work as expected. + return new Timestamp(type, decodedEntry.timestampMonotonicNs); + } + else if (type === TimestampType.REAL) { + return new Timestamp(type, decodedEntry.timestampRealtimeNs); + } + return undefined; } - override processDecodedEntry(timestamp: number): ScreenRecordingTraceEntry { - const videoTimeSeconds = (timestamp - this.timestamps[0]) / 1000000000 + ParserScreenRecording.EPSILON; + override processDecodedEntry(entry: ScreenRecordingMetadataEntry): ScreenRecordingTraceEntry { + const initialTimestampNs = this.getTimestamps(TimestampType.ELAPSED)![0].getValueNs(); + const currentTimestampNs = entry.timestampMonotonicNs; + const videoTimeSeconds = Number(currentTimestampNs - initialTimestampNs) / 1000000000; const videoData = this.trace; - return new ScreenRecordingTraceEntry(timestamp, videoTimeSeconds, videoData); + return new ScreenRecordingTraceEntry(videoTimeSeconds, videoData); } private searchMagicString(videoData: Uint8Array): number { @@ -56,22 +90,40 @@ class ParserScreenRecording extends Parser { return pos; } - private parseTimestampsCount(videoData: Uint8Array, pos: number) : [number, number] { - if (pos + 4 >= videoData.length) { - throw new TypeError("video data is too short. Expected timestamps count doesn't fit"); + private parseMetadataVersion(videoData: Uint8Array, pos: number) : [number, number] { + if (pos + 4 > videoData.length) { + throw new TypeError("Failed to parse metadata version. Video data is too short."); } - const timestampsCount = ArrayUtils.toUintLittleEndian(videoData, pos, pos+4); + const version = Number(ArrayUtils.toUintLittleEndian(videoData, pos, pos+4)); pos += 4; - return [pos, timestampsCount]; + return [pos, version]; } - private parseTimestamps(videoData: Uint8Array, pos: number, count: number): number[] { - if (pos + count * 8 >= videoData.length) { - throw new TypeError("video data is too short. Expected timestamps do not fit"); + private parseRealToMonotonicTimeOffsetNs(videoData: Uint8Array, pos: number) : [number, bigint] { + if (pos + 8 > videoData.length) { + throw new TypeError("Failed to parse realtime-to-monotonic time offset. Video data is too short."); } - const timestamps: number[] = []; + const offset = ArrayUtils.toIntLittleEndian(videoData, pos, pos+8); + pos += 8; + return [pos, offset]; + } + + private parseFramesCount(videoData: Uint8Array, pos: number) : [number, number] { + if (pos + 4 > videoData.length) { + throw new TypeError("Failed to parse frames count. Video data is too short."); + } + const count = Number(ArrayUtils.toUintLittleEndian(videoData, pos, pos+4)); + pos += 4; + return [pos, count]; + } + + private parseTimestampsMonotonicNs(videoData: Uint8Array, pos: number, count: number) : bigint[] { + if (pos + count * 16 > videoData.length) { + throw new TypeError("Failed to parse monotonic timestamps. Video data is too short."); + } + const timestamps: bigint[] = []; for (let i = 0; i < count; ++i) { - const timestamp = ArrayUtils.toUintLittleEndian(videoData, pos, pos+8) * 1000; + const timestamp = ArrayUtils.toUintLittleEndian(videoData, pos, pos+8); pos += 8; timestamps.push(timestamp); } @@ -79,8 +131,7 @@ class ParserScreenRecording extends Parser { } private static readonly MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42 - private static readonly WINSCOPE_META_MAGIC_STRING = [0x23, 0x56, 0x56, 0x31, 0x4e, 0x53, 0x43, 0x30, 0x50, 0x45, 0x54, 0x31, 0x4d, 0x45, 0x21, 0x23]; // #VV1NSC0PET1ME!# - private static readonly EPSILON = 0.00001; + private static readonly WINSCOPE_META_MAGIC_STRING = [0x23, 0x56, 0x56, 0x31, 0x4e, 0x53, 0x43, 0x30, 0x50, 0x45, 0x54, 0x31, 0x4d, 0x45, 0x32, 0x23]; // #VV1NSC0PET1ME2# } export {ParserScreenRecording}; diff --git a/tools/winscope-ng/src/parsers/parser_screen_recording_legacy.spec.ts b/tools/winscope-ng/src/parsers/parser_screen_recording_legacy.spec.ts new file mode 100644 index 000000000..a0c8b76f1 --- /dev/null +++ b/tools/winscope-ng/src/parsers/parser_screen_recording_legacy.spec.ts @@ -0,0 +1,76 @@ +/* + * 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 {ScreenRecordingTraceEntry} from "common/trace/screen_recording"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; +import {UnitTestUtils} from "test/unit/utils"; +import {Parser} from "./parser"; + +describe("ParserScreenRecordingLegacy", () => { + let parser: Parser; + + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/screen_recording.mp4"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.SCREEN_RECORDING); + }); + + it("provides elapsed timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!; + + expect(timestamps.length) + .toEqual(85); + + let expected = [ + new Timestamp(TimestampType.ELAPSED, 19446131807000n), + new Timestamp(TimestampType.ELAPSED, 19446158500000n), + new Timestamp(TimestampType.ELAPSED, 19446167117000n), + ]; + expect(timestamps.slice(0, 3)) + .toEqual(expected); + + expected = [ + new Timestamp(TimestampType.ELAPSED, 19448470076000n), + new Timestamp(TimestampType.ELAPSED, 19448487525000n), + new Timestamp(TimestampType.ELAPSED, 19448501007000n), + ]; + expect(timestamps.slice(timestamps.length-3, timestamps.length)) + .toEqual(expected); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); + + it("retrieves trace entry", () => { + { + const timestamp = new Timestamp(TimestampType.ELAPSED, 19446131807000n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry); + expect(Number(entry.videoTimeSeconds)).toBeCloseTo(0); + } + + { + const timestamp = new Timestamp(TimestampType.ELAPSED, 19448501007000n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry); + expect(Number(entry.videoTimeSeconds)).toBeCloseTo(2.37, 0.001); + } + }); +}); diff --git a/tools/winscope-ng/src/parsers/parser_screen_recording_legacy.ts b/tools/winscope-ng/src/parsers/parser_screen_recording_legacy.ts new file mode 100644 index 000000000..71c57a263 --- /dev/null +++ b/tools/winscope-ng/src/parsers/parser_screen_recording_legacy.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 {Timestamp, TimestampType} from "common/trace/timestamp"; +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: Blob) { + super(trace); + } + + override getTraceType(): TraceType { + return TraceType.SCREEN_RECORDING; + } + + override getMagicNumber(): number[] { + return ParserScreenRecordingLegacy.MPEG4_MAGIC_NMBER; + } + + override decodeTrace(videoData: Uint8Array): Timestamp[] { + const posCount = this.searchMagicString(videoData); + const [posTimestamps, count] = this.parseFramesCount(videoData, posCount); + return this.parseTimestamps(videoData, posTimestamps, count); + } + + override getTimestamp(type: TimestampType, decodedEntry: Timestamp): undefined|Timestamp { + if (type !== TimestampType.ELAPSED) { + return undefined; + } + return decodedEntry; + } + + override processDecodedEntry(entry: Timestamp): ScreenRecordingTraceEntry { + const currentTimestamp = entry; + const initialTimestamp = this.getTimestamps(TimestampType.ELAPSED)![0]; + const videoTimeSeconds = + Number(currentTimestamp.getValueNs() - initialTimestamp.getValueNs()) / 1000000000 + + ParserScreenRecordingLegacy.EPSILON; + const videoData = this.trace; + return new ScreenRecordingTraceEntry(videoTimeSeconds, videoData); + } + + private searchMagicString(videoData: Uint8Array): number { + let pos = ArrayUtils.searchSubarray(videoData, ParserScreenRecordingLegacy.WINSCOPE_META_MAGIC_STRING); + if (pos === undefined) { + throw new TypeError("video data doesn't contain winscope magic string"); + } + pos += ParserScreenRecordingLegacy.WINSCOPE_META_MAGIC_STRING.length; + return pos; + } + + private parseFramesCount(videoData: Uint8Array, pos: number) : [number, number] { + if (pos + 4 > videoData.length) { + throw new TypeError("Failed to parse frames count. Video data is too short."); + } + const framesCount = Number(ArrayUtils.toUintLittleEndian(videoData, pos, pos+4)); + pos += 4; + return [pos, framesCount]; + } + + private parseTimestamps(videoData: Uint8Array, pos: number, count: number): Timestamp[] { + if (pos + count * 8 > videoData.length) { + throw new TypeError("Failed to parse timestamps. Video data is too short."); + } + const timestamps: Timestamp[] = []; + for (let i = 0; i < count; ++i) { + const value = ArrayUtils.toUintLittleEndian(videoData, pos, pos+8) * 1000n; + pos += 8; + timestamps.push(new Timestamp(TimestampType.ELAPSED, value)); + } + return timestamps; + } + + private static readonly MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42 + private static readonly WINSCOPE_META_MAGIC_STRING = [0x23, 0x56, 0x56, 0x31, 0x4e, 0x53, 0x43, 0x30, 0x50, 0x45, 0x54, 0x31, 0x4d, 0x45, 0x21, 0x23]; // #VV1NSC0PET1ME!# + private static readonly EPSILON = 0.00001; +} + +export {ParserScreenRecordingLegacy}; diff --git a/tools/winscope-ng/src/parsers/parser_surface_flinger.spec.ts b/tools/winscope-ng/src/parsers/parser_surface_flinger.spec.ts index aa4b6c8f3..d67494dd6 100644 --- a/tools/winscope-ng/src/parsers/parser_surface_flinger.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_surface_flinger.spec.ts @@ -13,34 +13,78 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {LayerTraceEntry} from "common/trace/flickerlib/layers/LayerTraceEntry"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; import {Parser} from "./parser"; -import {ParserFactory} from "./parser_factory"; describe("ParserSurfaceFlinger", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_SurfaceFlinger.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/SurfaceFlinger.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.SURFACE_FLINGER); + }); + + it("provides elapsed timestamps", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 14500282843n), + new Timestamp(TimestampType.ELAPSED, 14631249355n), + new Timestamp(TimestampType.ELAPSED, 15403446377n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)!.slice(0, 3)) + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 1659107089102062832n), + new Timestamp(TimestampType.REAL, 1659107089233029344n), + new Timestamp(TimestampType.REAL, 1659107090005226366n), + ]; + expect(parser.getTimestamps(TimestampType.REAL)!.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 14631249355n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(LayerTraceEntry); + expect(BigInt(entry.timestampMs)).toEqual(14631249355n); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089233029344n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(LayerTraceEntry); + expect(BigInt(entry.timestampMs)).toEqual(14631249355n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.SURFACE_FLINGER); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([850335483446, 850686322883, 850736507697]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/SurfaceFlinger.pb"); + }); - it("retrieves trace entry", () => { - const entry = parser.getTraceEntry(850335483446)!; - expect(entry).toBeInstanceOf(LayerTraceEntry); - expect(Number(entry.timestampMs)).toEqual(850335483446); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.SURFACE_FLINGER); + }); + + it("provides elapsed timestamps", () => { + expect(parser.getTimestamps(TimestampType.ELAPSED)![0]) + .toEqual(new Timestamp(TimestampType.ELAPSED, 850335483446n)); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_surface_flinger.ts b/tools/winscope-ng/src/parsers/parser_surface_flinger.ts index 15eb57f57..62a6a73f9 100644 --- a/tools/winscope-ng/src/parsers/parser_surface_flinger.ts +++ b/tools/winscope-ng/src/parsers/parser_surface_flinger.ts @@ -13,18 +13,20 @@ * 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 {TraceTypeId} from "common/trace/type_id"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {LayersTraceFileProto} from "./proto_types"; class ParserSurfaceFlinger extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.SURFACE_FLINGER; + override getTraceType(): TraceType { + return TraceType.SURFACE_FLINGER; } override getMagicNumber(): number[] { @@ -32,17 +34,36 @@ class ParserSurfaceFlinger extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { - return (LayersTraceFileProto.decode(buffer)).entry; + const decoded = LayersTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return decoded.entry; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + const isDump = !Object.prototype.hasOwnProperty.call(entryProto, "elapsedRealtimeNanos"); + if (type === TimestampType.ELAPSED) { + return isDump + ? new Timestamp(type, 0n) + : new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { + return isDump + ? new Timestamp(type, 0n) + : new Timestamp(type, this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos)); + } + return undefined; } override processDecodedEntry(entryProto: any): any { return LayerTraceEntry.fromProto(entryProto.layers.layers, entryProto.displays, entryProto.elapsedRealtimeNanos, entryProto.hwcBlob); } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE } diff --git a/tools/winscope-ng/src/parsers/parser_surface_flinger_dump.spec.ts b/tools/winscope-ng/src/parsers/parser_surface_flinger_dump.spec.ts index 5fdb0697d..e32da20e2 100644 --- a/tools/winscope-ng/src/parsers/parser_surface_flinger_dump.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_surface_flinger_dump.spec.ts @@ -13,33 +13,73 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {LayerTraceEntry} from "common/trace/flickerlib/layers/LayerTraceEntry"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; import {Parser} from "./parser"; -import {ParserFactory} from "./parser_factory"; describe("ParserSurfaceFlingerDump", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("dump_SurfaceFlinger.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/dump_SurfaceFlinger.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.SURFACE_FLINGER); + }); + + it("provides elapsed timestamp", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 0n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)).toEqual(expected); + }); + + it("provides real timestamp (always zero)", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 0n), + ]; + expect(parser.getTimestamps(TimestampType.REAL)).toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 0n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(LayerTraceEntry); + expect(BigInt(entry.timestampMs)).toEqual(0n); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 0n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(LayerTraceEntry); + expect(BigInt(entry.timestampMs)).toEqual(0n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.SURFACE_FLINGER); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamp", () => { - expect(parser.getTimestamps()).toEqual([0]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/dump_SurfaceFlinger.pb"); + }); - it("retrieves trace entry", () => { - const entry = parser.getTraceEntry(0)!; - expect(entry).toBeInstanceOf(LayerTraceEntry); - expect(Number(entry.timestampMs)).toEqual(0); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.SURFACE_FLINGER); + }); + + it("provides elapsed timestamp (always zero)", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 0n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)).toEqual(expected); + }); + + it("doesn't provide real timestamp", () => { + expect(parser.getTimestamps(TimestampType.REAL)).toEqual(undefined); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_transactions.spec.ts b/tools/winscope-ng/src/parsers/parser_transactions.spec.ts index 6a195e590..2bbf63973 100644 --- a/tools/winscope-ng/src/parsers/parser_transactions.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_transactions.spec.ts @@ -13,35 +13,95 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {ParserFactory} from "./parser_factory"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserTransactions", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_Transactions.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/Transactions.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.TRANSACTIONS); + }); + + it("provides elapsed timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!; + + expect(timestamps.length) + .toEqual(712); + + const expected = [ + new Timestamp(TimestampType.ELAPSED, 2450981445n), + new Timestamp(TimestampType.ELAPSED, 2517952515n), + new Timestamp(TimestampType.ELAPSED, 4021151449n), + ]; + expect(timestamps.slice(0, 3)) + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.REAL)!; + + expect(timestamps.length) + .toEqual(712); + + const expected = [ + new Timestamp(TimestampType.REAL, 1659507541051480997n), + new Timestamp(TimestampType.REAL, 1659507541118452067n), + new Timestamp(TimestampType.REAL, 1659507542621651001n), + ]; + expect(timestamps.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry from elsapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 2517952515n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(2517952515n); + }); + + it("retrieves trace entry from real timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659507541118452067n); + expect(BigInt(parser.getTraceEntry(timestamp)!.elapsedRealtimeNanos)) + .toEqual(2517952515n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.TRANSACTIONS); - }); + describe("trace with elapsed (only) timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - const timestamps = parser.getTimestamps(); - expect(timestamps.length) - .toEqual(4997); - expect(timestamps.slice(0, 3)) - .toEqual([14862317023, 14873423549, 14884850511]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/Transactions.pb"); + }); - it("retrieves trace entry", () => { - expect(Number(parser.getTraceEntry(14862317023)!.elapsedRealtimeNanos)) - .toEqual(14862317023); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.TRANSACTIONS); + }); + + it("provides elapsed timestamps", () => { + const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!; + + expect(timestamps.length) + .toEqual(4997); + + const expected = [ + new Timestamp(TimestampType.ELAPSED, 14862317023n), + new Timestamp(TimestampType.ELAPSED, 14873423549n), + new Timestamp(TimestampType.ELAPSED, 14884850511n), + ]; + expect(timestamps.slice(0, 3)) + .toEqual(expected); + }); + + it("doesn't provide real timestamps", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_transactions.ts b/tools/winscope-ng/src/parsers/parser_transactions.ts index 3aecb54ff..6af4c4c55 100644 --- a/tools/winscope-ng/src/parsers/parser_transactions.ts +++ b/tools/winscope-ng/src/parsers/parser_transactions.ts @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {TransactionsTraceFileProto} from "./proto_types"; +import {AccessibilityTraceFileProto, TransactionsTraceFileProto} from "./proto_types"; class ParserTransactions extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.TRANSACTIONS; + override getTraceType(): TraceType { + return TraceType.TRANSACTIONS; } override getMagicNumber(): number[] { @@ -31,17 +33,31 @@ class ParserTransactions extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { - return (TransactionsTraceFileProto.decode(buffer)).entry; + const decoded = TransactionsTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return decoded.entry; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type === TimestampType.ELAPSED) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { + return new Timestamp(type, this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos)); + } + return undefined; } override processDecodedEntry(entryProto: any): any { return entryProto; } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x54, 0x4e, 0x58, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TNXTRACE } diff --git a/tools/winscope-ng/src/parsers/parser_window_manager.spec.ts b/tools/winscope-ng/src/parsers/parser_window_manager.spec.ts index 1d4fe1389..3c50fc02b 100644 --- a/tools/winscope-ng/src/parsers/parser_window_manager.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_window_manager.spec.ts @@ -14,33 +14,84 @@ * limitations under the License. */ import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState"; -import {TraceTypeId} from "common/trace/type_id"; -import {ParserFactory} from "./parser_factory"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserWindowManager", () => { - let parser: Parser; + describe("trace with elapsed + real timestamp", () => { + let parser: Parser; - beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("trace_WindowManager.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_and_real_timestamp/WindowManager.pb"); + }); + + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.WINDOW_MANAGER); + }); + + it("provides elapsed timestamps", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 14474594000n), + new Timestamp(TimestampType.ELAPSED, 15398076788n), + new Timestamp(TimestampType.ELAPSED, 15409222011n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)!.slice(0, 3)) + .toEqual(expected); + }); + + it("provides real timestamps", () => { + const expected = [ + new Timestamp(TimestampType.REAL, 1659107089075566202n), + new Timestamp(TimestampType.REAL, 1659107089999048990n), + new Timestamp(TimestampType.REAL, 1659107090010194213n), + ]; + expect(parser.getTimestamps(TimestampType.REAL)!.slice(0, 3)) + .toEqual(expected); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 15398076788n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(WindowManagerState); + expect(BigInt(entry.timestampMs)).toEqual(15398076788n); + }); + + it("retrieves trace entry from real timestamp", () => { + const timestamp = new Timestamp(TimestampType.REAL, 1659107089999048990n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(WindowManagerState); + expect(BigInt(entry.timestampMs)).toEqual(15398076788n); + }); }); - it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.WINDOW_MANAGER); - }); + describe("trace elapsed timestamp", () => { + let parser: Parser; - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([850254319343, 850763506110, 850782750048]); - }); + beforeAll(async () => { + parser = await UnitTestUtils.getParser("traces/elapsed_timestamp/WindowManager.pb"); + }); - it("retrieves trace entry", () => { - const entry = parser.getTraceEntry(850254319343)!; - expect(entry).toBeInstanceOf(WindowManagerState); - expect(Number(entry.timestampMs)).toEqual(850254319343); + it("has expected trace type", () => { + expect(parser.getTraceType()).toEqual(TraceType.WINDOW_MANAGER); + }); + + it("provides timestamps", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 850254319343n), + new Timestamp(TimestampType.ELAPSED, 850763506110n), + new Timestamp(TimestampType.ELAPSED, 850782750048n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)) + .toEqual(expected); + }); + + it("retrieves trace entry", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 850254319343n); + const entry = parser.getTraceEntry(timestamp)!; + expect(entry).toBeInstanceOf(WindowManagerState); + expect(BigInt(entry.timestampMs)).toEqual(850254319343n); + }); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_window_manager.ts b/tools/winscope-ng/src/parsers/parser_window_manager.ts index 820143ed1..08a6f6004 100644 --- a/tools/winscope-ng/src/parsers/parser_window_manager.ts +++ b/tools/winscope-ng/src/parsers/parser_window_manager.ts @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {WindowManagerTraceFileProto} from "./proto_types"; import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState"; @@ -21,10 +22,11 @@ import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerS class ParserWindowManager extends Parser { constructor(trace: Blob) { super(trace); + this.realToElapsedTimeOffsetNs = undefined; } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.WINDOW_MANAGER; + override getTraceType(): TraceType { + return TraceType.WINDOW_MANAGER; } override getMagicNumber(): number[] { @@ -32,17 +34,31 @@ class ParserWindowManager extends Parser { } override decodeTrace(buffer: Uint8Array): any[] { - return (WindowManagerTraceFileProto.decode(buffer)).entry; + const decoded = WindowManagerTraceFileProto.decode(buffer); + if (Object.prototype.hasOwnProperty.call(decoded, "realToElapsedTimeOffsetNanos")) { + this.realToElapsedTimeOffsetNs = BigInt(decoded.realToElapsedTimeOffsetNanos); + } + else { + this.realToElapsedTimeOffsetNs = undefined; + } + return decoded.entry; } - override getTimestamp(entryProto: any): number { - return Number(entryProto.elapsedRealtimeNanos); + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type === TimestampType.ELAPSED) { + return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); + } + else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { + return new Timestamp(type, this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos)); + } + return undefined; } override processDecodedEntry(entryProto: any): WindowManagerState { return WindowManagerState.fromProto(entryProto.windowManagerService, entryProto.elapsedRealtimeNanos, entryProto.where); } + private realToElapsedTimeOffsetNs: undefined|bigint; private static readonly MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE } diff --git a/tools/winscope-ng/src/parsers/parser_window_manager_dump.spec.ts b/tools/winscope-ng/src/parsers/parser_window_manager_dump.spec.ts index 62138353e..107400042 100644 --- a/tools/winscope-ng/src/parsers/parser_window_manager_dump.spec.ts +++ b/tools/winscope-ng/src/parsers/parser_window_manager_dump.spec.ts @@ -14,33 +14,39 @@ * limitations under the License. */ import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState"; -import {TraceTypeId} from "common/trace/type_id"; -import {ParserFactory} from "./parser_factory"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; -import {TestUtils} from "test/test_utils"; +import {UnitTestUtils} from "test/unit/utils"; describe("ParserWindowManagerDump", () => { let parser: Parser; beforeAll(async () => { - const buffer = TestUtils.getFixtureBlob("dump_WindowManager.pb"); - const parsers = await new ParserFactory().createParsers([buffer]); - expect(parsers.length).toEqual(1); - parser = parsers[0]; + parser = await UnitTestUtils.getParser("traces/dump_WindowManager.pb"); }); it("has expected trace type", () => { - expect(parser.getTraceTypeId()).toEqual(TraceTypeId.WINDOW_MANAGER); + expect(parser.getTraceType()).toEqual(TraceType.WINDOW_MANAGER); }); - it("provides timestamps", () => { - expect(parser.getTimestamps()) - .toEqual([0]); + it("provides elapsed timestamp (always zero)", () => { + const expected = [ + new Timestamp(TimestampType.ELAPSED, 0n), + ]; + expect(parser.getTimestamps(TimestampType.ELAPSED)) + .toEqual(expected); }); - it("retrieves trace entry", () => { - const entry = parser.getTraceEntry(0)!; + it("doesn't provide real timestamp (never)", () => { + expect(parser.getTimestamps(TimestampType.REAL)) + .toEqual(undefined); + }); + + it("retrieves trace entry from elapsed timestamp", () => { + const timestamp = new Timestamp(TimestampType.ELAPSED, 0n); + const entry = parser.getTraceEntry(timestamp)!; expect(entry).toBeInstanceOf(WindowManagerState); - expect(Number(entry.timestampMs)).toEqual(0); + expect(BigInt(entry.timestampMs)).toEqual(0n); }); }); diff --git a/tools/winscope-ng/src/parsers/parser_window_manager_dump.ts b/tools/winscope-ng/src/parsers/parser_window_manager_dump.ts index 2b4f9ae0a..0e93e4728 100644 --- a/tools/winscope-ng/src/parsers/parser_window_manager_dump.ts +++ b/tools/winscope-ng/src/parsers/parser_window_manager_dump.ts @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; +import {TraceType} from "common/trace/trace_type"; import {Parser} from "./parser"; import {WindowManagerServiceDumpProto} from "./proto_types"; import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState"; @@ -23,8 +24,8 @@ class ParserWindowManagerDump extends Parser { super(trace); } - override getTraceTypeId(): TraceTypeId { - return TraceTypeId.WINDOW_MANAGER; + override getTraceType(): TraceType { + return TraceType.WINDOW_MANAGER; } override getMagicNumber(): undefined { @@ -35,8 +36,11 @@ class ParserWindowManagerDump extends Parser { return [WindowManagerServiceDumpProto.decode(buffer)]; } - override getTimestamp(entryProto: any): number { - return 0; + override getTimestamp(type: TimestampType, entryProto: any): undefined|Timestamp { + if (type !== TimestampType.ELAPSED) { + return undefined; + } + return new Timestamp(TimestampType.ELAPSED, 0n); } override processDecodedEntry(entryProto: any): WindowManagerState { diff --git a/tools/winscope-ng/src/test/blob.ts b/tools/winscope-ng/src/test/common/blob.ts similarity index 100% rename from tools/winscope-ng/src/test/blob.ts rename to tools/winscope-ng/src/test/common/blob.ts diff --git a/tools/winscope-ng/src/test/test_utils.ts b/tools/winscope-ng/src/test/common/utils.ts similarity index 67% rename from tools/winscope-ng/src/test/test_utils.ts rename to tools/winscope-ng/src/test/common/utils.ts index dcb05487e..041f82617 100644 --- a/tools/winscope-ng/src/test/test_utils.ts +++ b/tools/winscope-ng/src/test/common/utils.ts @@ -17,27 +17,30 @@ import * as fs from "fs"; import * as path from "path"; import {Blob} from "./blob"; -class TestUtils { +class CommonTestUtils { static getFixtureBlob(filename: string): Blob { - const buffer = TestUtils.loadFixture(filename); + const buffer = CommonTestUtils.loadFixture(filename); return new Blob(buffer); } static loadFixture(filename: string): ArrayBuffer { - return fs.readFileSync(TestUtils.getFixturePath(filename)); + return fs.readFileSync(CommonTestUtils.getFixturePath(filename)); } static getFixturePath(filename: string): string { - return path.join(TestUtils.getProjectRootPath(), "src/test/fixtures", filename); - } - - static getProductionIndexHtmlPath(): string { - return path.join(TestUtils.getProjectRootPath(), "dist/prod/index.html"); + if (path.isAbsolute(filename)) { + return filename; + } + return path.join(CommonTestUtils.getProjectRootPath(), "src/test/fixtures", filename); } static getProjectRootPath(): string { - return path.join(__dirname, "../.."); + let root = __dirname; + while (path.basename(root) !== "winscope-ng") { + root = path.dirname(root); + } + return root; } } -export {TestUtils}; +export {CommonTestUtils}; diff --git a/tools/winscope-ng/src/test/e2e/utils.ts b/tools/winscope-ng/src/test/e2e/utils.ts new file mode 100644 index 000000000..a286b7db6 --- /dev/null +++ b/tools/winscope-ng/src/test/e2e/utils.ts @@ -0,0 +1,25 @@ +/* + * 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 * as path from "path"; +import {CommonTestUtils} from "../common/utils"; + +class E2eTestUtils extends CommonTestUtils { + static getProductionIndexHtmlPath(): string { + return path.join(CommonTestUtils.getProjectRootPath(), "dist/prod/index.html"); + } +} + +export {E2eTestUtils}; diff --git a/tools/winscope-ng/src/test/e2e/viewer_window_manager.spec.ts b/tools/winscope-ng/src/test/e2e/viewer_window_manager.spec.ts index 0b8da4979..501fcfbc3 100644 --- a/tools/winscope-ng/src/test/e2e/viewer_window_manager.spec.ts +++ b/tools/winscope-ng/src/test/e2e/viewer_window_manager.spec.ts @@ -14,17 +14,17 @@ * limitations under the License. */ import {browser, element, by} from "protractor"; -import {TestUtils} from "../test_utils"; +import {E2eTestUtils} from "./utils"; describe("Viewer WindowManager", () => { beforeAll(async () => { browser.manage().timeouts().implicitlyWait(1000); - browser.get("file://" + TestUtils.getProductionIndexHtmlPath()); + browser.get("file://" + E2eTestUtils.getProductionIndexHtmlPath()); }), it("processes trace and renders view", () => { const inputFile = element(by.css("input[type=\"file\"]")); - inputFile.sendKeys(TestUtils.getFixturePath("trace_WindowManager.pb")); + inputFile.sendKeys(E2eTestUtils.getFixturePath("traces/elapsed_and_real_timestamp/WindowManager.pb")); const windowManagerViewerTitle = element(by.css(".viewer-window-manager .title")); expect(windowManagerViewerTitle.getText()).toContain("Window Manager"); diff --git a/tools/winscope-ng/src/test/e2e/winscope.spec.ts b/tools/winscope-ng/src/test/e2e/winscope.spec.ts index 5cb0d605d..ac7032ad1 100644 --- a/tools/winscope-ng/src/test/e2e/winscope.spec.ts +++ b/tools/winscope-ng/src/test/e2e/winscope.spec.ts @@ -14,11 +14,11 @@ * limitations under the License. */ import {browser, element, by} from "protractor"; -import {TestUtils} from "../test_utils"; +import {E2eTestUtils} from "./utils"; describe("winscope", () => { beforeAll(() => { - browser.get("file://" + TestUtils.getProductionIndexHtmlPath()); + browser.get("file://" + E2eTestUtils.getProductionIndexHtmlPath()); }), it("has title", () => { diff --git a/tools/winscope-ng/src/test/fixtures/dump_WindowManager.pb b/tools/winscope-ng/src/test/fixtures/traces/dump_WindowManager.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/dump_WindowManager.pb rename to tools/winscope-ng/src/test/fixtures/traces/dump_WindowManager.pb diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/Accessibility.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/Accessibility.pb new file mode 100644 index 000000000..6780f22ea Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/Accessibility.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodClients.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodClients.pb new file mode 100644 index 000000000..b70ea7f3c Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodClients.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodManagerService.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodManagerService.pb new file mode 100644 index 000000000..cf5f0caf7 Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodManagerService.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodService.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodService.pb new file mode 100644 index 000000000..4b7c330cd Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/InputMethodService.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/trace_ProtoLog.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/ProtoLog.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_ProtoLog.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/ProtoLog.pb diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/SurfaceFlinger.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/SurfaceFlinger.pb new file mode 100644 index 000000000..d26f5cc79 Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/SurfaceFlinger.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/Transactions.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/Transactions.pb new file mode 100644 index 000000000..3ffe81a0f Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/Transactions.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/WindowManager.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/WindowManager.pb new file mode 100644 index 000000000..7749b4bc7 Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/WindowManager.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/dump_SurfaceFlinger.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/dump_SurfaceFlinger.pb new file mode 100644 index 000000000..b5b884f0e Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/dump_SurfaceFlinger.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/screen_recording.mp4 b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/screen_recording.mp4 new file mode 100644 index 000000000..0d28a1d71 Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/elapsed_and_real_timestamp/screen_recording.mp4 differ diff --git a/tools/winscope-ng/src/test/fixtures/trace_Accessibility.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/Accessibility.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_Accessibility.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/Accessibility.pb diff --git a/tools/winscope-ng/src/test/fixtures/trace_InputMethodClients.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/InputMethodClients.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_InputMethodClients.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/InputMethodClients.pb diff --git a/tools/winscope-ng/src/test/fixtures/trace_InputMethodManagerService.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/InputMethodManagerService.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_InputMethodManagerService.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/InputMethodManagerService.pb diff --git a/tools/winscope-ng/src/test/fixtures/trace_InputMethodService.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/InputMethodService.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_InputMethodService.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/InputMethodService.pb diff --git a/tools/winscope-ng/src/test/fixtures/trace_SurfaceFlinger.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/SurfaceFlinger.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_SurfaceFlinger.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/SurfaceFlinger.pb diff --git a/tools/winscope-ng/src/test/fixtures/trace_Transactions.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/Transactions.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_Transactions.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/Transactions.pb diff --git a/tools/winscope-ng/src/test/fixtures/trace_WindowManager.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/WindowManager.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/trace_WindowManager.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/WindowManager.pb diff --git a/tools/winscope-ng/src/test/fixtures/dump_SurfaceFlinger.pb b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/dump_SurfaceFlinger.pb similarity index 100% rename from tools/winscope-ng/src/test/fixtures/dump_SurfaceFlinger.pb rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/dump_SurfaceFlinger.pb diff --git a/tools/winscope-ng/src/test/fixtures/screen_recording.mp4 b/tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/screen_recording.mp4 similarity index 100% rename from tools/winscope-ng/src/test/fixtures/screen_recording.mp4 rename to tools/winscope-ng/src/test/fixtures/traces/elapsed_timestamp/screen_recording.mp4 diff --git a/tools/winscope-ng/src/test/unit/utils.ts b/tools/winscope-ng/src/test/unit/utils.ts new file mode 100644 index 000000000..7d42d0d67 --- /dev/null +++ b/tools/winscope-ng/src/test/unit/utils.ts @@ -0,0 +1,29 @@ +/* + * 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 {Parser} from "parsers/parser"; +import {ParserFactory} from "parsers/parser_factory"; +import {CommonTestUtils} from "test/common/utils"; + +class UnitTestUtils extends CommonTestUtils { + static async getParser(filename: string): Promise { + const trace = CommonTestUtils.getFixtureBlob(filename); + const parsers = await new ParserFactory().createParsers([trace]); + expect(parsers.length).toEqual(1); + return parsers[0]; + } +} + +export {UnitTestUtils}; diff --git a/tools/winscope-ng/src/viewers/viewer.ts b/tools/winscope-ng/src/viewers/viewer.ts index b8ef3ece2..5c66d09b2 100644 --- a/tools/winscope-ng/src/viewers/viewer.ts +++ b/tools/winscope-ng/src/viewers/viewer.ts @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TraceTypeId } from "common/trace/type_id"; +import { TraceType } from "common/trace/trace_type"; interface Viewer { //TODO: add TraceEntry data type - notifyCurrentTraceEntries(entries: Map): void; + notifyCurrentTraceEntries(entries: Map): void; getView(): HTMLElement; } diff --git a/tools/winscope-ng/src/viewers/viewer_factory.ts b/tools/winscope-ng/src/viewers/viewer_factory.ts index 45bbacafd..82cf1e3c9 100644 --- a/tools/winscope-ng/src/viewers/viewer_factory.ts +++ b/tools/winscope-ng/src/viewers/viewer_factory.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TraceTypeId } from "common/trace/type_id"; +import { TraceType } from "common/trace/trace_type"; import { Viewer } from "./viewer"; import { ViewerWindowManager } from "./viewer_window_manager/viewer_window_manager"; @@ -22,11 +22,11 @@ class ViewerFactory { ViewerWindowManager, ]; - public createViewers(activeTraceTypes: Set): Viewer[] { + public createViewers(activeTraceTypes: Set): Viewer[] { const viewers: Viewer[] = []; for (const Viewer of ViewerFactory.VIEWERS) { - const areViewerDepsSatisfied = Viewer.DEPENDENCIES.every((traceType: TraceTypeId) => + const areViewerDepsSatisfied = Viewer.DEPENDENCIES.every((traceType: TraceType) => activeTraceTypes.has(traceType) ); diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts index d4ca2b2bc..30bf20fd9 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {TraceType} from "common/trace/trace_type"; import {UiData} from "./ui_data"; type UiDataCallbackType = (uiData: UiData) => void; @@ -25,7 +25,7 @@ class Presenter { this.uiDataCallback(this.uiData); } - public notifyCurrentTraceEntries(entries: Map) { + public notifyCurrentTraceEntries(entries: Map) { this.uiData = new UiData("UI data selected by user on time scrub"); this.uiDataCallback(this.uiData); } diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.ts index 697d744a3..1f4b1c400 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceTypeId} from "common/trace/type_id"; +import {TraceType} from "common/trace/trace_type"; import {Viewer} from "viewers/viewer"; import {Presenter} from "./presenter"; import {UiData} from "./ui_data"; @@ -27,7 +27,7 @@ class ViewerWindowManager implements Viewer { this.view.addEventListener("outputEvent", () => this.presenter.notifyUiEvent()); } - public notifyCurrentTraceEntries(entries: Map): void { + public notifyCurrentTraceEntries(entries: Map): void { this.presenter.notifyCurrentTraceEntries(entries); } @@ -35,7 +35,7 @@ class ViewerWindowManager implements Viewer { return this.view; } - public static readonly DEPENDENCIES: TraceTypeId[] = [TraceTypeId.WINDOW_MANAGER]; + public static readonly DEPENDENCIES: TraceType[] = [TraceType.WINDOW_MANAGER]; private view: HTMLElement; private presenter: Presenter; }